From ed970314cd352623faea8701e97b58bd01924e7f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Aug 2024 08:32:43 +0200 Subject: [PATCH 01/25] Bump crate-ci/typos from 1.22.9 to 1.23.6 (#2027) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.22.9 to 1.23.6. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/v1.22.9...v1.23.6) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/SpellCheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/SpellCheck.yml b/.github/workflows/SpellCheck.yml index 8f6d12179eb..71eea717691 100644 --- a/.github/workflows/SpellCheck.yml +++ b/.github/workflows/SpellCheck.yml @@ -10,4 +10,4 @@ jobs: - name: Checkout Actions Repository uses: actions/checkout@v4 - name: Check spelling - uses: crate-ci/typos@v1.22.9 + uses: crate-ci/typos@v1.23.6 From 50cf879cab9ef8a1d629b33239ced49aeb1d166f Mon Sep 17 00:00:00 2001 From: Valentin Churavy Date: Mon, 5 Aug 2024 14:47:09 +0200 Subject: [PATCH 02/25] Add a preference to disable Polyester (#2029) * Add preference to disable Polyester usage Co-authored-by: Hendrik Ranocha * Apply suggestions from code review Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> --------- Co-authored-by: Hendrik Ranocha Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> --- src/Trixi.jl | 1 + src/auxiliary/auxiliary.jl | 51 ++++++++++++++++------------------- src/auxiliary/math.jl | 15 +++++++++++ src/callbacks_step/summary.jl | 3 +++ src/solvers/dg.jl | 2 +- 5 files changed, 43 insertions(+), 29 deletions(-) diff --git a/src/Trixi.jl b/src/Trixi.jl index 1a509ed92d1..23a8cfe1d0a 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -80,6 +80,7 @@ using Preferences: @load_preference, set_preferences! const _PREFERENCE_SQRT = @load_preference("sqrt", "sqrt_Trixi_NaN") const _PREFERENCE_LOG = @load_preference("log", "log_Trixi_NaN") +const _PREFERENCE_POLYESTER = @load_preference("polyester", true) # finite difference SBP operators using SummationByPartsOperators: AbstractDerivativeOperator, diff --git a/src/auxiliary/auxiliary.jl b/src/auxiliary/auxiliary.jl index 6259e936737..97263405d2a 100644 --- a/src/auxiliary/auxiliary.jl +++ b/src/auxiliary/auxiliary.jl @@ -204,36 +204,31 @@ Some discussion can be found at [https://discourse.julialang.org/t/overhead-of-t and [https://discourse.julialang.org/t/threads-threads-with-one-thread-how-to-remove-the-overhead/58435](https://discourse.julialang.org/t/threads-threads-with-one-thread-how-to-remove-the-overhead/58435). """ macro threaded(expr) - # Use `esc(quote ... end)` for nested macro calls as suggested in - # https://github.com/JuliaLang/julia/issues/23221 - # - # The following code is a simple version using only `Threads.@threads` from the - # standard library with an additional check whether only a single thread is used - # to reduce some overhead (and allocations) for serial execution. - # - # return esc(quote - # let - # if Threads.nthreads() == 1 - # $(expr) - # else - # Threads.@threads $(expr) - # end - # end - # end) - # - # However, the code below using `@batch` from Polyester.jl is more efficient, - # since this packages provides threads with less overhead. Since it is written - # by Chris Elrod, the author of LoopVectorization.jl, we expect this package - # to provide the most efficient and useful implementation of threads (as we use - # them) available in Julia. # !!! danger "Heisenbug" # Look at the comments for `wrap_array` when considering to change this macro. - - # By using `Trixi.@batch` we allow users of Trixi.jl to use `@threaded` without having - # Polyester.jl in their namespace. - return esc(quote - Trixi.@batch $(expr) - end) + expr = if _PREFERENCE_POLYESTER + # Currently using `@batch` from Polyester.jl is more efficient, + # bypasses the Julia task scheduler and provides parallelization with less overhead. + quote + $Trixi.@batch $(expr) + end + else + # The following code is a simple version using only `Threads.@threads` from the + # standard library with an additional check whether only a single thread is used + # to reduce some overhead (and allocations) for serial execution. + quote + let + if $Threads.nthreads() == 1 + $(expr) + else + $Threads.@threads :static $(expr) + end + end + end + end + # Use `esc(quote ... end)` for nested macro calls as suggested in + # https://github.com/JuliaLang/julia/issues/23221 + return esc(expr) end """ diff --git a/src/auxiliary/math.jl b/src/auxiliary/math.jl index 9e3aaa181bf..0bd5ad438f3 100644 --- a/src/auxiliary/math.jl +++ b/src/auxiliary/math.jl @@ -7,6 +7,21 @@ const TRIXI_UUID = UUID("a7f1ee26-1774-49b1-8366-f1abc58fbfcb") +""" + Trixi.set_polyester!(toggle::Bool; force = true) + +Toggle the usage of [Polyester.jl](https://github.com/JuliaSIMD/Polyester.jl) for multithreading. +By default, Polyester.jl is enabled, but it can +be useful for performance comparisons to switch to the Julia core backend. + +This does not fully disable Polyester.jl, +buy only its use as part of Trixi.jl's `@threaded` macro. +""" +function set_polyester!(toggle::Bool; force = true) + set_preferences!(TRIXI_UUID, "polyester" => toggle, force = force) + @info "Please restart Julia and reload Trixi.jl for the `polyester` change to take effect" +end + """ Trixi.set_sqrt_type(type; force = true) diff --git a/src/callbacks_step/summary.jl b/src/callbacks_step/summary.jl index 21c7fc780a5..465cc10a310 100644 --- a/src/callbacks_step/summary.jl +++ b/src/callbacks_step/summary.jl @@ -207,6 +207,9 @@ function initialize_summary_callback(cb::DiscreteCallback, u, t, integrator; # technical details setup = Pair{String, Any}["#threads" => Threads.nthreads()] + if !_PREFERENCE_POLYESTER + push!(setup, "Polyester" => "disabled") + end if mpi_isparallel() push!(setup, "#MPI ranks" => mpi_nranks()) diff --git a/src/solvers/dg.jl b/src/solvers/dg.jl index fb4c8f182e0..628e39e6a87 100644 --- a/src/solvers/dg.jl +++ b/src/solvers/dg.jl @@ -629,7 +629,7 @@ end # since LoopVectorization does not support `ForwardDiff.Dual`s. Hence, we use # optimized `PtrArray`s whenever possible and fall back to plain `Array`s # otherwise. - if LoopVectorization.check_args(u_ode) + if _PREFERENCE_POLYESTER && LoopVectorization.check_args(u_ode) # This version using `PtrArray`s from StrideArrays.jl is very fast and # does not result in allocations. # From 94c81fdd407352f4355e0ca7ffed93f0cb1482f0 Mon Sep 17 00:00:00 2001 From: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Date: Wed, 7 Aug 2024 11:19:16 +0200 Subject: [PATCH 03/25] Add bang to `set_sqrt_type` and `set_log_type` (#2031) * add bang to set_sqrt_type and set_log_type * Apply suggestions from code review Co-authored-by: Hendrik Ranocha --------- Co-authored-by: Hendrik Ranocha --- src/auxiliary/math.jl | 52 ++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/auxiliary/math.jl b/src/auxiliary/math.jl index 0bd5ad438f3..171c631a843 100644 --- a/src/auxiliary/math.jl +++ b/src/auxiliary/math.jl @@ -23,44 +23,47 @@ function set_polyester!(toggle::Bool; force = true) end """ - Trixi.set_sqrt_type(type; force = true) + Trixi.set_sqrt_type!(type; force = true) Set the `type` of the square root function to be used in Trixi.jl. The default is `"sqrt_Trixi_NaN"` which returns `NaN` for negative arguments instead of throwing an error. -Alternatively, you can set `type` to `"sqrt_Base"` to use the Julia built-in `sqrt` function +Alternatively, you can set `type` to `"sqrt_Base"` to use the Julia built-in `sqrt` function which provides a stack-trace of the error which might come in handy when debugging code. """ -function set_sqrt_type(type; force = true) +function set_sqrt_type!(type; force = true) @assert type == "sqrt_Trixi_NaN"||type == "sqrt_Base" "Only allowed `sqrt` function types are `\"sqrt_Trixi_NaN\"` and `\"sqrt_Base\"`" set_preferences!(TRIXI_UUID, "sqrt" => type, force = force) @info "Please restart Julia and reload Trixi.jl for the `sqrt` computation change to take effect" end +# TODO: deprecation introduced in v0.8 +@deprecate set_sqrt_type(type; force = true) set_sqrt_type!(type; force = true) false + @static if _PREFERENCE_SQRT == "sqrt_Trixi_NaN" """ Trixi.sqrt(x::Real) Custom square root function which returns `NaN` for negative arguments instead of throwing an error. - This is required to ensure [correct results for multithreaded computations](https://github.com/trixi-framework/Trixi.jl/issues/1766) - when using the [`Polyester` package](https://github.com/JuliaSIMD/Polyester.jl), + This is required to ensure [correct results for multithreaded computations](https://github.com/trixi-framework/Trixi.jl/issues/1766) + when using the [`Polyester` package](https://github.com/JuliaSIMD/Polyester.jl), i.e., using the `@batch` macro instead of the Julia built-in `@threads` macro, see [`@threaded`](@ref). - We dispatch this function for `Float64, Float32, Float16` to the LLVM intrinsics - `llvm.sqrt.f64`, `llvm.sqrt.f32`, `llvm.sqrt.f16` as for these the LLVM functions can be used out-of the box, + We dispatch this function for `Float64, Float32, Float16` to the LLVM intrinsics + `llvm.sqrt.f64`, `llvm.sqrt.f32`, `llvm.sqrt.f16` as for these the LLVM functions can be used out-of the box, i.e., they return `NaN` for negative arguments. - In principle, one could also use the `sqrt_llvm` call, but for transparency and consistency with [`log`](@ref) we - spell out the datatype-dependent functions here. + In principle, one could also use the `sqrt_llvm` call, but for transparency and consistency with [`log`](@ref) we + spell out the datatype-dependent functions here. For other types, such as integers or dual numbers required for algorithmic differentiation, we fall back to the Julia built-in `sqrt` function after a check for negative arguments. - Since these cases are not performance critical, the check for negativity does not hurt here + Since these cases are not performance critical, the check for negativity does not hurt here and can (as of now) even be optimized away by the compiler due to the implementation of `sqrt` in Julia. - When debugging code, it might be useful to change the implementation of this function to redirect to - the Julia built-in `sqrt` function, as this reports the exact place in code where the domain is violated + When debugging code, it might be useful to change the implementation of this function to redirect to + the Julia built-in `sqrt` function, as this reports the exact place in code where the domain is violated in the stacktrace. - See also [`Trixi.set_sqrt_type`](@ref). + See also [`Trixi.set_sqrt_type!`](@ref). """ @inline sqrt(x::Real) = x < zero(x) ? oftype(x, NaN) : Base.sqrt(x) @@ -74,41 +77,44 @@ end end """ - Trixi.set_log_type(type; force = true) + Trixi.set_log_type!(type; force = true) Set the `type` of the (natural) `log` function to be used in Trixi.jl. The default is `"sqrt_Trixi_NaN"` which returns `NaN` for negative arguments instead of throwing an error. -Alternatively, you can set `type` to `"sqrt_Base"` to use the Julia built-in `sqrt` function +Alternatively, you can set `type` to `"sqrt_Base"` to use the Julia built-in `sqrt` function which provides a stack-trace of the error which might come in handy when debugging code. """ -function set_log_type(type; force = true) +function set_log_type!(type; force = true) @assert type == "log_Trixi_NaN"||type == "log_Base" "Only allowed log function types are `\"log_Trixi_NaN\"` and `\"log_Base\"`." set_preferences!(TRIXI_UUID, "log" => type, force = force) @info "Please restart Julia and reload Trixi.jl for the `log` computation change to take effect" end +# TODO: deprecation introduced in v0.8 +@deprecate set_log_type(type; force = true) set_log_type!(type; force = true) false + @static if _PREFERENCE_LOG == "log_Trixi_NaN" """ Trixi.log(x::Real) Custom natural logarithm function which returns `NaN` for negative arguments instead of throwing an error. - This is required to ensure [correct results for multithreaded computations](https://github.com/trixi-framework/Trixi.jl/issues/1766) - when using the [`Polyester` package](https://github.com/JuliaSIMD/Polyester.jl), + This is required to ensure [correct results for multithreaded computations](https://github.com/trixi-framework/Trixi.jl/issues/1766) + when using the [`Polyester` package](https://github.com/JuliaSIMD/Polyester.jl), i.e., using the `@batch` macro instead of the Julia built-in `@threads` macro, see [`@threaded`](@ref). - We dispatch this function for `Float64, Float32, Float16` to the respective LLVM intrinsics - `llvm.log.f64`, `llvm.log.f32`, `llvm.log.f16` as for this the LLVM functions can be used out-of the box, i.e., + We dispatch this function for `Float64, Float32, Float16` to the respective LLVM intrinsics + `llvm.log.f64`, `llvm.log.f32`, `llvm.log.f16` as for this the LLVM functions can be used out-of the box, i.e., they return `NaN` for negative arguments. For other types, such as integers or dual numbers required for algorithmic differentiation, we fall back to the Julia built-in `log` function after a check for negative arguments. Since these cases are not performance critical, the check for negativity does not hurt here. - When debugging code, it might be useful to change the implementation of this function to redirect to - the Julia built-in `log` function, as this reports the exact place in code where the domain is violated + When debugging code, it might be useful to change the implementation of this function to redirect to + the Julia built-in `log` function, as this reports the exact place in code where the domain is violated in the stacktrace. - See also [`Trixi.set_log_type`](@ref). + See also [`Trixi.set_log_type!`](@ref). """ @inline log(x::Real) = x < zero(x) ? oftype(x, NaN) : Base.log(x) From bef2544070123b0ae9b51f5e959aa3dba5119515 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 7 Aug 2024 15:31:58 +0200 Subject: [PATCH 04/25] set version to v0.8.5 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index a0ce119fec5..52b2789d251 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Trixi" uuid = "a7f1ee26-1774-49b1-8366-f1abc58fbfcb" authors = ["Michael Schlottke-Lakemper ", "Gregor Gassner ", "Hendrik Ranocha ", "Andrew R. Winters ", "Jesse Chan "] -version = "0.8.5-DEV" +version = "0.8.5" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From e1aabb309249841e78d42da5072dde21989a9f11 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 7 Aug 2024 15:32:22 +0200 Subject: [PATCH 05/25] set development version to v0.8.6-DEV --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 52b2789d251..1ad055a5cff 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Trixi" uuid = "a7f1ee26-1774-49b1-8366-f1abc58fbfcb" authors = ["Michael Schlottke-Lakemper ", "Gregor Gassner ", "Hendrik Ranocha ", "Andrew R. Winters ", "Jesse Chan "] -version = "0.8.5" +version = "0.8.6-DEV" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 5f5a23204e5c13817162800b01a33f9d082ae26b Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Tue, 13 Aug 2024 19:35:40 +0200 Subject: [PATCH 06/25] Specify Callback Argument Type in init Functions in ODE solvers (2N, 3Sstar, PairedExplicitRK, SSP) (#2026) * Update function signatures to include type annotations for callback parameter * Update error messages for unsupported continuous callbacks in time integration methods * Update error messages for unsupported continuous callbacks in time integration methods * Update src/time_integration/methods_2N.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update src/time_integration/methods_3Sstar.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * change error message in ssp integrator * fix error message in ssp --------- Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> --- src/time_integration/methods_2N.jl | 6 ++---- src/time_integration/methods_3Sstar.jl | 6 ++---- src/time_integration/methods_SSP.jl | 6 ++---- .../paired_explicit_runge_kutta/methods_PERK2.jl | 6 ++---- 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/time_integration/methods_2N.jl b/src/time_integration/methods_2N.jl index e5b970c6bda..1143e4ecb93 100644 --- a/src/time_integration/methods_2N.jl +++ b/src/time_integration/methods_2N.jl @@ -105,7 +105,7 @@ function Base.getproperty(integrator::SimpleIntegrator2N, field::Symbol) end function init(ode::ODEProblem, alg::SimpleAlgorithm2N; - dt, callback = nothing, kwargs...) + dt, callback::Union{CallbackSet, Nothing} = nothing, kwargs...) u = copy(ode.u0) du = similar(u) u_tmp = similar(u) @@ -119,13 +119,11 @@ function init(ode::ODEProblem, alg::SimpleAlgorithm2N; # initialize callbacks if callback isa CallbackSet foreach(callback.continuous_callbacks) do cb - error("unsupported") + throw(ArgumentError("Continuous callbacks are unsupported with the 2N storage time integration methods.")) end foreach(callback.discrete_callbacks) do cb cb.initialize(cb, integrator.u, integrator.t, integrator) end - elseif !isnothing(callback) - error("unsupported") end return integrator diff --git a/src/time_integration/methods_3Sstar.jl b/src/time_integration/methods_3Sstar.jl index 6128d1551d8..a3ab023b64b 100644 --- a/src/time_integration/methods_3Sstar.jl +++ b/src/time_integration/methods_3Sstar.jl @@ -172,7 +172,7 @@ function Base.getproperty(integrator::SimpleIntegrator3Sstar, field::Symbol) end function init(ode::ODEProblem, alg::SimpleAlgorithm3Sstar; - dt, callback = nothing, kwargs...) + dt, callback::Union{CallbackSet, Nothing} = nothing, kwargs...) u = copy(ode.u0) du = similar(u) u_tmp1 = similar(u) @@ -189,13 +189,11 @@ function init(ode::ODEProblem, alg::SimpleAlgorithm3Sstar; # initialize callbacks if callback isa CallbackSet foreach(callback.continuous_callbacks) do cb - error("unsupported") + throw(ArgumentError("Continuous callbacks are unsupported with the 3 star time integration methods.")) end foreach(callback.discrete_callbacks) do cb cb.initialize(cb, integrator.u, integrator.t, integrator) end - elseif !isnothing(callback) - error("unsupported") end return integrator diff --git a/src/time_integration/methods_SSP.jl b/src/time_integration/methods_SSP.jl index 18f9c613249..285827850c9 100644 --- a/src/time_integration/methods_SSP.jl +++ b/src/time_integration/methods_SSP.jl @@ -138,7 +138,7 @@ of type `SimpleAlgorithmSSP`. This is an experimental feature and may change in future releases. """ function solve(ode::ODEProblem, alg = SimpleSSPRK33()::SimpleAlgorithmSSP; - dt, callback = nothing, kwargs...) + dt, callback::Union{CallbackSet, Nothing} = nothing, kwargs...) u = copy(ode.u0) du = similar(u) r0 = similar(u) @@ -157,13 +157,11 @@ function solve(ode::ODEProblem, alg = SimpleSSPRK33()::SimpleAlgorithmSSP; # initialize callbacks if callback isa CallbackSet foreach(callback.continuous_callbacks) do cb - error("unsupported") + throw(ArgumentError("Continuous callbacks are unsupported with the SSP time integration methods.")) end foreach(callback.discrete_callbacks) do cb cb.initialize(cb, integrator.u, integrator.t, integrator) end - elseif !isnothing(callback) - error("unsupported") end for stage_callback in alg.stage_callbacks diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK2.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK2.jl index ddcc1b365be..23a3ceba76c 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK2.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK2.jl @@ -261,7 +261,7 @@ function Base.getproperty(integrator::PairedExplicitRK, field::Symbol) end function init(ode::ODEProblem, alg::PairedExplicitRK2; - dt, callback = nothing, kwargs...) + dt, callback::Union{CallbackSet, Nothing} = nothing, kwargs...) u0 = copy(ode.u0) du = zero(u0) u_tmp = zero(u0) @@ -286,13 +286,11 @@ function init(ode::ODEProblem, alg::PairedExplicitRK2; # initialize callbacks if callback isa CallbackSet for cb in callback.continuous_callbacks - error("unsupported") + throw(ArgumentError("Continuous callbacks are unsupported with paired explicit Runge-Kutta methods.")) end for cb in callback.discrete_callbacks cb.initialize(cb, integrator.u, integrator.t, integrator) end - elseif !isnothing(callback) - error("unsupported") end return integrator From 0cc13ddcd0134059ae57647f8829563a274cc163 Mon Sep 17 00:00:00 2001 From: Huiyu Xie Date: Tue, 13 Aug 2024 20:43:56 -1000 Subject: [PATCH 07/25] Add numerical support for other real types (`fluxes`) (#2021) * start * fix broken tests --- src/equations/numerical_fluxes.jl | 4 +- test/test_type.jl | 314 ++++++++---------------------- 2 files changed, 88 insertions(+), 230 deletions(-) diff --git a/src/equations/numerical_fluxes.jl b/src/equations/numerical_fluxes.jl index e3e798381ae..ea75b99b7f2 100644 --- a/src/equations/numerical_fluxes.jl +++ b/src/equations/numerical_fluxes.jl @@ -21,7 +21,7 @@ DG method (except floating point errors). f_rr = flux(u_rr, orientation_or_normal_direction, equations) # Average regular fluxes - return 0.5 * (f_ll + f_rr) + return 0.5f0 * (f_ll + f_rr) end """ @@ -172,7 +172,7 @@ DissipationLocalLaxFriedrichs() = DissipationLocalLaxFriedrichs(max_abs_speed_na equations) λ = dissipation.max_abs_speed(u_ll, u_rr, orientation_or_normal_direction, equations) - return -0.5 * λ * (u_rr - u_ll) + return -0.5f0 * λ * (u_rr - u_ll) end function Base.show(io::IO, d::DissipationLocalLaxFriedrichs) diff --git a/test/test_type.jl b/test/test_type.jl index 6c51460e6d9..39f8895fdd3 100644 --- a/test/test_type.jl +++ b/test/test_type.jl @@ -45,39 +45,17 @@ isdir(outdir) && rm(outdir, recursive = true) for orientation in orientations for direction in directions - if RealT == Float32 - # check `surface_flux_function` (test broken) - @test_broken eltype(@inferred boundary_condition_wall(u_inner, - orientation, - direction, x, - t, - surface_flux_function, - equations)) == - RealT - else - @test eltype(@inferred boundary_condition_wall(u_inner, orientation, - direction, x, t, - surface_flux_function, - equations)) == RealT - end + @test eltype(@inferred boundary_condition_wall(u_inner, orientation, + direction, x, t, + surface_flux_function, + equations)) == RealT end end - - if RealT == Float32 - # check `surface_flux_function` (test broken) - @test_broken eltype(@inferred boundary_condition_slip_wall(u_inner, - normal_direction, - x, t, - surface_flux_function, - equations)) == - RealT - else - @test eltype(@inferred boundary_condition_slip_wall(u_inner, - normal_direction, x, t, - surface_flux_function, - equations)) == - RealT - end + @test eltype(@inferred boundary_condition_slip_wall(u_inner, + normal_direction, x, t, + surface_flux_function, + equations)) == + RealT @test eltype(@inferred flux(u, normal_direction, equations)) == RealT @test typeof(@inferred max_abs_speed_naive(u_ll, u_rr, normal_direction, @@ -850,25 +828,13 @@ isdir(outdir) && rm(outdir, recursive = true) RealT for direction in directions - if RealT == Float32 - # check `surface_flux_function` (test broken) - @test_broken eltype(@inferred boundary_condition_poisson_nonperiodic(u_inner, - orientation, - direction, - x, - t, - surface_flux_function, - equations)) == - RealT - else - @test eltype(@inferred boundary_condition_poisson_nonperiodic(u_inner, - orientation, - direction, - x, t, - surface_flux_function, - equations)) == - RealT - end + @test eltype(@inferred boundary_condition_poisson_nonperiodic(u_inner, + orientation, + direction, + x, t, + surface_flux_function, + equations)) == + RealT end @test eltype(@inferred flux(u, orientation, equations)) == RealT @@ -911,25 +877,13 @@ isdir(outdir) && rm(outdir, recursive = true) for orientation in orientations for direction in directions - if RealT == Float32 - # check `surface_flux_function` (test broken) - @test_broken eltype(@inferred boundary_condition_poisson_nonperiodic(u_inner, - orientation, - direction, - x, - t, - surface_flux_function, - equations)) == - RealT - else - @test eltype(@inferred boundary_condition_poisson_nonperiodic(u_inner, - orientation, - direction, - x, t, - surface_flux_function, - equations)) == - RealT - end + @test eltype(@inferred boundary_condition_poisson_nonperiodic(u_inner, + orientation, + direction, + x, t, + surface_flux_function, + equations)) == + RealT end end @@ -985,25 +939,13 @@ isdir(outdir) && rm(outdir, recursive = true) for orientation in orientations for direction in directions - if RealT == Float32 - # check `surface_flux_function` (test broken) - @test_broken eltype(@inferred boundary_condition_poisson_nonperiodic(u_inner, - orientation, - direction, - x, - t, - surface_flux_function, - equations)) == - RealT - else - @test eltype(@inferred boundary_condition_poisson_nonperiodic(u_inner, - orientation, - direction, - x, t, - surface_flux_function, - equations)) == - RealT - end + @test eltype(@inferred boundary_condition_poisson_nonperiodic(u_inner, + orientation, + direction, + x, t, + surface_flux_function, + equations)) == + RealT end end @@ -1631,24 +1573,13 @@ isdir(outdir) && rm(outdir, recursive = true) RealT for direction in directions - if RealT == Float32 - # check `surface_flux_function` (test broken) - @test_broken eltype(@inferred Trixi.boundary_condition_linear_x(u_inner, - orientation, - direction, - x, t, - surface_flux_function, - equations)) == - RealT - else - @test eltype(@inferred Trixi.boundary_condition_linear_x(u_inner, - orientation, - direction, x, - t, - surface_flux_function, - equations)) == - RealT - end + @test eltype(@inferred Trixi.boundary_condition_linear_x(u_inner, + orientation, + direction, x, + t, + surface_flux_function, + equations)) == + RealT end @test eltype(@inferred flux(u, orientation, equations)) == RealT @@ -1701,58 +1632,30 @@ isdir(outdir) && rm(outdir, recursive = true) for orientation in orientations for direction in directions - if RealT == Float32 - # check `surface_flux_function` (test broken) - @test_broken eltype(@inferred Trixi.boundary_condition_linear_x_y(u_inner, - orientation, - direction, - x, - t, - surface_flux_function, - equations)) == - RealT - @test_broken eltype(@inferred Trixi.boundary_condition_linear_x(u_inner, - orientation, - direction, - x, - t, - surface_flux_function, - equations)) == - RealT - @test_broken eltype(@inferred Trixi.boundary_condition_linear_y(u_inner, - orientation, - direction, - x, - t, - surface_flux_function, - equations)) == - RealT - else - @test eltype(@inferred Trixi.boundary_condition_linear_x_y(u_inner, - orientation, - direction, - x, - t, - surface_flux_function, - equations)) == - RealT - @test eltype(@inferred Trixi.boundary_condition_linear_x(u_inner, - orientation, - direction, - x, - t, - surface_flux_function, - equations)) == - RealT - @test eltype(@inferred Trixi.boundary_condition_linear_y(u_inner, - orientation, - direction, - x, - t, - surface_flux_function, - equations)) == - RealT - end + @test eltype(@inferred Trixi.boundary_condition_linear_x_y(u_inner, + orientation, + direction, + x, + t, + surface_flux_function, + equations)) == + RealT + @test eltype(@inferred Trixi.boundary_condition_linear_x(u_inner, + orientation, + direction, + x, + t, + surface_flux_function, + equations)) == + RealT + @test eltype(@inferred Trixi.boundary_condition_linear_y(u_inner, + orientation, + direction, + x, + t, + surface_flux_function, + equations)) == + RealT end end @@ -1806,26 +1709,14 @@ isdir(outdir) && rm(outdir, recursive = true) for orientation in orientations for direction in directions - if RealT == Float32 - # check `surface_flux_function` (test broken) - @test_broken eltype(@inferred Trixi.boundary_condition_linear_z(u_inner, - orientation, - direction, - x, - t, - surface_flux_function, - equations)) == - RealT - else - @test eltype(@inferred Trixi.boundary_condition_linear_z(u_inner, - orientation, - direction, - x, - t, - surface_flux_function, - equations)) == - RealT - end + @test eltype(@inferred Trixi.boundary_condition_linear_z(u_inner, + orientation, + direction, + x, + t, + surface_flux_function, + equations)) == + RealT end end @@ -1904,24 +1795,12 @@ isdir(outdir) && rm(outdir, recursive = true) RealT for direction in directions - if RealT == Float32 - # check `surface_flux_function` (test broken) - @test_broken eltype(@inferred boundary_condition_slip_wall(u_inner, - orientation, - direction, - x, t, - surface_flux_function, - equations)) == - RealT - else - @test eltype(@inferred boundary_condition_slip_wall(u_inner, - orientation, - direction, - x, t, - surface_flux_function, - equations)) == RealT - end - + @test eltype(@inferred boundary_condition_slip_wall(u_inner, + orientation, + direction, + x, t, + surface_flux_function, + equations)) == RealT @test eltype(@inferred Trixi.calc_wavespeed_roe(u_ll, u_rr, direction, equations)) == RealT @@ -2006,22 +1885,12 @@ isdir(outdir) && rm(outdir, recursive = true) RealT @test eltype(@inferred initial_condition_weak_blast_wave(x, t, equations)) == RealT + @test eltype(@inferred boundary_condition_slip_wall(u_inner, + normal_direction, + x, t, + surface_flux_function, + equations)) == RealT - if RealT == Float32 - # check `surface_flux_function` (test broken) - @test_broken eltype(@inferred boundary_condition_slip_wall(u_inner, - normal_direction, - x, t, - surface_flux_function, - equations)) == - RealT - else - @test eltype(@inferred boundary_condition_slip_wall(u_inner, - normal_direction, - x, t, - surface_flux_function, - equations)) == RealT - end @test eltype(@inferred flux(u, normal_direction, equations)) == RealT @test eltype(@inferred flux_nonconservative_wintermeyer_etal(u_ll, u_rr, normal_direction_ll, @@ -2063,23 +1932,12 @@ isdir(outdir) && rm(outdir, recursive = true) for orientation in orientations for direction in directions - if RealT == Float32 - # check `surface_flux_function` (test broken) - @test_broken eltype(@inferred boundary_condition_slip_wall(u_inner, - orientation, - direction, - x, t, - surface_flux_function, - equations)) == - RealT - else - @test eltype(@inferred boundary_condition_slip_wall(u_inner, - orientation, - direction, x, t, - surface_flux_function, - equations)) == - RealT - end + @test eltype(@inferred boundary_condition_slip_wall(u_inner, + orientation, + direction, x, t, + surface_flux_function, + equations)) == + RealT end @test eltype(@inferred flux(u, orientation, equations)) == RealT From 19ab0825a1477cf6807af2a94dcd707df9eca96d Mon Sep 17 00:00:00 2001 From: Huiyu Xie Date: Wed, 14 Aug 2024 20:36:15 -1000 Subject: [PATCH 08/25] Add numerical support of other real types (`linearized_euler`) (#2002) * start * complete equations * unit test 1D * unit test 2D * unit test 3D --- src/equations/linearized_euler_2d.jl | 24 ++--- test/test_type.jl | 156 ++++++++++++++++++++++++++- 2 files changed, 167 insertions(+), 13 deletions(-) diff --git a/src/equations/linearized_euler_2d.jl b/src/equations/linearized_euler_2d.jl index 3df3093069d..985fd04e604 100644 --- a/src/equations/linearized_euler_2d.jl +++ b/src/equations/linearized_euler_2d.jl @@ -204,14 +204,14 @@ The diagonalization of the flux matrix can be found in lambda1_p = positive_part(lambda1) lambda2_p = positive_part(lambda2) lambda3_p = positive_part(lambda3) - lambda2p3_half_p = 0.5 * (lambda2_p + lambda3_p) - lambda3m2_half_p = 0.5 * (lambda3_p - lambda2_p) + lambda2p3_half_p = 0.5f0 * (lambda2_p + lambda3_p) + lambda3m2_half_p = 0.5f0 * (lambda3_p - lambda2_p) lambda1_m = negative_part(lambda1) lambda2_m = negative_part(lambda2) lambda3_m = negative_part(lambda3) - lambda2p3_half_m = 0.5 * (lambda2_m + lambda3_m) - lambda3m2_half_m = 0.5 * (lambda3_m - lambda2_m) + lambda2p3_half_m = 0.5f0 * (lambda2_m + lambda3_m) + lambda3m2_half_m = 0.5f0 * (lambda3_m - lambda2_m) f1p = (lambda1_p * rho_prime_ll + lambda3m2_half_p / c_mean_global * rho_mean_global * v1_prime_ll + @@ -244,14 +244,14 @@ The diagonalization of the flux matrix can be found in lambda1_p = positive_part(lambda1) lambda2_p = positive_part(lambda2) lambda3_p = positive_part(lambda3) - lambda2p3_half_p = 0.5 * (lambda2_p + lambda3_p) - lambda3m2_half_p = 0.5 * (lambda3_p - lambda2_p) + lambda2p3_half_p = 0.5f0 * (lambda2_p + lambda3_p) + lambda3m2_half_p = 0.5f0 * (lambda3_p - lambda2_p) lambda1_m = negative_part(lambda1) lambda2_m = negative_part(lambda2) lambda3_m = negative_part(lambda3) - lambda2p3_half_m = 0.5 * (lambda2_m + lambda3_m) - lambda3m2_half_m = 0.5 * (lambda3_m - lambda2_m) + lambda2p3_half_m = 0.5f0 * (lambda2_m + lambda3_m) + lambda3m2_half_m = 0.5f0 * (lambda3_m - lambda2_m) f1p = (lambda1_p * rho_prime_ll + lambda3m2_half_p / c_mean_global * rho_mean_global * v2_prime_ll + @@ -304,14 +304,14 @@ end lambda1_p = positive_part(lambda1) lambda2_p = positive_part(lambda2) lambda3_p = positive_part(lambda3) - lambda2p3_half_p = 0.5 * (lambda2_p + lambda3_p) - lambda3m2_half_p = 0.5 * (lambda3_p - lambda2_p) + lambda2p3_half_p = 0.5f0 * (lambda2_p + lambda3_p) + lambda3m2_half_p = 0.5f0 * (lambda3_p - lambda2_p) lambda1_m = negative_part(lambda1) lambda2_m = negative_part(lambda2) lambda3_m = negative_part(lambda3) - lambda2p3_half_m = 0.5 * (lambda2_m + lambda3_m) - lambda3m2_half_m = 0.5 * (lambda3_m - lambda2_m) + lambda2p3_half_m = 0.5f0 * (lambda2_m + lambda3_m) + lambda3m2_half_m = 0.5f0 * (lambda3_m - lambda2_m) f1p = (lambda1_p * rho_prime_ll + lambda3m2_half_p / c_mean_global * rho_mean_global * v_prime_normal_ll + diff --git a/test/test_type.jl b/test/test_type.jl index 39f8895fdd3..9b8c3366cfb 100644 --- a/test/test_type.jl +++ b/test/test_type.jl @@ -176,7 +176,7 @@ isdir(outdir) && rm(outdir, recursive = true) @timed_testset "Compressible Euler 2D" begin for RealT in (Float32, Float64) - # set gamma = 2 for the coupling convergence test\ + # set gamma = 2 for the coupling convergence test equations = @inferred CompressibleEulerEquations2D(RealT(2)) x = SVector(zero(RealT), zero(RealT)) @@ -1772,6 +1772,160 @@ isdir(outdir) && rm(outdir, recursive = true) end end + @timed_testset "Linearized Euler 1D" begin + for RealT in (Float32, Float64) + equations = @inferred LinearizedEulerEquations1D(v_mean_global = RealT(0), + c_mean_global = RealT(1), + rho_mean_global = RealT(1)) + + x = SVector(zero(RealT)) + t = zero(RealT) + u = u_ll = u_rr = u_inner = SVector(one(RealT), one(RealT), one(RealT)) + orientation = 1 + directions = [1, 2] + + surface_flux_function = flux_hll + + @test eltype(@inferred initial_condition_convergence_test(x, t, equations)) == + RealT + + for direction in directions + @test eltype(@inferred boundary_condition_wall(u_inner, orientation, + direction, x, t, + surface_flux_function, + equations)) == RealT + end + + @test eltype(@inferred flux(u, orientation, equations)) == RealT + + @test typeof(@inferred Trixi.max_abs_speeds(equations)) == + RealT + @test typeof(@inferred max_abs_speed_naive(u_ll, u_rr, orientation, equations)) == + RealT + @test eltype(@inferred min_max_speed_naive(u_ll, u_rr, orientation, equations)) == + RealT + @test eltype(@inferred min_max_speed_davis(u_ll, u_rr, orientation, equations)) == + RealT + + @test eltype(@inferred cons2prim(u, equations)) == RealT + @test eltype(@inferred cons2entropy(u, equations)) == RealT + end + end + + @timed_testset "Linearized Euler 2D" begin + for RealT in (Float32, Float64) + equations = @inferred LinearizedEulerEquations2D(v_mean_global = (RealT(0), + RealT(0)), + c_mean_global = RealT(1), + rho_mean_global = RealT(1)) + + x = SVector(zero(RealT), zero(RealT)) + t = zero(RealT) + u = u_ll = u_rr = u_inner = SVector(one(RealT), one(RealT), one(RealT), + one(RealT)) + orientations = [1, 2] + directions = [1, 2, 3, 4] + normal_direction = SVector(one(RealT), zero(RealT)) + + surface_flux_function = flux_hll + + @test eltype(@inferred initial_condition_convergence_test(x, t, equations)) == + RealT + + for orientation in orientations + for direction in directions + @test eltype(@inferred boundary_condition_wall(u_inner, orientation, + direction, x, t, + surface_flux_function, + equations)) == RealT + end + + @test eltype(@inferred flux(u, orientation, equations)) == RealT + @test eltype(@inferred flux_godunov(u_ll, u_rr, orientation, equations)) == + RealT + + @test typeof(@inferred max_abs_speed_naive(u_ll, u_rr, orientation, + equations)) == + RealT + @test eltype(@inferred min_max_speed_naive(u_ll, u_rr, orientation, + equations)) == + RealT + @test eltype(@inferred min_max_speed_davis(u_ll, u_rr, orientation, + equations)) == + RealT + end + + @test eltype(@inferred flux(u, normal_direction, equations)) == RealT + @test eltype(@inferred flux_godunov(u_ll, u_rr, normal_direction, equations)) == + RealT + + @test eltype(@inferred Trixi.max_abs_speeds(equations)) == RealT + @test typeof(@inferred max_abs_speed_naive(u_ll, u_rr, normal_direction, + equations)) == RealT + @test eltype(@inferred min_max_speed_naive(u_ll, u_rr, normal_direction, + equations)) == RealT + @test eltype(@inferred min_max_speed_davis(u_ll, u_rr, normal_direction, + equations)) == RealT + + @test eltype(@inferred cons2prim(u, equations)) == RealT + @test eltype(@inferred cons2entropy(u, equations)) == RealT + end + end + + @timed_testset "Linearized Euler 3D" begin + for RealT in (Float32, Float64) + equations = @inferred LinearizedEulerEquations3D(v_mean_global = (RealT(0), + RealT(0), + RealT(0)), + c_mean_global = RealT(1), + rho_mean_global = RealT(1)) + + x = SVector(zero(RealT), zero(RealT), zero(RealT)) + t = zero(RealT) + u = u_ll = u_rr = u_inner = SVector(one(RealT), one(RealT), one(RealT), + one(RealT), one(RealT)) + orientations = [1, 2, 3] + directions = [1, 2, 3, 4, 5, 6] + normal_direction = SVector(one(RealT), zero(RealT), zero(RealT)) + + surface_flux_function = flux_hll + + @test eltype(@inferred initial_condition_convergence_test(x, t, equations)) == + RealT + + for orientation in orientations + for direction in directions + @test eltype(@inferred boundary_condition_wall(u_inner, orientation, + direction, x, t, + surface_flux_function, + equations)) == RealT + end + + @test eltype(@inferred flux(u, orientation, equations)) == RealT + + @test typeof(@inferred max_abs_speed_naive(u_ll, u_rr, orientation, + equations)) == RealT + @test eltype(@inferred min_max_speed_naive(u_ll, u_rr, orientation, + equations)) == RealT + @test eltype(@inferred min_max_speed_davis(u_ll, u_rr, orientation, + equations)) == RealT + end + + @test eltype(@inferred flux(u, normal_direction, equations)) == RealT + + @test eltype(@inferred Trixi.max_abs_speeds(equations)) == RealT + @test typeof(@inferred max_abs_speed_naive(u_ll, u_rr, normal_direction, + equations)) == RealT + @test eltype(@inferred min_max_speed_naive(u_ll, u_rr, normal_direction, + equations)) == RealT + @test eltype(@inferred min_max_speed_davis(u_ll, u_rr, normal_direction, + equations)) == RealT + + @test eltype(@inferred cons2prim(u, equations)) == RealT + @test eltype(@inferred cons2entropy(u, equations)) == RealT + end + end + @timed_testset "Shallow Water 1D" begin for RealT in (Float32, Float64) equations = @inferred ShallowWaterEquations1D(gravity_constant = RealT(9.81)) From ab6fb783eb6ad1408e4d101b4fa8aa0e2d0be71b Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Thu, 15 Aug 2024 16:23:15 +0200 Subject: [PATCH 09/25] More accurate comments MPI Mortar Containers (#2041) --- src/solvers/dgsem_p4est/containers_parallel.jl | 16 ++++++++-------- src/solvers/dgsem_tree/containers_2d.jl | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/solvers/dgsem_p4est/containers_parallel.jl b/src/solvers/dgsem_p4est/containers_parallel.jl index fd2749155bb..676b37efff3 100644 --- a/src/solvers/dgsem_p4est/containers_parallel.jl +++ b/src/solvers/dgsem_p4est/containers_parallel.jl @@ -7,10 +7,10 @@ mutable struct P4estMPIInterfaceContainer{NDIMS, uEltype <: Real, NDIMSP2} <: AbstractContainer - u::Array{uEltype, NDIMSP2} # [primary/secondary, variable, i, j, interface] - local_neighbor_ids::Vector{Int} # [interface] + u::Array{uEltype, NDIMSP2} # [primary/secondary, variable, i, j, interface] + local_neighbor_ids::Vector{Int} # [interface] node_indices::Vector{NTuple{NDIMS, Symbol}} # [interface] - local_sides::Vector{Int} # [interface] + local_sides::Vector{Int} # [interface] # internal `resize!`able storage _u::Vector{uEltype} @@ -89,11 +89,11 @@ end # the normal vectors on the surface of the small elements for each mortar. mutable struct P4estMPIMortarContainer{NDIMS, uEltype <: Real, RealT <: Real, NDIMSP1, NDIMSP2, NDIMSP3} <: AbstractContainer - u::Array{uEltype, NDIMSP3} # [small/large side, variable, position, i, j, mortar] - local_neighbor_ids::Vector{Vector{Int}} # [mortar] - local_neighbor_positions::Vector{Vector{Int}} # [mortar] - node_indices::Matrix{NTuple{NDIMS, Symbol}} # [small/large, mortar] - normal_directions::Array{RealT, NDIMSP2} # [dimension, i, j, position, mortar] + u::Array{uEltype, NDIMSP3} # [small/large side, variable, position, i, j, mortar] + local_neighbor_ids::Vector{Vector{Int}} # [mortar][ids] + local_neighbor_positions::Vector{Vector{Int}} # [mortar][positions] + node_indices::Matrix{NTuple{NDIMS, Symbol}} # [small/large, mortar] + normal_directions::Array{RealT, NDIMSP2} # [dimension, i, j, position, mortar] # internal `resize!`able storage _u::Vector{uEltype} _node_indices::Vector{NTuple{NDIMS, Symbol}} diff --git a/src/solvers/dgsem_tree/containers_2d.jl b/src/solvers/dgsem_tree/containers_2d.jl index 7048739a226..c02faa1c0ba 100644 --- a/src/solvers/dgsem_tree/containers_2d.jl +++ b/src/solvers/dgsem_tree/containers_2d.jl @@ -941,8 +941,8 @@ end mutable struct MPIL2MortarContainer2D{uEltype <: Real} <: AbstractContainer u_upper::Array{uEltype, 4} # [leftright, variables, i, mortars] u_lower::Array{uEltype, 4} # [leftright, variables, i, mortars] - local_neighbor_ids::Vector{Vector{Int}} # [mortars] - local_neighbor_positions::Vector{Vector{Int}} # [mortars] + local_neighbor_ids::Vector{Vector{Int}} # [mortars][ids] + local_neighbor_positions::Vector{Vector{Int}} # [mortars][positions] # Large sides: left -> 1, right -> 2 large_sides::Vector{Int} # [mortars] orientations::Vector{Int} # [mortars] From bb528a465e43f9a439404afa41d5eae66234f939 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Thu, 15 Aug 2024 18:57:15 +0200 Subject: [PATCH 10/25] Note new file name in benchmark docs (#2030) --- docs/src/performance.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/src/performance.md b/docs/src/performance.md index 9f81d3c3d8e..b31efabbb51 100644 --- a/docs/src/performance.md +++ b/docs/src/performance.md @@ -42,7 +42,8 @@ For example, the following steps were used to benchmark the changes introduced i ```julia julia> using BenchmarkTools, Revise; using Trixi - julia> trixi_include("examples/2d/elixir_euler_sedov_blast_wave.jl") + julia> # nowadays "examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave.jl" + trixi_include("examples/2d/elixir_euler_sedov_blast_wave.jl") julia> du_test = copy(sol.u[end]); u_test = copy(sol.u[end]); @@ -65,7 +66,8 @@ For example, the following steps were used to benchmark the changes introduced i shell> git checkout 222241ff54f8a4ca9876cc1fc25ae262416a4ea0 - julia> trixi_include("examples/2d/elixir_euler_sedov_blast_wave.jl") + julia> # nowadays "examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave.jl" + trixi_include("examples/2d/elixir_euler_sedov_blast_wave.jl") julia> @benchmark Trixi.rhs!( $(du_test), @@ -85,6 +87,10 @@ For example, the following steps were used to benchmark the changes introduced i evals/sample: 1 ``` Run the `@benchmark ...` commands multiple times to see whether there are any significant fluctuations. + Note that the elixir name has changed since + [PR #256](https://github.com/trixi-framework/Trixi.jl/pull/256). + Nowadays, the relevant elixir is + [`examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave.jl). Follow these steps for both commits you want to compare. The relevant benchmark results you should typically be looking at are the median and mean values of the runtime and the memory/allocs estimate. In this example, the differences From e64be77d9758a9c1a916908a7485cab3e515a021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Fri, 16 Aug 2024 06:06:31 +0200 Subject: [PATCH 11/25] Moved dimension check in the constructor of SemidiscretizationHyperbolic (#2039) --- src/semidiscretization/semidiscretization_hyperbolic.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/semidiscretization/semidiscretization_hyperbolic.jl b/src/semidiscretization/semidiscretization_hyperbolic.jl index 7c82a132a0b..e35c0e2ea97 100644 --- a/src/semidiscretization/semidiscretization_hyperbolic.jl +++ b/src/semidiscretization/semidiscretization_hyperbolic.jl @@ -41,8 +41,6 @@ struct SemidiscretizationHyperbolic{Mesh, Equations, InitialCondition, SourceTerms, Solver, Cache} - @assert ndims(mesh) == ndims(equations) - performance_counter = PerformanceCounter() new(mesh, equations, initial_condition, boundary_conditions, source_terms, @@ -67,6 +65,8 @@ function SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver # while `uEltype` is used as element type of solutions etc. RealT = real(solver), uEltype = RealT, initial_cache = NamedTuple()) + @assert ndims(mesh) == ndims(equations) + cache = (; create_cache(mesh, equations, solver, RealT, uEltype)..., initial_cache...) _boundary_conditions = digest_boundary_conditions(boundary_conditions, mesh, solver, From a38a8d256a652f87021fd0d79cb41cc5125049cc Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 16 Aug 2024 06:58:52 +0200 Subject: [PATCH 12/25] set version to v0.8.6 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 1ad055a5cff..3e2489886ad 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Trixi" uuid = "a7f1ee26-1774-49b1-8366-f1abc58fbfcb" authors = ["Michael Schlottke-Lakemper ", "Gregor Gassner ", "Hendrik Ranocha ", "Andrew R. Winters ", "Jesse Chan "] -version = "0.8.6-DEV" +version = "0.8.6" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 345f53acf3b2c1d80431b2a330d16fdca7638728 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 16 Aug 2024 06:59:10 +0200 Subject: [PATCH 13/25] set development version to v0.8.7-DEV --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 3e2489886ad..d5627651d6d 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Trixi" uuid = "a7f1ee26-1774-49b1-8366-f1abc58fbfcb" authors = ["Michael Schlottke-Lakemper ", "Gregor Gassner ", "Hendrik Ranocha ", "Andrew R. Winters ", "Jesse Chan "] -version = "0.8.6" +version = "0.8.7-DEV" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From b9ace6d7ff34eec684eaaba337f66fdfa571a99a Mon Sep 17 00:00:00 2001 From: Huiyu Xie Date: Fri, 16 Aug 2024 04:23:48 -1000 Subject: [PATCH 14/25] Add numerical support of other real types (`polytropic_euler`) (#2015) * start * fix flux tests * keep conflicts * complete equations * complete unit test --- src/equations/polytropic_euler_2d.jl | 52 +++++++++---------- test/test_type.jl | 74 ++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 25 deletions(-) diff --git a/src/equations/polytropic_euler_2d.jl b/src/equations/polytropic_euler_2d.jl index e900fd64073..571d4723f6f 100644 --- a/src/equations/polytropic_euler_2d.jl +++ b/src/equations/polytropic_euler_2d.jl @@ -62,7 +62,7 @@ in combination with [`source_terms_convergence_test`](@ref). function initial_condition_convergence_test(x, t, equations::PolytropicEulerEquations2D) # manufactured initial condition from Winters (2019) [0.1007/s10543-019-00789-w] # domain must be set to [0, 1] x [0, 1] - h = 8 + cos(2 * pi * x[1]) * sin(2 * pi * x[2]) * cos(2 * pi * t) + h = 8 + cospi(2 * x[1]) * sinpi(2 * x[2]) * cospi(2 * t) return SVector(h, h / 2, 3 * h / 2) end @@ -78,19 +78,20 @@ Source terms used for convergence tests in combination with rho, v1, v2 = cons2prim(u, equations) # Residual from Winters (2019) [0.1007/s10543-019-00789-w] eq. (5.2). - h = 8 + cos(2 * pi * x[1]) * sin(2 * pi * x[2]) * cos(2 * pi * t) - h_t = -2 * pi * cos(2 * pi * x[1]) * sin(2 * pi * x[2]) * sin(2 * pi * t) - h_x = -2 * pi * sin(2 * pi * x[1]) * sin(2 * pi * x[2]) * cos(2 * pi * t) - h_y = 2 * pi * cos(2 * pi * x[1]) * cos(2 * pi * x[2]) * cos(2 * pi * t) + RealT = eltype(u) + h = 8 + cospi(2 * x[1]) * sinpi(2 * x[2]) * cospi(2 * t) + h_t = -2 * convert(RealT, pi) * cospi(2 * x[1]) * sinpi(2 * x[2]) * sinpi(2 * t) + h_x = -2 * convert(RealT, pi) * sinpi(2 * x[1]) * sinpi(2 * x[2]) * cospi(2 * t) + h_y = 2 * convert(RealT, pi) * cospi(2 * x[1]) * cospi(2 * x[2]) * cospi(2 * t) rho_x = h_x rho_y = h_y b = equations.kappa * equations.gamma * h^(equations.gamma - 1) - r_1 = h_t + h_x / 2 + 3 / 2 * h_y - r_2 = h_t / 2 + h_x / 4 + b * rho_x + 3 / 4 * h_y - r_3 = 3 / 2 * h_t + 3 / 4 * h_x + 9 / 4 * h_y + b * rho_y + r_1 = h_t + h_x / 2 + 3 * h_y / 2 + r_2 = h_t / 2 + h_x / 4 + b * rho_x + 3 * h_y / 4 + r_3 = 3 * h_t / 2 + 3 * h_x / 4 + 9 * h_y / 4 + b * rho_y return SVector(r_1, r_2, r_3) end @@ -113,9 +114,10 @@ function initial_condition_weak_blast_wave(x, t, equations::PolytropicEulerEquat phi = atan(y_norm, x_norm) # Calculate primitive variables - rho = r > 0.5 ? 1.0 : 1.1691 - v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) - v2 = r > 0.5 ? 0.0 : 0.1882 * sin(phi) + RealT = eltype(x) + rho = r > 0.5f0 ? one(RealT) : convert(RealT, 1.1691) + v1 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * cos(phi) + v2 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * sin(phi) return prim2cons(SVector(rho, v1, v2), equations) end @@ -181,17 +183,17 @@ For details see Section 3.2 of the following reference v_dot_n_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] # Compute the necessary mean values - if equations.gamma == 1.0 # isothermal gas + if equations.gamma == 1 # isothermal gas rho_mean = ln_mean(rho_ll, rho_rr) else # equations.gamma > 1 # polytropic gas rho_mean = stolarsky_mean(rho_ll, rho_rr, equations.gamma) end - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - p_avg = 0.5 * (p_ll + p_rr) + v1_avg = 0.5f0 * (v1_ll + v1_rr) + v2_avg = 0.5f0 * (v2_ll + v2_rr) + p_avg = 0.5f0 * (p_ll + p_rr) # Calculate fluxes depending on normal_direction - f1 = rho_mean * 0.5 * (v_dot_n_ll + v_dot_n_rr) + f1 = rho_mean * 0.5f0 * (v_dot_n_ll + v_dot_n_rr) f2 = f1 * v1_avg + p_avg * normal_direction[1] f3 = f1 * v2_avg + p_avg * normal_direction[2] @@ -207,21 +209,21 @@ end p_rr = equations.kappa * rho_rr^equations.gamma # Compute the necessary mean values - if equations.gamma == 1.0 # isothermal gas + if equations.gamma == 1 # isothermal gas rho_mean = ln_mean(rho_ll, rho_rr) else # equations.gamma > 1 # polytropic gas rho_mean = stolarsky_mean(rho_ll, rho_rr, equations.gamma) end - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - p_avg = 0.5 * (p_ll + p_rr) + v1_avg = 0.5f0 * (v1_ll + v1_rr) + v2_avg = 0.5f0 * (v2_ll + v2_rr) + p_avg = 0.5f0 * (p_ll + p_rr) if orientation == 1 # x-direction - f1 = rho_mean * 0.5 * (v1_ll + v1_rr) + f1 = rho_mean * 0.5f0 * (v1_ll + v1_rr) f2 = f1 * v1_avg + p_avg f3 = f1 * v2_avg else # y-direction - f1 = rho_mean * 0.5 * (v2_ll + v2_rr) + f1 = rho_mean * 0.5f0 * (v2_ll + v2_rr) f2 = f1 * v1_avg f3 = f1 * v2_avg + p_avg end @@ -360,14 +362,14 @@ end v_square = v1^2 + v2^2 p = pressure(u, equations) # Form of the internal energy depends on gas type - if equations.gamma == 1.0 # isothermal gas + if equations.gamma == 1 # isothermal gas internal_energy = equations.kappa * log(rho) else # equations.gamma > 1 # polytropic gas internal_energy = equations.kappa * rho^(equations.gamma - 1) / - (equations.gamma - 1.0) + (equations.gamma - 1) end - w1 = internal_energy + p / rho - 0.5 * v_square + w1 = internal_energy + p / rho - 0.5f0 * v_square w2 = v1 w3 = v2 diff --git a/test/test_type.jl b/test/test_type.jl index 9b8c3366cfb..d22afa65c0a 100644 --- a/test/test_type.jl +++ b/test/test_type.jl @@ -1926,6 +1926,80 @@ isdir(outdir) && rm(outdir, recursive = true) end end + @timed_testset "Polytropic Euler 2D" begin + for RealT in (Float32, Float64) + equations1 = @inferred PolytropicEulerEquations2D(RealT(1), + RealT(1)) # equations.gamma == 1 + equations2 = @inferred PolytropicEulerEquations2D(RealT(1.4), RealT(0.5)) # equations.gamma > 1 + + for equations in (equations1, equations2) + x = SVector(zero(RealT), zero(RealT)) + t = zero(RealT) + u = u_ll = u_rr = SVector(one(RealT), one(RealT), one(RealT)) + orientations = [1, 2] + directions = [1, 2, 3, 4] + normal_direction = SVector(one(RealT), zero(RealT)) + + @test eltype(@inferred initial_condition_convergence_test(x, t, equations)) == + RealT + @test eltype(@inferred source_terms_convergence_test(u, x, t, equations)) == + RealT + @test eltype(@inferred initial_condition_weak_blast_wave(x, t, equations)) == + RealT + + @test eltype(@inferred flux(u, normal_direction, equations)) == RealT + if RealT == Float32 + # check `ln_mean` and `stolarsky_mean` (test broken) + @test_broken eltype(@inferred flux_winters_etal(u_ll, u_rr, + normal_direction, + equations)) == + RealT + else + @test eltype(@inferred flux_winters_etal(u_ll, u_rr, normal_direction, + equations)) == + RealT + end + @test eltype(@inferred min_max_speed_naive(u_ll, u_rr, normal_direction, + equations)) == + RealT + @test eltype(@inferred min_max_speed_davis(u_ll, u_rr, normal_direction, + equations)) == + RealT + @test typeof(@inferred max_abs_speed_naive(u_ll, u_rr, normal_direction, + equations)) == + RealT + + for orientation in orientations + @test eltype(@inferred flux(u, orientation, equations)) == RealT + if RealT == Float32 + # check `ln_mean` and `stolarsky_mean` (test broken) + @test_broken eltype(@inferred flux_winters_etal(u_ll, u_rr, + orientation, + equations)) == + RealT + else + @test eltype(@inferred flux_winters_etal(u_ll, u_rr, orientation, + equations)) == + RealT + end + @test eltype(@inferred min_max_speed_davis(u_ll, u_rr, orientation, + equations)) == + RealT + @test typeof(@inferred max_abs_speed_naive(u_ll, u_rr, orientation, + equations)) == + RealT + end + + @test eltype(@inferred Trixi.max_abs_speeds(u, equations)) == RealT + @test eltype(@inferred cons2prim(u, equations)) == RealT + @test eltype(@inferred prim2cons(u, equations)) == RealT + @test eltype(@inferred cons2entropy(u, equations)) == RealT + @test typeof(@inferred density(u, equations)) == RealT + @test typeof(@inferred pressure(u, equations)) == RealT + end + end + end + @timed_testset "Shallow Water 1D" begin for RealT in (Float32, Float64) equations = @inferred ShallowWaterEquations1D(gravity_constant = RealT(9.81)) From b0d3a44dc55b6b61148947cc9fc2d8832fb3a33f Mon Sep 17 00:00:00 2001 From: Patrick Ersing <114223904+patrickersing@users.noreply.github.com> Date: Mon, 19 Aug 2024 10:47:46 +0200 Subject: [PATCH 15/25] Update NC-fluxes for the SWE (#2038) * rewrite nonconservative fluxes * update test values for unstructured2d * update test values for unstructured 2d --------- Co-authored-by: Andrew Winters --- .../tree_2d_dgsem/elixir_shallowwater_wall.jl | 4 +- src/Trixi.jl | 1 - src/equations/shallow_water_1d.jl | 69 ++------ src/equations/shallow_water_2d.jl | 151 +++--------------- test/test_tree_1d_shallowwater.jl | 32 ++-- test/test_tree_2d_shallowwater.jl | 26 ++- test/test_type.jl | 10 -- test/test_unstructured_2d.jl | 40 ++--- 8 files changed, 88 insertions(+), 245 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_shallowwater_wall.jl b/examples/tree_2d_dgsem/elixir_shallowwater_wall.jl index b8dbad50680..f8f601d4120 100644 --- a/examples/tree_2d_dgsem/elixir_shallowwater_wall.jl +++ b/examples/tree_2d_dgsem/elixir_shallowwater_wall.jl @@ -29,8 +29,8 @@ boundary_condition = boundary_condition_slip_wall ############################################################################### # Get the DG approximation space -volume_flux = (flux_wintermeyer_etal, flux_nonconservative_ersing_etal) -surface_flux = (flux_lax_friedrichs, flux_nonconservative_ersing_etal) +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) +surface_flux = (flux_lax_friedrichs, flux_nonconservative_wintermeyer_etal) solver = DGSEM(polydeg = 3, surface_flux = surface_flux, volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) diff --git a/src/Trixi.jl b/src/Trixi.jl index 23a8cfe1d0a..90fa590c50a 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -179,7 +179,6 @@ export flux, flux_central, flux_lax_friedrichs, flux_hll, flux_hllc, flux_hlle, flux_kennedy_gruber, flux_shima_etal, flux_ec, flux_fjordholm_etal, flux_nonconservative_fjordholm_etal, flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal, - flux_nonconservative_ersing_etal, flux_chan_etal, flux_nonconservative_chan_etal, flux_winters_etal, hydrostatic_reconstruction_audusse_etal, flux_nonconservative_audusse_etal, FluxPlusDissipation, DissipationGlobalLaxFriedrichs, DissipationLocalLaxFriedrichs, diff --git a/src/equations/shallow_water_1d.jl b/src/equations/shallow_water_1d.jl index 998deb04de2..3c218eee9d9 100644 --- a/src/equations/shallow_water_1d.jl +++ b/src/equations/shallow_water_1d.jl @@ -201,20 +201,27 @@ end Non-symmetric two-point volume flux discretizing the nonconservative (source) term that contains the gradient of the bottom topography [`ShallowWaterEquations1D`](@ref). -Further details are available in the paper: +Gives entropy conservation and well-balancedness on both the volume and surface when combined with +[`flux_wintermeyer_etal`](@ref). + +Further details are available in the papers: - Niklas Wintermeyer, Andrew R. Winters, Gregor J. Gassner and David A. Kopriva (2017) An entropy stable nodal discontinuous Galerkin method for the two dimensional shallow water equations on unstructured curvilinear meshes with discontinuous bathymetry [DOI: 10.1016/j.jcp.2017.03.036](https://doi.org/10.1016/j.jcp.2017.03.036) +- Patrick Ersing, Andrew R. Winters (2023) + An entropy stable discontinuous Galerkin method for the two-layer shallow water equations on + curvilinear meshes + [DOI: 10.48550/arXiv.2306.12699](https://doi.org/10.48550/arXiv.2306.12699) """ @inline function flux_nonconservative_wintermeyer_etal(u_ll, u_rr, orientation::Integer, equations::ShallowWaterEquations1D) # Pull the necessary left and right state information h_ll = waterheight(u_ll, equations) - b_rr = u_rr[3] + b_jump = u_rr[3] - u_ll[3] # Bottom gradient nonconservative term: (0, g h b_x, 0) - f = SVector(0, equations.gravity * h_ll * b_rr, 0) + f = SVector(0, equations.gravity * h_ll * b_jump, 0) return f end @@ -226,11 +233,8 @@ end Non-symmetric two-point surface flux discretizing the nonconservative (source) term of that contains the gradient of the bottom topography [`ShallowWaterEquations1D`](@ref). -This contains additional terms compared to [`flux_nonconservative_wintermeyer_etal`](@ref) -that account for possible discontinuities in the bottom topography function. -Thus, this flux should be used in general at interfaces. For flux differencing volume terms, -[`flux_nonconservative_wintermeyer_etal`](@ref) is analytically equivalent but slightly -cheaper. +This flux can be used together with [`flux_fjordholm_etal`](@ref) at interfaces to ensure entropy +conservation and well-balancedness. Further details for the original finite volume formulation are available in - Ulrik S. Fjordholm, Siddhartha Mishr and Eitan Tadmor (2011) @@ -256,7 +260,6 @@ and for curvilinear 2D case in the paper: # cross-averaging across a discontinuous bottom topography # (ii) True surface part that uses `h_average` and `b_jump` to handle discontinuous bathymetry f = SVector(0, - equations.gravity * h_ll * b_ll + equations.gravity * h_average * b_jump, 0) @@ -285,7 +288,7 @@ Further details on the hydrostatic reconstruction and its motivation can be foun orientation::Integer, equations::ShallowWaterEquations1D) # Pull the water height and bottom topography on the left - h_ll, _, b_ll = u_ll + h_ll, _, _ = u_ll # Create the hydrostatic reconstruction for the left solution state u_ll_star, _ = hydrostatic_reconstruction_audusse_etal(u_ll, u_rr, equations) @@ -293,52 +296,11 @@ Further details on the hydrostatic reconstruction and its motivation can be foun # Copy the reconstructed water height for easier to read code h_ll_star = u_ll_star[1] - # Includes two parts: - # (i) Diagonal (consistent) term from the volume flux that uses `b_ll` to avoid - # cross-averaging across a discontinuous bottom topography - # (ii) True surface part that uses `h_ll` and `h_ll_star` to handle discontinuous bathymetry return SVector(0, - equations.gravity * h_ll * b_ll + equations.gravity * (h_ll^2 - h_ll_star^2), 0) end -""" - flux_nonconservative_ersing_etal(u_ll, u_rr, orientation::Integer, - equations::ShallowWaterEquations1D) - -!!! warning "Experimental code" - This numerical flux is experimental and may change in any future release. - -Non-symmetric path-conservative two-point volume flux discretizing the nonconservative (source) term -that contains the gradient of the bottom topography [`ShallowWaterEquations1D`](@ref). - -This is a modified version of [`flux_nonconservative_wintermeyer_etal`](@ref) that gives entropy -conservation and well-balancedness in both the volume and surface when combined with -[`flux_wintermeyer_etal`](@ref). - -For further details see: -- Patrick Ersing, Andrew R. Winters (2023) - An entropy stable discontinuous Galerkin method for the two-layer shallow water equations on - curvilinear meshes - [DOI: 10.48550/arXiv.2306.12699](https://doi.org/10.48550/arXiv.2306.12699) -""" -@inline function flux_nonconservative_ersing_etal(u_ll, u_rr, orientation::Integer, - equations::ShallowWaterEquations1D) - # Pull the necessary left and right state information - h_ll = waterheight(u_ll, equations) - b_rr = u_rr[3] - b_ll = u_ll[3] - - # Calculate jump - b_jump = b_rr - b_ll - - # Bottom gradient nonconservative term: (0, g h b_x, 0) - f = SVector(0, equations.gravity * h_ll * b_jump, 0) - - return f -end - """ flux_fjordholm_etal(u_ll, u_rr, orientation, equations::ShallowWaterEquations1D) @@ -378,7 +340,8 @@ end Total energy conservative (mathematical entropy for shallow water equations) split form. When the bottom topography is nonzero this scheme will be well-balanced when used as a `volume_flux`. -The `surface_flux` should still use, e.g., [`flux_fjordholm_etal`](@ref). +For the `surface_flux` either [`flux_wintermeyer_etal`](@ref) or [`flux_fjordholm_etal`](@ref) can +be used to ensure well-balancedness and entropy conservation. Further details are available in Theorem 1 of the paper: - Niklas Wintermeyer, Andrew R. Winters, Gregor J. Gassner and David A. Kopriva (2017) @@ -571,7 +534,7 @@ end # Note, only the first two are the entropy variables, the third entry still # just carries the bottom topography values for convenience @inline function cons2entropy(u, equations::ShallowWaterEquations1D) - h, h_v, b = u + h, _, b = u v = velocity(u, equations) diff --git a/src/equations/shallow_water_2d.jl b/src/equations/shallow_water_2d.jl index db8f00fc15b..4ecaf3b6e14 100644 --- a/src/equations/shallow_water_2d.jl +++ b/src/equations/shallow_water_2d.jl @@ -274,28 +274,30 @@ end Non-symmetric two-point volume flux discretizing the nonconservative (source) term that contains the gradient of the bottom topography [`ShallowWaterEquations2D`](@ref). -On curvilinear meshes, this nonconservative flux depends on both the -contravariant vector (normal direction) at the current node and the averaged -one. This is different from numerical fluxes used to discretize conservative -terms. +For the `surface_flux` either [`flux_wintermeyer_etal`](@ref) or [`flux_fjordholm_etal`](@ref) can +be used to ensure well-balancedness and entropy conservation. -Further details are available in the paper: +Further details are available in the papers: - Niklas Wintermeyer, Andrew R. Winters, Gregor J. Gassner and David A. Kopriva (2017) An entropy stable nodal discontinuous Galerkin method for the two dimensional shallow water equations on unstructured curvilinear meshes with discontinuous bathymetry [DOI: 10.1016/j.jcp.2017.03.036](https://doi.org/10.1016/j.jcp.2017.03.036) +- Patrick Ersing, Andrew R. Winters (2023) + An entropy stable discontinuous Galerkin method for the two-layer shallow water equations on + curvilinear meshes + [DOI: 10.48550/arXiv.2306.12699](https://doi.org/10.48550/arXiv.2306.12699) """ @inline function flux_nonconservative_wintermeyer_etal(u_ll, u_rr, orientation::Integer, equations::ShallowWaterEquations2D) # Pull the necessary left and right state information h_ll = waterheight(u_ll, equations) - b_rr = u_rr[4] + b_jump = u_rr[4] - u_ll[4] # Bottom gradient nonconservative term: (0, g h b_x, g h b_y, 0) if orientation == 1 - f = SVector(0, equations.gravity * h_ll * b_rr, 0, 0) + f = SVector(0, equations.gravity * h_ll * b_jump, 0, 0) else # orientation == 2 - f = SVector(0, 0, equations.gravity * h_ll * b_rr, 0) + f = SVector(0, 0, equations.gravity * h_ll * b_jump, 0) end return f end @@ -306,12 +308,12 @@ end equations::ShallowWaterEquations2D) # Pull the necessary left and right state information h_ll = waterheight(u_ll, equations) - b_rr = u_rr[4] - # Note this routine only uses the `normal_direction_average` and the average of the - # bottom topography to get a quadratic split form DG gradient on curved elements + b_jump = u_rr[4] - u_ll[4] + + # Bottom gradient nonconservative term: (0, g h b_x, g h b_y, 0) return SVector(0, - normal_direction_average[1] * equations.gravity * h_ll * b_rr, - normal_direction_average[2] * equations.gravity * h_ll * b_rr, + normal_direction_average[1] * equations.gravity * h_ll * b_jump, + normal_direction_average[2] * equations.gravity * h_ll * b_jump, 0) end @@ -326,16 +328,8 @@ end Non-symmetric two-point surface flux discretizing the nonconservative (source) term of that contains the gradient of the bottom topography [`ShallowWaterEquations2D`](@ref). -On curvilinear meshes, this nonconservative flux depends on both the -contravariant vector (normal direction) at the current node and the averaged -one. This is different from numerical fluxes used to discretize conservative -terms. - -This contains additional terms compared to [`flux_nonconservative_wintermeyer_etal`](@ref) -that account for possible discontinuities in the bottom topography function. -Thus, this flux should be used in general at interfaces. For flux differencing volume terms, -[`flux_nonconservative_wintermeyer_etal`](@ref) is analytically equivalent but slightly -cheaper. +This flux can be used together with [`flux_fjordholm_etal`](@ref) at interfaces to ensure entropy +conservation and well-balancedness. Further details for the original finite volume formulation are available in - Ulrik S. Fjordholm, Siddhartha Mishr and Eitan Tadmor (2011) @@ -356,18 +350,13 @@ and for curvilinear 2D case in the paper: h_average = 0.5f0 * (h_ll + h_rr) b_jump = b_rr - b_ll - # Includes two parts: - # (i) Diagonal (consistent) term from the volume flux that uses `b_ll` to avoid - # cross-averaging across a discontinuous bottom topography - # (ii) True surface part that uses `h_average` and `b_jump` to handle discontinuous bathymetry + # Bottom gradient nonconservative term: (0, g h b_x, g h b_y, 0) if orientation == 1 f = SVector(0, - equations.gravity * h_ll * b_ll + equations.gravity * h_average * b_jump, 0, 0) else # orientation == 2 f = SVector(0, 0, - equations.gravity * h_ll * b_ll + equations.gravity * h_average * b_jump, 0) end @@ -383,20 +372,12 @@ end h_ll, _, _, b_ll = u_ll h_rr, _, _, b_rr = u_rr - # Comes in two parts: - # (i) Diagonal (consistent) term from the volume flux that uses `normal_direction_average` - # but we use `b_ll` to avoid cross-averaging across a discontinuous bottom topography - - f2 = normal_direction_average[1] * equations.gravity * h_ll * b_ll - f3 = normal_direction_average[2] * equations.gravity * h_ll * b_ll - - # (ii) True surface part that uses `normal_direction_ll`, `h_average` and `b_jump` - # to handle discontinuous bathymetry h_average = 0.5f0 * (h_ll + h_rr) b_jump = b_rr - b_ll - f2 += normal_direction_ll[1] * equations.gravity * h_average * b_jump - f3 += normal_direction_ll[2] * equations.gravity * h_average * b_jump + # Bottom gradient nonconservative term: (0, g h b_x, g h b_y, 0) + f2 = normal_direction_average[1] * equations.gravity * h_average * b_jump + f3 = normal_direction_average[2] * equations.gravity * h_average * b_jump # First and last equations do not have a nonconservative flux f1 = f4 = 0 @@ -472,18 +453,12 @@ Further details for the hydrostatic reconstruction and its motivation can be fou # Copy the reconstructed water height for easier to read code h_ll_star = u_ll_star[1] - # Includes two parts: - # (i) Diagonal (consistent) term from the volume flux that uses `b_ll` to avoid - # cross-averaging across a discontinuous bottom topography - # (ii) True surface part that uses `h_ll` and `h_ll_star` to handle discontinuous bathymetry if orientation == 1 f = SVector(0, - equations.gravity * h_ll * b_ll + equations.gravity * (h_ll^2 - h_ll_star^2), 0, 0) else # orientation == 2 f = SVector(0, 0, - equations.gravity * h_ll * b_ll + equations.gravity * (h_ll^2 - h_ll_star^2), 0) end @@ -504,18 +479,8 @@ end # Copy the reconstructed water height for easier to read code h_ll_star = u_ll_star[1] - # Comes in two parts: - # (i) Diagonal (consistent) term from the volume flux that uses `normal_direction_average` - # but we use `b_ll` to avoid cross-averaging across a discontinuous bottom topography - - f2 = normal_direction_average[1] * equations.gravity * h_ll * b_ll - f3 = normal_direction_average[2] * equations.gravity * h_ll * b_ll - - # (ii) True surface part that uses `normal_direction_ll`, `h_ll` and `h_ll_star` - # to handle discontinuous bathymetry - - f2 += normal_direction_ll[1] * equations.gravity * (h_ll^2 - h_ll_star^2) - f3 += normal_direction_ll[2] * equations.gravity * (h_ll^2 - h_ll_star^2) + f2 = normal_direction_average[1] * equations.gravity * (h_ll^2 - h_ll_star^2) + f3 = normal_direction_average[2] * equations.gravity * (h_ll^2 - h_ll_star^2) # First and last equations do not have a nonconservative flux f1 = f4 = 0 @@ -523,73 +488,6 @@ end return SVector(f1, f2, f3, f4) end -""" - flux_nonconservative_ersing_etal(u_ll, u_rr, orientation::Integer, - equations::ShallowWaterEquations2D) - flux_nonconservative_ersing_etal(u_ll, u_rr, - normal_direction_ll::AbstractVector, - normal_direction_average::AbstractVector, - equations::ShallowWaterEquations2D) - -!!! warning "Experimental code" - This numerical flux is experimental and may change in any future release. - -Non-symmetric path-conservative two-point volume flux discretizing the nonconservative (source) term -that contains the gradient of the bottom topography [`ShallowWaterEquations2D`](@ref). - -On curvilinear meshes, this nonconservative flux depends on both the -contravariant vector (normal direction) at the current node and the averaged -one. This is different from numerical fluxes used to discretize conservative -terms. - -This is a modified version of [`flux_nonconservative_wintermeyer_etal`](@ref) that gives entropy -conservation and well-balancedness in both the volume and surface when combined with -[`flux_wintermeyer_etal`](@ref). - -For further details see: -- Patrick Ersing, Andrew R. Winters (2023) - An entropy stable discontinuous Galerkin method for the two-layer shallow water equations on - curvilinear meshes - [DOI: 10.48550/arXiv.2306.12699](https://doi.org/10.48550/arXiv.2306.12699) -""" -@inline function flux_nonconservative_ersing_etal(u_ll, u_rr, orientation::Integer, - equations::ShallowWaterEquations2D) - # Pull the necessary left and right state information - h_ll = waterheight(u_ll, equations) - b_rr = u_rr[4] - b_ll = u_ll[4] - - # Calculate jump - b_jump = b_rr - b_ll - - # Bottom gradient nonconservative term: (0, g h b_x, g h b_y, 0) - if orientation == 1 - f = SVector(0, equations.gravity * h_ll * b_jump, 0, 0) - else # orientation == 2 - f = SVector(0, 0, equations.gravity * h_ll * b_jump, 0) - end - return f -end - -@inline function flux_nonconservative_ersing_etal(u_ll, u_rr, - normal_direction_ll::AbstractVector, - normal_direction_average::AbstractVector, - equations::ShallowWaterEquations2D) - # Pull the necessary left and right state information - h_ll = waterheight(u_ll, equations) - b_rr = u_rr[4] - b_ll = u_ll[4] - - # Calculate jump - b_jump = b_rr - b_ll - # Note this routine only uses the `normal_direction_average` and the average of the - # bottom topography to get a quadratic split form DG gradient on curved elements - return SVector(0, - normal_direction_average[1] * equations.gravity * h_ll * b_jump, - normal_direction_average[2] * equations.gravity * h_ll * b_jump, - 0) -end - """ flux_fjordholm_etal(u_ll, u_rr, orientation_or_normal_direction, equations::ShallowWaterEquations2D) @@ -664,7 +562,8 @@ end Total energy conservative (mathematical entropy for shallow water equations) split form. When the bottom topography is nonzero this scheme will be well-balanced when used as a `volume_flux`. -The `surface_flux` should still use, e.g., [`flux_fjordholm_etal`](@ref). +For the `surface_flux` either [`flux_wintermeyer_etal`](@ref) or [`flux_fjordholm_etal`](@ref) can +be used to ensure well-balancedness and entropy conservation. Further details are available in Theorem 1 of the paper: - Niklas Wintermeyer, Andrew R. Winters, Gregor J. Gassner and David A. Kopriva (2017) diff --git a/test/test_tree_1d_shallowwater.jl b/test/test_tree_1d_shallowwater.jl index 8fe3291a938..42a91e578e4 100644 --- a/test/test_tree_1d_shallowwater.jl +++ b/test/test_tree_1d_shallowwater.jl @@ -98,7 +98,7 @@ end end end -@trixi_testset "elixir_shallowwater_well_balanced.jl with flux_nonconservative_ersing_etal" begin +@trixi_testset "elixir_shallowwater_well_balanced.jl with flux_nonconservative_wintermeyer_etal" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced.jl"), l2=[ 0.10416666834254838, @@ -107,9 +107,7 @@ end ], linf=[2.0000000000000004, 3.0610625110157164e-14, 2.0], surface_flux=(flux_wintermeyer_etal, - flux_nonconservative_ersing_etal), - volume_flux=(flux_wintermeyer_etal, - flux_nonconservative_ersing_etal), + flux_nonconservative_wintermeyer_etal), tspan=(0.0, 0.25)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) @@ -169,7 +167,7 @@ end end end -@trixi_testset "elixir_shallowwater_source_terms.jl with flux_nonconservative_ersing_etal" begin +@trixi_testset "elixir_shallowwater_source_terms.jl with flux_nonconservative_wintermeyer_etal" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), l2=[ 0.005774284062933275, @@ -182,9 +180,7 @@ end 9.098379777450205e-5, ], surface_flux=(flux_wintermeyer_etal, - flux_nonconservative_ersing_etal), - volume_flux=(flux_wintermeyer_etal, - flux_nonconservative_ersing_etal), + flux_nonconservative_wintermeyer_etal), tspan=(0.0, 0.025)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) @@ -200,13 +196,13 @@ end @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms_dirichlet.jl"), l2=[ - 0.0022851099219788917, - 0.01560453773635554, - 4.43649172558535e-5, + 0.0022667320585353927, + 0.01571629729279524, + 4.4364917255842716e-5, ], linf=[ - 0.008934615705174398, - 0.059403169140869405, + 0.008945234652224965, + 0.059403165802872415, 9.098379777405796e-5, ], tspan=(0.0, 0.025)) @@ -224,13 +220,13 @@ end @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms_dirichlet.jl"), l2=[ - 0.0022956052733432287, - 0.015540053559855601, - 4.43649172558535e-5, + 0.0022774071143995952, + 0.01566214422689219, + 4.4364917255842716e-5, ], linf=[ - 0.008460440313118323, - 0.05720939349382359, + 0.008451721489057373, + 0.05720939055279217, 9.098379777405796e-5, ], surface_flux=(FluxHydrostaticReconstruction(FluxHLL(min_max_speed_naive), diff --git a/test/test_tree_2d_shallowwater.jl b/test/test_tree_2d_shallowwater.jl index 9a3ba36c7d4..bcad663008c 100644 --- a/test/test_tree_2d_shallowwater.jl +++ b/test/test_tree_2d_shallowwater.jl @@ -114,7 +114,7 @@ end end end -@trixi_testset "elixir_shallowwater_well_balanced.jl with flux_nonconservative_ersing_etal" begin +@trixi_testset "elixir_shallowwater_well_balanced.jl with flux_nonconservative_wintermeyer_etal" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced.jl"), l2=[ 0.9130579602987146, @@ -129,9 +129,7 @@ end 2.1130620376156584, ], surface_flux=(flux_wintermeyer_etal, - flux_nonconservative_ersing_etal), - volume_flux=(flux_wintermeyer_etal, - flux_nonconservative_ersing_etal), + flux_nonconservative_wintermeyer_etal), tspan=(0.0, 0.25)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) @@ -172,15 +170,15 @@ end @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms_dirichlet.jl"), l2=[ - 0.0018746929418489125, - 0.017332321628469628, - 0.01634953679145536, - 6.274146767717023e-5, + 0.0018596727473552813, + 0.017306217777629147, + 0.016367646997420396, + 6.274146767723934e-5, ], linf=[ - 0.016262353691956388, - 0.08726160620859424, - 0.09043621801418844, + 0.016548007102923368, + 0.08726160568822783, + 0.09043621622245013, 0.0001819675955490041, ], tspan=(0.0, 0.025)) @@ -248,7 +246,7 @@ end end end -@trixi_testset "elixir_shallowwater_source_terms.jl with flux_nonconservative_ersing_etal" begin +@trixi_testset "elixir_shallowwater_source_terms.jl with flux_nonconservative_wintermeyer_etal" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), l2=[ 0.002471853426064005, @@ -263,9 +261,7 @@ end 0.0001819675955490041, ], surface_flux=(flux_wintermeyer_etal, - flux_nonconservative_ersing_etal), - volume_flux=(flux_wintermeyer_etal, - flux_nonconservative_ersing_etal), + flux_nonconservative_wintermeyer_etal), tspan=(0.0, 0.25)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) diff --git a/test/test_type.jl b/test/test_type.jl index d22afa65c0a..c15ac5f78c6 100644 --- a/test/test_type.jl +++ b/test/test_type.jl @@ -2045,8 +2045,6 @@ isdir(outdir) && rm(outdir, recursive = true) @test eltype(@inferred flux_nonconservative_audusse_etal(u_ll, u_rr, orientation, equations)) == RealT - @test eltype(@inferred flux_nonconservative_ersing_etal(u_ll, u_rr, orientation, - equations)) == RealT @test eltype(@inferred flux_fjordholm_etal(u_ll, u_rr, orientation, equations)) == RealT @test eltype(@inferred flux_wintermeyer_etal(u_ll, u_rr, orientation, @@ -2133,10 +2131,6 @@ isdir(outdir) && rm(outdir, recursive = true) normal_direction_ll, normal_direction_average, equations)) == RealT - @test eltype(@inferred flux_nonconservative_ersing_etal(u_ll, u_rr, - normal_direction_ll, - normal_direction_average, - equations)) == RealT @test eltype(@inferred flux_fjordholm_etal(u_ll, u_rr, normal_direction, equations)) == RealT @test eltype(@inferred flux_wintermeyer_etal(u_ll, u_rr, normal_direction, @@ -2181,10 +2175,6 @@ isdir(outdir) && rm(outdir, recursive = true) orientation, equations)) == RealT - @test eltype(eltype(@inferred flux_nonconservative_ersing_etal(u_ll, u_rr, - orientation, - equations))) == - RealT @test eltype(@inferred flux_fjordholm_etal(u_ll, u_rr, orientation, equations)) == RealT @test eltype(@inferred flux_wintermeyer_etal(u_ll, u_rr, orientation, diff --git a/test/test_unstructured_2d.jl b/test/test_unstructured_2d.jl index 5c228d1e04c..563f99792d0 100644 --- a/test/test_unstructured_2d.jl +++ b/test/test_unstructured_2d.jl @@ -351,16 +351,16 @@ end @trixi_testset "elixir_shallowwater_well_balanced.jl with FluxHydrostaticReconstruction" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced.jl"), l2=[ - 1.2164292510839085, - 1.2643106818778908e-12, - 1.269230436589819e-12, - 1.2164292510839079, + 1.2164292510839063, + 1.2676379081600215e-12, + 1.255855785593831e-12, + 1.2164292510839074, ], linf=[ - 1.513851228231562, - 1.6670644673575802e-11, - 1.8426585188623954e-11, - 1.513851228231574, + 1.5138512282315604, + 1.658245722058109e-11, + 1.8665562182185795e-11, + 1.5138512282315737, ], surface_flux=(FluxHydrostaticReconstruction(flux_lax_friedrichs, hydrostatic_reconstruction_audusse_etal), @@ -376,7 +376,7 @@ end end end -@trixi_testset "elixir_shallowwater_well_balanced.jl with flux_nonconservative_ersing_etal" begin +@trixi_testset "elixir_shallowwater_well_balanced.jl with flux_nonconservative_wintermeyer_etal" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced.jl"), l2=[ 1.2164292510839083, @@ -391,9 +391,7 @@ end 1.513851228231574, ], surface_flux=(flux_wintermeyer_etal, - flux_nonconservative_ersing_etal), - volume_flux=(flux_wintermeyer_etal, - flux_nonconservative_ersing_etal), + flux_nonconservative_wintermeyer_etal), tspan=(0.0, 0.25)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) @@ -458,7 +456,7 @@ end end end -@trixi_testset "elixir_shallowwater_source_terms.jl with flux_nonconservative_ersing_etal" begin +@trixi_testset "elixir_shallowwater_source_terms.jl with flux_nonconservative_wintermeyer_etal" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), l2=[ 0.001118046975499805, @@ -473,9 +471,7 @@ end 2.6407324614341476e-5, ], surface_flux=(flux_wintermeyer_etal, - flux_nonconservative_ersing_etal), - volume_flux=(flux_wintermeyer_etal, - flux_nonconservative_ersing_etal), + flux_nonconservative_wintermeyer_etal), tspan=(0.0, 0.025)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) @@ -517,12 +513,16 @@ end @trixi_testset "elixir_shallowwater_dirichlet.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_dirichlet.jl"), l2=[ - 1.1577518608938916e-5, 4.859252379740366e-13, - 4.639600837197925e-13, 1.1577518608952174e-5, + 1.1577518608950964e-5, + 4.761947272222427e-13, + 4.546045873135486e-13, + 1.157751860893347e-5, ], linf=[ - 8.3940638787805e-5, 1.1446362498574484e-10, - 1.1124515748367981e-10, 8.39406387962427e-5, + 8.394063879002545e-5, + 1.1211566736150389e-10, + 1.0890426250906834e-10, + 8.394063879602065e-5, ], tspan=(0.0, 2.0)) # Ensure that we do not have excessive memory allocations From ef1100d4f1152fa48d674b875e529761eac8966e Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 19 Aug 2024 10:48:40 +0200 Subject: [PATCH 16/25] set version to v0.8.7 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index d5627651d6d..7800b904c89 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Trixi" uuid = "a7f1ee26-1774-49b1-8366-f1abc58fbfcb" authors = ["Michael Schlottke-Lakemper ", "Gregor Gassner ", "Hendrik Ranocha ", "Andrew R. Winters ", "Jesse Chan "] -version = "0.8.7-DEV" +version = "0.8.7" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 26ab5fa1230fb2ef761bb6bb6553f99d9c7e99d3 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 19 Aug 2024 10:48:58 +0200 Subject: [PATCH 17/25] set development version to v0.8.8-DEV --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 7800b904c89..923cf5248a8 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Trixi" uuid = "a7f1ee26-1774-49b1-8366-f1abc58fbfcb" authors = ["Michael Schlottke-Lakemper ", "Gregor Gassner ", "Hendrik Ranocha ", "Andrew R. Winters ", "Jesse Chan "] -version = "0.8.7" +version = "0.8.8-DEV" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From ba82d36cc7f7aa9d78a55e92cb94cd5215923d06 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Mon, 19 Aug 2024 13:40:08 +0200 Subject: [PATCH 18/25] Conservative AMR (#2028) * small typo fixes * Interpolate and project Ju instead of u to retain discrete conservation * add specialized routines for TreeMesh and P4estMesh. Hopefully some tests pass now * remove unused copy * remove false comment * simplify the method on the children * update 2d p4est tests * update 3d p4est tests * update 2d t8code tests * update 3d t8code tests * update mpi test values * fix formatting * remove unnecessary comment * add new 2d tests including conservation * add new 3d tests including conservation * update t8code 2d mpi test * remove unnecessary Union * add comments regarding how element ids are incremented during refine or coarsen * typo fixes * another typo fix * fix comment * Apply suggestions from code review Co-authored-by: Daniel Doehring * Apply suggestions from code review Co-authored-by: Hendrik Ranocha * combine GC.preserve blocks * fix formatting in elixir * simplify implementation and add if blocks for P4estMesh specialities * unify structure across P4estMesh and T8codeMesh * fix some of the bad formatting * Apply suggestions from code review Co-authored-by: Hendrik Ranocha * add news * Update NEWS.md Co-authored-by: Andrew Winters --------- Co-authored-by: Daniel Doehring Co-authored-by: Hendrik Ranocha --- NEWS.md | 8 + .../elixir_euler_weak_blast_wave_amr.jl | 117 +++++++++++++ .../elixir_euler_weak_blast_wave_amr.jl | 114 ++++++++++++ .../elixir_advection_amr_unstructured_flag.jl | 3 +- .../elixir_euler_weak_blast_wave_amr.jl | 114 ++++++++++++ .../elixir_euler_weak_blast_wave_amr.jl | 116 +++++++++++++ src/callbacks_step/amr_dg2d.jl | 152 ++++++++++++++-- src/callbacks_step/amr_dg3d.jl | 163 +++++++++++++++--- src/meshes/structured_mesh.jl | 4 +- src/meshes/surface_interpolant.jl | 2 +- test/test_mpi_p4est_2d.jl | 4 +- test/test_mpi_p4est_3d.jl | 4 +- test/test_mpi_t8code_2d.jl | 5 +- test/test_mpi_t8code_3d.jl | 4 +- test/test_p4est_2d.jl | 127 +++++++++----- test/test_p4est_3d.jl | 61 +++++-- test/test_t8code_2d.jl | 52 +++++- test/test_t8code_3d.jl | 59 +++++-- 18 files changed, 980 insertions(+), 129 deletions(-) create mode 100644 examples/p4est_2d_dgsem/elixir_euler_weak_blast_wave_amr.jl create mode 100644 examples/p4est_3d_dgsem/elixir_euler_weak_blast_wave_amr.jl create mode 100644 examples/t8code_2d_dgsem/elixir_euler_weak_blast_wave_amr.jl create mode 100644 examples/t8code_3d_dgsem/elixir_euler_weak_blast_wave_amr.jl diff --git a/NEWS.md b/NEWS.md index bca7d03e954..9371cafa07f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,14 @@ Trixi.jl follows the interpretation of [semantic versioning (semver)](https://ju used in the Julia ecosystem. Notable changes will be documented in this file for human readability. +## Changes in the v0.8 lifecycle + +#### Changed + +- The AMR routines for `P4estMesh` and `T8codeMesh` were changed to work on the product + of the Jacobian and the conserved variables instead of the conserved variables only + to make AMR fully conservative ([#2028]). This may change AMR results slightly. + ## Changes when updating to v0.8 from v0.7.x #### Added diff --git a/examples/p4est_2d_dgsem/elixir_euler_weak_blast_wave_amr.jl b/examples/p4est_2d_dgsem/elixir_euler_weak_blast_wave_amr.jl new file mode 100644 index 00000000000..68680673712 --- /dev/null +++ b/examples/p4est_2d_dgsem/elixir_euler_weak_blast_wave_amr.jl @@ -0,0 +1,117 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations2D(1.4) + +function initial_condition_weak_blast_wave(x, t, equations::CompressibleEulerEquations2D) + # Set up polar coordinates + inicenter = SVector(0.0, 0.0) + x_norm = x[1] - inicenter[1] + y_norm = x[2] - inicenter[2] + r = sqrt(x_norm^2 + y_norm^2) + + r0 = 0.2 + E = 1 + p0_inner = 3 + p0_outer = 1 + + # Calculate primitive variables + rho = 1.1 + v1 = 0.0 + v2 = 0.0 + p = r > r0 ? p0_outer : p0_inner + + return prim2cons(SVector(rho, v1, v2, p), equations) +end + +initial_condition = initial_condition_weak_blast_wave + +# Get the DG approximation space + +# Activate the shock capturing + flux differencing +surface_flux = flux_lax_friedrichs +volume_flux = flux_ranocha +polydeg = 4 +basis = LobattoLegendreBasis(polydeg) +indicator_sc = IndicatorHennemannGassner(equations, basis, + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = density_pressure) +volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) + +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral) + +############################################################################### + +# Affine type mapping to take the [-1,1]^2 domain +# and warp it as described in https://arxiv.org/abs/2012.12040 +# Warping with the coefficient 0.2 is even more extreme. +function mapping_twist(xi, eta) + y = eta + 0.125 * cos(1.5 * pi * xi) * cos(0.5 * pi * eta) + x = xi + 0.125 * cos(0.5 * pi * xi) * cos(2.0 * pi * y) + return SVector(x, y) +end + +# The mesh below can be made periodic +# Create P4estMesh with 8 x 8 trees +trees_per_dimension = (8, 8) +mesh = P4estMesh(trees_per_dimension, polydeg = 4, + mapping = mapping_twist, + initial_refinement_level = 0, + periodicity = true) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 1.2) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 400 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_errors = (:conservation_error,)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(dt = 0.2, + save_initial_solution = true, + save_final_solution = true) + +amr_indicator = IndicatorLöhner(semi, variable = Trixi.density) +amr_controller = ControllerThreeLevel(semi, amr_indicator, + base_level = 0, + med_level = 1, med_threshold = 0.05, + max_level = 2, max_threshold = 0.1) +amr_callback = AMRCallback(semi, amr_controller, + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) + +stepsize_callback = StepsizeCallback(cfl = 0.5) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + amr_callback, + stepsize_callback) + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks);#, maxiters=4); +summary_callback() # print the timer summary diff --git a/examples/p4est_3d_dgsem/elixir_euler_weak_blast_wave_amr.jl b/examples/p4est_3d_dgsem/elixir_euler_weak_blast_wave_amr.jl new file mode 100644 index 00000000000..b5b56220004 --- /dev/null +++ b/examples/p4est_3d_dgsem/elixir_euler_weak_blast_wave_amr.jl @@ -0,0 +1,114 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations3D(1.4) + +function initial_condition_weak_blast_wave(x, t, + equations::CompressibleEulerEquations3D) + # Set up polar coordinates + inicenter = SVector(0.0, 0.0, 0.0) + x_norm = x[1] - inicenter[1] + y_norm = x[2] - inicenter[2] + z_norm = x[3] - inicenter[3] + r = sqrt(x_norm^2 + y_norm^2 + z_norm^2) + + r0 = 0.2 + E = 1.0 + p0_inner = 3 + p0_outer = 1 + + # Calculate primitive variables + rho = 1.1 + v1 = 0.0 + v2 = 0.0 + v3 = 0.0 + p = r > r0 ? p0_outer : p0_inner + + return prim2cons(SVector(rho, v1, v2, v3, p), equations) +end + +initial_condition = initial_condition_weak_blast_wave + +surface_flux = flux_lax_friedrichs +volume_flux = flux_ranocha +polydeg = 4 +basis = LobattoLegendreBasis(polydeg) +indicator_sc = IndicatorHennemannGassner(equations, basis, + alpha_max = 1.0, + alpha_min = 0.001, + alpha_smooth = true, + variable = density_pressure) +volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) + +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral) + +# Setup a periodic mesh with 4 x 4 x 4 trees and 8 x 8 x 8 elements +trees_per_dimension = (4, 4, 4) + +# Affine type mapping to take the [-1,1]^3 domain +# and warp it as described in https://arxiv.org/abs/2012.12040 +function mapping_twist(xi, eta, zeta) + y = eta + 1 / 6 * (cos(1.5 * pi * xi) * cos(0.5 * pi * eta) * cos(0.5 * pi * zeta)) + + x = xi + 1 / 6 * (cos(0.5 * pi * xi) * cos(2 * pi * y) * cos(0.5 * pi * zeta)) + + z = zeta + 1 / 6 * (cos(0.5 * pi * x) * cos(pi * y) * cos(0.5 * pi * zeta)) + + return SVector(x, y, z) +end + +mesh = P4estMesh(trees_per_dimension, + polydeg = 2, + mapping = mapping_twist, + initial_refinement_level = 1, + periodicity = true) + +# Create the semidiscretization object +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 1.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:conservation_error,)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +amr_indicator = IndicatorLöhner(semi, variable = Trixi.density) +amr_controller = ControllerThreeLevel(semi, amr_indicator, + base_level = 1, + med_level = 2, med_threshold = 0.05, + max_level = 3, max_threshold = 0.15) +amr_callback = AMRCallback(semi, amr_controller, + interval = 1, + adapt_initial_condition = false, + adapt_initial_condition_only_refine = false) + +stepsize_callback = StepsizeCallback(cfl = 0.5) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + amr_callback, + stepsize_callback) + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); +summary_callback() # print the timer summary diff --git a/examples/t8code_2d_dgsem/elixir_advection_amr_unstructured_flag.jl b/examples/t8code_2d_dgsem/elixir_advection_amr_unstructured_flag.jl index 9138586cccf..d8893854811 100644 --- a/examples/t8code_2d_dgsem/elixir_advection_amr_unstructured_flag.jl +++ b/examples/t8code_2d_dgsem/elixir_advection_amr_unstructured_flag.jl @@ -61,7 +61,8 @@ amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first) amr_callback = AMRCallback(semi, amr_controller, interval = 5, adapt_initial_condition = true, - adapt_initial_condition_only_refine = true) + adapt_initial_condition_only_refine = true, + dynamic_load_balancing = true) stepsize_callback = StepsizeCallback(cfl = 0.7) diff --git a/examples/t8code_2d_dgsem/elixir_euler_weak_blast_wave_amr.jl b/examples/t8code_2d_dgsem/elixir_euler_weak_blast_wave_amr.jl new file mode 100644 index 00000000000..a3366caa317 --- /dev/null +++ b/examples/t8code_2d_dgsem/elixir_euler_weak_blast_wave_amr.jl @@ -0,0 +1,114 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations2D(1.4) + +function initial_condition_weak_blast_wave(x, t, equations::CompressibleEulerEquations2D) + # Set up polar coordinates + inicenter = SVector(0.0, 0.0) + x_norm = x[1] - inicenter[1] + y_norm = x[2] - inicenter[2] + r = sqrt(x_norm^2 + y_norm^2) + + r0 = 0.2 + E = 1 + p0_inner = 3 + p0_outer = 1 + + # Calculate primitive variables + rho = 1.1 + v1 = 0.0 + v2 = 0.0 + p = r > r0 ? p0_outer : p0_inner + + return prim2cons(SVector(rho, v1, v2, p), equations) +end + +initial_condition = initial_condition_weak_blast_wave + +# Get the DG approximation space + +# Activate the shock capturing + flux differencing +surface_flux = flux_lax_friedrichs +volume_flux = flux_ranocha +polydeg = 4 +basis = LobattoLegendreBasis(polydeg) +indicator_sc = IndicatorHennemannGassner(equations, basis, + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = density_pressure) +volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) + +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral) + +# Affine type mapping to take the [-1,1]^2 domain +# and warp it as described in https://arxiv.org/abs/2012.12040 +# Warping with the coefficient 0.2 is even more extreme. +function mapping_twist(xi, eta) + y = eta + 0.125 * cos(1.5 * pi * xi) * cos(0.5 * pi * eta) + x = xi + 0.125 * cos(0.5 * pi * xi) * cos(2.0 * pi * y) + return SVector(x, y) +end + +# The mesh below can be made periodic +# Create T8codeMesh with 8 x 8 trees +trees_per_dimension = (8, 8) +mesh = T8codeMesh(trees_per_dimension, polydeg = 4, + mapping = mapping_twist, + initial_refinement_level = 0, + periodicity = true) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 1.2) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 400 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_errors = (:conservation_error,)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +amr_indicator = IndicatorLöhner(semi, variable = Trixi.density) +amr_controller = ControllerThreeLevel(semi, amr_indicator, + base_level = 0, + med_level = 1, med_threshold = 0.05, + max_level = 2, max_threshold = 0.1) +amr_callback = AMRCallback(semi, amr_controller, + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) + +stepsize_callback = StepsizeCallback(cfl = 0.5) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + amr_callback, + stepsize_callback) + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks);#, maxiters=4); +summary_callback() # print the timer summary + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_3d_dgsem/elixir_euler_weak_blast_wave_amr.jl b/examples/t8code_3d_dgsem/elixir_euler_weak_blast_wave_amr.jl new file mode 100644 index 00000000000..106b4821144 --- /dev/null +++ b/examples/t8code_3d_dgsem/elixir_euler_weak_blast_wave_amr.jl @@ -0,0 +1,116 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations3D(1.4) + +function initial_condition_weak_blast_wave(x, t, + equations::CompressibleEulerEquations3D) + # Set up polar coordinates + inicenter = SVector(0.0, 0.0, 0.0) + x_norm = x[1] - inicenter[1] + y_norm = x[2] - inicenter[2] + z_norm = x[3] - inicenter[3] + r = sqrt(x_norm^2 + y_norm^2 + z_norm^2) + + r0 = 0.2 + E = 1.0 + p0_inner = 3 + p0_outer = 1 + + # Calculate primitive variables + rho = 1.1 + v1 = 0.0 + v2 = 0.0 + v3 = 0.0 + p = r > r0 ? p0_outer : p0_inner + + return prim2cons(SVector(rho, v1, v2, v3, p), equations) +end + +initial_condition = initial_condition_weak_blast_wave + +surface_flux = flux_lax_friedrichs +volume_flux = flux_ranocha +polydeg = 4 +basis = LobattoLegendreBasis(polydeg) +indicator_sc = IndicatorHennemannGassner(equations, basis, + alpha_max = 1.0, + alpha_min = 0.001, + alpha_smooth = true, + variable = density_pressure) +volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) + +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral) + +# Setup a periodic mesh with 4 x 4 x 4 trees and 8 x 8 x 8 elements +trees_per_dimension = (4, 4, 4) + +function mapping_twist(xi, eta, zeta) + y = eta + 1 / 6 * (cos(1.5 * pi * xi) * cos(0.5 * pi * eta) * cos(0.5 * pi * zeta)) + + x = xi + 1 / 6 * (cos(0.5 * pi * xi) * cos(2 * pi * y) * cos(0.5 * pi * zeta)) + + z = zeta + 1 / 6 * (cos(0.5 * pi * x) * cos(pi * y) * cos(0.5 * pi * zeta)) + + return SVector(x, y, z) +end + +mesh = T8codeMesh(trees_per_dimension, + polydeg = 2, + mapping = mapping_twist, + initial_refinement_level = 1, + periodicity = true) + +# Create the semidiscretization object +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 1.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:conservation_error,)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +amr_indicator = IndicatorLöhner(semi, variable = Trixi.density) +amr_controller = ControllerThreeLevel(semi, amr_indicator, + base_level = 1, + med_level = 2, med_threshold = 0.05, + max_level = 3, max_threshold = 0.15) +amr_callback = AMRCallback(semi, amr_controller, + interval = 1, + adapt_initial_condition = false, + adapt_initial_condition_only_refine = false) + +stepsize_callback = StepsizeCallback(cfl = 0.5) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + amr_callback, + stepsize_callback) + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); +summary_callback() # print the timer summary + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/src/callbacks_step/amr_dg2d.jl b/src/callbacks_step/amr_dg2d.jl index 94524b23a3a..062020b6d42 100644 --- a/src/callbacks_step/amr_dg2d.jl +++ b/src/callbacks_step/amr_dg2d.jl @@ -76,7 +76,10 @@ function rebalance_solver!(u_ode::AbstractVector, mesh::TreeMesh{2}, equations, end # GC.@preserve old_u_ode end -# Refine elements in the DG solver based on a list of cell_ids that should be refined +# Refine elements in the DG solver based on a list of cell_ids that should be refined. +# On `P4estMesh`, if an element refines the solution scaled by the Jacobian `J*u` is interpolated +# from the parent element into the four children elements. The solution on each child +# element is then recovered by dividing by the new element Jacobians. function refine!(u_ode::AbstractVector, adaptor, mesh::Union{TreeMesh{2}, P4estMesh{2}}, equations, dg::DGSEM, cache, elements_to_refine) # Return early if there is nothing to do @@ -96,9 +99,23 @@ function refine!(u_ode::AbstractVector, adaptor, mesh::Union{TreeMesh{2}, P4estM # Retain current solution data old_n_elements = nelements(dg, cache) old_u_ode = copy(u_ode) - GC.@preserve old_u_ode begin # OBS! If we don't GC.@preserve old_u_ode, it might be GC'ed + old_inverse_jacobian = copy(cache.elements.inverse_jacobian) + # OBS! If we don't GC.@preserve old_u_ode and old_inverse_jacobian, they might be GC'ed + GC.@preserve old_u_ode old_inverse_jacobian begin old_u = wrap_array(old_u_ode, mesh, equations, dg, cache) + if mesh isa P4estMesh + # Loop over all elements in old container and scale the old solution by the Jacobian + # prior to projection + for old_element_id in 1:old_n_elements + for v in eachvariable(equations) + old_u[v, .., old_element_id] .= (old_u[v, .., old_element_id] ./ + old_inverse_jacobian[.., + old_element_id]) + end + end + end + reinitialize_containers!(mesh, equations, dg, cache) resize!(u_ode, @@ -112,10 +129,34 @@ function refine!(u_ode::AbstractVector, adaptor, mesh::Union{TreeMesh{2}, P4estM # Refine element and store solution directly in new data structure refine_element!(u, element_id, old_u, old_element_id, adaptor, equations, dg) + + if mesh isa P4estMesh + # Before `element_id` is incremented, divide by the new Jacobians on each + # child element and save the result + for m in 0:3 # loop over the children + for v in eachvariable(equations) + u[v, .., element_id + m] .*= (0.25f0 .* + cache.elements.inverse_jacobian[.., + element_id + m]) + end + end + end + + # Increment `element_id` on the refined mesh with the number + # of children, i.e., 4 in 2D element_id += 2^ndims(mesh) else - # Copy old element data to new element container - @views u[:, .., element_id] .= old_u[:, .., old_element_id] + if mesh isa P4estMesh + # Copy old element data to new element container and remove Jacobian scaling + for v in eachvariable(equations) + u[v, .., element_id] .= (old_u[v, .., old_element_id] .* + old_inverse_jacobian[.., + old_element_id]) + end + else # isa TreeMesh + @views u[:, .., element_id] .= old_u[:, .., old_element_id] + end + # No refinement occurred, so increment `element_id` on the new mesh by one element_id += 1 end end @@ -125,7 +166,7 @@ function refine!(u_ode::AbstractVector, adaptor, mesh::Union{TreeMesh{2}, P4estM @assert element_id == nelements(dg, cache) + 1||element_id == nelements(dg, cache) + 2^ndims(mesh) "element_id = $element_id, nelements(dg, cache) = $(nelements(dg, cache))" - end # GC.@preserve old_u_ode + end # GC.@preserve old_u_ode old_inverse_jacobian # Sanity check if mesh isa TreeMesh && isperiodic(mesh.tree) && nmortars(cache.mortars) == 0 && @@ -228,7 +269,10 @@ function refine_element!(u::AbstractArray{<:Any, 4}, element_id, return nothing end -# Coarsen elements in the DG solver based on a list of cell_ids that should be removed +# Coarsen elements in the DG solver based on a list of cell_ids that should be removed. +# On `P4estMesh`, if an element coarsens the solution scaled by the Jacobian `J*u` is projected +# from the four children elements back onto the parent element. The solution on the parent +# element is then recovered by dividing by the new element Jacobian. function coarsen!(u_ode::AbstractVector, adaptor, mesh::Union{TreeMesh{2}, P4estMesh{2}}, equations, dg::DGSEM, cache, elements_to_remove) @@ -246,12 +290,26 @@ function coarsen!(u_ode::AbstractVector, adaptor, to_be_removed = falses(nelements(dg, cache)) to_be_removed[elements_to_remove] .= true - # Retain current solution data + # Retain current solution data and Jacobians old_n_elements = nelements(dg, cache) old_u_ode = copy(u_ode) - GC.@preserve old_u_ode begin # OBS! If we don't GC.@preserve old_u_ode, it might be GC'ed + old_inverse_jacobian = copy(cache.elements.inverse_jacobian) + # OBS! If we don't GC.@preserve old_u_ode and old_inverse_jacobian, they might be GC'ed + GC.@preserve old_u_ode old_inverse_jacobian begin old_u = wrap_array(old_u_ode, mesh, equations, dg, cache) + if mesh isa P4estMesh + # Loop over all elements in old container and scale the old solution by the Jacobian + # prior to projection + for old_element_id in 1:old_n_elements + for v in eachvariable(equations) + old_u[v, .., old_element_id] .= (old_u[v, .., old_element_id] ./ + old_inverse_jacobian[.., + old_element_id]) + end + end + end + reinitialize_containers!(mesh, equations, dg, cache) resize!(u_ode, @@ -277,17 +335,39 @@ function coarsen!(u_ode::AbstractVector, adaptor, # Coarsen elements and store solution directly in new data structure coarsen_elements!(u, element_id, old_u, old_element_id, adaptor, equations, dg) + + if mesh isa P4estMesh + # Before `element_id` is incremented, divide by the new Jacobian and save + # the result in the parent element + for v in eachvariable(equations) + u[v, .., element_id] .*= (4 .* + cache.elements.inverse_jacobian[.., + element_id]) + end + end + + # Increment `element_id` on the coarsened mesh by one and `skip` = 3 in 2D + # because 4 children elements become 1 parent element element_id += 1 skip = 2^ndims(mesh) - 1 else - # Copy old element data to new element container - @views u[:, .., element_id] .= old_u[:, .., old_element_id] + if mesh isa P4estMesh + # Copy old element data to new element container and remove Jacobian scaling + for v in eachvariable(equations) + u[v, .., element_id] .= (old_u[v, .., old_element_id] .* + old_inverse_jacobian[.., + old_element_id]) + end + else # isa TreeMesh + @views u[:, .., element_id] .= old_u[:, .., old_element_id] + end + # No coarsening occurred, so increment `element_id` on the new mesh by one element_id += 1 end end # If everything is correct, we should have processed all elements. @assert element_id==nelements(dg, cache) + 1 "element_id = $element_id, nelements(dg, cache) = $(nelements(dg, cache))" - end # GC.@preserve old_u_ode + end # GC.@preserve old_u_ode old_inverse_jacobian # Sanity check if mesh isa TreeMesh && isperiodic(mesh.tree) && nmortars(cache.mortars) == 0 && @@ -404,16 +484,27 @@ function adapt!(u_ode::AbstractVector, adaptor, mesh::T8codeMesh{2}, equations, # Note: This is true for `quads`. T8_CHILDREN = 4 - # Retain current solution data. + # Retain current solution and inverse Jacobian data. old_u_ode = copy(u_ode) + old_inverse_jacobian = copy(cache.elements.inverse_jacobian) + # OBS! If we don't GC.@preserve old_u_ode and old_inverse_jacobian, they might be GC'ed GC.@preserve old_u_ode begin old_u = wrap_array(old_u_ode, mesh, equations, dg, cache) + # Loop over all elements in old container and scale the old solution by the Jacobian + # prior to interpolation or projection + for old_element_id in 1:old_nelems + for v in eachvariable(equations) + old_u[v, .., old_element_id] .= (old_u[v, .., old_element_id] ./ + old_inverse_jacobian[.., + old_element_id]) + end + end + reinitialize_containers!(mesh, equations, dg, cache) - resize!(u_ode, - nvariables(equations) * nnodes(dg)^ndims(mesh) * nelements(dg, cache)) + resize!(u_ode, nvariables(equations) * ndofs(mesh, dg, cache)) u = wrap_array(u_ode, mesh, equations, dg, cache) while old_index <= old_nelems && new_index <= new_nelems @@ -422,6 +513,18 @@ function adapt!(u_ode::AbstractVector, adaptor, mesh::T8codeMesh{2}, equations, # Refine element and store solution directly in new data structure. refine_element!(u, new_index, old_u, old_index, adaptor, equations, dg) + # Before indices are incremented divide by the new Jacobians on each + # child element and save the result + for m in 0:3 # loop over the children + for v in eachvariable(equations) + u[v, .., new_index + m] .*= (0.25f0 .* + cache.elements.inverse_jacobian[.., + new_index + m]) + end + end + + # Increment `old_index` on the original mesh and the `new_index` + # on the refined mesh with the number of children, i.e., T8_CHILDREN = 4 old_index += 1 new_index += T8_CHILDREN @@ -436,19 +539,34 @@ function adapt!(u_ode::AbstractVector, adaptor, mesh::T8codeMesh{2}, equations, coarsen_elements!(u, new_index, old_u, old_index, adaptor, equations, dg) + # Before the indices are incremented divide by the new Jacobian and save + # the result again in the parent element + for v in eachvariable(equations) + u[v, .., new_index] .*= (4 .* cache.elements.inverse_jacobian[.., + new_index]) + end + + # Increment `old_index` on the original mesh with the number of children + # (T8_CHILDREN = 4 in 2D) and the `new_index` by one for the single + # coarsened element old_index += T8_CHILDREN new_index += 1 else # No changes. - # Copy old element data to new element container. - @views u[:, .., new_index] .= old_u[:, .., old_index] + # Copy old element data to new element container and remove Jacobian scaling + for v in eachvariable(equations) + u[v, .., new_index] .= (old_u[v, .., old_index] .* + old_inverse_jacobian[.., old_index]) + end + # No refinement / coarsening occurred, so increment element index + # on each mesh by one old_index += 1 new_index += 1 end end # while - end # GC.@preserve old_u_ode + end # GC.@preserve old_u_ode old_inverse_jacobian return nothing end diff --git a/src/callbacks_step/amr_dg3d.jl b/src/callbacks_step/amr_dg3d.jl index 3f67951bafe..594c30dcca5 100644 --- a/src/callbacks_step/amr_dg3d.jl +++ b/src/callbacks_step/amr_dg3d.jl @@ -5,9 +5,11 @@ @muladd begin #! format: noindent -# Refine elements in the DG solver based on a list of cell_ids that should be refined -function refine!(u_ode::AbstractVector, adaptor, - mesh::Union{TreeMesh{3}, P4estMesh{3}}, +# Refine elements in the DG solver based on a list of cell_ids that should be refined. +# On `P4estMesh`, if an element refines the solution scaled by the Jacobian `J*u` is interpolated +# from the parent element into the eight children elements. The solution on each child +# element is then recovered by dividing by the new element Jacobians. +function refine!(u_ode::AbstractVector, adaptor, mesh::Union{TreeMesh{3}, P4estMesh{3}}, equations, dg::DGSEM, cache, elements_to_refine) # Return early if there is nothing to do if isempty(elements_to_refine) @@ -26,9 +28,23 @@ function refine!(u_ode::AbstractVector, adaptor, # Retain current solution data old_n_elements = nelements(dg, cache) old_u_ode = copy(u_ode) - GC.@preserve old_u_ode begin # OBS! If we don't GC.@preserve old_u_ode, it might be GC'ed + old_inverse_jacobian = copy(cache.elements.inverse_jacobian) + # OBS! If we don't GC.@preserve old_u_ode and old_inverse_jacobian, they might be GC'ed + GC.@preserve old_u_ode old_inverse_jacobian begin old_u = wrap_array(old_u_ode, mesh, equations, dg, cache) + if mesh isa P4estMesh + # Loop over all elements in old container and scale the old solution by the Jacobian + # prior to projection + for old_element_id in 1:old_n_elements + for v in eachvariable(equations) + old_u[v, .., old_element_id] .= (old_u[v, .., old_element_id] ./ + old_inverse_jacobian[.., + old_element_id]) + end + end + end + reinitialize_containers!(mesh, equations, dg, cache) resize!(u_ode, @@ -44,12 +60,36 @@ function refine!(u_ode::AbstractVector, adaptor, for old_element_id in 1:old_n_elements if needs_refinement[old_element_id] # Refine element and store solution directly in new data structure - refine_element!(u, element_id, old_u, old_element_id, - adaptor, equations, dg, u_tmp1, u_tmp2) + refine_element!(u, element_id, old_u, old_element_id, adaptor, + equations, dg, u_tmp1, u_tmp2) + + if mesh isa P4estMesh + # Before `element_id` is incremented, divide by the new Jacobians on each + # child element and save the result + for m in 0:7 # loop over the children + for v in eachvariable(equations) + u[v, .., element_id + m] .*= (0.125f0 .* + cache.elements.inverse_jacobian[.., + element_id + m]) + end + end + end + + # Increment `element_id` on the refined mesh with the number + # of children, i.e., 8 in 3D element_id += 2^ndims(mesh) else - # Copy old element data to new element container - @views u[:, .., element_id] .= old_u[:, .., old_element_id] + if mesh isa P4estMesh + # Copy old element data to new element container and remove Jacobian scaling + for v in eachvariable(equations) + u[v, .., element_id] .= (old_u[v, .., old_element_id] .* + old_inverse_jacobian[.., + old_element_id]) + end + else # isa TreeMesh + @views u[:, .., element_id] .= old_u[:, .., old_element_id] + end + # No refinement occurred, so increment `element_id` on the new mesh by one element_id += 1 end end @@ -59,7 +99,7 @@ function refine!(u_ode::AbstractVector, adaptor, @assert element_id == nelements(dg, cache) + 1||element_id == nelements(dg, cache) + 2^ndims(mesh) "element_id = $element_id, nelements(dg, cache) = $(nelements(dg, cache))" - end # GC.@preserve old_u_ode + end # GC.@preserve old_u_ode old_inverse_jacobian # Sanity check if mesh isa TreeMesh && isperiodic(mesh.tree) && nmortars(cache.mortars) == 0 @@ -145,7 +185,10 @@ function refine_element!(u::AbstractArray{<:Any, 5}, element_id, return nothing end -# Coarsen elements in the DG solver based on a list of cell_ids that should be removed +# Coarsen elements in the DG solver based on a list of cell_ids that should be removed. +# On `P4estMesh`, if an element coarsens the solution scaled by the Jacobian `J*u` is projected +# from the eight children elements back onto the parent element. The solution on the parent +# element is then recovered by dividing by the new element Jacobian. function coarsen!(u_ode::AbstractVector, adaptor, mesh::Union{TreeMesh{3}, P4estMesh{3}}, equations, dg::DGSEM, cache, elements_to_remove) @@ -163,12 +206,26 @@ function coarsen!(u_ode::AbstractVector, adaptor, to_be_removed = falses(nelements(dg, cache)) to_be_removed[elements_to_remove] .= true - # Retain current solution data + # Retain current solution data and Jacobians old_n_elements = nelements(dg, cache) old_u_ode = copy(u_ode) - GC.@preserve old_u_ode begin # OBS! If we don't GC.@preserve old_u_ode, it might be GC'ed + old_inverse_jacobian = copy(cache.elements.inverse_jacobian) + # OBS! If we don't GC.@preserve old_u_ode and old_inverse_jacobian, they might be GC'ed + GC.@preserve old_u_ode old_inverse_jacobian begin old_u = wrap_array(old_u_ode, mesh, equations, dg, cache) + if mesh isa P4estMesh + # Loop over all elements in old container and scale the old solution by the Jacobian + # prior to projection + for old_element_id in 1:old_n_elements + for v in eachvariable(equations) + old_u[v, .., old_element_id] .= (old_u[v, .., old_element_id] ./ + old_inverse_jacobian[.., + old_element_id]) + end + end + end + reinitialize_containers!(mesh, equations, dg, cache) resize!(u_ode, @@ -196,19 +253,41 @@ function coarsen!(u_ode::AbstractVector, adaptor, @assert all(to_be_removed[old_element_id:(old_element_id + 2^ndims(mesh) - 1)]) "bad cell/element order" # Coarsen elements and store solution directly in new data structure - coarsen_elements!(u, element_id, old_u, old_element_id, - adaptor, equations, dg, u_tmp1, u_tmp2) + coarsen_elements!(u, element_id, old_u, old_element_id, adaptor, + equations, dg, u_tmp1, u_tmp2) + + if mesh isa P4estMesh + # Before `element_id` is incremented, divide by the new Jacobian and save + # the result in the parent element + for v in eachvariable(equations) + u[v, .., element_id] .*= (8 .* + cache.elements.inverse_jacobian[.., + element_id]) + end + end + + # Increment `element_id` on the coarsened mesh by one and `skip` = 7 in 3D + # because 8 children elements become 1 parent element element_id += 1 skip = 2^ndims(mesh) - 1 else - # Copy old element data to new element container - @views u[:, .., element_id] .= old_u[:, .., old_element_id] + if mesh isa P4estMesh + # Copy old element data to new element container and remove Jacobian scaling + for v in eachvariable(equations) + u[v, .., element_id] .= (old_u[v, .., old_element_id] .* + old_inverse_jacobian[.., + old_element_id]) + end + else # isa TreeMesh + @views u[:, .., element_id] .= old_u[:, .., old_element_id] + end + # No coarsening occurred, so increment `element_id` on the new mesh by one element_id += 1 end end # If everything is correct, we should have processed all elements. @assert element_id==nelements(dg, cache) + 1 "element_id = $element_id, nelements(dg, cache) = $(nelements(dg, cache))" - end # GC.@preserve old_u_ode + end # GC.@preserve old_u_ode old_inverse_jacobian # Sanity check if mesh isa TreeMesh && isperiodic(mesh.tree) && nmortars(cache.mortars) == 0 @@ -335,16 +414,27 @@ function adapt!(u_ode::AbstractVector, adaptor, mesh::T8codeMesh{3}, equations, # Note: This is only true for `hexs`. T8_CHILDREN = 8 - # Retain current solution data. + # Retain current solution and inverse Jacobian data. old_u_ode = copy(u_ode) + old_inverse_jacobian = copy(cache.elements.inverse_jacobian) + # OBS! If we don't GC.@preserve old_u_ode and old_inverse_jacobian, they might be GC'ed GC.@preserve old_u_ode begin old_u = wrap_array(old_u_ode, mesh, equations, dg, cache) + # Loop over all elements in old container and scale the old solution by the Jacobian + # prior to interpolation or projection + for old_element_id in 1:old_nelems + for v in eachvariable(equations) + old_u[v, .., old_element_id] .= (old_u[v, .., old_element_id] ./ + old_inverse_jacobian[.., + old_element_id]) + end + end + reinitialize_containers!(mesh, equations, dg, cache) - resize!(u_ode, - nvariables(equations) * ndofs(mesh, dg, cache)) + resize!(u_ode, nvariables(equations) * ndofs(mesh, dg, cache)) u = wrap_array(u_ode, mesh, equations, dg, cache) u_tmp1 = Array{eltype(u), 4}(undef, nvariables(equations), nnodes(dg), @@ -359,6 +449,18 @@ function adapt!(u_ode::AbstractVector, adaptor, mesh::T8codeMesh{3}, equations, refine_element!(u, new_index, old_u, old_index, adaptor, equations, dg, u_tmp1, u_tmp2) + # Before indices are incremented divide by the new Jacobians on each + # child element and save the result + for m in 0:7 # loop over the children + for v in eachvariable(equations) + u[v, .., new_index + m] .*= (0.125f0 .* + cache.elements.inverse_jacobian[.., + new_index + m]) + end + end + + # Increment `old_index` on the original mesh and the `new_index` + # on the refined mesh with the number of children, i.e., T8_CHILDREN = 8 old_index += 1 new_index += T8_CHILDREN @@ -373,19 +475,34 @@ function adapt!(u_ode::AbstractVector, adaptor, mesh::T8codeMesh{3}, equations, coarsen_elements!(u, new_index, old_u, old_index, adaptor, equations, dg, u_tmp1, u_tmp2) + # Before the indices are incremented divide by the new Jacobian and save + # the result again in the parent element + for v in eachvariable(equations) + u[v, .., new_index] .*= (8 .* cache.elements.inverse_jacobian[.., + new_index]) + end + + # Increment `old_index` on the original mesh with the number of children + # (T8_CHILDREN = 8 in 3D) and the `new_index` by one for the single + # coarsened element old_index += T8_CHILDREN new_index += 1 else # No changes. - # Copy old element data to new element container. - @views u[:, .., new_index] .= old_u[:, .., old_index] + # Copy old element data to new element container and remove Jacobian scaling + for v in eachvariable(equations) + u[v, .., new_index] .= (old_u[v, .., old_index] .* + old_inverse_jacobian[.., old_index]) + end + # No refinement / coarsening occurred, so increment element index + # on each mesh by one old_index += 1 new_index += 1 end end # while - end # GC.@preserve old_u_ode + end # GC.@preserve old_u_ode old_inverse_jacobian return nothing end diff --git a/src/meshes/structured_mesh.jl b/src/meshes/structured_mesh.jl index 553aabbbc20..9e5c55197d8 100644 --- a/src/meshes/structured_mesh.jl +++ b/src/meshes/structured_mesh.jl @@ -255,13 +255,15 @@ function correction_term_3d(x, y, z, faces) linear_interpolate(x, faces[1](1, z), faces[2](1, z)) + linear_interpolate(z, faces[5](x, 1), faces[6](x, 1))) - # Correction for x-terms + # Correction for z-terms c_z = linear_interpolate(z, linear_interpolate(x, faces[1](y, -1), faces[2](y, -1)) + linear_interpolate(y, faces[3](x, -1), faces[4](x, -1)), linear_interpolate(x, faces[1](y, 1), faces[2](y, 1)) + linear_interpolate(y, faces[3](x, 1), faces[4](x, 1))) + # Each of the 12 edges are counted twice above + # so we divide the correction term by two return 0.5 * (c_x + c_y + c_z) end diff --git a/src/meshes/surface_interpolant.jl b/src/meshes/surface_interpolant.jl index 22d14e38c5c..6a7c5c7834b 100644 --- a/src/meshes/surface_interpolant.jl +++ b/src/meshes/surface_interpolant.jl @@ -52,7 +52,7 @@ function derivative_at(s, boundary_curve::CurvedSurface) y_coordinate_at_s_on_boundary_curve_prime end -# Chebysehv-Gauss-Lobatto nodes and weights for use with curved boundaries +# Chebyshev-Gauss-Lobatto nodes and weights for use with curved boundaries function chebyshev_gauss_lobatto_nodes_weights(n_nodes::Integer) # Initialize output diff --git a/test/test_mpi_p4est_2d.jl b/test/test_mpi_p4est_2d.jl index 6d66bc68a26..29de4efc6d0 100644 --- a/test/test_mpi_p4est_2d.jl +++ b/test/test_mpi_p4est_2d.jl @@ -97,8 +97,8 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_2d_dgsem") @trixi_testset "elixir_advection_amr_unstructured_flag.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_unstructured_flag.jl"), - l2=[0.0012766060609964525], - linf=[0.01750280631586159], + l2=[0.0012808538770535593], + linf=[0.01752690016659812], coverage_override=(maxiters = 6,)) # Ensure that we do not have excessive memory allocations diff --git a/test/test_mpi_p4est_3d.jl b/test/test_mpi_p4est_3d.jl index cca9093ec51..4f9465b85dc 100644 --- a/test/test_mpi_p4est_3d.jl +++ b/test/test_mpi_p4est_3d.jl @@ -69,8 +69,8 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_3d_dgsem") @trixi_testset "elixir_advection_amr_unstructured_curved.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_unstructured_curved.jl"), - l2=[1.6236411810065552e-5], - linf=[0.0010554006923731395], + l2=[1.6163120948209677e-5], + linf=[0.0010572201890564834], tspan=(0.0, 1.0), coverage_override=(maxiters = 6, initial_refinement_level = 0, diff --git a/test/test_mpi_t8code_2d.jl b/test/test_mpi_t8code_2d.jl index 7c7fc03898c..75e65c8c380 100644 --- a/test/test_mpi_t8code_2d.jl +++ b/test/test_mpi_t8code_2d.jl @@ -97,8 +97,9 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "t8code_2d_dgsem") @trixi_testset "elixir_advection_amr_unstructured_flag.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_unstructured_flag.jl"), - l2=[0.001980652042312077], - linf=[0.0328882442132265], + l2=[0.002019623611753929], + linf=[0.03542375961299987], + dynamic_load_balancing=false, coverage_override=(maxiters = 6,)) # Ensure that we do not have excessive memory allocations diff --git a/test/test_mpi_t8code_3d.jl b/test/test_mpi_t8code_3d.jl index a15690a7629..2e837f79ad8 100644 --- a/test/test_mpi_t8code_3d.jl +++ b/test/test_mpi_t8code_3d.jl @@ -69,8 +69,8 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "t8code_3d_dgsem") @trixi_testset "elixir_advection_amr_unstructured_curved.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_unstructured_curved.jl"), - l2=[2.0556575425846923e-5], - linf=[0.00105682693484822], + l2=[2.0535121347526814e-5], + linf=[0.0010586603797777504], tspan=(0.0, 1.0), coverage_override=(maxiters = 6, initial_refinement_level = 0, diff --git a/test/test_p4est_2d.jl b/test/test_p4est_2d.jl index ef5ac2c9de3..f56dc9cd769 100644 --- a/test/test_p4est_2d.jl +++ b/test/test_p4est_2d.jl @@ -78,8 +78,8 @@ end @trixi_testset "elixir_advection_amr_unstructured_flag.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_unstructured_flag.jl"), - l2=[0.0012766060609964525], - linf=[0.01750280631586159], + l2=[0.0012808538770535593], + linf=[0.01752690016659812], coverage_override=(maxiters = 6,)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) @@ -301,16 +301,16 @@ end @trixi_testset "elixir_euler_blast_wave_amr.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blast_wave_amr.jl"), l2=[ - 6.32183914e-01, - 3.86914231e-01, - 3.86869171e-01, - 1.06575688e+00, + 0.6321850210104147, + 0.38691446170269167, + 0.3868695626809587, + 1.0657553825683956, ], linf=[ - 2.76020890e+00, - 2.32659890e+00, - 2.32580837e+00, - 2.15778188e+00, + 2.7602280007469666, + 2.3265993814913672, + 2.3258078438689673, + 2.1577683028925416, ], tspan=(0.0, 0.3), coverage_override=(maxiters = 6,)) @@ -327,16 +327,16 @@ end @trixi_testset "elixir_euler_wall_bc_amr.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_wall_bc_amr.jl"), l2=[ - 0.020291447969983396, - 0.017479614254319948, - 0.011387644425613437, - 0.0514420126021293, + 0.02026685991647352, + 0.017467584076280237, + 0.011378371604813321, + 0.05138942558296091, ], linf=[ - 0.3582779022370579, - 0.32073537890751663, - 0.221818049107692, - 0.9209559420400415, + 0.35924402060711524, + 0.32068389566068806, + 0.2361141752119986, + 0.9289840057748628, ], tspan=(0.0, 0.15)) # Ensure that we do not have excessive memory allocations @@ -352,16 +352,16 @@ end @trixi_testset "elixir_euler_forward_step_amr.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_forward_step_amr.jl"), l2=[ - 0.004194875320833303, - 0.003785140699353966, - 0.0013696609105790351, - 0.03265268616046424, + 0.004191480950848891, + 0.003781298410569231, + 0.0013470418422981045, + 0.03262817609394949, ], linf=[ - 2.0585399781442852, - 2.213428805506876, - 3.862362410419163, - 17.75187237459251, + 2.0581500751947113, + 2.2051301367971288, + 3.8502467979250254, + 17.750333649853616, ], tspan=(0.0, 0.0001), rtol=1.0e-7, @@ -409,16 +409,16 @@ end @trixi_testset "elixir_euler_supersonic_cylinder.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_supersonic_cylinder.jl"), l2=[ - 0.026798021911954406, - 0.05118546368109259, - 0.03206703583774831, - 0.19680026567208672, + 0.02676082999794676, + 0.05110830068968181, + 0.03205164257040607, + 0.1965981012724311, ], linf=[ - 3.653905721692421, - 4.285035711361009, - 6.8544353186357645, - 31.748244912257533, + 3.6830683476364476, + 4.284442685012427, + 6.857777546171545, + 31.749285097390576, ], tspan=(0.0, 0.001), skip_coverage=true) @@ -529,16 +529,17 @@ end @trixi_testset "elixir_mhd_rotor.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_rotor.jl"), - l2=[0.4552084651735862, 0.8918048264575757, 0.832471223081887, + l2=[0.4552094211937344, 0.8918052934760807, 0.8324715234680768, 0.0, - 0.9801264164951583, 0.10475690769435382, 0.1555132409149897, + 0.9801268321975978, 0.10475722739111007, + 0.15551326369033164, 0.0, - 2.0597079362763556e-5], - linf=[10.194181233788775, 18.25472397868819, 10.031307436191334, + 2.0602990858239632e-5], + linf=[10.19421969147307, 18.254409357804683, 10.031954811332596, 0.0, - 19.647239392277378, 1.3938810140985936, 1.8724965294853084, + 19.646870938371492, 1.3938679692894465, 1.8725058401937984, 0.0, - 0.0016290067532561904], + 0.0016201762010257296], tspan=(0.0, 0.02)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) @@ -617,12 +618,12 @@ end @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_NACA0012airfoil_mach085.jl"), l2=[ - 5.634402680811982e-7, 6.748066107517321e-6, - 1.091879472416885e-5, 0.0006686372064029146, + 5.56114097044427e-7, 6.62284247153255e-6, + 1.0823259724601275e-5, 0.000659804574787503, ], linf=[ - 0.0021456247890772823, 0.03957142889488085, - 0.03832024233032798, 2.6628739573358495, + 0.002157589754528455, 0.039163189253511164, + 0.038386804399707625, 2.6685831417913914, ], amr_interval=1, base_level=0, med_level=1, max_level=1, @@ -652,8 +653,8 @@ end lift = Trixi.analyze(lift_coefficient, du, u, tspan[2], mesh, equations, solver, semi.cache, semi) - @test isapprox(lift, 0.029076443678087403, atol = 1e-13) - @test isapprox(drag, 0.13564720009197903, atol = 1e-13) + @test isapprox(lift, 0.029094009322876882, atol = 1e-13) + @test isapprox(drag, 0.13579200776643238, atol = 1e-13) end @trixi_testset "elixir_euler_blast_wave_pure_fv.jl" begin @@ -684,6 +685,40 @@ end @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 end end + +@trixi_testset "elixir_euler_weak_blast_wave_amr.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weak_blast_wave_amr.jl"), + l2=[ + 0.11134260363848127, + 0.11752357091804219, + 0.11829112104640764, + 0.7557891142955036, + ], + linf=[ + 0.5728647031475109, + 0.8353132977670252, + 0.8266797080712205, + 3.9792506230548317, + ], + tspan=(0.0, 0.1), + coverage_override=(maxiters = 6,)) + # Ensure that we do not have excessive memory allocations + # (e.g., from type instabilities) + let + t = sol.t[end] + u_ode = sol.u[end] + du_ode = similar(u_ode) + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 + end + # Check for conservation + state_integrals = Trixi.integrate(sol.u[2], semi) + initial_state_integrals = analysis_callback.affect!.initial_state_integrals + + @test isapprox(state_integrals[1], initial_state_integrals[1], atol = 1e-13) + @test isapprox(state_integrals[2], initial_state_integrals[2], atol = 1e-13) + @test isapprox(state_integrals[3], initial_state_integrals[3], atol = 1e-13) + @test isapprox(state_integrals[4], initial_state_integrals[4], atol = 1e-13) +end end # Clean up afterwards: delete Trixi.jl output directory diff --git a/test/test_p4est_3d.jl b/test/test_p4est_3d.jl index 7483cde2752..7b69d1c0cf2 100644 --- a/test/test_p4est_3d.jl +++ b/test/test_p4est_3d.jl @@ -78,8 +78,8 @@ end @trixi_testset "elixir_advection_amr_unstructured_curved.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_unstructured_curved.jl"), - l2=[1.6236411810065552e-5], - linf=[0.0010554006923731395], + l2=[1.6163120948209677e-5], + linf=[0.0010572201890564834], tspan=(0.0, 1.0), coverage_override=(maxiters = 6, initial_refinement_level = 0, base_level = 0, med_level = 1, max_level = 2)) @@ -542,16 +542,16 @@ end @trixi_testset "elixir_mhd_shockcapturing_amr.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_shockcapturing_amr.jl"), - l2=[0.006298541670176575, 0.0064368506652601265, - 0.007108729762852636, 0.006530420607206385, - 0.02061185869237284, 0.005562033787605515, - 0.007571716276627825, 0.005571862660453231, - 3.909755063709152e-6], - linf=[0.20904054009050665, 0.18622917151105936, - 0.2347957890323218, 0.19432508025509926, - 0.6858860133405615, 0.15172116633332622, - 0.22432820727833747, 0.16805989780225183, - 0.000535219040687628], + l2=[0.006297229188299052, 0.0064363477630573936, + 0.007109134822960387, 0.0065295379843073945, + 0.02061487028361094, 0.005561406556868266, + 0.007570747563219415, 0.005571060186624124, + 3.910359570546058e-6], + linf=[0.20904050617411984, 0.18630026905465372, + 0.23476537952044518, 0.19430178061639747, + 0.6858488631108304, 0.15169972134884624, + 0.22431157069631724, 0.16823638724229162, + 0.0005352202836463904], tspan=(0.0, 0.04), coverage_override=(maxiters = 6, initial_refinement_level = 1, base_level = 1, max_level = 2)) @@ -586,6 +586,43 @@ end @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 end end + +@trixi_testset "elixir_euler_weak_blast_wave_amr.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weak_blast_wave_amr.jl"), + l2=[ + 0.011345993108796831, + 0.018525073963833696, + 0.019102348105917946, + 0.01920515438943838, + 0.15060493968460148, + ], + linf=[ + 0.2994949779783401, + 0.5530175050084679, + 0.5335803757792128, + 0.5647252867336123, + 3.6462732329242566, + ], + tspan=(0.0, 0.025), + coverage_override=(maxiters = 6,)) + # Ensure that we do not have excessive memory allocations + # (e.g., from type instabilities) + let + t = sol.t[end] + u_ode = sol.u[end] + du_ode = similar(u_ode) + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 + end + # Check for conservation + state_integrals = Trixi.integrate(sol.u[2], semi) + initial_state_integrals = analysis_callback.affect!.initial_state_integrals + + @test isapprox(state_integrals[1], initial_state_integrals[1], atol = 1e-13) + @test isapprox(state_integrals[2], initial_state_integrals[2], atol = 1e-13) + @test isapprox(state_integrals[3], initial_state_integrals[3], atol = 1e-13) + @test isapprox(state_integrals[4], initial_state_integrals[4], atol = 1e-13) + @test isapprox(state_integrals[5], initial_state_integrals[5], atol = 1e-13) +end end # Clean up afterwards: delete Trixi.jl output directory diff --git a/test/test_t8code_2d.jl b/test/test_t8code_2d.jl index b63d2a105ac..c1fcc355218 100644 --- a/test/test_t8code_2d.jl +++ b/test/test_t8code_2d.jl @@ -121,8 +121,8 @@ end @trixi_testset "elixir_advection_amr_unstructured_flag.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_unstructured_flag.jl"), - l2=[0.001993165013217687], - linf=[0.032891018571625796], + l2=[0.002019623611753929], + linf=[0.03542375961299987], coverage_override=(maxiters = 6,)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) @@ -305,16 +305,16 @@ end # This test is identical to the one in `test_p4est_2d.jl` besides minor # deviations in the expected error norms. @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_rotor.jl"), - l2=[0.44211360369891683, 0.8805178316216257, 0.8262710688468049, + l2=[0.44207324634847545, 0.8804644301177857, 0.8262542320669426, 0.0, - 0.9616090460973586, 0.10386643568745411, - 0.15403457366543802, 0.0, - 2.8399715649715473e-5], - linf=[10.04369305341599, 17.995640564998403, 9.576041548174265, + 0.9615023124189027, 0.10386709616755131, 0.1540308191628843, 0.0, - 19.429658884314534, 1.3821395681242314, 1.818559351543182, + 2.8350276854372125e-5], + linf=[10.04548675437385, 17.998696852394836, 9.575802136190026, 0.0, - 0.002261930217575465], + 19.431290746184473, 1.3821685018474321, 1.8186235976551453, + 0.0, + 0.002309422702635547], tspan=(0.0, 0.02)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) @@ -325,6 +325,40 @@ end @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 end end + +@trixi_testset "elixir_euler_weak_blast_wave_amr.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weak_blast_wave_amr.jl"), + l2=[ + 0.10823279736983638, + 0.1158152939803735, + 0.11633970342992006, + 0.751152651902375, + ], + linf=[ + 0.5581611332828653, + 0.8354026029724041, + 0.834485181423738, + 3.923553028014343, + ], + tspan=(0.0, 0.1), + coverage_override=(maxiters = 6,)) + # Ensure that we do not have excessive memory allocations + # (e.g., from type instabilities) + let + t = sol.t[end] + u_ode = sol.u[end] + du_ode = similar(u_ode) + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 + end + # Check for conservation + state_integrals = Trixi.integrate(sol.u[2], semi) + initial_state_integrals = analysis_callback.affect!.initial_state_integrals + + @test isapprox(state_integrals[1], initial_state_integrals[1], atol = 1e-13) + @test isapprox(state_integrals[2], initial_state_integrals[2], atol = 1e-13) + @test isapprox(state_integrals[3], initial_state_integrals[3], atol = 1e-13) + @test isapprox(state_integrals[4], initial_state_integrals[4], atol = 1e-13) +end end # Clean up afterwards: delete Trixi.jl output directory diff --git a/test/test_t8code_3d.jl b/test/test_t8code_3d.jl index 5c452444be0..940d2c43372 100644 --- a/test/test_t8code_3d.jl +++ b/test/test_t8code_3d.jl @@ -61,7 +61,7 @@ mkdir(outdir) @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_nonconforming.jl"), l2=[0.00253595715323843], linf=[0.016486952252155795]) - # Ensure that we do not have excessive memory allocations + # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let t = sol.t[end] @@ -80,7 +80,7 @@ mkdir(outdir) linf=[0.0007889950196294793], coverage_override=(maxiters = 6, initial_refinement_level = 1, base_level = 1, med_level = 2, max_level = 3)) - # Ensure that we do not have excessive memory allocations + # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let t = sol.t[end] @@ -95,12 +95,12 @@ mkdir(outdir) @trixi_testset "elixir_advection_amr_unstructured_curved.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_unstructured_curved.jl"), - l2=[2.0556575425846923e-5], - linf=[0.00105682693484822], + l2=[2.0535121347526814e-5], + linf=[0.0010586603797777504], tspan=(0.0, 1.0), coverage_override=(maxiters = 6, initial_refinement_level = 0, base_level = 0, med_level = 1, max_level = 2)) - # Ensure that we do not have excessive memory allocations + # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let t = sol.t[end] @@ -129,7 +129,7 @@ mkdir(outdir) 0.008526972236273522, ], tspan=(0.0, 0.01)) - # Ensure that we do not have excessive memory allocations + # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let t = sol.t[end] @@ -158,7 +158,7 @@ mkdir(outdir) 0.01562861968368434, ], tspan=(0.0, 1.0)) - # Ensure that we do not have excessive memory allocations + # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let t = sol.t[end] @@ -186,7 +186,7 @@ mkdir(outdir) 9.412914891981927e-12, ], tspan=(0.0, 0.03)) - # Ensure that we do not have excessive memory allocations + # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let t = sol.t[end] @@ -214,7 +214,7 @@ mkdir(outdir) 9.592326932761353e-13, ], tspan=(0.0, 0.1), atol=5.0e-13,) - # Ensure that we do not have excessive memory allocations + # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let t = sol.t[end] @@ -243,7 +243,7 @@ mkdir(outdir) ], tspan=(0.0, 0.2), coverage_override=(polydeg = 3,)) # Prevent long compile time in CI - # Ensure that we do not have excessive memory allocations + # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let t = sol.t[end] @@ -273,7 +273,7 @@ mkdir(outdir) ], tspan=(0.0, 0.3), coverage_override=(polydeg = 3,)) # Prevent long compile time in CI - # Ensure that we do not have excessive memory allocations + # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let t = sol.t[end] @@ -316,6 +316,43 @@ mkdir(outdir) @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 end end + + @trixi_testset "elixir_euler_weak_blast_wave_amr.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weak_blast_wave_amr.jl"), + l2=[ + 0.010014531529951328, + 0.0176268986746271, + 0.01817514447099777, + 0.018271085903740675, + 0.15193033077438198, + ], + linf=[ + 0.2898958869606375, + 0.529717119064458, + 0.5567193302705906, + 0.570663236219957, + 3.5496520808512027, + ], + tspan=(0.0, 0.025), + coverage_override=(maxiters = 6,)) + # Ensure that we do not have excessive memory allocations + # (e.g., from type instabilities) + let + t = sol.t[end] + u_ode = sol.u[end] + du_ode = similar(u_ode) + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 + end + # Check for conservation + state_integrals = Trixi.integrate(sol.u[2], semi) + initial_state_integrals = analysis_callback.affect!.initial_state_integrals + + @test isapprox(state_integrals[1], initial_state_integrals[1], atol = 1e-13) + @test isapprox(state_integrals[2], initial_state_integrals[2], atol = 1e-13) + @test isapprox(state_integrals[3], initial_state_integrals[3], atol = 1e-13) + @test isapprox(state_integrals[4], initial_state_integrals[4], atol = 1e-13) + @test isapprox(state_integrals[5], initial_state_integrals[5], atol = 1e-13) + end end # Clean up afterwards: delete Trixi.jl output directory From 1c1d5ea0f7fc763dd3954121fe665c6001e21df1 Mon Sep 17 00:00:00 2001 From: Huiyu Xie Date: Mon, 19 Aug 2024 20:18:01 -1000 Subject: [PATCH 19/25] Add numerical support of other real types (`laplace`) (#2025) * start * reformat * Update test/test_type.jl Co-authored-by: Hendrik Ranocha * Update test/test_type.jl Co-authored-by: Hendrik Ranocha * Update test/test_type.jl Co-authored-by: Hendrik Ranocha --------- Co-authored-by: Hendrik Ranocha --- test/test_type.jl | 63 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/test/test_type.jl b/test/test_type.jl index c15ac5f78c6..d13b626b060 100644 --- a/test/test_type.jl +++ b/test/test_type.jl @@ -1459,6 +1459,69 @@ isdir(outdir) && rm(outdir, recursive = true) end end + @timed_testset "Laplace Diffusion 1D" begin + for RealT in (Float32, Float64) + equations = @inferred LinearScalarAdvectionEquation1D(RealT(1)) + equations_parabolic = @inferred LaplaceDiffusion1D(RealT(0.1), equations) + + x = SVector(zero(RealT)) + t = zero(RealT) + u = gradients = SVector(one(RealT)) + orientation = 1 + + @test eltype(@inferred flux(u, gradients, orientation, equations_parabolic)) == + RealT + + # TODO: BC tests for BoundaryConditionDirichlet + # TODO: BC tests for BoundaryConditionNeumann + end + end + + @timed_testset "Laplace Diffusion 2D" begin + for RealT in (Float32, Float64) + equations = LinearScalarAdvectionEquation2D(RealT(1), RealT(1)) + equations_parabolic = LaplaceDiffusion2D(RealT(0.1), equations) + + x = SVector(zero(RealT), zero(RealT)) + t = zero(RealT) + u = u_inner = u_outer = inv_h = gradients = SVector(one(RealT), one(RealT)) + orientations = [1, 2] + + for orientation in orientations + @test eltype(@inferred flux(u, gradients, orientation, equations_parabolic)) == + RealT + end + + parabolic_solver = ViscousFormulationLocalDG(RealT(0.1)) + @test eltype(@inferred Trixi.penalty(u_outer, u_inner, inv_h, + equations_parabolic, parabolic_solver)) == + RealT + end + end + + @timed_testset "Laplace Diffusion 3D" begin + for RealT in (Float32, Float64) + equations = LinearScalarAdvectionEquation3D(RealT(1), RealT(1), RealT(1)) + equations_parabolic = LaplaceDiffusion3D(RealT(0.1), equations) + + x = SVector(zero(RealT), zero(RealT), zero(RealT)) + t = zero(RealT) + u = u_inner = u_outer = inv_h = gradients = SVector(one(RealT), one(RealT), + one(RealT)) + orientations = [1, 2, 3] + + for orientation in orientations + @test eltype(@inferred flux(u, gradients, orientation, equations_parabolic)) == + RealT + end + + parabolic_solver = ViscousFormulationLocalDG(RealT(0.1)) + @test eltype(@inferred Trixi.penalty(u_outer, u_inner, inv_h, + equations_parabolic, parabolic_solver)) == + RealT + end + end + @timed_testset "Lattice Boltzmann 2D" begin for RealT in (Float32, Float64) equations = @inferred LatticeBoltzmannEquations2D(Ma = RealT(0.1), Re = 1000) From e47afa1048f43ac0bad93710afaabcedfb3989d0 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 20 Aug 2024 13:41:33 +0200 Subject: [PATCH 20/25] set version to v0.8.8 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 923cf5248a8..3283a41c1a9 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Trixi" uuid = "a7f1ee26-1774-49b1-8366-f1abc58fbfcb" authors = ["Michael Schlottke-Lakemper ", "Gregor Gassner ", "Hendrik Ranocha ", "Andrew R. Winters ", "Jesse Chan "] -version = "0.8.8-DEV" +version = "0.8.8" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From afd80605ef7e7f4d36e3fc12ddb0280a8db38bfd Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 20 Aug 2024 13:41:47 +0200 Subject: [PATCH 21/25] set development version to v0.8.9-DEV --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 3283a41c1a9..f8be84e0ce3 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Trixi" uuid = "a7f1ee26-1774-49b1-8366-f1abc58fbfcb" authors = ["Michael Schlottke-Lakemper ", "Gregor Gassner ", "Hendrik Ranocha ", "Andrew R. Winters ", "Jesse Chan "] -version = "0.8.8" +version = "0.8.9-DEV" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 20ab97bea82fbd4c286f8fc4cebad6ee12a1e465 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 21 Aug 2024 09:51:23 +0200 Subject: [PATCH 22/25] computations using only `Float32` and no `Float64` (#2042) * add example using only Float32 * make RHS work for examples/unstructured_2d_dgsem/elixir_shallowwater_ec_float32.jl * more fixes * format * more fixes * examples/p4est_3d_dgsem/elixir_euler_free_stream_boundaries_float32.jl * add tests * upwind FDSBP * format * format * fix reference values * adapt SWE EC test value after PR #2038 * more mesh fixes * more fixes * Apply suggestions from code review Co-authored-by: Andrew Winters * remove redundant using Downloads in examples * more comments * format --------- Co-authored-by: Andrew Winters --- .../elixir_euler_NACA0012airfoil_mach085.jl | 2 +- .../elixir_euler_NACA6412airfoil_mach2.jl | 9 +- .../elixir_euler_subsonic_cylinder.jl | 2 +- ...xir_navierstokes_NACA0012airfoil_mach08.jl | 4 +- .../elixir_euler_free_stream_boundaries.jl | 5 +- ...ir_euler_free_stream_boundaries_float32.jl | 62 +++++++++ .../elixir_advection_float32.jl | 61 +++++++++ .../elixir_shallowwater_ec_float32.jl | 124 ++++++++++++++++++ ...elixir_euler_free_stream_upwind_float32.jl | 88 +++++++++++++ src/auxiliary/auxiliary.jl | 2 +- src/meshes/p4est_mesh.jl | 14 +- src/meshes/structured_mesh.jl | 8 +- src/meshes/surface_interpolant.jl | 8 +- src/meshes/t8code_mesh.jl | 4 +- src/meshes/transfinite_mappings_3d.jl | 6 +- .../semidiscretization_coupled.jl | 4 +- src/solvers/dgsem_p4est/dg_2d.jl | 14 +- src/solvers/dgsem_p4est/dg_2d_parabolic.jl | 58 ++++---- src/solvers/dgsem_p4est/dg_3d.jl | 14 +- src/solvers/dgsem_p4est/dg_3d_parabolic.jl | 34 ++--- src/solvers/dgsem_structured/containers_3d.jl | 12 +- src/solvers/dgsem_structured/dg_2d.jl | 26 ++-- .../dg_2d_subcell_limiters.jl | 4 +- src/solvers/dgsem_structured/dg_3d.jl | 34 ++--- src/solvers/dgsem_structured/indicators_1d.jl | 5 +- src/solvers/dgsem_structured/indicators_2d.jl | 10 +- src/solvers/dgsem_structured/indicators_3d.jl | 15 ++- src/solvers/dgsem_t8code/containers_3d.jl | 6 +- src/solvers/dgsem_tree/dg_1d.jl | 16 +-- src/solvers/dgsem_tree/dg_1d_parabolic.jl | 4 +- src/solvers/dgsem_tree/dg_2d.jl | 28 ++-- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 10 +- .../dgsem_tree/dg_2d_subcell_limiters.jl | 4 +- src/solvers/dgsem_tree/dg_3d.jl | 42 +++--- src/solvers/dgsem_tree/dg_3d_parabolic.jl | 10 +- src/solvers/dgsem_tree/indicators.jl | 7 +- src/solvers/dgsem_tree/indicators_1d.jl | 4 +- src/solvers/dgsem_tree/indicators_2d.jl | 12 +- src/solvers/dgsem_tree/indicators_3d.jl | 24 ++-- src/solvers/dgsem_tree/subcell_limiters_2d.jl | 2 +- src/solvers/dgsem_unstructured/dg_2d.jl | 9 +- .../dgsem_unstructured/indicators_2d.jl | 4 +- .../mappings_geometry_curved_2d.jl | 62 +++++---- .../mappings_geometry_straight_2d.jl | 40 +++--- src/visualization/utilities.jl | 2 +- test/test_p4est_3d.jl | 29 ++++ test/test_structured_2d.jl | 17 +++ test/test_trixi.jl | 19 ++- test/test_unstructured_2d.jl | 44 +++++++ 49 files changed, 737 insertions(+), 287 deletions(-) create mode 100644 examples/p4est_3d_dgsem/elixir_euler_free_stream_boundaries_float32.jl create mode 100644 examples/structured_2d_dgsem/elixir_advection_float32.jl create mode 100644 examples/unstructured_2d_dgsem/elixir_shallowwater_ec_float32.jl create mode 100644 examples/unstructured_2d_fdsbp/elixir_euler_free_stream_upwind_float32.jl diff --git a/examples/p4est_2d_dgsem/elixir_euler_NACA0012airfoil_mach085.jl b/examples/p4est_2d_dgsem/elixir_euler_NACA0012airfoil_mach085.jl index 8806f9cc2af..45b750728c9 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_NACA0012airfoil_mach085.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_NACA0012airfoil_mach085.jl @@ -1,4 +1,4 @@ -using Downloads: download + using OrdinaryDiffEq using Trixi diff --git a/examples/p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl b/examples/p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl index 7e55a259596..573d182e158 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl @@ -1,7 +1,6 @@ using Trixi using OrdinaryDiffEq -using Downloads: download ############################################################################### # semidiscretization of the compressible Euler equations @@ -62,7 +61,7 @@ volume_integral = VolumeIntegralShockCapturingHG(shock_indicator; volume_flux_dg = volume_flux, volume_flux_fv = surface_flux) -# DG Solver +# DG Solver solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, volume_integral = volume_integral) @@ -70,8 +69,8 @@ solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, # https://gist.githubusercontent.com/DanielDoehring/5ade6d93629f0d8c23a598812dbee2a9/raw/d2bc904fe92146eae1a36156e7f5c535dc1a80f1/NACA6412.geo mesh_file = joinpath(@__DIR__, "mesh_NACA6412.inp") isfile(mesh_file) || - download("https://gist.githubusercontent.com/DanielDoehring/e2a389f04f1e37b33819b9637e8ee4c3/raw/4bf7607a2ce4432fdb5cb87d5e264949b11bd5d7/mesh_NACA6412.inp", - mesh_file) + Trixi.download("https://gist.githubusercontent.com/DanielDoehring/e2a389f04f1e37b33819b9637e8ee4c3/raw/4bf7607a2ce4432fdb5cb87d5e264949b11bd5d7/mesh_NACA6412.inp", + mesh_file) boundary_symbols = [:PhysicalLine1, :PhysicalLine2, :PhysicalLine3, :PhysicalLine4] @@ -79,7 +78,7 @@ mesh = P4estMesh{2}(mesh_file, polydeg = polydeg, boundary_symbols = boundary_sy boundary_conditions = Dict(:PhysicalLine1 => boundary_condition_supersonic_inflow, # Left boundary :PhysicalLine2 => boundary_condition_supersonic_outflow, # Right boundary - :PhysicalLine3 => boundary_condition_supersonic_outflow, # Top and bottom boundary + :PhysicalLine3 => boundary_condition_supersonic_outflow, # Top and bottom boundary :PhysicalLine4 => boundary_condition_slip_wall) # Airfoil semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, diff --git a/examples/p4est_2d_dgsem/elixir_euler_subsonic_cylinder.jl b/examples/p4est_2d_dgsem/elixir_euler_subsonic_cylinder.jl index e522a0dcfd3..21df724da4d 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_subsonic_cylinder.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_subsonic_cylinder.jl @@ -1,4 +1,4 @@ -using Downloads: download + using OrdinaryDiffEq using Trixi diff --git a/examples/p4est_2d_dgsem/elixir_navierstokes_NACA0012airfoil_mach08.jl b/examples/p4est_2d_dgsem/elixir_navierstokes_NACA0012airfoil_mach08.jl index 3e4679f5afe..40baef6ef96 100644 --- a/examples/p4est_2d_dgsem/elixir_navierstokes_NACA0012airfoil_mach08.jl +++ b/examples/p4est_2d_dgsem/elixir_navierstokes_NACA0012airfoil_mach08.jl @@ -1,4 +1,4 @@ -using Downloads: download + using OrdinaryDiffEq using Trixi @@ -15,7 +15,7 @@ using Trixi # Structured and Unstructured Grid Methods (2016) # [https://ntrs.nasa.gov/citations/20160003623] (https://ntrs.nasa.gov/citations/20160003623) # - Deep Ray, Praveen Chandrashekar (2017) -# An entropy stable finite volume scheme for the +# An entropy stable finite volume scheme for the # two dimensional Navier–Stokes equations on triangular grids # [DOI:10.1016/j.amc.2017.07.020](https://doi.org/10.1016/j.amc.2017.07.020) diff --git a/examples/p4est_3d_dgsem/elixir_euler_free_stream_boundaries.jl b/examples/p4est_3d_dgsem/elixir_euler_free_stream_boundaries.jl index bdc4da26c1f..8c008fac2e4 100644 --- a/examples/p4est_3d_dgsem/elixir_euler_free_stream_boundaries.jl +++ b/examples/p4est_3d_dgsem/elixir_euler_free_stream_boundaries.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -18,8 +17,8 @@ solver = DGSEM(polydeg = polydeg, surface_flux = flux_lax_friedrichs) default_mesh_file = joinpath(@__DIR__, "mesh_cube_with_boundaries.inp") isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/DanielDoehring/710eab379fe3042dc08af6f2d1076e49/raw/38e9803bc0dab9b32a61d9542feac5343c3e6f4b/mesh_cube_with_boundaries.inp", - default_mesh_file) + Trixi.download("https://gist.githubusercontent.com/DanielDoehring/710eab379fe3042dc08af6f2d1076e49/raw/38e9803bc0dab9b32a61d9542feac5343c3e6f4b/mesh_cube_with_boundaries.inp", + default_mesh_file) mesh_file = default_mesh_file boundary_symbols = [:PhysicalSurface1, :PhysicalSurface2] diff --git a/examples/p4est_3d_dgsem/elixir_euler_free_stream_boundaries_float32.jl b/examples/p4est_3d_dgsem/elixir_euler_free_stream_boundaries_float32.jl new file mode 100644 index 00000000000..c41ad9a4223 --- /dev/null +++ b/examples/p4est_3d_dgsem/elixir_euler_free_stream_boundaries_float32.jl @@ -0,0 +1,62 @@ +# Similar to p4est_3d_dgsem/elixir_euler_free_stream_boundaries.jl +# but using Float32 instead of the default Float64 + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations3D(1.4f0) + +initial_condition = initial_condition_constant + +polydeg = 3 +solver = DGSEM(polydeg = polydeg, surface_flux = flux_lax_friedrichs, RealT = Float32) + +############################################################################### +# Get the uncurved mesh from a file (downloads the file if not available locally) + +default_mesh_file = joinpath(@__DIR__, "mesh_cube_with_boundaries.inp") +isfile(default_mesh_file) || + Trixi.download("https://gist.githubusercontent.com/DanielDoehring/710eab379fe3042dc08af6f2d1076e49/raw/38e9803bc0dab9b32a61d9542feac5343c3e6f4b/mesh_cube_with_boundaries.inp", + default_mesh_file) +mesh_file = default_mesh_file + +boundary_symbols = [:PhysicalSurface1, :PhysicalSurface2] + +mesh = P4estMesh{3}(mesh_file, polydeg = polydeg, boundary_symbols = boundary_symbols, + RealT = Float32) + +boundary_conditions = Dict(:PhysicalSurface1 => BoundaryConditionDirichlet(initial_condition), + :PhysicalSurface2 => BoundaryConditionDirichlet(initial_condition)) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0f0, 1.0f0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +stepsize_callback = StepsizeCallback(cfl = 1.5f0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + stepsize_callback) + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0f0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); +summary_callback() # print the timer summary diff --git a/examples/structured_2d_dgsem/elixir_advection_float32.jl b/examples/structured_2d_dgsem/elixir_advection_float32.jl new file mode 100644 index 00000000000..20c30d4aeb1 --- /dev/null +++ b/examples/structured_2d_dgsem/elixir_advection_float32.jl @@ -0,0 +1,61 @@ +# Similar to structured_2d_dgsem/elixir_advection_basic.jl +# but using Float32 instead of the default Float64 + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear advection equation + +advection_velocity = (0.2f0, -0.7f0) +equations = LinearScalarAdvectionEquation2D(advection_velocity) + +# Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, RealT = Float32) + +coordinates_min = (-1.0f0, -1.0f0) # minimum coordinates (min(x), min(y)) +coordinates_max = (1.0f0, 1.0f0) # maximum coordinates (max(x), max(y)) + +cells_per_dimension = (16, 16) + +# Create curved mesh with 16 x 16 elements +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) + +# A semidiscretization collects data structures and functions for the spatial discretization +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, + solver) + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span from 0.0 to 1.0 +ode = semidiscretize(semi, (0.0f0, 1.0f0)) + +# At the beginning of the main loop, the SummaryCallback prints a summary of the simulation setup +# and resets the timers +summary_callback = SummaryCallback() + +# The AnalysisCallback allows to analyse the solution in regular intervals and prints the results +analysis_callback = AnalysisCallback(semi, interval = 100) + +# The SaveSolutionCallback allows to save the solution to a file in regular intervals +save_solution = SaveSolutionCallback(interval = 100, + solution_variables = cons2prim) + +# The StepsizeCallback handles the re-calculation of the maximum Δt after each time step +stepsize_callback = StepsizeCallback(cfl = 1.6f0) + +# Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver +callbacks = CallbackSet(summary_callback, analysis_callback, save_solution, + stepsize_callback) + +############################################################################### +# run the simulation + +# OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0f0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); + +# Print the timer summary +summary_callback() diff --git a/examples/unstructured_2d_dgsem/elixir_shallowwater_ec_float32.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_ec_float32.jl new file mode 100644 index 00000000000..cc527fc00e1 --- /dev/null +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_ec_float32.jl @@ -0,0 +1,124 @@ +# Similar to unstructured_2d_dgsem/elixir_shallowwater_ec_float32.jl +# but using Float32 instead of the default Float64 + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the shallow water equations with a discontinuous +# bottom topography function + +equations = ShallowWaterEquations2D(gravity_constant = 9.81f0) + +# Note, this initial condition is used to compute errors in the analysis callback but the initialization is +# overwritten by `initial_condition_ec_discontinuous_bottom` below. +initial_condition = initial_condition_weak_blast_wave + +############################################################################### +# Get the DG approximation space + +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) +solver = DGSEM(polydeg = 6, + surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux), + RealT = Float32) + +############################################################################### +# This setup is for the curved, split form entropy conservation testing (needs periodic BCs) + +# Get the unstructured quad mesh from a file (downloads the file if not available locally) +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", + joinpath(@__DIR__, "mesh_alfven_wave_with_twist_and_flip.mesh")) + +mesh = UnstructuredMesh2D(mesh_file, periodicity = true, RealT = Float32) + +# Create the semi discretization object +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solver + +tspan = (0.0f0, 2.0f0) +ode = semidiscretize(semi, tspan) + +############################################################################### +# Workaround to set a discontinuous bottom topography and initial condition for debugging and testing. + +# alternative version of the initial conditinon used to setup a truly discontinuous +# bottom topography function and initial condition for this academic testcase of entropy conservation. +# The errors from the analysis callback are not important but `∑∂S/∂U ⋅ Uₜ` should be around machine roundoff +# In contrast to the usual signature of initial conditions, this one get passed the +# `element_id` explicitly. In particular, this initial conditions works as intended +# only for the specific mesh loaded above! +function initial_condition_ec_discontinuous_bottom(x, t, element_id, + equations::ShallowWaterEquations2D) + RealT = eltype(x) + + # Set up polar coordinates + inicenter = SVector{2, RealT}(0.7, 0.7) + x_norm = x[1] - inicenter[1] + y_norm = x[2] - inicenter[2] + r = sqrt(x_norm^2 + y_norm^2) + phi = atan(y_norm, x_norm) + sin_phi, cos_phi = sincos(phi) + + # Set the background values + H = 3.25f0 + v1 = zero(RealT) + v2 = zero(RealT) + b = zero(RealT) + + # setup the discontinuous water height and velocities + if element_id == 10 + H = 4.0f0 + v1 = convert(RealT, 0.1882) * cos_phi + v2 = convert(RealT, 0.1882) * sin_phi + end + + # Setup a discontinuous bottom topography using the element id number + if element_id == 7 + b = 2 + 0.5f0 * sinpi(2 * x[1]) + 0.5f0 * cospi(2 * x[2]) + end + + return prim2cons(SVector(H, v1, v2, b), equations) +end + +# point to the data we want to augment +u = Trixi.wrap_array(ode.u0, semi) +# reset the initial condition +for element in eachelement(semi.solver, semi.cache) + for j in eachnode(semi.solver), i in eachnode(semi.solver) + x_node = Trixi.get_node_coords(semi.cache.elements.node_coordinates, equations, + semi.solver, i, j, element) + u_node = initial_condition_ec_discontinuous_bottom(x_node, first(tspan), element, + equations) + Trixi.set_node_vars!(u, u_node, equations, semi.solver, i, j, element) + end +end + +############################################################################### +# Callbacks + +summary_callback = SummaryCallback() + +analysis_interval = 1000 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true) + +stepsize_callback = StepsizeCallback(cfl = 1.0f0) + +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, + stepsize_callback) + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0f0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); +summary_callback() # print the timer summary diff --git a/examples/unstructured_2d_fdsbp/elixir_euler_free_stream_upwind_float32.jl b/examples/unstructured_2d_fdsbp/elixir_euler_free_stream_upwind_float32.jl new file mode 100644 index 00000000000..9cfd45a4d34 --- /dev/null +++ b/examples/unstructured_2d_fdsbp/elixir_euler_free_stream_upwind_float32.jl @@ -0,0 +1,88 @@ +# !!! warning "Experimental implementation (upwind SBP)" +# This is an experimental feature and may change in future releases. +# Similar to unstructured_2d_fdsbp/elixir_euler_free_stream_upwind.jl +# but using Float32 instead of the default Float64 + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations2D(1.4f0) + +initial_condition = initial_condition_constant + +# Boundary conditions for free-stream preservation test +boundary_condition_free_stream = BoundaryConditionDirichlet(initial_condition) + +boundary_conditions = Dict(:outerCircle => boundary_condition_free_stream, + :cone1 => boundary_condition_free_stream, + :cone2 => boundary_condition_free_stream, + :iceCream => boundary_condition_free_stream) + +############################################################################### +# Get the Upwind FDSBP approximation space + +# TODO: FDSBP +# Note, one must set `xmin=-1` and `xmax=1` due to the reuse +# of interpolation routines from `calc_node_coordinates!` to create +# the physical coordinates in the mappings. +D_upw = upwind_operators(SummationByPartsOperators.Mattsson2017, + derivative_order = 1, + accuracy_order = 8, + xmin = -1.0f0, xmax = 1.0f0, + N = 17) + +flux_splitting = splitting_vanleer_haenel +solver = FDSBP(D_upw, + surface_integral = SurfaceIntegralStrongForm(FluxUpwind(flux_splitting)), + volume_integral = VolumeIntegralUpwind(flux_splitting)) + +############################################################################### +# Get the curved quad mesh from a file (downloads the file if not available locally) + +# Mesh with second-order boundary polynomials requires an upwind SBP operator +# with (at least) 4th order boundary closure to guarantee the approximation is +# free-stream preserving +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/ec9a345f09199ebe471d35d5c1e4e08f/raw/15975943d8642e42f8292235314b6f1b30aa860d/mesh_inner_outer_boundaries.mesh", + joinpath(@__DIR__, "mesh_inner_outer_boundaries.mesh")) + +mesh = UnstructuredMesh2D(mesh_file, RealT = Float32) + +############################################################################### +# create the semi discretization object + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0f0, 5.0f0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + save_solution, + alive_callback) + +############################################################################### +# run the simulation + +# set small tolerances for the free-stream preservation test +sol = solve(ode, SSPRK43(), abstol = 1.0f-6, reltol = 1.0f-6, + save_everystep = false, callback = callbacks) + +summary_callback() # print the timer summary diff --git a/src/auxiliary/auxiliary.jl b/src/auxiliary/auxiliary.jl index 97263405d2a..8ab798dd336 100644 --- a/src/auxiliary/auxiliary.jl +++ b/src/auxiliary/auxiliary.jl @@ -207,7 +207,7 @@ macro threaded(expr) # !!! danger "Heisenbug" # Look at the comments for `wrap_array` when considering to change this macro. expr = if _PREFERENCE_POLYESTER - # Currently using `@batch` from Polyester.jl is more efficient, + # Currently using `@batch` from Polyester.jl is more efficient, # bypasses the Julia task scheduler and provides parallelization with less overhead. quote $Trixi.@batch $(expr) diff --git a/src/meshes/p4est_mesh.jl b/src/meshes/p4est_mesh.jl index 2046220aeca..526f5d9f23b 100644 --- a/src/meshes/p4est_mesh.jl +++ b/src/meshes/p4est_mesh.jl @@ -349,7 +349,7 @@ For example, if a two-dimensional base mesh contains 25 elements then setting independent of domain partitioning. Should be `false` for static meshes to permit more fine-grained partitioning. - `boundary_symbols::Vector{Symbol}`: A vector of symbols that correspond to the boundary names in the `meshfile`. - If `nothing` is passed then all boundaries are named `:all`. + If `nothing` is passed then all boundaries are named `:all`. """ function P4estMesh{NDIMS}(meshfile::String; mapping = nothing, polydeg = 1, RealT = Float64, @@ -534,7 +534,7 @@ function parse_elements(meshfile, n_trees, n_dims) element_types = n_dims == 2 ? ["*ELEMENT, type=CPS4", "*ELEMENT, type=C2D4", "*ELEMENT, type=S4"] : ["*ELEMENT, type=C3D8"] - # 2D quads: 4 nodes + element index, 3D hexes: 8 nodes + element index + # 2D quads: 4 nodes + element index, 3D hexes: 8 nodes + element index expected_content_length = n_dims == 2 ? 5 : 9 element_node_matrix = Matrix{Int64}(undef, n_trees, expected_content_length - 1) @@ -617,7 +617,7 @@ function assign_boundaries_standard_abaqus!(boundary_names, n_trees, ::Val{2}) # 2D version for tree in 1:n_trees tree_nodes = element_node_matrix[tree, :] - # For node labeling, see + # For node labeling, see # https://docs.software.vt.edu/abaqusv2022/English/SIMACAEELMRefMap/simaelm-r-2delem.htm#simaelm-r-2delem-t-nodedef1 # and search for "Node ordering and face numbering on elements" for boundary in keys(node_set_dict) # Loop over specified boundaries @@ -658,7 +658,7 @@ function assign_boundaries_standard_abaqus!(boundary_names, n_trees, ::Val{3}) # 3D version for tree in 1:n_trees tree_nodes = element_node_matrix[tree, :] - # For node labeling, see + # For node labeling, see # https://web.mit.edu/calculix_v2.7/CalculiX/ccx_2.7/doc/ccx/node26.html for boundary in keys(node_set_dict) # Loop over specified boundaries # Check "front face" (y_min) @@ -1460,7 +1460,7 @@ function cubed_sphere_mapping(xi, eta, zeta, inner_radius, thickness, direction) r = sqrt(1 + x^2 + y^2) # Radius of the sphere - R = inner_radius + thickness * (0.5 * (zeta + 1)) + R = inner_radius + thickness * (0.5f0 * (zeta + 1)) # Projection onto the sphere return R / r * cube_coordinates[direction] @@ -1650,7 +1650,7 @@ function calc_tree_node_coordinates!(node_coordinates::AbstractArray{<:Any, 5}, nodes[q]) end else # curved_check[face] == 1 - # Curved face boundary information is supplied by + # Curved face boundary information is supplied by # the mesh file. Just read it into a work array for q in 1:nnodes, p in 1:nnodes file_idx += 1 @@ -1723,7 +1723,7 @@ end # and return the 3D coordinate point (x, y, z) function bilinear_interpolation!(coordinate, face_vertices, u, v) for j in 1:3 - coordinate[j] = 0.25 * (face_vertices[j, 1] * (1 - u) * (1 - v) + coordinate[j] = 0.25f0 * (face_vertices[j, 1] * (1 - u) * (1 - v) + face_vertices[j, 2] * (1 + u) * (1 - v) + face_vertices[j, 3] * (1 + u) * (1 + v) + face_vertices[j, 4] * (1 - u) * (1 + v)) diff --git a/src/meshes/structured_mesh.jl b/src/meshes/structured_mesh.jl index 9e5c55197d8..155bad8464a 100644 --- a/src/meshes/structured_mesh.jl +++ b/src/meshes/structured_mesh.jl @@ -160,7 +160,7 @@ end # Interpolate linearly between left and right value where s should be between -1 and 1 function linear_interpolate(s, left_value, right_value) - 0.5 * ((1 - s) * left_value + (1 + s) * right_value) + 0.5f0 * ((1 - s) * left_value + (1 + s) * right_value) end # Convert min and max coordinates of a rectangle to the corresponding transformation mapping @@ -197,7 +197,7 @@ function bilinear_mapping(x, y, faces) x3 = faces[1](1) # Top left x4 = faces[2](1) # Top right - return 0.25 * (x1 * (1 - x) * (1 - y) + + return 0.25f0 * (x1 * (1 - x) * (1 - y) + x2 * (1 + x) * (1 - y) + x3 * (1 - x) * (1 + y) + x4 * (1 + x) * (1 + y)) @@ -215,7 +215,7 @@ function trilinear_mapping(x, y, z, faces) x7 = faces[1](1, 1) # mapped from (-1, 1, 1) x8 = faces[2](1, 1) # mapped from ( 1, 1, 1) - return 0.125 * (x1 * (1 - x) * (1 - y) * (1 - z) + + return 0.125f0 * (x1 * (1 - x) * (1 - y) * (1 - z) + x2 * (1 + x) * (1 - y) * (1 - z) + x3 * (1 - x) * (1 + y) * (1 - z) + x4 * (1 + x) * (1 + y) * (1 - z) + @@ -264,7 +264,7 @@ function correction_term_3d(x, y, z, faces) # Each of the 12 edges are counted twice above # so we divide the correction term by two - return 0.5 * (c_x + c_y + c_z) + return 0.5f0 * (c_x + c_y + c_z) end # In 3D diff --git a/src/meshes/surface_interpolant.jl b/src/meshes/surface_interpolant.jl index 6a7c5c7834b..20a6611668b 100644 --- a/src/meshes/surface_interpolant.jl +++ b/src/meshes/surface_interpolant.jl @@ -66,8 +66,8 @@ function chebyshev_gauss_lobatto_nodes_weights(n_nodes::Integer) nodes[j] = -cospi((j - 1) / N) weights[j] = pi / N end - weights[1] = 0.5 * weights[1] - weights[end] = 0.5 * weights[end] + weights[1] = 0.5f0 * weights[1] + weights[end] = 0.5f0 * weights[end] return nodes, weights end @@ -80,7 +80,9 @@ function lagrange_interpolation(x, nodes, fvals, wbary) denominator = zero(eltype(fvals)) for j in eachindex(nodes) - if isapprox(x, nodes[j], rtol = eps(x)) + # using eps(nodes[j]) instead of eps(x) allows us to use integer + # coordinates for the target location x + if isapprox(x, nodes[j], rtol = eps(nodes[j])) return fvals[j] end t = wbary[j] / (x - nodes[j]) diff --git a/src/meshes/t8code_mesh.jl b/src/meshes/t8code_mesh.jl index 10a042be3ba..aa49e641dc9 100644 --- a/src/meshes/t8code_mesh.jl +++ b/src/meshes/t8code_mesh.jl @@ -121,7 +121,7 @@ function T8codeMesh{NDIMS, RealT}(forest::Ptr{t8_forest}, boundary_names; polyde mapping = nothing) where {NDIMS, RealT} # In t8code reference space is [0,1]. basis = LobattoLegendreBasis(RealT, polydeg) - nodes = 0.5 .* (basis.nodes .+ 1.0) + nodes = 0.5f0 .* (basis.nodes .+ 1) cmesh = t8_forest_get_cmesh(forest) number_of_trees = t8_forest_get_num_global_trees(forest) @@ -572,7 +572,7 @@ For example, if a two-dimensional base mesh contains 25 elements then setting - `RealT::Type`: The type that should be used for coordinates. - `initial_refinement_level::Integer`: Refine the mesh uniformly to this level before the simulation starts. - `boundary_symbols::Vector{Symbol}`: A vector of symbols that correspond to the boundary names in the `meshfile`. - If `nothing` is passed then all boundaries are named `:all`. + If `nothing` is passed then all boundaries are named `:all`. """ function T8codeMesh(meshfile::AbaqusFile{NDIMS}; mapping = nothing, polydeg = 1, RealT = Float64, diff --git a/src/meshes/transfinite_mappings_3d.jl b/src/meshes/transfinite_mappings_3d.jl index 59a02f33e1a..a82526bc1d4 100644 --- a/src/meshes/transfinite_mappings_3d.jl +++ b/src/meshes/transfinite_mappings_3d.jl @@ -52,7 +52,7 @@ function straight_side_hex_map(xi, eta, zeta, corner_points) coordinate = zeros(eltype(xi), 3) for j in 1:3 - coordinate[j] += (0.125 * + coordinate[j] += (0.125f0 * (corner_points[j, 1] * (1 - xi) * (1 - eta) * (1 - zeta) + corner_points[j, 2] * (1 + xi) * (1 - eta) * (1 - zeta) + corner_points[j, 3] * (1 + xi) * (1 + eta) * (1 - zeta) @@ -131,7 +131,7 @@ function transfinite_hex_map(xi, eta, zeta, face_curves::AbstractVector{<:Curved # Compute the transfinite mapping for j in 1:3 # Linear interpolation between opposite faces - coordinate[j] = (0.5 * + coordinate[j] = (0.5f0 * (face_values[j, 6] * (1 - xi) + face_values[j, 4] * (1 + xi) + face_values[j, 1] * (1 - eta) + face_values[j, 2] * (1 + eta) @@ -139,7 +139,7 @@ function transfinite_hex_map(xi, eta, zeta, face_curves::AbstractVector{<:Curved face_values[j, 5] * (1 + zeta))) # Edge corrections to ensure faces match - coordinate[j] -= (0.25 * (edge_values[j, 1] * (1 - eta) * (1 - zeta) + coordinate[j] -= (0.25f0 * (edge_values[j, 1] * (1 - eta) * (1 - zeta) + edge_values[j, 2] * (1 + xi) * (1 - eta) + edge_values[j, 3] * (1 - eta) * (1 + zeta) + edge_values[j, 4] * (1 - xi) * (1 - eta) diff --git a/src/semidiscretization/semidiscretization_coupled.jl b/src/semidiscretization/semidiscretization_coupled.jl index 6b009cfad20..7c1fbef972b 100644 --- a/src/semidiscretization/semidiscretization_coupled.jl +++ b/src/semidiscretization/semidiscretization_coupled.jl @@ -486,13 +486,13 @@ function (boundary_condition::BoundaryConditionCoupled)(u_inner, orientation, di if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary flux = (surface_flux_function[1](u_inner, u_boundary, orientation, equations) + - 0.5 * + 0.5f0 * surface_flux_function[2](u_inner, u_boundary, orientation, equations)) else # u_boundary is "left" of boundary, u_inner is "right" of boundary flux = (surface_flux_function[1](u_boundary, u_inner, orientation, equations) + - 0.5 * + 0.5f0 * surface_flux_function[2](u_boundary, u_inner, orientation, equations)) end diff --git a/src/solvers/dgsem_p4est/dg_2d.jl b/src/solvers/dgsem_p4est/dg_2d.jl index 36624f2ce8a..29e94f43704 100644 --- a/src/solvers/dgsem_p4est/dg_2d.jl +++ b/src/solvers/dgsem_p4est/dg_2d.jl @@ -238,10 +238,10 @@ end # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs surface_flux_values[v, primary_node_index, primary_direction_index, primary_element_index] = (flux_[v] + - 0.5 * + 0.5f0 * noncons_primary[v]) surface_flux_values[v, secondary_node_index, secondary_direction_index, secondary_element_index] = -(flux_[v] + - 0.5 * + 0.5f0 * noncons_secondary[v]) end end @@ -501,10 +501,10 @@ function calc_mortar_flux!(surface_flux_values, # copying in the correct orientation u_buffer = cache.u_threaded[Threads.threadid()] - # in calc_interface_flux!, the interface flux is computed once over each - # interface using the normal from the "primary" element. The result is then - # passed back to the "secondary" element, flipping the sign to account for the - # change in the normal direction. For mortars, this sign flip occurs in + # in calc_interface_flux!, the interface flux is computed once over each + # interface using the normal from the "primary" element. The result is then + # passed back to the "secondary" element, flipping the sign to account for the + # change in the normal direction. For mortars, this sign flip occurs in # "mortar_fluxes_to_elements!" instead. mortar_fluxes_to_elements!(surface_flux_values, mesh, equations, mortar_l2, dg, cache, @@ -557,7 +557,7 @@ end noncons = nonconservative_flux(u_ll, u_rr, normal_direction, normal_direction, equations) - flux_plus_noncons = flux + 0.5 * noncons + flux_plus_noncons = flux + 0.5f0 * noncons # Copy to buffer set_node_vars!(fstar[position_index], flux_plus_noncons, equations, dg, node_index) diff --git a/src/solvers/dgsem_p4est/dg_2d_parabolic.jl b/src/solvers/dgsem_p4est/dg_2d_parabolic.jl index ed21f371449..4bf4c79ebee 100644 --- a/src/solvers/dgsem_p4est/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_p4est/dg_2d_parabolic.jl @@ -28,8 +28,8 @@ function create_cache_parabolic(mesh::P4estMesh{2}, end #= -Reusing `rhs_parabolic!` for `TreeMesh`es is not easily possible as -for `P4estMesh`es we call +Reusing `rhs_parabolic!` for `TreeMesh`es is not easily possible as +for `P4estMesh`es we call ``` prolong2mortars_divergence!(cache, flux_viscous, mesh, equations_parabolic, @@ -38,8 +38,8 @@ for `P4estMesh`es we call calc_mortar_flux_divergence!(cache_parabolic.elements.surface_flux_values, mesh, equations_parabolic, dg.mortar, dg.surface_integral, dg, cache) - ``` -instead of + ``` +instead of ``` prolong2mortars!(cache, flux_viscous, mesh, equations_parabolic, dg.mortar, dg.surface_integral, dg) @@ -221,14 +221,14 @@ function calc_gradient!(gradients, u_transformed, t, end end - # Prolong solution to interfaces. + # Prolong solution to interfaces. # This reuses `prolong2interfaces` for the purely hyperbolic case. @trixi_timeit timer() "prolong2interfaces" begin prolong2interfaces!(cache_parabolic, u_transformed, mesh, equations_parabolic, dg.surface_integral, dg) end - # Calculate interface fluxes for the gradient. + # Calculate interface fluxes for the gradient. # This reuses `calc_interface_flux!` for the purely hyperbolic case. @trixi_timeit timer() "interface flux" begin calc_interface_flux!(cache_parabolic.elements.surface_flux_values, @@ -257,8 +257,8 @@ function calc_gradient!(gradients, u_transformed, t, end # Calculate mortar fluxes. This reuses the hyperbolic version of `calc_mortar_flux`, - # along with a specialization on `calc_mortar_flux!(fstar, ...)` and `mortar_fluxes_to_elements!` for - # AbstractEquationsParabolic. + # along with a specialization on `calc_mortar_flux!(fstar, ...)` and `mortar_fluxes_to_elements!` for + # AbstractEquationsParabolic. @trixi_timeit timer() "mortar flux" begin calc_mortar_flux!(cache_parabolic.elements.surface_flux_values, mesh, False(), # False() = no nonconservative terms @@ -388,11 +388,11 @@ function calc_gradient!(gradients, u_transformed, t, return nothing end -# This version is called during `calc_gradients!` and must be specialized because the -# flux for the gradient is {u}, which doesn't depend on the outward normal. Thus, -# you don't need to scale by 2 (e.g., the scaling factor in the normals (and in the -# contravariant vectors) along large/small elements across a non-conforming -# interface in 2D) and flip the sign when storing the mortar fluxes back +# This version is called during `calc_gradients!` and must be specialized because the +# flux for the gradient is {u}, which doesn't depend on the outward normal. Thus, +# you don't need to scale by 2 (e.g., the scaling factor in the normals (and in the +# contravariant vectors) along large/small elements across a non-conforming +# interface in 2D) and flip the sign when storing the mortar fluxes back # into `surface_flux_values`. @inline function mortar_fluxes_to_elements!(surface_flux_values, mesh::Union{P4estMesh{2}, T8codeMesh{2}}, @@ -462,7 +462,7 @@ end u_ll, u_rr = get_surface_node_vars(u, equations, dg, primary_node_index, interface_index) - flux_ = 0.5 * (u_ll + u_rr) # we assume that the gradient computations utilize a central flux + flux_ = 0.5f0 * (u_ll + u_rr) # we assume that the gradient computations utilize a central flux # Note that we don't flip the sign on the secondary flux. This is because for parabolic terms, # the normals are not embedded in `flux_` for the parabolic gradient computations. @@ -604,7 +604,7 @@ function prolong2interfaces!(cache_parabolic, flux_viscous, return nothing end -# This version is used for divergence flux computations +# This version is used for divergence flux computations function calc_interface_flux!(surface_flux_values, mesh::P4estMesh{2}, equations_parabolic, dg::DG, cache_parabolic) @@ -645,7 +645,7 @@ function calc_interface_flux!(surface_flux_values, end for node in eachnode(dg) - # We prolong the viscous flux dotted with respect the outward normal on the + # We prolong the viscous flux dotted with respect the outward normal on the # primary element. We assume a BR-1 type of flux. viscous_flux_normal_ll, viscous_flux_normal_rr = get_surface_node_vars(cache_parabolic.interfaces.u, equations_parabolic, @@ -653,7 +653,7 @@ function calc_interface_flux!(surface_flux_values, node, interface) - flux = 0.5 * (viscous_flux_normal_ll + viscous_flux_normal_rr) + flux = 0.5f0 * (viscous_flux_normal_ll + viscous_flux_normal_rr) for v in eachvariable(equations_parabolic) surface_flux_values[v, node, primary_direction_index, primary_element] = flux[v] @@ -741,11 +741,11 @@ function prolong2mortars_divergence!(cache, flux_viscous::Vector{Array{uEltype, flux_viscous = SVector(flux_viscous_x[v, i_large, j_large, element], flux_viscous_y[v, i_large, j_large, element]) - # We prolong the viscous flux dotted with respect the outward normal - # on the small element. We scale by -1/2 here because the normal - # direction on the large element is negative 2x that of the small + # We prolong the viscous flux dotted with respect the outward normal + # on the small element. We scale by -1/2 here because the normal + # direction on the large element is negative 2x that of the small # element (these normal directions are "scaled" by the surface Jacobian) - u_buffer[v, i] = -0.5 * dot(flux_viscous, normal_direction) + u_buffer[v, i] = -0.5f0 * dot(flux_viscous, normal_direction) end i_large += i_large_step j_large += j_large_step @@ -763,8 +763,8 @@ function prolong2mortars_divergence!(cache, flux_viscous::Vector{Array{uEltype, return nothing end -# We specialize `calc_mortar_flux!` for the divergence part of -# the parabolic terms. +# We specialize `calc_mortar_flux!` for the divergence part of +# the parabolic terms. function calc_mortar_flux_divergence!(surface_flux_values, mesh::Union{P4estMesh{2}, T8codeMesh{2}}, equations::AbstractEquationsParabolic, @@ -789,7 +789,7 @@ function calc_mortar_flux_divergence!(surface_flux_values, mortar] # TODO: parabolic; only BR1 at the moment - fstar[position][v, node] = 0.5 * (viscous_flux_normal_ll + + fstar[position][v, node] = 0.5f0 * (viscous_flux_normal_ll + viscous_flux_normal_rr) end end @@ -808,11 +808,11 @@ function calc_mortar_flux_divergence!(surface_flux_values, return nothing end -# We structure `calc_interface_flux!` similarly to "calc_mortar_flux!" for -# hyperbolic equations with no nonconservative terms. -# The reasoning is that parabolic fluxes are treated like conservative +# We structure `calc_interface_flux!` similarly to "calc_mortar_flux!" for +# hyperbolic equations with no nonconservative terms. +# The reasoning is that parabolic fluxes are treated like conservative # terms (e.g., we compute a viscous conservative "flux") and thus no -# non-conservative terms are present. +# non-conservative terms are present. @inline function calc_mortar_flux!(fstar, mesh::Union{P4estMesh{2}, T8codeMesh{2}}, nonconservative_terms::False, @@ -827,7 +827,7 @@ end mortar_index) # TODO: parabolic; only BR1 at the moment - flux_ = 0.5 * (u_ll + u_rr) + flux_ = 0.5f0 * (u_ll + u_rr) # Copy flux to buffer set_node_vars!(fstar[position_index], flux_, equations, dg, node_index) diff --git a/src/solvers/dgsem_p4est/dg_3d.jl b/src/solvers/dgsem_p4est/dg_3d.jl index 5b3c5ae5ca8..ece4840b74b 100644 --- a/src/solvers/dgsem_p4est/dg_3d.jl +++ b/src/solvers/dgsem_p4est/dg_3d.jl @@ -305,10 +305,10 @@ end # central fluxes/SATs surface_flux_values[v, primary_i_node_index, primary_j_node_index, primary_direction_index, primary_element_index] = flux_[v] + - 0.5 * noncons_primary[v] + 0.5f0 * noncons_primary[v] surface_flux_values[v, secondary_i_node_index, secondary_j_node_index, secondary_direction_index, secondary_element_index] = -(flux_[v] + - 0.5 * + 0.5f0 * noncons_secondary[v]) end end @@ -580,10 +580,10 @@ function calc_mortar_flux!(surface_flux_values, # copying in the correct orientation u_buffer = cache.u_threaded[Threads.threadid()] - # in calc_interface_flux!, the interface flux is computed once over each - # interface using the normal from the "primary" element. The result is then - # passed back to the "secondary" element, flipping the sign to account for the - # change in the normal direction. For mortars, this sign flip occurs in + # in calc_interface_flux!, the interface flux is computed once over each + # interface using the normal from the "primary" element. The result is then + # passed back to the "secondary" element, flipping the sign to account for the + # change in the normal direction. For mortars, this sign flip occurs in # "mortar_fluxes_to_elements!" instead. mortar_fluxes_to_elements!(surface_flux_values, mesh, equations, mortar_l2, dg, cache, @@ -635,7 +635,7 @@ end # central fluxes/SATs noncons = nonconservative_flux(u_ll, u_rr, normal_direction, normal_direction, equations) - flux_plus_noncons = flux + 0.5 * noncons + flux_plus_noncons = flux + 0.5f0 * noncons # Copy to buffer set_node_vars!(fstar, flux_plus_noncons, equations, dg, i_node_index, j_node_index, diff --git a/src/solvers/dgsem_p4est/dg_3d_parabolic.jl b/src/solvers/dgsem_p4est/dg_3d_parabolic.jl index 63d431d35d5..3f286ca01fc 100644 --- a/src/solvers/dgsem_p4est/dg_3d_parabolic.jl +++ b/src/solvers/dgsem_p4est/dg_3d_parabolic.jl @@ -144,7 +144,7 @@ function calc_gradient!(gradients, u_transformed, t, end # Prolong solution to mortars. These should reuse the hyperbolic version of `prolong2mortars` - # !!! NOTE: we reuse the hyperbolic cache here, since it contains both `mortars` and `u_threaded`. + # !!! NOTE: we reuse the hyperbolic cache here, since it contains both `mortars` and `u_threaded`. # !!! should we have a separate mortars/u_threaded in cache_parabolic? @trixi_timeit timer() "prolong2mortars" begin prolong2mortars!(cache, u_transformed, mesh, equations_parabolic, @@ -152,8 +152,8 @@ function calc_gradient!(gradients, u_transformed, t, end # Calculate mortar fluxes. These should reuse the hyperbolic version of `calc_mortar_flux`, - # along with a specialization on `calc_mortar_flux!` and `mortar_fluxes_to_elements!` for - # AbstractEquationsParabolic. + # along with a specialization on `calc_mortar_flux!` and `mortar_fluxes_to_elements!` for + # AbstractEquationsParabolic. @trixi_timeit timer() "mortar flux" begin calc_mortar_flux!(cache_parabolic.elements.surface_flux_values, mesh, False(), # False() = no nonconservative terms @@ -265,7 +265,7 @@ function calc_gradient!(gradients, u_transformed, t, end # This version is called during `calc_gradients!` and must be specialized because the flux -# in the gradient is {u} which doesn't depend on normals. Thus, you don't need to scale by +# in the gradient is {u} which doesn't depend on normals. Thus, you don't need to scale by # 2 and flip the sign when storing the mortar fluxes back into surface_flux_values @inline function mortar_fluxes_to_elements!(surface_flux_values, mesh::P4estMesh{3}, @@ -369,7 +369,7 @@ end primary_j_node_index, interface_index) - flux_ = 0.5 * (u_ll + u_rr) # we assume that the gradient computations utilize a central flux + flux_ = 0.5f0 * (u_ll + u_rr) # we assume that the gradient computations utilize a central flux # Note that we don't flip the sign on the secondondary flux. This is because for parabolic terms, # the normals are not embedded in `flux_` for the parabolic gradient computations. @@ -558,7 +558,7 @@ function prolong2interfaces!(cache_parabolic, flux_viscous, return nothing end -# This version is used for divergence flux computations +# This version is used for divergence flux computations function calc_interface_flux!(surface_flux_values, mesh::P4estMesh{3}, equations_parabolic, dg::DG, cache_parabolic) @@ -603,7 +603,7 @@ function calc_interface_flux!(surface_flux_values, for j in eachnode(dg) for i in eachnode(dg) - # We prolong the viscous flux dotted with respect the outward normal on the + # We prolong the viscous flux dotted with respect the outward normal on the # primary element. We assume a BR-1 type of flux. viscous_flux_normal_ll, viscous_flux_normal_rr = get_surface_node_vars(cache_parabolic.interfaces.u, equations_parabolic, @@ -612,7 +612,7 @@ function calc_interface_flux!(surface_flux_values, j, interface) - flux = 0.5 * (viscous_flux_normal_ll + viscous_flux_normal_rr) + flux = 0.5f0 * (viscous_flux_normal_ll + viscous_flux_normal_rr) for v in eachvariable(equations_parabolic) surface_flux_values[v, i, j, primary_direction_index, primary_element] = flux[v] @@ -738,11 +738,11 @@ function prolong2mortars_divergence!(cache, flux_viscous, flux_viscous_z[v, i_large, j_large, k_large, element]) - # We prolong the viscous flux dotted with respect the outward normal - # on the small element. We scale by -1/2 here because the normal - # direction on the large element is negative 2x that of the small + # We prolong the viscous flux dotted with respect the outward normal + # on the small element. We scale by -1/2 here because the normal + # direction on the large element is negative 2x that of the small # element (these normal directions are "scaled" by the surface Jacobian) - u_buffer[v, i, j] = -0.5 * dot(flux_viscous, normal_direction) + u_buffer[v, i, j] = -0.5f0 * dot(flux_viscous, normal_direction) end i_large += i_large_step_i j_large += j_large_step_i @@ -779,8 +779,8 @@ function prolong2mortars_divergence!(cache, flux_viscous, return nothing end -# We specialize `calc_mortar_flux!` for the divergence part of -# the parabolic terms. +# We specialize `calc_mortar_flux!` for the divergence part of +# the parabolic terms. function calc_mortar_flux_divergence!(surface_flux_values, mesh::Union{P4estMesh{3}, T8codeMesh{3}}, equations::AbstractEquationsParabolic, @@ -821,7 +821,7 @@ function calc_mortar_flux_divergence!(surface_flux_values, mortar] # TODO: parabolic; only BR1 at the moment - fstar[v, i, j, position] = 0.5 * (viscous_flux_normal_ll + + fstar[v, i, j, position] = 0.5f0 * (viscous_flux_normal_ll + viscous_flux_normal_rr) end @@ -849,7 +849,7 @@ function calc_mortar_flux_divergence!(surface_flux_values, end # NOTE: Use analogy to "calc_mortar_flux!" for hyperbolic eqs with no nonconservative terms. -# Reasoning: "calc_interface_flux!" for parabolic part is implemented as the version for +# Reasoning: "calc_interface_flux!" for parabolic part is implemented as the version for # hyperbolic terms with conserved terms only, i.e., no nonconservative terms. @inline function calc_mortar_flux!(fstar, mesh::P4estMesh{3}, @@ -865,7 +865,7 @@ end j_node_index, mortar_index) # TODO: parabolic; only BR1 at the moment - flux_ = 0.5 * (u_ll + u_rr) + flux_ = 0.5f0 * (u_ll + u_rr) # Copy flux to buffer set_node_vars!(fstar, flux_, equations, dg, i_node_index, j_node_index, position_index) diff --git a/src/solvers/dgsem_structured/containers_3d.jl b/src/solvers/dgsem_structured/containers_3d.jl index e843e869bf5..75cc98bf2b7 100644 --- a/src/solvers/dgsem_structured/containers_3d.jl +++ b/src/solvers/dgsem_structured/containers_3d.jl @@ -144,7 +144,7 @@ function calc_contravariant_vectors!(contravariant_vectors::AbstractArray{<:Any, for ii in eachnode(basis) # Multiply derivative_matrix to j-dimension to differentiate wrt η - result += 0.5 * derivative_matrix[j, ii] * + result += 0.5f0 * derivative_matrix[j, ii] * (node_coordinates[m, i, ii, k, element] * jacobian_matrix[l, 3, i, ii, k, element] - node_coordinates[l, i, ii, k, element] * @@ -160,7 +160,7 @@ function calc_contravariant_vectors!(contravariant_vectors::AbstractArray{<:Any, for ii in eachnode(basis) # Multiply derivative_matrix to k-dimension to differentiate wrt ζ - result += 0.5 * derivative_matrix[k, ii] * + result += 0.5f0 * derivative_matrix[k, ii] * (node_coordinates[m, i, j, ii, element] * jacobian_matrix[l, 2, i, j, ii, element] - node_coordinates[l, i, j, ii, element] * @@ -178,7 +178,7 @@ function calc_contravariant_vectors!(contravariant_vectors::AbstractArray{<:Any, for ii in eachnode(basis) # Multiply derivative_matrix to k-dimension to differentiate wrt ζ - result += 0.5 * derivative_matrix[k, ii] * + result += 0.5f0 * derivative_matrix[k, ii] * (node_coordinates[m, i, j, ii, element] * jacobian_matrix[l, 1, i, j, ii, element] - node_coordinates[l, i, j, ii, element] * @@ -194,7 +194,7 @@ function calc_contravariant_vectors!(contravariant_vectors::AbstractArray{<:Any, for ii in eachnode(basis) # Multiply derivative_matrix to i-dimension to differentiate wrt ξ - result += 0.5 * derivative_matrix[i, ii] * + result += 0.5f0 * derivative_matrix[i, ii] * (node_coordinates[m, ii, j, k, element] * jacobian_matrix[l, 3, ii, j, k, element] - node_coordinates[l, ii, j, k, element] * @@ -212,7 +212,7 @@ function calc_contravariant_vectors!(contravariant_vectors::AbstractArray{<:Any, for ii in eachnode(basis) # Multiply derivative_matrix to i-dimension to differentiate wrt ξ - result += 0.5 * derivative_matrix[i, ii] * + result += 0.5f0 * derivative_matrix[i, ii] * (node_coordinates[m, ii, j, k, element] * jacobian_matrix[l, 2, ii, j, k, element] - node_coordinates[l, ii, j, k, element] * @@ -228,7 +228,7 @@ function calc_contravariant_vectors!(contravariant_vectors::AbstractArray{<:Any, for ii in eachnode(basis) # Multiply derivative_matrix to j-dimension to differentiate wrt η - result += 0.5 * derivative_matrix[j, ii] * + result += 0.5f0 * derivative_matrix[j, ii] * (node_coordinates[m, i, ii, k, element] * jacobian_matrix[l, 1, i, ii, k, element] - node_coordinates[l, i, ii, k, element] * diff --git a/src/solvers/dgsem_structured/dg_2d.jl b/src/solvers/dgsem_structured/dg_2d.jl index 51b91eac6be..6023c9e6192 100644 --- a/src/solvers/dgsem_structured/dg_2d.jl +++ b/src/solvers/dgsem_structured/dg_2d.jl @@ -50,8 +50,8 @@ function rhs!(du, u, t, end #= -`weak_form_kernel!` is only implemented for conserved terms as -non-conservative terms should always be discretized in conjunction with a flux-splitting scheme, +`weak_form_kernel!` is only implemented for conserved terms as +non-conservative terms should always be discretized in conjunction with a flux-splitting scheme, see `flux_differencing_kernel!`. This treatment is required to achieve, e.g., entropy-stability or well-balancedness. See also https://github.com/trixi-framework/Trixi.jl/issues/1671#issuecomment-1765644064 @@ -128,7 +128,7 @@ end # pull the contravariant vectors and compute the average Ja1_node_ii = get_contravariant_vector(1, contravariant_vectors, ii, j, element) - Ja1_avg = 0.5 * (Ja1_node + Ja1_node_ii) + Ja1_avg = 0.5f0 * (Ja1_node + Ja1_node_ii) # compute the contravariant sharp flux in the direction of the # averaged contravariant vector fluxtilde1 = volume_flux(u_node, u_node_ii, Ja1_avg, equations) @@ -144,7 +144,7 @@ end # pull the contravariant vectors and compute the average Ja2_node_jj = get_contravariant_vector(2, contravariant_vectors, i, jj, element) - Ja2_avg = 0.5 * (Ja2_node + Ja2_node_jj) + Ja2_avg = 0.5f0 * (Ja2_node + Ja2_node_jj) # compute the contravariant sharp flux in the direction of the # averaged contravariant vector fluxtilde2 = volume_flux(u_node, u_node_jj, Ja2_avg, equations) @@ -193,7 +193,7 @@ end # pull the contravariant vectors and compute the average Ja1_node_ii = get_contravariant_vector(1, contravariant_vectors, ii, j, element) - Ja1_avg = 0.5 * (Ja1_node + Ja1_node_ii) + Ja1_avg = 0.5f0 * (Ja1_node + Ja1_node_ii) # Compute the contravariant nonconservative flux. fluxtilde1 = nonconservative_flux(u_node, u_node_ii, Ja1_node, Ja1_avg, equations) @@ -207,7 +207,7 @@ end # pull the contravariant vectors and compute the average Ja2_node_jj = get_contravariant_vector(2, contravariant_vectors, i, jj, element) - Ja2_avg = 0.5 * (Ja2_node + Ja2_node_jj) + Ja2_avg = 0.5f0 * (Ja2_node + Ja2_node_jj) # compute the contravariant nonconservative flux in the direction of the # averaged contravariant vector fluxtilde2 = nonconservative_flux(u_node, u_node_jj, Ja2_node, Ja2_avg, @@ -217,7 +217,7 @@ end end # The factor 0.5 cancels the factor 2 in the flux differencing form - multiply_add_to_node_vars!(du, alpha * 0.5, integral_contribution, equations, + multiply_add_to_node_vars!(du, alpha * 0.5f0, integral_contribution, equations, dg, i, j, element) end end @@ -337,10 +337,10 @@ end # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs ftilde1_L = ftilde1 + - 0.5 * nonconservative_flux(u_ll, u_rr, normal_direction, + 0.5f0 * nonconservative_flux(u_ll, u_rr, normal_direction, normal_direction, equations) ftilde1_R = ftilde1 + - 0.5 * nonconservative_flux(u_rr, u_ll, normal_direction, + 0.5f0 * nonconservative_flux(u_rr, u_ll, normal_direction, normal_direction, equations) set_node_vars!(fstar1_L, ftilde1_L, equations, dg, i, j) @@ -377,10 +377,10 @@ end # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs ftilde2_L = ftilde2 + - 0.5 * nonconservative_flux(u_ll, u_rr, normal_direction, + 0.5f0 * nonconservative_flux(u_ll, u_rr, normal_direction, normal_direction, equations) ftilde2_R = ftilde2 + - 0.5 * nonconservative_flux(u_rr, u_ll, normal_direction, + 0.5f0 * nonconservative_flux(u_rr, u_ll, normal_direction, normal_direction, equations) set_node_vars!(fstar2_L, ftilde2_L, equations, dg, i, j) @@ -545,10 +545,10 @@ end # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs surface_flux_values[v, i, right_direction, left_element] = flux[v] + - 0.5 * + 0.5f0 * noncons_left[v] surface_flux_values[v, i, left_direction, right_element] = flux[v] + - 0.5 * + 0.5f0 * noncons_right[v] end end diff --git a/src/solvers/dgsem_structured/dg_2d_subcell_limiters.jl b/src/solvers/dgsem_structured/dg_2d_subcell_limiters.jl index 4da402425ea..e10a5295459 100644 --- a/src/solvers/dgsem_structured/dg_2d_subcell_limiters.jl +++ b/src/solvers/dgsem_structured/dg_2d_subcell_limiters.jl @@ -48,7 +48,7 @@ # pull the contravariant vectors and compute the average Ja1_node_ii = get_contravariant_vector(1, contravariant_vectors, ii, j, element) - Ja1_avg = 0.5 * (Ja1_node + Ja1_node_ii) + Ja1_avg = 0.5f0 * (Ja1_node + Ja1_node_ii) # compute the contravariant sharp flux in the direction of the averaged contravariant vector fluxtilde1 = volume_flux(u_node, u_node_ii, Ja1_avg, equations) @@ -85,7 +85,7 @@ # pull the contravariant vectors and compute the average Ja2_node_jj = get_contravariant_vector(2, contravariant_vectors, i, jj, element) - Ja2_avg = 0.5 * (Ja2_node + Ja2_node_jj) + Ja2_avg = 0.5f0 * (Ja2_node + Ja2_node_jj) # compute the contravariant sharp flux in the direction of the averaged contravariant vector fluxtilde2 = volume_flux(u_node, u_node_jj, Ja2_avg, equations) multiply_add_to_node_vars!(flux_temp, derivative_split[j, jj], fluxtilde2, diff --git a/src/solvers/dgsem_structured/dg_3d.jl b/src/solvers/dgsem_structured/dg_3d.jl index 1df9f408895..e8430eaa491 100644 --- a/src/solvers/dgsem_structured/dg_3d.jl +++ b/src/solvers/dgsem_structured/dg_3d.jl @@ -50,8 +50,8 @@ function rhs!(du, u, t, end #= -`weak_form_kernel!` is only implemented for conserved terms as -non-conservative terms should always be discretized in conjunction with a flux-splitting scheme, +`weak_form_kernel!` is only implemented for conserved terms as +non-conservative terms should always be discretized in conjunction with a flux-splitting scheme, see `flux_differencing_kernel!`. This treatment is required to achieve, e.g., entropy-stability or well-balancedness. See also https://github.com/trixi-framework/Trixi.jl/issues/1671#issuecomment-1765644064 @@ -145,7 +145,7 @@ end # pull the contravariant vectors and compute the average Ja1_node_ii = get_contravariant_vector(1, contravariant_vectors, ii, j, k, element) - Ja1_avg = 0.5 * (Ja1_node + Ja1_node_ii) + Ja1_avg = 0.5f0 * (Ja1_node + Ja1_node_ii) # compute the contravariant sharp flux in the direction of the # averaged contravariant vector fluxtilde1 = volume_flux(u_node, u_node_ii, Ja1_avg, equations) @@ -161,7 +161,7 @@ end # pull the contravariant vectors and compute the average Ja2_node_jj = get_contravariant_vector(2, contravariant_vectors, i, jj, k, element) - Ja2_avg = 0.5 * (Ja2_node + Ja2_node_jj) + Ja2_avg = 0.5f0 * (Ja2_node + Ja2_node_jj) # compute the contravariant sharp flux in the direction of the # averaged contravariant vector fluxtilde2 = volume_flux(u_node, u_node_jj, Ja2_avg, equations) @@ -177,7 +177,7 @@ end # pull the contravariant vectors and compute the average Ja3_node_kk = get_contravariant_vector(3, contravariant_vectors, i, j, kk, element) - Ja3_avg = 0.5 * (Ja3_node + Ja3_node_kk) + Ja3_avg = 0.5f0 * (Ja3_node + Ja3_node_kk) # compute the contravariant sharp flux in the direction of the # averaged contravariant vector fluxtilde3 = volume_flux(u_node, u_node_kk, Ja3_avg, equations) @@ -225,7 +225,7 @@ end # pull the contravariant vectors and compute the average Ja1_node_ii = get_contravariant_vector(1, contravariant_vectors, ii, j, k, element) - Ja1_avg = 0.5 * (Ja1_node + Ja1_node_ii) + Ja1_avg = 0.5f0 * (Ja1_node + Ja1_node_ii) # compute the contravariant nonconservative flux in the direction of the # averaged contravariant vector fluxtilde1 = nonconservative_flux(u_node, u_node_ii, Ja1_node, Ja1_avg, @@ -240,7 +240,7 @@ end # pull the contravariant vectors and compute the average Ja2_node_jj = get_contravariant_vector(2, contravariant_vectors, i, jj, k, element) - Ja2_avg = 0.5 * (Ja2_node + Ja2_node_jj) + Ja2_avg = 0.5f0 * (Ja2_node + Ja2_node_jj) # compute the contravariant nonconservative flux in the direction of the # averaged contravariant vector fluxtilde2 = nonconservative_flux(u_node, u_node_jj, Ja2_node, Ja2_avg, @@ -255,7 +255,7 @@ end # pull the contravariant vectors and compute the average Ja3_node_kk = get_contravariant_vector(3, contravariant_vectors, i, j, kk, element) - Ja3_avg = 0.5 * (Ja3_node + Ja3_node_kk) + Ja3_avg = 0.5f0 * (Ja3_node + Ja3_node_kk) # compute the contravariant nonconservative flux in the direction of the # averaged contravariant vector fluxtilde3 = nonconservative_flux(u_node, u_node_kk, Ja3_node, Ja3_avg, @@ -265,7 +265,7 @@ end end # The factor 0.5 cancels the factor 2 in the flux differencing form - multiply_add_to_node_vars!(du, alpha * 0.5, integral_contribution, equations, + multiply_add_to_node_vars!(du, alpha * 0.5f0, integral_contribution, equations, dg, i, j, k, element) end end @@ -411,10 +411,10 @@ end # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs ftilde_L = ftilde + - 0.5 * nonconservative_flux(u_ll, u_rr, normal_direction, + 0.5f0 * nonconservative_flux(u_ll, u_rr, normal_direction, normal_direction, equations) ftilde_R = ftilde + - 0.5 * nonconservative_flux(u_rr, u_ll, normal_direction, + 0.5f0 * nonconservative_flux(u_rr, u_ll, normal_direction, normal_direction, equations) set_node_vars!(fstar1_L, ftilde_L, equations, dg, i, j, k) @@ -449,10 +449,10 @@ end # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs ftilde_L = ftilde + - 0.5 * nonconservative_flux(u_ll, u_rr, normal_direction, + 0.5f0 * nonconservative_flux(u_ll, u_rr, normal_direction, normal_direction, equations) ftilde_R = ftilde + - 0.5 * nonconservative_flux(u_rr, u_ll, normal_direction, + 0.5f0 * nonconservative_flux(u_rr, u_ll, normal_direction, normal_direction, equations) set_node_vars!(fstar2_L, ftilde_L, equations, dg, i, j, k) @@ -487,10 +487,10 @@ end # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs ftilde_L = ftilde + - 0.5 * nonconservative_flux(u_ll, u_rr, normal_direction, + 0.5f0 * nonconservative_flux(u_ll, u_rr, normal_direction, normal_direction, equations) ftilde_R = ftilde + - 0.5 * nonconservative_flux(u_rr, u_ll, normal_direction, + 0.5f0 * nonconservative_flux(u_rr, u_ll, normal_direction, normal_direction, equations) set_node_vars!(fstar3_L, ftilde_L, equations, dg, i, j, k) @@ -681,10 +681,10 @@ end # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs surface_flux_values[v, i, j, right_direction, left_element] = flux[v] + - 0.5 * + 0.5f0 * noncons_left[v] surface_flux_values[v, i, j, left_direction, right_element] = flux[v] + - 0.5 * + 0.5f0 * noncons_right[v] end end diff --git a/src/solvers/dgsem_structured/indicators_1d.jl b/src/solvers/dgsem_structured/indicators_1d.jl index 4299ec603dd..a6d518699dd 100644 --- a/src/solvers/dgsem_structured/indicators_1d.jl +++ b/src/solvers/dgsem_structured/indicators_1d.jl @@ -19,8 +19,9 @@ function apply_smoothing!(mesh::StructuredMesh{1}, alpha, alpha_tmp, dg, cache) left = cache.elements.left_neighbors[1, element] # Apply smoothing - alpha[left] = max(alpha_tmp[left], 0.5 * alpha_tmp[element], alpha[left]) - alpha[element] = max(alpha_tmp[element], 0.5 * alpha_tmp[left], alpha[element]) + alpha[left] = max(alpha_tmp[left], 0.5f0 * alpha_tmp[element], alpha[left]) + alpha[element] = max(alpha_tmp[element], 0.5f0 * alpha_tmp[left], + alpha[element]) end end end # @muladd diff --git a/src/solvers/dgsem_structured/indicators_2d.jl b/src/solvers/dgsem_structured/indicators_2d.jl index f4b07b70cb8..52d6ac2a955 100644 --- a/src/solvers/dgsem_structured/indicators_2d.jl +++ b/src/solvers/dgsem_structured/indicators_2d.jl @@ -20,11 +20,13 @@ function apply_smoothing!(mesh::StructuredMesh{2}, alpha, alpha_tmp, dg, cache) lower = cache.elements.left_neighbors[2, element] # Apply smoothing - alpha[left] = max(alpha_tmp[left], 0.5 * alpha_tmp[element], alpha[left]) - alpha[element] = max(alpha_tmp[element], 0.5 * alpha_tmp[left], alpha[element]) + alpha[left] = max(alpha_tmp[left], 0.5f0 * alpha_tmp[element], alpha[left]) + alpha[element] = max(alpha_tmp[element], 0.5f0 * alpha_tmp[left], + alpha[element]) - alpha[lower] = max(alpha_tmp[lower], 0.5 * alpha_tmp[element], alpha[lower]) - alpha[element] = max(alpha_tmp[element], 0.5 * alpha_tmp[lower], alpha[element]) + alpha[lower] = max(alpha_tmp[lower], 0.5f0 * alpha_tmp[element], alpha[lower]) + alpha[element] = max(alpha_tmp[element], 0.5f0 * alpha_tmp[lower], + alpha[element]) end end end # @muladd diff --git a/src/solvers/dgsem_structured/indicators_3d.jl b/src/solvers/dgsem_structured/indicators_3d.jl index 155bf50dc68..8b477da2e8f 100644 --- a/src/solvers/dgsem_structured/indicators_3d.jl +++ b/src/solvers/dgsem_structured/indicators_3d.jl @@ -21,14 +21,17 @@ function apply_smoothing!(mesh::StructuredMesh{3}, alpha, alpha_tmp, dg, cache) front = cache.elements.left_neighbors[3, element] # Apply smoothing - alpha[left] = max(alpha_tmp[left], 0.5 * alpha_tmp[element], alpha[left]) - alpha[element] = max(alpha_tmp[element], 0.5 * alpha_tmp[left], alpha[element]) + alpha[left] = max(alpha_tmp[left], 0.5f0 * alpha_tmp[element], alpha[left]) + alpha[element] = max(alpha_tmp[element], 0.5f0 * alpha_tmp[left], + alpha[element]) - alpha[lower] = max(alpha_tmp[lower], 0.5 * alpha_tmp[element], alpha[lower]) - alpha[element] = max(alpha_tmp[element], 0.5 * alpha_tmp[lower], alpha[element]) + alpha[lower] = max(alpha_tmp[lower], 0.5f0 * alpha_tmp[element], alpha[lower]) + alpha[element] = max(alpha_tmp[element], 0.5f0 * alpha_tmp[lower], + alpha[element]) - alpha[front] = max(alpha_tmp[front], 0.5 * alpha_tmp[element], alpha[front]) - alpha[element] = max(alpha_tmp[element], 0.5 * alpha_tmp[front], alpha[element]) + alpha[front] = max(alpha_tmp[front], 0.5f0 * alpha_tmp[element], alpha[front]) + alpha[element] = max(alpha_tmp[element], 0.5f0 * alpha_tmp[front], + alpha[element]) end end end # @muladd diff --git a/src/solvers/dgsem_t8code/containers_3d.jl b/src/solvers/dgsem_t8code/containers_3d.jl index 4d56bc734aa..1375782631a 100644 --- a/src/solvers/dgsem_t8code/containers_3d.jl +++ b/src/solvers/dgsem_t8code/containers_3d.jl @@ -44,13 +44,13 @@ function calc_node_coordinates!(node_coordinates, pointer(element_coords)) nodes_out_x = (2 * - (element_length * 0.5 * (nodes .+ 1) .+ element_coords[1]) .- + (element_length * 0.5f0 * (nodes .+ 1) .+ element_coords[1]) .- 1) nodes_out_y = (2 * - (element_length * 0.5 * (nodes .+ 1) .+ element_coords[2]) .- + (element_length * 0.5f0 * (nodes .+ 1) .+ element_coords[2]) .- 1) nodes_out_z = (2 * - (element_length * 0.5 * (nodes .+ 1) .+ element_coords[3]) .- + (element_length * 0.5f0 * (nodes .+ 1) .+ element_coords[3]) .- 1) polynomial_interpolation_matrix!(matrix1, mesh.nodes, nodes_out_x, diff --git a/src/solvers/dgsem_tree/dg_1d.jl b/src/solvers/dgsem_tree/dg_1d.jl index 225b85a0598..641c944d5f7 100644 --- a/src/solvers/dgsem_tree/dg_1d.jl +++ b/src/solvers/dgsem_tree/dg_1d.jl @@ -145,8 +145,8 @@ function calc_volume_integral!(du, u, end #= -`weak_form_kernel!` is only implemented for conserved terms as -non-conservative terms should always be discretized in conjunction with a flux-splitting scheme, +`weak_form_kernel!` is only implemented for conserved terms as +non-conservative terms should always be discretized in conjunction with a flux-splitting scheme, see `flux_differencing_kernel!`. This treatment is required to achieve, e.g., entropy-stability or well-balancedness. See also https://github.com/trixi-framework/Trixi.jl/issues/1671#issuecomment-1765644064 @@ -245,7 +245,7 @@ end end # The factor 0.5 cancels the factor 2 in the flux differencing form - multiply_add_to_node_vars!(du, alpha * 0.5, integral_contribution, equations, + multiply_add_to_node_vars!(du, alpha * 0.5f0, integral_contribution, equations, dg, i, element) end end @@ -377,8 +377,8 @@ end # Note the factor 0.5 necessary for the nonconservative fluxes based on # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs - f1_L = f1 + 0.5 * nonconservative_flux(u_ll, u_rr, 1, equations) - f1_R = f1 + 0.5 * nonconservative_flux(u_rr, u_ll, 1, equations) + f1_L = f1 + 0.5f0 * nonconservative_flux(u_ll, u_rr, 1, equations) + f1_R = f1 + 0.5f0 * nonconservative_flux(u_rr, u_ll, 1, equations) # Copy to temporary storage set_node_vars!(fstar1_L, f1_L, equations, dg, i) @@ -471,9 +471,9 @@ function calc_interface_flux!(surface_flux_values, # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs surface_flux_values[v, left_direction, left_id] = flux[v] + - 0.5 * noncons_left[v] + 0.5f0 * noncons_left[v] surface_flux_values[v, right_direction, right_id] = flux[v] + - 0.5 * noncons_right[v] + 0.5f0 * noncons_right[v] end end @@ -595,7 +595,7 @@ function calc_boundary_flux_by_direction!(surface_flux_values::AbstractArray{<:A # Copy flux to left and right element storage for v in eachvariable(equations) surface_flux_values[v, direction, neighbor] = flux[v] + - 0.5 * noncons_flux[v] + 0.5f0 * noncons_flux[v] end end diff --git a/src/solvers/dgsem_tree/dg_1d_parabolic.jl b/src/solvers/dgsem_tree/dg_1d_parabolic.jl index 0017f9ca88e..fb96e0535ad 100644 --- a/src/solvers/dgsem_tree/dg_1d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_1d_parabolic.jl @@ -190,7 +190,7 @@ function calc_interface_flux!(surface_flux_values, # Compute interface flux as mean of left and right viscous fluxes # TODO: parabolic; only BR1 at the moment - flux = 0.5 * (flux_ll + flux_rr) + flux = 0.5f0 * (flux_ll + flux_rr) # Copy flux to left and right element storage for v in eachvariable(equations_parabolic) @@ -456,7 +456,7 @@ function calc_gradient!(gradients, u_transformed, t, # Call pointwise Riemann solver u_ll, u_rr = get_surface_node_vars(cache_parabolic.interfaces.u, equations_parabolic, dg, interface) - flux = 0.5 * (u_ll + u_rr) + flux = 0.5f0 * (u_ll + u_rr) # Copy flux to left and right element storage for v in eachvariable(equations_parabolic) diff --git a/src/solvers/dgsem_tree/dg_2d.jl b/src/solvers/dgsem_tree/dg_2d.jl index 4f2c72cd677..734a31d5470 100644 --- a/src/solvers/dgsem_tree/dg_2d.jl +++ b/src/solvers/dgsem_tree/dg_2d.jl @@ -196,8 +196,8 @@ function calc_volume_integral!(du, u, end #= -`weak_form_kernel!` is only implemented for conserved terms as -non-conservative terms should always be discretized in conjunction with a flux-splitting scheme, +`weak_form_kernel!` is only implemented for conserved terms as +non-conservative terms should always be discretized in conjunction with a flux-splitting scheme, see `flux_differencing_kernel!`. This treatment is required to achieve, e.g., entropy-stability or well-balancedness. See also https://github.com/trixi-framework/Trixi.jl/issues/1671#issuecomment-1765644064 @@ -325,7 +325,7 @@ end end # The factor 0.5 cancels the factor 2 in the flux differencing form - multiply_add_to_node_vars!(du, alpha * 0.5, integral_contribution, equations, + multiply_add_to_node_vars!(du, alpha * 0.5f0, integral_contribution, equations, dg, i, j, element) end end @@ -504,8 +504,8 @@ end # Note the factor 0.5 necessary for the nonconservative fluxes based on # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs - f1_L = f1 + 0.5 * nonconservative_flux(u_ll, u_rr, 1, equations) - f1_R = f1 + 0.5 * nonconservative_flux(u_rr, u_ll, 1, equations) + f1_L = f1 + 0.5f0 * nonconservative_flux(u_ll, u_rr, 1, equations) + f1_R = f1 + 0.5f0 * nonconservative_flux(u_rr, u_ll, 1, equations) # Copy to temporary storage set_node_vars!(fstar1_L, f1_L, equations, dg, i, j) @@ -530,8 +530,8 @@ end # Note the factor 0.5 necessary for the nonconservative fluxes based on # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs - f2_L = f2 + 0.5 * nonconservative_flux(u_ll, u_rr, 2, equations) - f2_R = f2 + 0.5 * nonconservative_flux(u_rr, u_ll, 2, equations) + f2_L = f2 + 0.5f0 * nonconservative_flux(u_ll, u_rr, 2, equations) + f2_R = f2 + 0.5f0 * nonconservative_flux(u_rr, u_ll, 2, equations) # Copy to temporary storage set_node_vars!(fstar2_L, f2_L, equations, dg, i, j) @@ -637,10 +637,10 @@ function calc_interface_flux!(surface_flux_values, # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs surface_flux_values[v, i, left_direction, left_id] = flux[v] + - 0.5 * + 0.5f0 * noncons_left[v] surface_flux_values[v, i, right_direction, right_id] = flux[v] + - 0.5 * + 0.5f0 * noncons_right[v] end end @@ -790,7 +790,7 @@ function calc_boundary_flux_by_direction!(surface_flux_values::AbstractArray{<:A # Copy flux to left and right element storage for v in eachvariable(equations) surface_flux_values[v, i, direction, neighbor] = flux[v] + - 0.5 * noncons_flux[v] + 0.5f0 * noncons_flux[v] end end end @@ -968,9 +968,9 @@ function calc_mortar_flux!(surface_flux_values, noncons_lower = nonconservative_flux(u_lower_ll, u_lower_rr, orientation, equations) # Add to primary and secondary temporary storage - multiply_add_to_node_vars!(fstar_upper, 0.5, noncons_upper, equations, + multiply_add_to_node_vars!(fstar_upper, 0.5f0, noncons_upper, equations, dg, i) - multiply_add_to_node_vars!(fstar_lower, 0.5, noncons_lower, equations, + multiply_add_to_node_vars!(fstar_lower, 0.5f0, noncons_lower, equations, dg, i) end else # large_sides[mortar] == 2 -> small elements on the left @@ -986,9 +986,9 @@ function calc_mortar_flux!(surface_flux_values, noncons_lower = nonconservative_flux(u_lower_rr, u_lower_ll, orientation, equations) # Add to primary and secondary temporary storage - multiply_add_to_node_vars!(fstar_upper, 0.5, noncons_upper, equations, + multiply_add_to_node_vars!(fstar_upper, 0.5f0, noncons_upper, equations, dg, i) - multiply_add_to_node_vars!(fstar_lower, 0.5, noncons_lower, equations, + multiply_add_to_node_vars!(fstar_lower, 0.5f0, noncons_lower, equations, dg, i) end end diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index a6c962e03cd..f84a08cb69b 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -228,7 +228,7 @@ function calc_interface_flux!(surface_flux_values, # Compute interface flux as mean of left and right viscous fluxes # TODO: parabolic; only BR1 at the moment - flux = 0.5 * (flux_ll + flux_rr) + flux = 0.5f0 * (flux_ll + flux_rr) # Copy flux to left and right element storage for v in eachvariable(equations_parabolic) @@ -513,8 +513,8 @@ end # `cache` is the hyperbolic cache, i.e., in particular not `cache_parabolic`. # This is because mortar handling is done in the (hyperbolic) `cache`. -# Specialization `flux_viscous::Vector{Array{uEltype, 4}}` needed since -#`prolong2mortars!` in dg_2d.jl is used for both purely hyperbolic and +# Specialization `flux_viscous::Vector{Array{uEltype, 4}}` needed since +#`prolong2mortars!` in dg_2d.jl is used for both purely hyperbolic and # hyperbolic-parabolic systems. function prolong2mortars!(cache, flux_viscous::Vector{Array{uEltype, 4}}, mesh::TreeMesh{2}, @@ -654,7 +654,7 @@ end u_ll, u_rr = get_surface_node_vars(u_interfaces, equations_parabolic, dg, i, interface) # TODO: parabolic; only BR1 at the moment - flux = 0.5 * (u_ll + u_rr) + flux = 0.5f0 * (u_ll + u_rr) # Copy flux to left and right element storage set_node_vars!(destination, flux, equations_parabolic, dg, i) @@ -801,7 +801,7 @@ function calc_gradient!(gradients, u_transformed, t, u_ll, u_rr = get_surface_node_vars(cache_parabolic.interfaces.u, equations_parabolic, dg, i, interface) - flux = 0.5 * (u_ll + u_rr) + flux = 0.5f0 * (u_ll + u_rr) # Copy flux to left and right element storage for v in eachvariable(equations_parabolic) diff --git a/src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl b/src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl index 2cc5e2cae82..998790ef8e1 100644 --- a/src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl +++ b/src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl @@ -262,11 +262,11 @@ end flux1_noncons = volume_flux_noncons(u_node, u_node_ii, 1, equations, NonConservativeSymmetric(), noncons) multiply_add_to_node_vars!(flux_noncons_temp, - 0.5 * derivative_split[i, ii], + 0.5f0 * derivative_split[i, ii], flux1_noncons, equations, dg, noncons, i, j) multiply_add_to_node_vars!(flux_noncons_temp, - 0.5 * derivative_split[ii, i], + 0.5f0 * derivative_split[ii, i], flux1_noncons, equations, dg, noncons, ii, j) end diff --git a/src/solvers/dgsem_tree/dg_3d.jl b/src/solvers/dgsem_tree/dg_3d.jl index 2e7e882f5ef..acd90cee09d 100644 --- a/src/solvers/dgsem_tree/dg_3d.jl +++ b/src/solvers/dgsem_tree/dg_3d.jl @@ -227,8 +227,8 @@ function calc_volume_integral!(du, u, end #= -`weak_form_kernel!` is only implemented for conserved terms as -non-conservative terms should always be discretized in conjunction with a flux-splitting scheme, +`weak_form_kernel!` is only implemented for conserved terms as +non-conservative terms should always be discretized in conjunction with a flux-splitting scheme, see `flux_differencing_kernel!`. This treatment is required to achieve, e.g., entropy-stability or well-balancedness. See also https://github.com/trixi-framework/Trixi.jl/issues/1671#issuecomment-1765644064 @@ -374,7 +374,7 @@ end end # The factor 0.5 cancels the factor 2 in the flux differencing form - multiply_add_to_node_vars!(du, alpha * 0.5, integral_contribution, equations, + multiply_add_to_node_vars!(du, alpha * 0.5f0, integral_contribution, equations, dg, i, j, k, element) end end @@ -550,8 +550,8 @@ end # Note the factor 0.5 necessary for the nonconservative fluxes based on # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs - flux_L = flux + 0.5 * nonconservative_flux(u_ll, u_rr, 1, equations) - flux_R = flux + 0.5 * nonconservative_flux(u_rr, u_ll, 1, equations) + flux_L = flux + 0.5f0 * nonconservative_flux(u_ll, u_rr, 1, equations) + flux_R = flux + 0.5f0 * nonconservative_flux(u_rr, u_ll, 1, equations) set_node_vars!(fstar1_L, flux_L, equations, dg, i, j, k) set_node_vars!(fstar1_R, flux_R, equations, dg, i, j, k) @@ -573,8 +573,8 @@ end # Note the factor 0.5 necessary for the nonconservative fluxes based on # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs - flux_L = flux + 0.5 * nonconservative_flux(u_ll, u_rr, 2, equations) - flux_R = flux + 0.5 * nonconservative_flux(u_rr, u_ll, 2, equations) + flux_L = flux + 0.5f0 * nonconservative_flux(u_ll, u_rr, 2, equations) + flux_R = flux + 0.5f0 * nonconservative_flux(u_rr, u_ll, 2, equations) set_node_vars!(fstar2_L, flux_L, equations, dg, i, j, k) set_node_vars!(fstar2_R, flux_R, equations, dg, i, j, k) @@ -596,8 +596,8 @@ end # Note the factor 0.5 necessary for the nonconservative fluxes based on # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs - flux_L = flux + 0.5 * nonconservative_flux(u_ll, u_rr, 3, equations) - flux_R = flux + 0.5 * nonconservative_flux(u_rr, u_ll, 3, equations) + flux_L = flux + 0.5f0 * nonconservative_flux(u_ll, u_rr, 3, equations) + flux_R = flux + 0.5f0 * nonconservative_flux(u_rr, u_ll, 3, equations) set_node_vars!(fstar3_L, flux_L, equations, dg, i, j, k) set_node_vars!(fstar3_R, flux_R, equations, dg, i, j, k) @@ -712,10 +712,10 @@ function calc_interface_flux!(surface_flux_values, # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs surface_flux_values[v, i, j, left_direction, left_id] = flux[v] + - 0.5 * + 0.5f0 * noncons_left[v] surface_flux_values[v, i, j, right_direction, right_id] = flux[v] + - 0.5 * + 0.5f0 * noncons_right[v] end end @@ -1145,13 +1145,15 @@ function calc_mortar_flux!(surface_flux_values, u_lower_right_rr, orientation, equations) # Add to primary and secondary temporary storage - multiply_add_to_node_vars!(fstar_upper_left, 0.5, noncons_upper_left, + multiply_add_to_node_vars!(fstar_upper_left, 0.5f0, noncons_upper_left, equations, dg, i, j) - multiply_add_to_node_vars!(fstar_upper_right, 0.5, noncons_upper_right, + multiply_add_to_node_vars!(fstar_upper_right, 0.5f0, + noncons_upper_right, equations, dg, i, j) - multiply_add_to_node_vars!(fstar_lower_left, 0.5, noncons_lower_left, + multiply_add_to_node_vars!(fstar_lower_left, 0.5f0, noncons_lower_left, equations, dg, i, j) - multiply_add_to_node_vars!(fstar_lower_right, 0.5, noncons_lower_right, + multiply_add_to_node_vars!(fstar_lower_right, 0.5f0, + noncons_lower_right, equations, dg, i, j) end else # large_sides[mortar] == 2 -> small elements on the left @@ -1185,13 +1187,15 @@ function calc_mortar_flux!(surface_flux_values, u_lower_right_ll, orientation, equations) # Add to primary and secondary temporary storage - multiply_add_to_node_vars!(fstar_upper_left, 0.5, noncons_upper_left, + multiply_add_to_node_vars!(fstar_upper_left, 0.5f0, noncons_upper_left, equations, dg, i, j) - multiply_add_to_node_vars!(fstar_upper_right, 0.5, noncons_upper_right, + multiply_add_to_node_vars!(fstar_upper_right, 0.5f0, + noncons_upper_right, equations, dg, i, j) - multiply_add_to_node_vars!(fstar_lower_left, 0.5, noncons_lower_left, + multiply_add_to_node_vars!(fstar_lower_left, 0.5f0, noncons_lower_left, equations, dg, i, j) - multiply_add_to_node_vars!(fstar_lower_right, 0.5, noncons_lower_right, + multiply_add_to_node_vars!(fstar_lower_right, 0.5f0, + noncons_lower_right, equations, dg, i, j) end end diff --git a/src/solvers/dgsem_tree/dg_3d_parabolic.jl b/src/solvers/dgsem_tree/dg_3d_parabolic.jl index d5504744742..69956d58341 100644 --- a/src/solvers/dgsem_tree/dg_3d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_3d_parabolic.jl @@ -141,7 +141,7 @@ function calc_interface_flux!(surface_flux_values, # Compute interface flux as mean of left and right viscous fluxes # TODO: parabolic; only BR1 at the moment - flux = 0.5 * (flux_ll + flux_rr) + flux = 0.5f0 * (flux_ll + flux_rr) # Copy flux to left and right element storage for v in eachvariable(equations_parabolic) @@ -488,8 +488,8 @@ end # `cache` is the hyperbolic cache, i.e., in particular not `cache_parabolic`. # This is because mortar handling is done in the (hyperbolic) `cache`. -# Specialization `flux_viscous::Vector{Array{uEltype, 4}}` needed since -#`prolong2mortars!` in dg_2d.jl is used for both purely hyperbolic and +# Specialization `flux_viscous::Vector{Array{uEltype, 4}}` needed since +#`prolong2mortars!` in dg_2d.jl is used for both purely hyperbolic and # hyperbolic-parabolic systems. function prolong2mortars!(cache, flux_viscous::Vector{Array{uEltype, 5}}, @@ -773,7 +773,7 @@ end u_ll, u_rr = get_surface_node_vars(u_interfaces, equations_parabolic, dg, i, j, interface) # TODO: parabolic; only BR1 at the moment - flux = 0.5 * (u_ll + u_rr) + flux = 0.5f0 * (u_ll + u_rr) # Copy flux to left and right element storage set_node_vars!(destination, flux, equations_parabolic, dg, i, j) @@ -854,7 +854,7 @@ function calc_gradient!(gradients, u_transformed, t, u_ll, u_rr = get_surface_node_vars(cache_parabolic.interfaces.u, equations_parabolic, dg, i, j, interface) - flux = 0.5 * (u_ll + u_rr) + flux = 0.5f0 * (u_ll + u_rr) # Copy flux to left and right element storage for v in eachvariable(equations_parabolic) diff --git a/src/solvers/dgsem_tree/indicators.jl b/src/solvers/dgsem_tree/indicators.jl index 9f25a6d2dbb..323c1236c21 100644 --- a/src/solvers/dgsem_tree/indicators.jl +++ b/src/solvers/dgsem_tree/indicators.jl @@ -114,8 +114,11 @@ function (indicator_hg::IndicatorHennemannGassner)(u, mesh, equations, dg::DGSEM end # magic parameters - threshold = 0.5 * 10^(-1.8 * (nnodes(dg))^0.25) - parameter_s = log((1 - 0.0001) / 0.0001) + # TODO: Are there better values for Float32? + RealT = real(dg) + threshold = 0.5f0 * 10^(convert(RealT, -1.8) * nnodes(dg)^convert(RealT, 0.25)) + o_0001 = convert(RealT, 0.0001) + parameter_s = log((1 - o_0001) / o_0001) @threaded for element in eachelement(dg, cache) # This is dispatched by mesh dimension. diff --git a/src/solvers/dgsem_tree/indicators_1d.jl b/src/solvers/dgsem_tree/indicators_1d.jl index 4796ddcc602..9d11d05edcf 100644 --- a/src/solvers/dgsem_tree/indicators_1d.jl +++ b/src/solvers/dgsem_tree/indicators_1d.jl @@ -104,8 +104,8 @@ function apply_smoothing!(mesh::Union{TreeMesh{1}, P4estMesh{1}}, alpha, alpha_t right = cache.interfaces.neighbor_ids[2, interface] # Apply smoothing - alpha[left] = max(alpha_tmp[left], 0.5 * alpha_tmp[right], alpha[left]) - alpha[right] = max(alpha_tmp[right], 0.5 * alpha_tmp[left], alpha[right]) + alpha[left] = max(alpha_tmp[left], 0.5f0 * alpha_tmp[right], alpha[left]) + alpha[right] = max(alpha_tmp[right], 0.5f0 * alpha_tmp[left], alpha[right]) end end diff --git a/src/solvers/dgsem_tree/indicators_2d.jl b/src/solvers/dgsem_tree/indicators_2d.jl index 665d2254e5d..6ef65c4e9da 100644 --- a/src/solvers/dgsem_tree/indicators_2d.jl +++ b/src/solvers/dgsem_tree/indicators_2d.jl @@ -111,8 +111,8 @@ function apply_smoothing!(mesh::Union{TreeMesh{2}, P4estMesh{2}, T8codeMesh{2}}, right = cache.interfaces.neighbor_ids[2, interface] # Apply smoothing - alpha[left] = max(alpha_tmp[left], 0.5 * alpha_tmp[right], alpha[left]) - alpha[right] = max(alpha_tmp[right], 0.5 * alpha_tmp[left], alpha[right]) + alpha[left] = max(alpha_tmp[left], 0.5f0 * alpha_tmp[right], alpha[left]) + alpha[right] = max(alpha_tmp[right], 0.5f0 * alpha_tmp[left], alpha[right]) end # Loop over L2 mortars @@ -123,10 +123,10 @@ function apply_smoothing!(mesh::Union{TreeMesh{2}, P4estMesh{2}, T8codeMesh{2}}, large = cache.mortars.neighbor_ids[3, mortar] # Apply smoothing - alpha[lower] = max(alpha_tmp[lower], 0.5 * alpha_tmp[large], alpha[lower]) - alpha[upper] = max(alpha_tmp[upper], 0.5 * alpha_tmp[large], alpha[upper]) - alpha[large] = max(alpha_tmp[large], 0.5 * alpha_tmp[lower], alpha[large]) - alpha[large] = max(alpha_tmp[large], 0.5 * alpha_tmp[upper], alpha[large]) + alpha[lower] = max(alpha_tmp[lower], 0.5f0 * alpha_tmp[large], alpha[lower]) + alpha[upper] = max(alpha_tmp[upper], 0.5f0 * alpha_tmp[large], alpha[upper]) + alpha[large] = max(alpha_tmp[large], 0.5f0 * alpha_tmp[lower], alpha[large]) + alpha[large] = max(alpha_tmp[large], 0.5f0 * alpha_tmp[upper], alpha[large]) end return alpha diff --git a/src/solvers/dgsem_tree/indicators_3d.jl b/src/solvers/dgsem_tree/indicators_3d.jl index a11a8e06e4b..6d4ee63618a 100644 --- a/src/solvers/dgsem_tree/indicators_3d.jl +++ b/src/solvers/dgsem_tree/indicators_3d.jl @@ -116,8 +116,8 @@ function apply_smoothing!(mesh::Union{TreeMesh{3}, P4estMesh{3}, T8codeMesh{3}}, right = cache.interfaces.neighbor_ids[2, interface] # Apply smoothing - alpha[left] = max(alpha_tmp[left], 0.5 * alpha_tmp[right], alpha[left]) - alpha[right] = max(alpha_tmp[right], 0.5 * alpha_tmp[left], alpha[right]) + alpha[left] = max(alpha_tmp[left], 0.5f0 * alpha_tmp[right], alpha[left]) + alpha[right] = max(alpha_tmp[right], 0.5f0 * alpha_tmp[left], alpha[right]) end # Loop over L2 mortars @@ -130,19 +130,23 @@ function apply_smoothing!(mesh::Union{TreeMesh{3}, P4estMesh{3}, T8codeMesh{3}}, large = cache.mortars.neighbor_ids[5, mortar] # Apply smoothing - alpha[lower_left] = max(alpha_tmp[lower_left], 0.5 * alpha_tmp[large], + alpha[lower_left] = max(alpha_tmp[lower_left], 0.5f0 * alpha_tmp[large], alpha[lower_left]) - alpha[lower_right] = max(alpha_tmp[lower_right], 0.5 * alpha_tmp[large], + alpha[lower_right] = max(alpha_tmp[lower_right], 0.5f0 * alpha_tmp[large], alpha[lower_right]) - alpha[upper_left] = max(alpha_tmp[upper_left], 0.5 * alpha_tmp[large], + alpha[upper_left] = max(alpha_tmp[upper_left], 0.5f0 * alpha_tmp[large], alpha[upper_left]) - alpha[upper_right] = max(alpha_tmp[upper_right], 0.5 * alpha_tmp[large], + alpha[upper_right] = max(alpha_tmp[upper_right], 0.5f0 * alpha_tmp[large], alpha[upper_right]) - alpha[large] = max(alpha_tmp[large], 0.5 * alpha_tmp[lower_left], alpha[large]) - alpha[large] = max(alpha_tmp[large], 0.5 * alpha_tmp[lower_right], alpha[large]) - alpha[large] = max(alpha_tmp[large], 0.5 * alpha_tmp[upper_left], alpha[large]) - alpha[large] = max(alpha_tmp[large], 0.5 * alpha_tmp[upper_right], alpha[large]) + alpha[large] = max(alpha_tmp[large], 0.5f0 * alpha_tmp[lower_left], + alpha[large]) + alpha[large] = max(alpha_tmp[large], 0.5f0 * alpha_tmp[lower_right], + alpha[large]) + alpha[large] = max(alpha_tmp[large], 0.5f0 * alpha_tmp[upper_left], + alpha[large]) + alpha[large] = max(alpha_tmp[large], 0.5f0 * alpha_tmp[upper_right], + alpha[large]) end end diff --git a/src/solvers/dgsem_tree/subcell_limiters_2d.jl b/src/solvers/dgsem_tree/subcell_limiters_2d.jl index 4095f0853f9..b185cd4c540 100644 --- a/src/solvers/dgsem_tree/subcell_limiters_2d.jl +++ b/src/solvers/dgsem_tree/subcell_limiters_2d.jl @@ -588,7 +588,7 @@ end # Check bounds if (beta < beta_L) || (beta > beta_R) || (dgoal_dbeta == 0) || isnan(beta) # Out of bounds, do a bisection step - beta = 0.5 * (beta_L + beta_R) + beta = 0.5f0 * (beta_L + beta_R) # Get new u u_curr = u + beta * dt * antidiffusive_flux diff --git a/src/solvers/dgsem_unstructured/dg_2d.jl b/src/solvers/dgsem_unstructured/dg_2d.jl index ce602e178d8..645bf05f07a 100644 --- a/src/solvers/dgsem_unstructured/dg_2d.jl +++ b/src/solvers/dgsem_unstructured/dg_2d.jl @@ -20,7 +20,8 @@ function create_cache(mesh::UnstructuredMesh2D, equations, # perform a check on the sufficient metric identities condition for free-stream preservation # and halt computation if it fails - if !isapprox(max_discrete_metric_identities(dg, cache), 0, atol = 1e-12) + atol = max(100 * eps(RealT), eps(RealT)^convert(RealT, 0.75f0)) + if !isapprox(max_discrete_metric_identities(dg, cache), 0, atol = atol) error("metric terms fail free-stream preservation check with maximum error $(max_discrete_metric_identities(dg, cache))") end @@ -260,10 +261,10 @@ function calc_interface_flux!(surface_flux_values, # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs surface_flux_values[v, primary_index, primary_side, primary_element] = (flux[v] + - 0.5 * + 0.5f0 * noncons_primary[v]) surface_flux_values[v, secondary_index, secondary_side, secondary_element] = -(flux[v] + - 0.5 * + 0.5f0 * noncons_secondary[v]) end @@ -459,7 +460,7 @@ end # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs surface_flux_values[v, node_index, side_index, element_index] = flux[v] + - 0.5 * + 0.5f0 * noncons_flux[v] end end diff --git a/src/solvers/dgsem_unstructured/indicators_2d.jl b/src/solvers/dgsem_unstructured/indicators_2d.jl index 8052534ad48..e331cb5ee71 100644 --- a/src/solvers/dgsem_unstructured/indicators_2d.jl +++ b/src/solvers/dgsem_unstructured/indicators_2d.jl @@ -17,8 +17,8 @@ function apply_smoothing!(mesh::UnstructuredMesh2D, alpha, alpha_tmp, dg, cache) right = cache.interfaces.element_ids[2, interface] # Apply smoothing - alpha[left] = max(alpha_tmp[left], 0.5 * alpha_tmp[right], alpha[left]) - alpha[right] = max(alpha_tmp[right], 0.5 * alpha_tmp[left], alpha[right]) + alpha[left] = max(alpha_tmp[left], 0.5f0 * alpha_tmp[right], alpha[left]) + alpha[right] = max(alpha_tmp[right], 0.5f0 * alpha_tmp[left], alpha[right]) end end end # @muladd diff --git a/src/solvers/dgsem_unstructured/mappings_geometry_curved_2d.jl b/src/solvers/dgsem_unstructured/mappings_geometry_curved_2d.jl index 75b9a1f4da2..5949e1f97e8 100644 --- a/src/solvers/dgsem_unstructured/mappings_geometry_curved_2d.jl +++ b/src/solvers/dgsem_unstructured/mappings_geometry_curved_2d.jl @@ -11,10 +11,10 @@ function transfinite_quad_map(xi, eta, surface_curves::AbstractVector{<:CurvedSurface}) # evaluate the gamma curves to get the four corner points of the element - x_corner1, y_corner1 = evaluate_at(-1.0, surface_curves[1]) - x_corner2, y_corner2 = evaluate_at(1.0, surface_curves[1]) - x_corner3, y_corner3 = evaluate_at(1.0, surface_curves[3]) - x_corner4, y_corner4 = evaluate_at(-1.0, surface_curves[3]) + x_corner1, y_corner1 = evaluate_at(-1, surface_curves[1]) + x_corner2, y_corner2 = evaluate_at(1, surface_curves[1]) + x_corner3, y_corner3 = evaluate_at(1, surface_curves[3]) + x_corner4, y_corner4 = evaluate_at(-1, surface_curves[3]) # evaluate along the gamma curves at a particular point (ξ, η) in computational space to get # the value (x,y) in physical space @@ -23,17 +23,15 @@ function transfinite_quad_map(xi, eta, surface_curves::AbstractVector{<:CurvedSu x3, y3 = evaluate_at(xi, surface_curves[3]) x4, y4 = evaluate_at(eta, surface_curves[4]) - x = (0.5 * - ((1.0 - xi) * x4 + (1.0 + xi) * x2 + (1.0 - eta) * x1 + (1.0 + eta) * x3) + x = (0.5f0 * ((1 - xi) * x4 + (1 + xi) * x2 + (1 - eta) * x1 + (1 + eta) * x3) - - 0.25 * ((1.0 - xi) * ((1.0 - eta) * x_corner1 + (1.0 + eta) * x_corner4) + - (1.0 + xi) * ((1.0 - eta) * x_corner2 + (1.0 + eta) * x_corner3))) + 0.25f0 * ((1 - xi) * ((1 - eta) * x_corner1 + (1 + eta) * x_corner4) + + (1 + xi) * ((1 - eta) * x_corner2 + (1 + eta) * x_corner3))) - y = (0.5 * - ((1.0 - xi) * y4 + (1.0 + xi) * y2 + (1.0 - eta) * y1 + (1.0 + eta) * y3) + y = (0.5f0 * ((1 - xi) * y4 + (1 + xi) * y2 + (1 - eta) * y1 + (1 + eta) * y3) - - 0.25 * ((1.0 - xi) * ((1.0 - eta) * y_corner1 + (1.0 + eta) * y_corner4) + - (1.0 + xi) * ((1.0 - eta) * y_corner2 + (1.0 + eta) * y_corner3))) + 0.25f0 * ((1 - xi) * ((1 - eta) * y_corner1 + (1 + eta) * y_corner4) + + (1 + xi) * ((1 - eta) * y_corner2 + (1 + eta) * y_corner3))) return x, y end @@ -44,10 +42,10 @@ function transfinite_quad_map_metrics(xi, eta, surface_curves::AbstractVector{<:CurvedSurface}) # evaluate the gamma curves to get the four corner points of the element - x_corner1, y_corner1 = evaluate_at(-1.0, surface_curves[1]) - x_corner2, y_corner2 = evaluate_at(1.0, surface_curves[1]) - x_corner3, y_corner3 = evaluate_at(1.0, surface_curves[3]) - x_corner4, y_corner4 = evaluate_at(-1.0, surface_curves[3]) + x_corner1, y_corner1 = evaluate_at(-1, surface_curves[1]) + x_corner2, y_corner2 = evaluate_at(1, surface_curves[1]) + x_corner3, y_corner3 = evaluate_at(1, surface_curves[3]) + x_corner4, y_corner4 = evaluate_at(-1, surface_curves[3]) # evaluate along the gamma curves at a particular point (ξ, η) in computational space to get # the value (x,y) in physical space @@ -63,25 +61,25 @@ function transfinite_quad_map_metrics(xi, eta, x3_prime, y3_prime = derivative_at(xi, surface_curves[3]) x4_prime, y4_prime = derivative_at(eta, surface_curves[4]) - X_xi = (0.5 * (x2 - x4 + (1.0 - eta) * x1_prime + (1.0 + eta) * x3_prime) + X_xi = (0.5f0 * (x2 - x4 + (1 - eta) * x1_prime + (1 + eta) * x3_prime) - - 0.25 * ((1.0 - eta) * (x_corner2 - x_corner1) + - (1.0 + eta) * (x_corner3 - x_corner4))) + 0.25f0 * ((1 - eta) * (x_corner2 - x_corner1) + + (1 + eta) * (x_corner3 - x_corner4))) - X_eta = (0.5 * ((1.0 - xi) * x4_prime + (1.0 + xi) * x2_prime + x3 - x1) + X_eta = (0.5f0 * ((1 - xi) * x4_prime + (1 + xi) * x2_prime + x3 - x1) - - 0.25 * ((1.0 - xi) * (x_corner4 - x_corner1) + - (1.0 + xi) * (x_corner3 - x_corner2))) + 0.25f0 * ((1 - xi) * (x_corner4 - x_corner1) + + (1 + xi) * (x_corner3 - x_corner2))) - Y_xi = (0.5 * (y2 - y4 + (1.0 - eta) * y1_prime + (1.0 + eta) * y3_prime) + Y_xi = (0.5f0 * (y2 - y4 + (1 - eta) * y1_prime + (1 + eta) * y3_prime) - - 0.25 * ((1.0 - eta) * (y_corner2 - y_corner1) + - (1.0 + eta) * (y_corner3 - y_corner4))) + 0.25f0 * ((1 - eta) * (y_corner2 - y_corner1) + + (1 + eta) * (y_corner3 - y_corner4))) - Y_eta = (0.5 * ((1.0 - xi) * y4_prime + (1.0 + xi) * y2_prime + y3 - y1) + Y_eta = (0.5f0 * ((1 - xi) * y4_prime + (1 + xi) * y2_prime + y3 - y1) - - 0.25 * ((1.0 - xi) * (y_corner4 - y_corner1) + - (1.0 + xi) * (y_corner3 - y_corner2))) + 0.25f0 * ((1 - xi) * (y_corner4 - y_corner1) + + (1 + xi) * (y_corner3 - y_corner2))) return X_xi, X_eta, Y_xi, Y_eta end @@ -127,14 +125,14 @@ function calc_normal_directions!(normal_directions, element, nodes, # normal directions on the boundary for the left (local side 4) and right (local side 2) for j in eachindex(nodes) # side 2 - X_xi, X_eta, Y_xi, Y_eta = transfinite_quad_map_metrics(1.0, nodes[j], + X_xi, X_eta, Y_xi, Y_eta = transfinite_quad_map_metrics(1, nodes[j], surface_curves) Jtemp = X_xi * Y_eta - X_eta * Y_xi normal_directions[1, j, 2, element] = sign(Jtemp) * (Y_eta) normal_directions[2, j, 2, element] = sign(Jtemp) * (-X_eta) # side 4 - X_xi, X_eta, Y_xi, Y_eta = transfinite_quad_map_metrics(-1.0, nodes[j], + X_xi, X_eta, Y_xi, Y_eta = transfinite_quad_map_metrics(-1, nodes[j], surface_curves) Jtemp = X_xi * Y_eta - X_eta * Y_xi normal_directions[1, j, 4, element] = -sign(Jtemp) * (Y_eta) @@ -144,14 +142,14 @@ function calc_normal_directions!(normal_directions, element, nodes, # normal directions on the boundary for the top (local side 3) and bottom (local side 1) for i in eachindex(nodes) # side 1 - X_xi, X_eta, Y_xi, Y_eta = transfinite_quad_map_metrics(nodes[i], -1.0, + X_xi, X_eta, Y_xi, Y_eta = transfinite_quad_map_metrics(nodes[i], -1, surface_curves) Jtemp = X_xi * Y_eta - X_eta * Y_xi normal_directions[1, i, 1, element] = -sign(Jtemp) * (-Y_xi) normal_directions[2, i, 1, element] = -sign(Jtemp) * (X_xi) # side 3 - X_xi, X_eta, Y_xi, Y_eta = transfinite_quad_map_metrics(nodes[i], 1.0, + X_xi, X_eta, Y_xi, Y_eta = transfinite_quad_map_metrics(nodes[i], 1, surface_curves) Jtemp = X_xi * Y_eta - X_eta * Y_xi normal_directions[1, i, 3, element] = sign(Jtemp) * (-Y_xi) diff --git a/src/solvers/dgsem_unstructured/mappings_geometry_straight_2d.jl b/src/solvers/dgsem_unstructured/mappings_geometry_straight_2d.jl index 7ceba93188d..4f2f4e6f4b9 100644 --- a/src/solvers/dgsem_unstructured/mappings_geometry_straight_2d.jl +++ b/src/solvers/dgsem_unstructured/mappings_geometry_straight_2d.jl @@ -9,15 +9,15 @@ # in physical coordinate space for a quadrilateral element with straight sides # Alg. 95 from the blue book of Kopriva function straight_side_quad_map(xi, eta, corner_points) - x = 0.25 * (corner_points[1, 1] * (1.0 - xi) * (1.0 - eta) - + corner_points[2, 1] * (1.0 + xi) * (1.0 - eta) - + corner_points[3, 1] * (1.0 + xi) * (1.0 + eta) - + corner_points[4, 1] * (1.0 - xi) * (1.0 + eta)) + x = 0.25f0 * (corner_points[1, 1] * (1 - xi) * (1 - eta) + + corner_points[2, 1] * (1 + xi) * (1 - eta) + + corner_points[3, 1] * (1 + xi) * (1 + eta) + + corner_points[4, 1] * (1 - xi) * (1 + eta)) - y = 0.25 * (corner_points[1, 2] * (1.0 - xi) * (1.0 - eta) - + corner_points[2, 2] * (1.0 + xi) * (1.0 - eta) - + corner_points[3, 2] * (1.0 + xi) * (1.0 + eta) - + corner_points[4, 2] * (1.0 - xi) * (1.0 + eta)) + y = 0.25f0 * (corner_points[1, 2] * (1 - xi) * (1 - eta) + + corner_points[2, 2] * (1 + xi) * (1 - eta) + + corner_points[3, 2] * (1 + xi) * (1 + eta) + + corner_points[4, 2] * (1 - xi) * (1 + eta)) return x, y end @@ -25,17 +25,17 @@ end # Compute the metric terms for the straight sided quadrilateral mapping # Alg. 100 from the blue book of Kopriva function straight_side_quad_map_metrics(xi, eta, corner_points) - X_xi = 0.25 * ((1.0 - eta) * (corner_points[2, 1] - corner_points[1, 1]) + - (1.0 + eta) * (corner_points[3, 1] - corner_points[4, 1])) + X_xi = 0.25f0 * ((1 - eta) * (corner_points[2, 1] - corner_points[1, 1]) + + (1 + eta) * (corner_points[3, 1] - corner_points[4, 1])) - X_eta = 0.25 * ((1.0 - xi) * (corner_points[4, 1] - corner_points[1, 1]) + - (1.0 + xi) * (corner_points[3, 1] - corner_points[2, 1])) + X_eta = 0.25f0 * ((1 - xi) * (corner_points[4, 1] - corner_points[1, 1]) + + (1 + xi) * (corner_points[3, 1] - corner_points[2, 1])) - Y_xi = 0.25 * ((1.0 - eta) * (corner_points[2, 2] - corner_points[1, 2]) + - (1.0 + eta) * (corner_points[3, 2] - corner_points[4, 2])) + Y_xi = 0.25f0 * ((1 - eta) * (corner_points[2, 2] - corner_points[1, 2]) + + (1 + eta) * (corner_points[3, 2] - corner_points[4, 2])) - Y_eta = 0.25 * ((1.0 - xi) * (corner_points[4, 2] - corner_points[1, 2]) + - (1.0 + xi) * (corner_points[3, 2] - corner_points[2, 2])) + Y_eta = 0.25f0 * ((1 - xi) * (corner_points[4, 2] - corner_points[1, 2]) + + (1 + xi) * (corner_points[3, 2] - corner_points[2, 2])) return X_xi, X_eta, Y_xi, Y_eta end @@ -78,14 +78,14 @@ function calc_normal_directions!(normal_directions, element, nodes, corners) # normal directions on the boundary for the left (local side 4) and right (local side 2) for j in eachindex(nodes) # side 2 - X_xi, X_eta, Y_xi, Y_eta = straight_side_quad_map_metrics(1.0, nodes[j], + X_xi, X_eta, Y_xi, Y_eta = straight_side_quad_map_metrics(1, nodes[j], corners) Jtemp = X_xi * Y_eta - X_eta * Y_xi normal_directions[1, j, 2, element] = sign(Jtemp) * (Y_eta) normal_directions[2, j, 2, element] = sign(Jtemp) * (-X_eta) # side 4 - X_xi, X_eta, Y_xi, Y_eta = straight_side_quad_map_metrics(-1.0, nodes[j], + X_xi, X_eta, Y_xi, Y_eta = straight_side_quad_map_metrics(-1, nodes[j], corners) Jtemp = X_xi * Y_eta - X_eta * Y_xi normal_directions[1, j, 4, element] = -sign(Jtemp) * (Y_eta) @@ -95,14 +95,14 @@ function calc_normal_directions!(normal_directions, element, nodes, corners) # normal directions on the boundary for the top (local side 3) and bottom (local side 1) for i in eachindex(nodes) # side 1 - X_xi, X_eta, Y_xi, Y_eta = straight_side_quad_map_metrics(nodes[i], -1.0, + X_xi, X_eta, Y_xi, Y_eta = straight_side_quad_map_metrics(nodes[i], -1, corners) Jtemp = X_xi * Y_eta - X_eta * Y_xi normal_directions[1, i, 1, element] = -sign(Jtemp) * (-Y_xi) normal_directions[2, i, 1, element] = -sign(Jtemp) * (X_xi) # side 3 - X_xi, X_eta, Y_xi, Y_eta = straight_side_quad_map_metrics(nodes[i], 1.0, + X_xi, X_eta, Y_xi, Y_eta = straight_side_quad_map_metrics(nodes[i], 1, corners) Jtemp = X_xi * Y_eta - X_eta * Y_xi normal_directions[1, i, 3, element] = sign(Jtemp) * (-Y_xi) diff --git a/src/visualization/utilities.jl b/src/visualization/utilities.jl index c1108128c92..1f843c6a9d2 100644 --- a/src/visualization/utilities.jl +++ b/src/visualization/utilities.jl @@ -14,7 +14,7 @@ # using the [Shoelace_formula](https://en.wikipedia.org/wiki/Shoelace_formula). function compute_triangle_area(tri) A, B, C = tri - return 0.5 * (A[1] * (B[2] - C[2]) + B[1] * (C[2] - A[2]) + C[1] * (A[2] - B[2])) + return 0.5f0 * (A[1] * (B[2] - C[2]) + B[1] * (C[2] - A[2]) + C[1] * (A[2] - B[2])) end # reference_plotting_triangulation(reference_plotting_coordinates) diff --git a/test/test_p4est_3d.jl b/test/test_p4est_3d.jl index 7b69d1c0cf2..3432bd69b23 100644 --- a/test/test_p4est_3d.jl +++ b/test/test_p4est_3d.jl @@ -257,6 +257,35 @@ end end end +@trixi_testset "elixir_euler_free_stream_boundaries_float32.jl" begin + # Expected errors are taken from elixir_euler_free_stream_boundaries.jl + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_free_stream_boundaries_float32.jl"), + l2=[ + Float32(6.530157034651212e-16), + Float32(1.6057829680004379e-15), + Float32(3.31107455378537e-15), + Float32(3.908829498281281e-15), + Float32(5.048390610424672e-15), + ], + linf=[ + Float32(4.884981308350689e-15), + Float32(1.1921019726912618e-14), + Float32(1.5432100042289676e-14), + Float32(2.298161660974074e-14), + Float32(6.039613253960852e-14), + ], + RealT=Float32) + # Ensure that we do not have excessive memory allocations + # (e.g., from type instabilities) + let + t = sol.t[end] + u_ode = sol.u[end] + du_ode = similar(u_ode) + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 + end +end + @trixi_testset "elixir_euler_free_stream_extruded.jl with HLLC FLux" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_free_stream_extruded.jl"), l2=[ diff --git a/test/test_structured_2d.jl b/test/test_structured_2d.jl index c22a8e038a7..82c76cc5d27 100644 --- a/test/test_structured_2d.jl +++ b/test/test_structured_2d.jl @@ -29,6 +29,23 @@ isdir(outdir) && rm(outdir, recursive = true) end end +@trixi_testset "elixir_advection_float32.jl" begin + # Expected errors are taken from elixir_advection_basic.jl + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_float32.jl"), + # Expected errors are taken from elixir_advection_basic.jl + l2=[Float32(8.311947673061856e-6)], + linf=[Float32(6.627000273229378e-5)], + RealT=Float32) + # Ensure that we do not have excessive memory allocations + # (e.g., from type instabilities) + let + t = sol.t[end] + u_ode = sol.u[end] + du_ode = similar(u_ode) + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 + end +end + @trixi_testset "elixir_advection_coupled.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_coupled.jl"), l2=[ diff --git a/test/test_trixi.jl b/test/test_trixi.jl index 9bfd73ea28d..be3521ed16a 100644 --- a/test/test_trixi.jl +++ b/test/test_trixi.jl @@ -4,8 +4,8 @@ import Trixi # Use a macro to avoid world age issues when defining new initial conditions etc. # inside an elixir. """ - @test_trixi_include(elixir; l2=nothing, linf=nothing, - atol=500*eps(), rtol=sqrt(eps()), + @test_trixi_include(elixir; l2=nothing, linf=nothing, RealT=Float64, + atol=500*eps(RealT), rtol=sqrt(eps(RealT)), parameters...) Test Trixi by calling `trixi_include(elixir; parameters...)`. @@ -17,8 +17,16 @@ as absolute/relative tolerance. macro test_trixi_include(elixir, args...) local l2 = get_kwarg(args, :l2, nothing) local linf = get_kwarg(args, :linf, nothing) - local atol = get_kwarg(args, :atol, 500 * eps()) - local rtol = get_kwarg(args, :rtol, sqrt(eps())) + local RealT = get_kwarg(args, :RealT, :Float64) + if RealT === :Float64 + atol_default = 500 * eps(Float64) + rtol_default = sqrt(eps(Float64)) + elseif RealT === :Float32 + atol_default = 500 * eps(Float32) + rtol_default = sqrt(eps(Float32)) + end + local atol = get_kwarg(args, :atol, atol_default) + local rtol = get_kwarg(args, :rtol, rtol_default) local skip_coverage = get_kwarg(args, :skip_coverage, false) local coverage_override = expr_to_named_tuple(get_kwarg(args, :coverage_override, :())) if !(:maxiters in keys(coverage_override)) @@ -33,7 +41,8 @@ macro test_trixi_include(elixir, args...) local kwargs = Pair{Symbol, Any}[] for arg in args if (arg.head == :(=) && - !(arg.args[1] in (:l2, :linf, :atol, :rtol, :coverage_override, :skip_coverage)) + !(arg.args[1] in (:l2, :linf, :RealT, :atol, :rtol, :coverage_override, + :skip_coverage)) && !(coverage && arg.args[1] in keys(coverage_override))) push!(kwargs, Pair(arg.args...)) end diff --git a/test/test_unstructured_2d.jl b/test/test_unstructured_2d.jl index 563f99792d0..43b911cc665 100644 --- a/test/test_unstructured_2d.jl +++ b/test/test_unstructured_2d.jl @@ -323,6 +323,33 @@ end end end +@trixi_testset "elixir_shallowwater_ec_float32.jl" begin + # Expected errors are nearly all taken from elixir_shallowwater_ec.jl + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_ec_float32.jl"), + l2=[ + Float32(0.6107326269462766), + Float32(0.48666631722018877), + Float32(0.48309775159067053), + Float32(0.29467422718511704), + ], + linf=[ + Float32(2.776782342826098), + 3.2162943f0, # this needs to be adapted + 3.6683278f0, # this needed to be adapted + Float32(2.052861364219655), + ], + tspan=(0.0f0, 0.25f0), + RealT=Float32) + # Ensure that we do not have excessive memory allocations + # (e.g., from type instabilities) + let + t = sol.t[end] + u_ode = sol.u[end] + du_ode = similar(u_ode) + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 + end +end + @trixi_testset "elixir_shallowwater_well_balanced.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced.jl"), l2=[ @@ -713,6 +740,23 @@ end @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 end end + +@trixi_testset "FDSBP (upwind): elixir_euler_free_stream_upwind_float32.jl" begin + @test_trixi_include(joinpath(pkgdir(Trixi, "examples", "unstructured_2d_fdsbp"), + "elixir_euler_free_stream_upwind_float32.jl"), + l2=[0, 0, 0, 0], + linf=[0, 0, 0, 0], + tspan=(0.0f0, 0.05f0), + atol=9.0f-4) + # Ensure that we do not have excessive memory allocations + # (e.g., from type instabilities) + let + t = sol.t[end] + u_ode = sol.u[end] + du_ode = similar(u_ode) + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 + end +end end # Clean up afterwards: delete Trixi.jl output directory From 8d7b20aae40fc19428b07f616aee2e755ba6beb8 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Thu, 22 Aug 2024 14:12:30 +0200 Subject: [PATCH 23/25] adapt auxiliary math functions for `Float32` (#2048) * adapt auxiliary math functions * adapt tests * more tests and fix shock capturing volume integral * fix typo in tests * p4est_2d_dgsem/elixir_euler_shockcapturing_ec_float32.jl * format * fix stolarsky_mean test * use Float32 for test tolerances * format * increase tolerance for CI * format --- .../elixir_euler_shockcapturing_ec_float32.jl | 66 ++++ src/auxiliary/math.jl | 53 ++- src/solvers/dgmulti/shock_capturing.jl | 6 +- src/solvers/dgsem_p4est/dg_2d.jl | 2 +- src/solvers/dgsem_tree/dg.jl | 6 +- src/solvers/dgsem_unstructured/dg_2d.jl | 2 + test/test_p4est_2d.jl | 28 ++ test/test_type.jl | 349 +++++------------- 8 files changed, 224 insertions(+), 288 deletions(-) create mode 100644 examples/p4est_2d_dgsem/elixir_euler_shockcapturing_ec_float32.jl diff --git a/examples/p4est_2d_dgsem/elixir_euler_shockcapturing_ec_float32.jl b/examples/p4est_2d_dgsem/elixir_euler_shockcapturing_ec_float32.jl new file mode 100644 index 00000000000..4f390f4fc2c --- /dev/null +++ b/examples/p4est_2d_dgsem/elixir_euler_shockcapturing_ec_float32.jl @@ -0,0 +1,66 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations2D(1.4f0) + +initial_condition = initial_condition_weak_blast_wave + +surface_flux = flux_ranocha +volume_flux = flux_ranocha +polydeg = 4 +basis = LobattoLegendreBasis(Float32, polydeg) +indicator_sc = IndicatorHennemannGassner(equations, basis, + alpha_max = 1.0f0, + alpha_min = 0.001f0, + alpha_smooth = true, + variable = density_pressure) +volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) + +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral, RealT = Float32) + +############################################################################### + +coordinates_min = (-1.0f0, -1.0f0) +coordinates_max = (+1.0f0, +1.0f0) + +trees_per_dimension = (4, 4) +mesh = P4estMesh(trees_per_dimension, + polydeg = 4, initial_refinement_level = 2, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + periodicity = true, RealT = Float32) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0f0, 2.0f0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +stepsize_callback = StepsizeCallback(cfl = 1.0f0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + stepsize_callback) +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0f0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); +summary_callback() # print the timer summary diff --git a/src/auxiliary/math.jl b/src/auxiliary/math.jl index 171c631a843..fa816da9a1e 100644 --- a/src/auxiliary/math.jl +++ b/src/auxiliary/math.jl @@ -124,7 +124,7 @@ end end """ - ln_mean(x, y) + Trixi.ln_mean(x::Real, y::Real) Compute the logarithmic mean @@ -171,18 +171,24 @@ Given ε = 1.0e-4, we use the following algorithm. for Intel, AMD, and VIA CPUs. [https://www.agner.org/optimize/instruction_tables.pdf](https://www.agner.org/optimize/instruction_tables.pdf) """ -@inline function ln_mean(x, y) - epsilon_f2 = 1.0e-4 +@inline ln_mean(x::Real, y::Real) = ln_mean(promote(x, y)...) + +@inline function ln_mean(x::RealT, y::RealT) where {RealT <: Real} + epsilon_f2 = convert(RealT, 1.0e-4) f2 = (x * (x - 2 * y) + y * y) / (x * (x + 2 * y) + y * y) # f2 = f^2 if f2 < epsilon_f2 - return (x + y) / @evalpoly(f2, 2, 2/3, 2/5, 2/7) + return (x + y) / @evalpoly(f2, + 2, + convert(RealT, 2 / 3), + convert(RealT, 2 / 5), + convert(RealT, 2 / 7)) else return (y - x) / log(y / x) end end """ - inv_ln_mean(x, y) + Trixi.inv_ln_mean(x::Real, y::Real) Compute the inverse `1 / ln_mean(x, y)` of the logarithmic mean [`ln_mean`](@ref). @@ -191,11 +197,17 @@ This function may be used to increase performance where the inverse of the logarithmic mean is needed, by replacing a (slow) division by a (fast) multiplication. """ -@inline function inv_ln_mean(x, y) - epsilon_f2 = 1.0e-4 +@inline inv_ln_mean(x::Real, y::Real) = inv_ln_mean(promote(x, y)...) + +@inline function inv_ln_mean(x::RealT, y::RealT) where {RealT <: Real} + epsilon_f2 = convert(RealT, 1.0e-4) f2 = (x * (x - 2 * y) + y * y) / (x * (x + 2 * y) + y * y) # f2 = f^2 if f2 < epsilon_f2 - return @evalpoly(f2, 2, 2/3, 2/5, 2/7) / (x + y) + return @evalpoly(f2, + 2, + convert(RealT, 2 / 3), + convert(RealT, 2 / 5), + convert(RealT, 2 / 7)) / (x + y) else return log(y / x) / (y - x) end @@ -273,7 +285,7 @@ end # [Fortran](https://godbolt.org/z/Yrsa1js7P) # or [C++](https://godbolt.org/z/674G7Pccv). """ - max(x, y, ...) + Trixi.max(x, y, ...) Return the maximum of the arguments. See also the `maximum` function to take the maximum element from a collection. @@ -292,7 +304,7 @@ julia> max(2, 5, 1) @inline max(args...) = @fastmath max(args...) """ - min(x, y, ...) + Trixi.min(x, y, ...) Return the minimum of the arguments. See also the `minimum` function to take the minimum element from a collection. @@ -311,7 +323,7 @@ julia> min(2, 5, 1) @inline min(args...) = @fastmath min(args...) """ - positive_part(x) + Trixi.positive_part(x) Return `x` if `x` is positive, else zero. In other words, return `(x + abs(x)) / 2` for real numbers `x`. @@ -321,7 +333,7 @@ Return `x` if `x` is positive, else zero. In other words, return end """ - negative_part(x) + Trixi.negative_part(x) Return `x` if `x` is negative, else zero. In other words, return `(x - abs(x)) / 2` for real numbers `x`. @@ -331,7 +343,7 @@ Return `x` if `x` is negative, else zero. In other words, return end """ - stolarsky_mean(x, y, gamma) + Trixi.stolarsky_mean(x::Real, y:Real, gamma::Real) Compute an instance of a weighted Stolarsky mean of the form @@ -382,15 +394,18 @@ Given ε = 1.0e-4, we use the following algorithm. for Intel, AMD, and VIA CPUs. [https://www.agner.org/optimize/instruction_tables.pdf](https://www.agner.org/optimize/instruction_tables.pdf) """ -@inline function stolarsky_mean(x, y, gamma) - epsilon_f2 = 1.0e-4 +@inline stolarsky_mean(x::Real, y::Real, gamma::Real) = stolarsky_mean(promote(x, y, + gamma)...) + +@inline function stolarsky_mean(x::RealT, y::RealT, gamma::RealT) where {RealT <: Real} + epsilon_f2 = convert(RealT, 1.0e-4) f2 = (x * (x - 2 * y) + y * y) / (x * (x + 2 * y) + y * y) # f2 = f^2 if f2 < epsilon_f2 # convenience coefficients - c1 = (1 / 3) * (gamma - 2) - c2 = -(1 / 15) * (gamma + 1) * (gamma - 3) * c1 - c3 = -(1 / 21) * (2 * gamma * (gamma - 2) - 9) * c2 - return 0.5 * (x + y) * @evalpoly(f2, 1, c1, c2, c3) + c1 = convert(RealT, 1 / 3) * (gamma - 2) + c2 = convert(RealT, -1 / 15) * (gamma + 1) * (gamma - 3) * c1 + c3 = convert(RealT, -1 / 21) * (2 * gamma * (gamma - 2) - 9) * c2 + return 0.5f0 * (x + y) * @evalpoly(f2, 1, c1, c2, c3) else return (gamma - 1) / gamma * (y^gamma - x^gamma) / (y^(gamma - 1) - x^(gamma - 1)) diff --git a/src/solvers/dgmulti/shock_capturing.jl b/src/solvers/dgmulti/shock_capturing.jl index d224e5ed03d..99261b82edf 100644 --- a/src/solvers/dgmulti/shock_capturing.jl +++ b/src/solvers/dgmulti/shock_capturing.jl @@ -160,10 +160,14 @@ function pure_and_blended_element_ids!(element_ids_dg, element_ids_dgfv, alpha, mesh::DGMultiMesh, dg::DGMulti) empty!(element_ids_dg) empty!(element_ids_dgfv) + # For `Float64`, this gives 1.8189894035458565e-12 + # For `Float32`, this gives 1.1920929f-5 + RealT = eltype(alpha) + atol = max(100 * eps(RealT), eps(RealT)^convert(RealT, 0.75f0)) for element in eachelement(mesh, dg) # Clip blending factor for values close to zero (-> pure DG) - dg_only = isapprox(alpha[element], 0, atol = 1e-12) + dg_only = isapprox(alpha[element], 0, atol = atol) if dg_only push!(element_ids_dg, element) else diff --git a/src/solvers/dgsem_p4est/dg_2d.jl b/src/solvers/dgsem_p4est/dg_2d.jl index 29e94f43704..17b9af04467 100644 --- a/src/solvers/dgsem_p4est/dg_2d.jl +++ b/src/solvers/dgsem_p4est/dg_2d.jl @@ -379,7 +379,7 @@ end # the interpretation of global SBP operators coupled discontinuously via # central fluxes/SATs surface_flux_values[v, node_index, direction_index, element_index] = flux_[v] + - 0.5 * + 0.5f0 * noncons_[v] end end diff --git a/src/solvers/dgsem_tree/dg.jl b/src/solvers/dgsem_tree/dg.jl index 0993b3c9b85..febfb0b121f 100644 --- a/src/solvers/dgsem_tree/dg.jl +++ b/src/solvers/dgsem_tree/dg.jl @@ -24,10 +24,14 @@ function pure_and_blended_element_ids!(element_ids_dg, element_ids_dgfv, alpha, cache) empty!(element_ids_dg) empty!(element_ids_dgfv) + # For `Float64`, this gives 1.8189894035458565e-12 + # For `Float32`, this gives 1.1920929f-5 + RealT = eltype(alpha) + atol = max(100 * eps(RealT), eps(RealT)^convert(RealT, 0.75f0)) for element in eachelement(dg, cache) # Clip blending factor for values close to zero (-> pure DG) - dg_only = isapprox(alpha[element], 0, atol = 1e-12) + dg_only = isapprox(alpha[element], 0, atol = atol) if dg_only push!(element_ids_dg, element) else diff --git a/src/solvers/dgsem_unstructured/dg_2d.jl b/src/solvers/dgsem_unstructured/dg_2d.jl index 645bf05f07a..a531ded91cc 100644 --- a/src/solvers/dgsem_unstructured/dg_2d.jl +++ b/src/solvers/dgsem_unstructured/dg_2d.jl @@ -20,6 +20,8 @@ function create_cache(mesh::UnstructuredMesh2D, equations, # perform a check on the sufficient metric identities condition for free-stream preservation # and halt computation if it fails + # For `Float64`, this gives 1.8189894035458565e-12 + # For `Float32`, this gives 1.1920929f-5 atol = max(100 * eps(RealT), eps(RealT)^convert(RealT, 0.75f0)) if !isapprox(max_discrete_metric_identities(dg, cache), 0, atol = atol) error("metric terms fail free-stream preservation check with maximum error $(max_discrete_metric_identities(dg, cache))") diff --git a/test/test_p4est_2d.jl b/test/test_p4est_2d.jl index f56dc9cd769..95c69b86954 100644 --- a/test/test_p4est_2d.jl +++ b/test/test_p4est_2d.jl @@ -221,6 +221,34 @@ end end end +@trixi_testset "elixir_euler_shockcapturing_ec_float32.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_shockcapturing_ec_float32.jl"), + l2=[ + 0.09539953f0, + 0.10563527f0, + 0.105637245f0, + 0.3507514f0, + ], + linf=[ + 0.2942562f0, + 0.4079147f0, + 0.3972956f0, + 1.0810697f0, + ], + tspan=(0.0f0, 1.0f0), + rtol=10 * sqrt(eps(Float32)), # to make CI pass + RealT=Float32) + # Ensure that we do not have excessive memory allocations + # (e.g., from type instabilities) + let + t = sol.t[end] + u_ode = sol.u[end] + du_ode = similar(u_ode) + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 + end +end + @trixi_testset "elixir_euler_sedov.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov.jl"), l2=[ diff --git a/test/test_type.jl b/test/test_type.jl index d13b626b060..bd553ee89c4 100644 --- a/test/test_type.jl +++ b/test/test_type.jl @@ -11,6 +11,20 @@ isdir(outdir) && rm(outdir, recursive = true) # Run unit tests for various equations @testset "Test Type Stability" begin + @timed_testset "mean values" begin + for RealT1 in (Float32, Float64), RealT2 in (Float32, Float64) + RealT = promote_type(RealT1, RealT2) + @test typeof(@inferred Trixi.ln_mean(RealT1(1), RealT2(2))) == RealT + @test typeof(@inferred Trixi.inv_ln_mean(RealT1(1), RealT2(2))) == RealT + for RealT3 in (Float32, Float64) + RealT = promote_type(RealT1, RealT2, RealT3) + @test typeof(@inferred Trixi.stolarsky_mean(RealT1(1), RealT2(2), + RealT3(3))) == + RealT + end + end + end + @timed_testset "Acoustic Perturbation 2D" begin for RealT in (Float32, Float64) v_mean_global = (zero(RealT), zero(RealT)) @@ -121,25 +135,11 @@ isdir(outdir) && rm(outdir, recursive = true) @test eltype(@inferred flux_kennedy_gruber(u_ll, u_rr, orientation, equations)) == RealT @test eltype(@inferred flux_hllc(u_ll, u_rr, orientation, equations)) == RealT - if RealT == Float32 - # check `ln_mean` (test broken) - @test_broken eltype(@inferred flux_chandrashekar(u_ll, u_rr, orientation, - equations)) == - RealT - else - @test eltype(@inferred flux_chandrashekar(u_ll, u_rr, orientation, - equations)) == - RealT - end - if RealT == Float32 - # check `ln_mean` and `inv_ln_mean` (test broken) - @test_broken eltype(@inferred flux_ranocha(u_ll, u_rr, orientation, - equations)) == - RealT - else - @test eltype(@inferred flux_ranocha(u_ll, u_rr, orientation, equations)) == - RealT - end + @test eltype(@inferred flux_chandrashekar(u_ll, u_rr, orientation, + equations)) == + RealT + @test eltype(@inferred flux_ranocha(u_ll, u_rr, orientation, equations)) == + RealT @test eltype(eltype(@inferred splitting_steger_warming(u, orientation, equations))) == @@ -228,26 +228,11 @@ isdir(outdir) && rm(outdir, recursive = true) RealT @test eltype(@inferred flux_hllc(u_ll, u_rr, normal_direction, equations)) == RealT - if RealT == Float32 - # check `ln_mean` (test broken) - @test_broken eltype(@inferred flux_chandrashekar(u_ll, u_rr, - normal_direction, - equations)) == - RealT - else - @test eltype(@inferred flux_chandrashekar(u_ll, u_rr, normal_direction, - equations)) == - RealT - end - if RealT == Float32 - # check `ln_mean` and `inv_ln_mean` (test broken) - @test_broken eltype(@inferred flux_ranocha(u_ll, u_rr, normal_direction, - equations)) == - RealT - else - @test eltype(@inferred flux_ranocha(u_ll, u_rr, normal_direction, - equations)) == RealT - end + @test eltype(@inferred flux_chandrashekar(u_ll, u_rr, normal_direction, + equations)) == + RealT + @test eltype(@inferred flux_ranocha(u_ll, u_rr, normal_direction, + equations)) == RealT @test eltype(eltype(@inferred splitting_drikakis_tsangaris(u, normal_direction, equations))) == RealT @@ -282,26 +267,11 @@ isdir(outdir) && rm(outdir, recursive = true) RealT @test eltype(@inferred flux_hllc(u_ll, u_rr, orientation, equations)) == RealT - if RealT == Float32 - # check `ln_mean` (test broken) - @test_broken eltype(@inferred flux_chandrashekar(u_ll, u_rr, - orientation, - equations)) == - RealT - else - @test eltype(@inferred flux_chandrashekar(u_ll, u_rr, orientation, - equations)) == - RealT - end - if RealT == Float32 - # check `ln_mean` and `inv_ln_mean` (test broken) - @test_broken eltype(@inferred flux_ranocha(u_ll, u_rr, orientation, - equations)) == - RealT - else - @test eltype(@inferred flux_ranocha(u_ll, u_rr, orientation, equations)) == - RealT - end + @test eltype(@inferred flux_chandrashekar(u_ll, u_rr, orientation, + equations)) == + RealT + @test eltype(@inferred flux_ranocha(u_ll, u_rr, orientation, equations)) == + RealT @test eltype(eltype(@inferred splitting_steger_warming(u, orientation, equations))) == @@ -351,7 +321,7 @@ isdir(outdir) && rm(outdir, recursive = true) @timed_testset "Compressible Euler 3D" begin for RealT in (Float32, Float64) - # set gamma = 2 for the coupling convergence test + # set gamma = 2 for the coupling convergence test equations = @inferred CompressibleEulerEquations3D(RealT(2)) x = SVector(zero(RealT), zero(RealT), zero(RealT)) @@ -400,24 +370,10 @@ isdir(outdir) && rm(outdir, recursive = true) RealT @test eltype(@inferred flux_hllc(u_ll, u_rr, normal_direction, equations)) == RealT - if RealT == Float32 - # check `ln_mean` (test broken) - @test_broken eltype(@inferred flux_chandrashekar(u_ll, u_rr, - normal_direction, - equations)) == RealT - else - @test eltype(@inferred flux_chandrashekar(u_ll, u_rr, normal_direction, - equations)) == RealT - end - if RealT == Float32 - # check `ln_mean` and `inv_ln_mean` (test broken) - @test_broken eltype(@inferred flux_ranocha(u_ll, u_rr, normal_direction, - equations)) == - RealT - else - @test eltype(@inferred flux_ranocha(u_ll, u_rr, normal_direction, - equations)) == RealT - end + @test eltype(@inferred flux_chandrashekar(u_ll, u_rr, normal_direction, + equations)) == RealT + @test eltype(@inferred flux_ranocha(u_ll, u_rr, normal_direction, + equations)) == RealT @test typeof(@inferred max_abs_speed_naive(u_ll, u_rr, normal_direction, equations)) == @@ -440,24 +396,10 @@ isdir(outdir) && rm(outdir, recursive = true) RealT @test eltype(@inferred flux_hllc(u_ll, u_rr, orientation, equations)) == RealT - if RealT == Float32 - # check `ln_mean` (test broken) - @test_broken eltype(@inferred flux_chandrashekar(u_ll, u_rr, - orientation, - equations)) == RealT - else - @test eltype(@inferred flux_chandrashekar(u_ll, u_rr, orientation, - equations)) == RealT - end - if RealT == Float32 - # check `ln_mean` and `inv_ln_mean` (test broken) - @test_broken eltype(@inferred flux_ranocha(u_ll, u_rr, orientation, - equations)) == - RealT - else - @test eltype(@inferred flux_ranocha(u_ll, u_rr, orientation, equations)) == - RealT - end + @test eltype(@inferred flux_chandrashekar(u_ll, u_rr, orientation, + equations)) == RealT + @test eltype(@inferred flux_ranocha(u_ll, u_rr, orientation, equations)) == + RealT @test eltype(eltype(@inferred splitting_steger_warming(u, orientation, equations))) == @@ -509,23 +451,10 @@ isdir(outdir) && rm(outdir, recursive = true) RealT @test eltype(@inferred flux(u, orientation, equations)) == RealT - if RealT == Float32 - # check `ln_mean` (test broken) - @test_broken eltype(@inferred flux_chandrashekar(u_ll, u_rr, orientation, - equations)) == RealT - else - @test eltype(@inferred flux_chandrashekar(u_ll, u_rr, orientation, - equations)) == RealT - end - if RealT == Float32 - # check `ln_mean` and `inv_ln_mean` (test broken) - @test_broken eltype(@inferred flux_ranocha(u_ll, u_rr, orientation, - equations)) == - RealT - else - @test eltype(@inferred flux_ranocha(u_ll, u_rr, orientation, equations)) == - RealT - end + @test eltype(@inferred flux_chandrashekar(u_ll, u_rr, orientation, + equations)) == RealT + @test eltype(@inferred flux_ranocha(u_ll, u_rr, orientation, equations)) == + RealT @test typeof(@inferred max_abs_speed_naive(u_ll, u_rr, orientation, equations)) == RealT @@ -565,34 +494,15 @@ isdir(outdir) && rm(outdir, recursive = true) RealT @test eltype(@inferred flux(u, normal_direction, equations)) == RealT - if RealT == Float32 - # check `ln_mean` and `inv_ln_mean` (test broken) - @test_broken eltype(@inferred flux_ranocha(u_ll, u_rr, normal_direction, - equations)) == RealT - else - @test eltype(@inferred flux_ranocha(u_ll, u_rr, normal_direction, - equations)) == RealT - end + @test eltype(@inferred flux_ranocha(u_ll, u_rr, normal_direction, + equations)) == RealT for orientation in orientations @test eltype(@inferred flux(u, orientation, equations)) == RealT - if RealT == Float32 - # check `ln_mean` (test broken) - @test_broken eltype(@inferred flux_chandrashekar(u_ll, u_rr, - orientation, - equations)) == RealT - else - @test eltype(@inferred flux_chandrashekar(u_ll, u_rr, orientation, - equations)) == RealT - end - if RealT == Float32 - # check `ln_mean` and `inv_ln_mean` (test broken) - @test_broken eltype(@inferred flux_ranocha(u_ll, u_rr, orientation, - equations)) == RealT - else - @test eltype(@inferred flux_ranocha(u_ll, u_rr, orientation, equations)) == - RealT - end + @test eltype(@inferred flux_chandrashekar(u_ll, u_rr, orientation, + equations)) == RealT + @test eltype(@inferred flux_ranocha(u_ll, u_rr, orientation, equations)) == + RealT @test typeof(@inferred max_abs_speed_naive(u_ll, u_rr, orientation, equations)) == @@ -637,15 +547,8 @@ isdir(outdir) && rm(outdir, recursive = true) @test eltype(@inferred flux_nonconservative_chan_etal(u_ll, u_rr, normal_ll, normal_rr, equations)) == RealT - if RealT == Float32 - # check `ln_mean` and `inv_ln_mean` (test broken) - @test_broken eltype(@inferred flux_chan_etal(u_ll, u_rr, orientation, - equations)) == - RealT - else - @test eltype(@inferred flux_chan_etal(u_ll, u_rr, orientation, equations)) == - RealT - end + @test eltype(@inferred flux_chan_etal(u_ll, u_rr, orientation, equations)) == + RealT @test typeof(@inferred max_abs_speed_naive(u_ll, u_rr, orientation, equations)) == RealT @@ -989,21 +892,11 @@ isdir(outdir) && rm(outdir, recursive = true) @test eltype(@inferred flux(u, orientation, equations)) == RealT @test eltype(@inferred flux_hllc(u_ll, u_rr, orientation, equations)) == RealT - if RealT == Float32 - # check `ln_mean` (test broken) - @test_broken eltype(@inferred flux_derigs_etal(u_ll, u_rr, orientation, - equations)) == RealT - # check `ln_mean` and `inv_ln_mean` (test broken) - @test_broken eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, - orientation, - equations)) == RealT - else - @test eltype(@inferred flux_derigs_etal(u_ll, u_rr, orientation, equations)) == - RealT - @test eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, - orientation, - equations)) == RealT - end + @test eltype(@inferred flux_derigs_etal(u_ll, u_rr, orientation, equations)) == + RealT + @test eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, + orientation, + equations)) == RealT @test typeof(@inferred max_abs_speed_naive(u_ll, u_rr, orientation, equations)) == RealT @@ -1073,15 +966,8 @@ isdir(outdir) && rm(outdir, recursive = true) normal_direction_ll, normal_direction_average, equations)) == RealT - if RealT == Float32 - # check `ln_mean` and `inv_ln_mean` (test broken) - @test_broken eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, - normal_direction, - equations)) == RealT - else - @test eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, normal_direction, - equations)) == RealT - end + @test eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, normal_direction, + equations)) == RealT @test typeof(@inferred max_abs_speed_naive(u_ll, u_rr, normal_direction, equations)) == RealT @@ -1101,22 +987,10 @@ isdir(outdir) && rm(outdir, recursive = true) orientation, equations)) == RealT - if RealT == Float32 - # check `ln_mean` (test broken) - @test_broken eltype(@inferred flux_derigs_etal(u_ll, u_rr, orientation, - equations)) == - RealT - # check `ln_mean` and `inv_ln_mean` (test broken) - @test_broken eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, - orientation, - equations)) == - RealT - else - @test eltype(@inferred flux_derigs_etal(u_ll, u_rr, orientation, - equations)) == RealT - @test eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, orientation, - equations)) == RealT - end + @test eltype(@inferred flux_derigs_etal(u_ll, u_rr, orientation, + equations)) == RealT + @test eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, orientation, + equations)) == RealT for nonconservative_term in nonconservative_terms @test eltype(@inferred flux_nonconservative_powell_local_symmetric(u_ll, orientation, @@ -1210,15 +1084,8 @@ isdir(outdir) && rm(outdir, recursive = true) normal_direction_ll, normal_direction_average, equations)) == RealT - if RealT == Float32 - # check `ln_mean` and `inv_ln_mean` (test broken) - @test_broken eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, - normal_direction, - equations)) == RealT - else - @test eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, normal_direction, - equations)) == RealT - end + @test eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, normal_direction, + equations)) == RealT @test typeof(@inferred max_abs_speed_naive(u_ll, u_rr, normal_direction, equations)) == RealT @@ -1233,22 +1100,10 @@ isdir(outdir) && rm(outdir, recursive = true) @test eltype(@inferred flux(u, orientation, equations)) == RealT @test eltype(@inferred flux_nonconservative_powell(u_ll, u_rr, orientation, equations)) == RealT - if RealT == Float32 - # check `ln_mean` (test broken) - @test_broken eltype(@inferred flux_derigs_etal(u_ll, u_rr, orientation, - equations)) == - RealT - # check `ln_mean` and `inv_ln_mean` (test broken) - @test_broken eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, - orientation, - equations)) == - RealT - else - @test eltype(@inferred flux_derigs_etal(u_ll, u_rr, orientation, - equations)) == RealT - @test eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, orientation, - equations)) == RealT - end + @test eltype(@inferred flux_derigs_etal(u_ll, u_rr, orientation, + equations)) == RealT + @test eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, orientation, + equations)) == RealT @test typeof(@inferred max_abs_speed_naive(u_ll, u_rr, orientation, equations)) == RealT @@ -1318,21 +1173,10 @@ isdir(outdir) && rm(outdir, recursive = true) RealT @test eltype(@inferred flux(u, orientation, equations)) == RealT - if RealT == Float32 - # check `ln_mean` (test broken) - @test_broken eltype(@inferred flux_derigs_etal(u_ll, u_rr, orientation, - equations)) == - RealT - # check `ln_mean` and `inv_ln_mean` (test broken) - @test_broken eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, - orientation, - equations)) == RealT - else - @test eltype(@inferred flux_derigs_etal(u_ll, u_rr, orientation, equations)) == - RealT - @test eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, orientation, - equations)) == RealT - end + @test eltype(@inferred flux_derigs_etal(u_ll, u_rr, orientation, equations)) == + RealT + @test eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, orientation, + equations)) == RealT @test typeof(@inferred max_abs_speed_naive(u_ll, u_rr, orientation, equations)) == RealT @@ -1381,22 +1225,11 @@ isdir(outdir) && rm(outdir, recursive = true) @test eltype(@inferred flux_nonconservative_powell(u_ll, u_rr, orientation, equations)) == RealT - if RealT == Float32 - # check `ln_mean` (test broken) - @test_broken eltype(@inferred flux_derigs_etal(u_ll, u_rr, orientation, - equations)) == RealT - # check `ln_mean` and `inv_ln_mean` (test broken) - @test_broken eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, - orientation, - equations)) == - RealT - else - @test eltype(@inferred flux_derigs_etal(u_ll, u_rr, orientation, - equations)) == - RealT - @test eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, orientation, - equations)) == RealT - end + @test eltype(@inferred flux_derigs_etal(u_ll, u_rr, orientation, + equations)) == + RealT + @test eltype(@inferred flux_hindenlang_gassner(u_ll, u_rr, orientation, + equations)) == RealT @test typeof(@inferred max_abs_speed_naive(u_ll, u_rr, orientation, equations)) == @@ -2011,17 +1844,9 @@ isdir(outdir) && rm(outdir, recursive = true) RealT @test eltype(@inferred flux(u, normal_direction, equations)) == RealT - if RealT == Float32 - # check `ln_mean` and `stolarsky_mean` (test broken) - @test_broken eltype(@inferred flux_winters_etal(u_ll, u_rr, - normal_direction, - equations)) == - RealT - else - @test eltype(@inferred flux_winters_etal(u_ll, u_rr, normal_direction, - equations)) == - RealT - end + @test eltype(@inferred flux_winters_etal(u_ll, u_rr, normal_direction, + equations)) == + RealT @test eltype(@inferred min_max_speed_naive(u_ll, u_rr, normal_direction, equations)) == RealT @@ -2034,17 +1859,9 @@ isdir(outdir) && rm(outdir, recursive = true) for orientation in orientations @test eltype(@inferred flux(u, orientation, equations)) == RealT - if RealT == Float32 - # check `ln_mean` and `stolarsky_mean` (test broken) - @test_broken eltype(@inferred flux_winters_etal(u_ll, u_rr, - orientation, - equations)) == - RealT - else - @test eltype(@inferred flux_winters_etal(u_ll, u_rr, orientation, - equations)) == - RealT - end + @test eltype(@inferred flux_winters_etal(u_ll, u_rr, orientation, + equations)) == + RealT @test eltype(@inferred min_max_speed_davis(u_ll, u_rr, orientation, equations)) == RealT @@ -2124,7 +1941,7 @@ isdir(outdir) && rm(outdir, recursive = true) @test eltype(@inferred dissipation(u_ll, u_rr, normal_direction, equations)) == RealT @test eltype(@inferred numflux(u_ll, u_rr, orientation, equations)) == RealT - # no matching method + # no matching method # @test eltype(@inferred numflux(u_ll, u_rr, normal_direction, equations)) == RealT @test eltype(@inferred min_max_speed_naive(u_ll, u_rr, orientation, equations)) == RealT From e6ba83857eb4447aaccc6574b7a3675bbd21f9ae Mon Sep 17 00:00:00 2001 From: Huiyu Xie Date: Thu, 22 Aug 2024 18:39:06 -1000 Subject: [PATCH 24/25] Add BC tests for type stability (#2045) * start * BC tests for Navier Stokes 1D * BC tests for Navier Stokes 2D * BC tests for Navier Stokes 3D * BC tests for Laplace Diffusion 1D --- test/test_type.jl | 279 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 261 insertions(+), 18 deletions(-) diff --git a/test/test_type.jl b/test/test_type.jl index bd553ee89c4..d507cded958 100644 --- a/test/test_type.jl +++ b/test/test_type.jl @@ -315,7 +315,13 @@ isdir(outdir) && rm(outdir, recursive = true) @test typeof(@inferred Trixi.entropy_thermodynamic(cons, equations)) == RealT @test typeof(@inferred energy_internal(cons, equations)) == RealT - # TODO: test `gradient_conservative`, not necessary but good to have + @test eltype(@inferred Trixi.gradient_conservative(pressure, u, equations)) == + RealT + @test eltype(@inferred Trixi.gradient_conservative(Trixi.entropy_math, u, + equations)) == RealT + @test eltype(@inferred Trixi.gradient_conservative(Trixi.entropy_guermond_etal, + u, + equations)) == RealT end end @@ -577,11 +583,33 @@ isdir(outdir) && rm(outdir, recursive = true) Prandtl = prandtl_number, gradient_variables = GradientVariablesEntropy()) - u = u_transformed = SVector(one(RealT), zero(RealT), - zero(RealT)) + x = SVector(zero(RealT)) + t = zero(RealT) + u = u_inner = u_transformed = flux_inner = SVector(one(RealT), zero(RealT), + zero(RealT)) orientation = 1 + directions = [1, 2] gradients = SVector(RealT(0.1), RealT(0.1), RealT(0.1)) + operator_gradient = Trixi.Gradient() + operator_divergence = Trixi.Divergence() + + # For BC tests + function initial_condition_navier_stokes_convergence_test(x, t, equations) + RealT_local = eltype(x) + A = 0.5f0 + c = 2 + + pi_x = convert(RealT_local, pi) * x[1] + pi_t = convert(RealT_local, pi) * t + + rho = c + A * cos(pi_x) * cos(pi_t) + v1 = log(x[1] + 2) * (1 - exp(-A * (x[1] - 1))) * cos(pi_t) + p = rho^2 + + return prim2cons(SVector(rho, v1, p), equations) + end + for equations_parabolic in (equations_parabolic_primitive, equations_parabolic_entropy) @test eltype(@inferred flux(u, gradients, orientation, equations_parabolic)) == @@ -599,10 +627,49 @@ isdir(outdir) && rm(outdir, recursive = true) @test eltype(@inferred Trixi.convert_derivative_to_primitive(u, gradients, equations_parabolic)) == RealT - end - # TODO: BC tests for GradientVariablesPrimitive - # TODO: BC tests for GradientVariablesEntropy + # For BC tests + velocity_bc_left_right = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, + t, + equations)[2]) + heat_bc_left = Isothermal((x, t, equations) -> Trixi.temperature(initial_condition_navier_stokes_convergence_test(x, + t, + equations), + equations_parabolic)) + heat_bc_right = Adiabatic((x, t, equations) -> oftype(t, 0)) + + boundary_condition_left = BoundaryConditionNavierStokesWall(velocity_bc_left_right, + heat_bc_left) + boundary_condition_right = BoundaryConditionNavierStokesWall(velocity_bc_left_right, + heat_bc_right) + # BC tests + for direction in directions + @test eltype(@inferred boundary_condition_right(flux_inner, u_inner, + orientation, direction, + x, + t, operator_gradient, + equations_parabolic)) == + RealT + @test eltype(@inferred boundary_condition_right(flux_inner, u_inner, + orientation, direction, + x, + t, operator_divergence, + equations_parabolic)) == + RealT + @test eltype(@inferred boundary_condition_left(flux_inner, u_inner, + orientation, direction, + x, + t, operator_gradient, + equations_parabolic)) == + RealT + @test eltype(@inferred boundary_condition_left(flux_inner, u_inner, + orientation, direction, + x, + t, operator_divergence, + equations_parabolic)) == + RealT + end + end end end @@ -620,11 +687,37 @@ isdir(outdir) && rm(outdir, recursive = true) Prandtl = prandtl_number, gradient_variables = GradientVariablesEntropy()) - u = u_transformed = SVector(one(RealT), zero(RealT), zero(RealT), zero(RealT)) + x = SVector(zero(RealT), zero(RealT)) + t = zero(RealT) + u = w_inner = u_transformed = flux_inner = normal = SVector(one(RealT), + zero(RealT), + zero(RealT), + zero(RealT)) orientations = [1, 2] gradient = SVector(RealT(0.1), RealT(0.1), RealT(0.1), RealT(0.1)) gradients = SVector(gradient, gradient) + operator_gradient = Trixi.Gradient() + operator_divergence = Trixi.Divergence() + + # For BC tests + function initial_condition_navier_stokes_convergence_test(x, t, equations) + RealT_local = eltype(x) + A = 0.5f0 + c = 2 + + pi_x = convert(RealT_local, pi) * x[1] + pi_y = convert(RealT_local, pi) * x[2] + pi_t = convert(RealT_local, pi) * t + + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + v1 = sin(pi_x) * log(x[2] + 2) * (1 - exp(-A * (x[2] - 1))) * cos(pi_t) + v2 = v1 + p = rho^2 + + return prim2cons(SVector(rho, v1, v2, p), equations) + end + for equations_parabolic in (equations_parabolic_primitive, equations_parabolic_entropy) for orientation in orientations @@ -648,10 +741,50 @@ isdir(outdir) && rm(outdir, recursive = true) @test eltype(@inferred Trixi.convert_derivative_to_primitive(u, gradient, equations_parabolic)) == RealT - end - # TODO: BC tests for GradientVariablesPrimitive - # TODO: BC tests for GradientVariablesEntropy + # For BC tests + velocity_bc_left_right = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, + t, + equations)[2:3]) + heat_bc_left = Isothermal((x, t, equations) -> Trixi.temperature(initial_condition_navier_stokes_convergence_test(x, + t, + equations), + equations_parabolic)) + heat_bc_right = Adiabatic((x, t, equations) -> oftype(t, 0)) + + boundary_condition_left = BoundaryConditionNavierStokesWall(velocity_bc_left_right, + heat_bc_left) + boundary_condition_right = BoundaryConditionNavierStokesWall(velocity_bc_left_right, + heat_bc_right) + + # BC tests + @test eltype(@inferred boundary_condition_right(flux_inner, w_inner, + normal, + x, + t, + operator_gradient, + equations_parabolic)) == + RealT + @test eltype(@inferred boundary_condition_right(flux_inner, w_inner, + normal, + x, + t, + operator_divergence, + equations_parabolic)) == + RealT + @test eltype(@inferred boundary_condition_left(flux_inner, w_inner, + normal, + x, + t, operator_gradient, + equations_parabolic)) == + RealT + @test eltype(@inferred boundary_condition_left(flux_inner, w_inner, + normal, + x, + t, operator_divergence, + equations_parabolic)) == + RealT + end end end @@ -669,12 +802,43 @@ isdir(outdir) && rm(outdir, recursive = true) Prandtl = prandtl_number, gradient_variables = GradientVariablesEntropy()) - u = u_transformed = SVector(one(RealT), zero(RealT), zero(RealT), zero(RealT), - zero(RealT)) + x = SVector(zero(RealT), zero(RealT), zero(RealT)) + t = zero(RealT) + u = w_inner = u_transformed = flux_inner = normal = SVector(one(RealT), + zero(RealT), + zero(RealT), + zero(RealT), + zero(RealT)) orientations = [1, 2, 3] gradient = SVector(RealT(0.1), RealT(0.1), RealT(0.1), RealT(0.1), RealT(0.1)) gradients = SVector(gradient, gradient, gradient) + operator_gradient = Trixi.Gradient() + operator_divergence = Trixi.Divergence() + + # For BC tests + function initial_condition_navier_stokes_convergence_test(x, t, equations) + RealT_local = eltype(x) + c = 2 + A1 = 0.5f0 + A2 = 1 + A3 = 0.5f0 + + pi_x = convert(RealT_local, pi) * x[1] + pi_y = convert(RealT_local, pi) * x[2] + pi_z = convert(RealT_local, pi) * x[3] + pi_t = convert(RealT_local, pi) * t + + rho = c + A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t) + v1 = A2 * sin(pi_x) * log(x[2] + 2) * (1 - exp(-A3 * (x[2] - 1))) * + sin(pi_z) * cos(pi_t) + v2 = v1 + v3 = v1 + p = rho^2 + + return prim2cons(SVector(rho, v1, v2, v3, p), equations) + end + for equations_parabolic in (equations_parabolic_primitive, equations_parabolic_entropy) for orientation in orientations @@ -698,10 +862,50 @@ isdir(outdir) && rm(outdir, recursive = true) @test eltype(@inferred Trixi.convert_derivative_to_primitive(u, gradient, equations_parabolic)) == RealT - end - # TODO: BC tests for GradientVariablesPrimitive - # TODO: BC tests for GradientVariablesEntropy + # For BC tests + velocity_bc_left_right = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, + t, + equations)[2:4]) + heat_bc_left = Isothermal((x, t, equations) -> Trixi.temperature(initial_condition_navier_stokes_convergence_test(x, + t, + equations), + equations_parabolic)) + heat_bc_right = Adiabatic((x, t, equations) -> oftype(t, 0)) + + boundary_condition_left = BoundaryConditionNavierStokesWall(velocity_bc_left_right, + heat_bc_left) + boundary_condition_right = BoundaryConditionNavierStokesWall(velocity_bc_left_right, + heat_bc_right) + + # BC tests + @test eltype(@inferred boundary_condition_right(flux_inner, w_inner, + normal, + x, + t, + operator_gradient, + equations_parabolic)) == + RealT + @test eltype(@inferred boundary_condition_right(flux_inner, w_inner, + normal, + x, + t, + operator_divergence, + equations_parabolic)) == + RealT + @test eltype(@inferred boundary_condition_left(flux_inner, w_inner, + normal, + x, + t, operator_gradient, + equations_parabolic)) == + RealT + @test eltype(@inferred boundary_condition_left(flux_inner, w_inner, + normal, + x, + t, operator_divergence, + equations_parabolic)) == + RealT + end end end @@ -1299,14 +1503,53 @@ isdir(outdir) && rm(outdir, recursive = true) x = SVector(zero(RealT)) t = zero(RealT) - u = gradients = SVector(one(RealT)) + u = u_inner = flux_inner = normal = gradients = SVector(one(RealT)) orientation = 1 + operator_gradient = Trixi.Gradient() + operator_divergence = Trixi.Divergence() + @test eltype(@inferred flux(u, gradients, orientation, equations_parabolic)) == RealT - # TODO: BC tests for BoundaryConditionDirichlet - # TODO: BC tests for BoundaryConditionNeumann + # For BC tests + function initial_condition_convergence_test(x, t, + equation::LaplaceDiffusion1D) + RealT_local = eltype(x) + x_trans = x[1] - equation.diffusivity * t + + c = 1 + A = 0.5f0 + L = 2 + f = 1.0f0 / L + omega = 2 * convert(RealT_local, pi) * f + scalar = c + A * sin(omega * sum(x_trans)) + return SVector(scalar) + end + + boundary_condition_dirichlet = BoundaryConditionDirichlet(initial_condition_convergence_test) + boundary_condition_neumann = BoundaryConditionNeumann((x, t, equations) -> oftype(t, + 0)) + + # BC tests + @test eltype(@inferred boundary_condition_dirichlet(flux_inner, u_inner, normal, + x, t, + operator_gradient, + equations_parabolic)) == + RealT + @test eltype(@inferred boundary_condition_dirichlet(flux_inner, u_inner, normal, + x, t, + operator_divergence, + equations_parabolic)) == + RealT + @test eltype(@inferred boundary_condition_neumann(flux_inner, u_inner, normal, + x, t, + operator_gradient, + equations_parabolic)) == RealT + @test eltype(@inferred boundary_condition_neumann(flux_inner, u_inner, normal, + x, t, + operator_divergence, + equations_parabolic)) == RealT end end From 90eebb032c23d38b435735a27498a5446ae51a89 Mon Sep 17 00:00:00 2001 From: Johannes Markert <10619309+jmark@users.noreply.github.com> Date: Fri, 23 Aug 2024 18:31:21 +0200 Subject: [PATCH 25/25] Fix t8code ocassionally segfaults (#2043) * Adding explicit finalizing calls in elixirs. * Wrapping forest commit call in disabled GC. * Applying formater. --------- Co-authored-by: Johannes Markert Co-authored-by: Andrew Winters --- .../elixir_advection_amr_solution_independent.jl | 4 ++++ .../elixir_advection_amr_unstructured_flag.jl | 4 ++++ examples/t8code_2d_dgsem/elixir_advection_basic.jl | 4 ++++ .../t8code_2d_dgsem/elixir_advection_nonconforming_flag.jl | 4 ++++ .../t8code_2d_dgsem/elixir_advection_unstructured_flag.jl | 4 ++++ examples/t8code_2d_dgsem/elixir_euler_free_stream.jl | 4 ++++ examples/t8code_2d_dgsem/elixir_euler_sedov.jl | 4 ++++ examples/t8code_2d_dgsem/elixir_euler_shockcapturing_ec.jl | 4 ++++ ...xir_euler_source_terms_nonconforming_unstructured_flag.jl | 4 ++++ examples/t8code_2d_dgsem/elixir_eulergravity_convergence.jl | 4 ++++ examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl | 4 ++++ examples/t8code_2d_dgsem/elixir_mhd_rotor.jl | 4 ++++ examples/t8code_2d_dgsem/elixir_shallowwater_source_terms.jl | 4 ++++ examples/t8code_3d_dgsem/elixir_advection_amr.jl | 4 ++++ .../elixir_advection_amr_unstructured_curved.jl | 4 ++++ examples/t8code_3d_dgsem/elixir_advection_basic.jl | 4 ++++ examples/t8code_3d_dgsem/elixir_advection_nonconforming.jl | 4 ++++ .../t8code_3d_dgsem/elixir_advection_unstructured_curved.jl | 4 ++++ examples/t8code_3d_dgsem/elixir_euler_ec.jl | 4 ++++ examples/t8code_3d_dgsem/elixir_euler_free_stream.jl | 4 ++++ .../t8code_3d_dgsem/elixir_euler_free_stream_extruded.jl | 4 ++++ examples/t8code_3d_dgsem/elixir_euler_sedov.jl | 4 ++++ ...r_euler_source_terms_nonconforming_unstructured_curved.jl | 4 ++++ .../t8code_3d_dgsem/elixir_euler_source_terms_nonperiodic.jl | 4 ++++ src/meshes/t8code_mesh.jl | 5 +++++ 25 files changed, 101 insertions(+) diff --git a/examples/t8code_2d_dgsem/elixir_advection_amr_solution_independent.jl b/examples/t8code_2d_dgsem/elixir_advection_amr_solution_independent.jl index 1ed08e1961b..618be7f8965 100644 --- a/examples/t8code_2d_dgsem/elixir_advection_amr_solution_independent.jl +++ b/examples/t8code_2d_dgsem/elixir_advection_amr_solution_independent.jl @@ -139,3 +139,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback save_everystep = false, callback = callbacks); summary_callback() # print the timer summary + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_2d_dgsem/elixir_advection_amr_unstructured_flag.jl b/examples/t8code_2d_dgsem/elixir_advection_amr_unstructured_flag.jl index d8893854811..c9c831d3471 100644 --- a/examples/t8code_2d_dgsem/elixir_advection_amr_unstructured_flag.jl +++ b/examples/t8code_2d_dgsem/elixir_advection_amr_unstructured_flag.jl @@ -78,3 +78,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), save_everystep = false, callback = callbacks); summary_callback() # print the timer summary + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_2d_dgsem/elixir_advection_basic.jl b/examples/t8code_2d_dgsem/elixir_advection_basic.jl index 26ced0970fe..2c19ace1dea 100644 --- a/examples/t8code_2d_dgsem/elixir_advection_basic.jl +++ b/examples/t8code_2d_dgsem/elixir_advection_basic.jl @@ -55,3 +55,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), # Print the timer summary summary_callback() + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_2d_dgsem/elixir_advection_nonconforming_flag.jl b/examples/t8code_2d_dgsem/elixir_advection_nonconforming_flag.jl index 48f78dd6da3..a8808f9ab72 100644 --- a/examples/t8code_2d_dgsem/elixir_advection_nonconforming_flag.jl +++ b/examples/t8code_2d_dgsem/elixir_advection_nonconforming_flag.jl @@ -85,3 +85,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), # Print the timer summary summary_callback() + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_2d_dgsem/elixir_advection_unstructured_flag.jl b/examples/t8code_2d_dgsem/elixir_advection_unstructured_flag.jl index e512f328234..f7917fb03b9 100644 --- a/examples/t8code_2d_dgsem/elixir_advection_unstructured_flag.jl +++ b/examples/t8code_2d_dgsem/elixir_advection_unstructured_flag.jl @@ -71,3 +71,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), # Print the timer summary. summary_callback() + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_2d_dgsem/elixir_euler_free_stream.jl b/examples/t8code_2d_dgsem/elixir_euler_free_stream.jl index d9d2c65d988..34e6d7d8c0c 100644 --- a/examples/t8code_2d_dgsem/elixir_euler_free_stream.jl +++ b/examples/t8code_2d_dgsem/elixir_euler_free_stream.jl @@ -85,3 +85,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback save_everystep = false, callback = callbacks); summary_callback() # print the timer summary + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_2d_dgsem/elixir_euler_sedov.jl b/examples/t8code_2d_dgsem/elixir_euler_sedov.jl index 82770a4050b..e1c51c1f96b 100644 --- a/examples/t8code_2d_dgsem/elixir_euler_sedov.jl +++ b/examples/t8code_2d_dgsem/elixir_euler_sedov.jl @@ -93,3 +93,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback save_everystep = false, callback = callbacks); summary_callback() # print the timer summary + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_2d_dgsem/elixir_euler_shockcapturing_ec.jl b/examples/t8code_2d_dgsem/elixir_euler_shockcapturing_ec.jl index 9ebbd1d28c4..92ed169756b 100644 --- a/examples/t8code_2d_dgsem/elixir_euler_shockcapturing_ec.jl +++ b/examples/t8code_2d_dgsem/elixir_euler_shockcapturing_ec.jl @@ -64,3 +64,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback save_everystep = false, callback = callbacks); summary_callback() # print the timer summary + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_2d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_flag.jl b/examples/t8code_2d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_flag.jl index 48684071d4b..59e5f996918 100644 --- a/examples/t8code_2d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_flag.jl +++ b/examples/t8code_2d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_flag.jl @@ -85,3 +85,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback save_everystep = false, callback = callbacks); summary_callback() # print the timer summary + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_2d_dgsem/elixir_eulergravity_convergence.jl b/examples/t8code_2d_dgsem/elixir_eulergravity_convergence.jl index cd10315945a..3fafbf8a4c1 100644 --- a/examples/t8code_2d_dgsem/elixir_eulergravity_convergence.jl +++ b/examples/t8code_2d_dgsem/elixir_eulergravity_convergence.jl @@ -72,3 +72,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), save_everystep = false, callback = callbacks); summary_callback() # print the timer summary println("Number of gravity subcycles: ", semi.gravity_counter.ncalls_since_readout) + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl b/examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl index e184cb3fd05..04c36dd8642 100644 --- a/examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl +++ b/examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl @@ -57,3 +57,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback save_everystep = false, callback = callbacks); summary_callback() # print the timer summary + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_2d_dgsem/elixir_mhd_rotor.jl b/examples/t8code_2d_dgsem/elixir_mhd_rotor.jl index 592d5b15a85..82e6d8ca4a6 100644 --- a/examples/t8code_2d_dgsem/elixir_mhd_rotor.jl +++ b/examples/t8code_2d_dgsem/elixir_mhd_rotor.jl @@ -124,3 +124,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback save_everystep = false, callback = callbacks); summary_callback() # print the timer summary + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_2d_dgsem/elixir_shallowwater_source_terms.jl b/examples/t8code_2d_dgsem/elixir_shallowwater_source_terms.jl index 3610639d554..9ce248ff3b5 100644 --- a/examples/t8code_2d_dgsem/elixir_shallowwater_source_terms.jl +++ b/examples/t8code_2d_dgsem/elixir_shallowwater_source_terms.jl @@ -55,3 +55,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-8, reltol = 1.0e-8, ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_3d_dgsem/elixir_advection_amr.jl b/examples/t8code_3d_dgsem/elixir_advection_amr.jl index 5a4b2218d57..83f897dac7c 100644 --- a/examples/t8code_3d_dgsem/elixir_advection_amr.jl +++ b/examples/t8code_3d_dgsem/elixir_advection_amr.jl @@ -64,3 +64,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback save_everystep = false, callback = callbacks); summary_callback() # print the timer summary + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_3d_dgsem/elixir_advection_amr_unstructured_curved.jl b/examples/t8code_3d_dgsem/elixir_advection_amr_unstructured_curved.jl index 1f9aa3449b0..ae95fa6c4df 100644 --- a/examples/t8code_3d_dgsem/elixir_advection_amr_unstructured_curved.jl +++ b/examples/t8code_3d_dgsem/elixir_advection_amr_unstructured_curved.jl @@ -95,3 +95,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback save_everystep = false, callback = callbacks); summary_callback() # print the timer summary + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_3d_dgsem/elixir_advection_basic.jl b/examples/t8code_3d_dgsem/elixir_advection_basic.jl index f49462035aa..b6479946971 100644 --- a/examples/t8code_3d_dgsem/elixir_advection_basic.jl +++ b/examples/t8code_3d_dgsem/elixir_advection_basic.jl @@ -57,3 +57,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), # Print the timer summary summary_callback() + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_3d_dgsem/elixir_advection_nonconforming.jl b/examples/t8code_3d_dgsem/elixir_advection_nonconforming.jl index 8d7a48370f5..cac6e30aa74 100644 --- a/examples/t8code_3d_dgsem/elixir_advection_nonconforming.jl +++ b/examples/t8code_3d_dgsem/elixir_advection_nonconforming.jl @@ -83,3 +83,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), # Print the timer summary summary_callback() + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_3d_dgsem/elixir_advection_unstructured_curved.jl b/examples/t8code_3d_dgsem/elixir_advection_unstructured_curved.jl index fe6aa48e7d9..dd8e7f21038 100644 --- a/examples/t8code_3d_dgsem/elixir_advection_unstructured_curved.jl +++ b/examples/t8code_3d_dgsem/elixir_advection_unstructured_curved.jl @@ -88,3 +88,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), # Print the timer summary summary_callback() + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_3d_dgsem/elixir_euler_ec.jl b/examples/t8code_3d_dgsem/elixir_euler_ec.jl index e1e4d850a86..ad23e3440d8 100644 --- a/examples/t8code_3d_dgsem/elixir_euler_ec.jl +++ b/examples/t8code_3d_dgsem/elixir_euler_ec.jl @@ -82,3 +82,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback save_everystep = false, callback = callbacks); summary_callback() # print the timer summary + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_3d_dgsem/elixir_euler_free_stream.jl b/examples/t8code_3d_dgsem/elixir_euler_free_stream.jl index 882e3aebebe..11f3ba94e25 100644 --- a/examples/t8code_3d_dgsem/elixir_euler_free_stream.jl +++ b/examples/t8code_3d_dgsem/elixir_euler_free_stream.jl @@ -108,3 +108,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback save_everystep = false, callback = callbacks); summary_callback() # print the timer summary + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_3d_dgsem/elixir_euler_free_stream_extruded.jl b/examples/t8code_3d_dgsem/elixir_euler_free_stream_extruded.jl index 777cccf7ad7..ca3722e6254 100644 --- a/examples/t8code_3d_dgsem/elixir_euler_free_stream_extruded.jl +++ b/examples/t8code_3d_dgsem/elixir_euler_free_stream_extruded.jl @@ -96,3 +96,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), #maxiters=1 dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback save_everystep = false, callback = callbacks); summary_callback() # print the timer summary + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_3d_dgsem/elixir_euler_sedov.jl b/examples/t8code_3d_dgsem/elixir_euler_sedov.jl index 618b170b661..55369fa14f2 100644 --- a/examples/t8code_3d_dgsem/elixir_euler_sedov.jl +++ b/examples/t8code_3d_dgsem/elixir_euler_sedov.jl @@ -95,3 +95,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback save_everystep = false, callback = callbacks); summary_callback() # print the timer summary + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_3d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_curved.jl b/examples/t8code_3d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_curved.jl index a06e7927dd0..9a16b104e6a 100644 --- a/examples/t8code_3d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_curved.jl +++ b/examples/t8code_3d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_curved.jl @@ -110,3 +110,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback save_everystep = false, callback = callbacks); summary_callback() # print the timer summary + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/examples/t8code_3d_dgsem/elixir_euler_source_terms_nonperiodic.jl b/examples/t8code_3d_dgsem/elixir_euler_source_terms_nonperiodic.jl index 7cb03bb312d..3962ce798cb 100644 --- a/examples/t8code_3d_dgsem/elixir_euler_source_terms_nonperiodic.jl +++ b/examples/t8code_3d_dgsem/elixir_euler_source_terms_nonperiodic.jl @@ -60,3 +60,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback save_everystep = false, callback = callbacks); summary_callback() # print the timer summary + +# Finalize `T8codeMesh` to make sure MPI related objects in t8code are +# released before `MPI` finalizes. +!isinteractive() && finalize(mesh) diff --git a/src/meshes/t8code_mesh.jl b/src/meshes/t8code_mesh.jl index aa49e641dc9..9b0e0b741a4 100644 --- a/src/meshes/t8code_mesh.jl +++ b/src/meshes/t8code_mesh.jl @@ -731,9 +731,14 @@ function adapt!(mesh::T8codeMesh, adapt_callback; recursive = true, balance = tr t8_forest_set_ghost(new_forest, ghost, T8_GHOST_FACES) # Note: MPI support not available yet so it is a dummy call. + # Julias's GC leads to random segfaults here. Temporarily switch it off. + GC.enable(false) + # The old forest is destroyed here. # Call `t8_forest_ref(Ref(mesh.forest))` to keep it. t8_forest_commit(new_forest) + + GC.enable(true) end mesh.forest = new_forest