From 95518c5670774dfccfd66db2fc0df15ec91b251f Mon Sep 17 00:00:00 2001 From: Simon Candelaresi <10759273+SimonCan@users.noreply.github.com> Date: Fri, 16 Jun 2023 20:35:24 +0100 Subject: [PATCH 001/263] Initial support for surface coupling of two systems (#1452) * Corrected bugs from coupled to main merger. * Added polytropic equation. * Added further polytropic equations and examples. * Added coupling equations. * Added coupling equation between Euler. * Commented debugging bits, like infiltrator. * Add missing `using` * Fix `destats` deprecation warning * Added coupled elixir. * Removed commented testing code. * Added other_list to the coupled semi discretisation elixir. * Removed flux coupling equation. * Removed surface coupling equation for polytropic Euler. * Removed polytropic Euler equation. * Removed any code related to BoundaryConditionCoupledAB. * Removed flux coupling code. * Removed numerical fluxes for BoundaryConditionCoupledAB. * Removed surface fluxes for BoundaryConditionCoupledAB. * Removed coupled elixir. * Remove Coupled StructuredMesh from visualization test. * Remove duplicate function definitions * make advection elixir go further * Removed initial_condition_peak. * Removed src/equations/hyperbolic_diffusion_2d.jl. * Removed 3d coupling. * Remopved 3d capability. * Removed 3d capability. * Removed 3d plotting of coupled data. * Remove extra dependencies * Remove whitespace changes * Fix type instability * Some temporary fixes. * Fix type in semidiscretization * Removed analysis_callback for simple coupled elixir. * Removed analysis callbacks for the coupled case. * Removed AnalysysCallback for coupled elixir. * Removed polytropic coupling elixir. * Update summary output * Update src/solvers/dgsem_structured/dg_2d.jl * Format summary * Fix save solution callback * Remove unused code * Move timeit call before dispatch on semi * Avoid copy on calculcate_dt * Avoid copy on save_solution_file * Remove unnnecessary override of wrap_array * Undo changes to analysis callback * Remove equations_list * Remove unused functions * nmeshes -> nsystems * Further cleanup * Move BoundaryConditionCoupled to the correct location * Visualize setup * Formatting improvmenets * Change 1:nsystems(semi) to eachsystem(semi) * Remove redundant ndofs(...) function * copy_to_coupled_boundary --> copy_to_coupled_boundary! * Move all SemidiscretizationCoupled-specific code to semi/semi_coupled.jl * Use uEltype for BCCoupled * Add comment * I --> Indices * Add comment * Remove Base.summary for SemiCoupled since it appears to be unused * Add parens * Int64 -> Int * Add xref for Documenter.jl * Fixup comment * Remove unused `total_volume` * Remove obsolete comment * summary_semi --> print_summary_semi for clarity * Make SemiCoupled ctor more convenient * Fix docstring * Add description to elixir * Rename elixir * Remove unused kwarg * Fix argument order and simplify interface for IO functions * Explicitly return nothing in functions that should do - nothing * Update comment * Add AnalysisCallback to coupled semidiscretization (#1505) * Add AnalysisCallback to coupled semidiscretization * First non-crashing version of the AnalysisCallbackCoupled * Added comment to offending line in the analysis callback. * Fix stupid bug * Rename variable for easier testing * Clean up code * Remove type instability * Prettify output * Add test * Enable `convergence_test` for SemidiscretizationCoupled * Increased the frequency of the solution write out for a more usable animation. * Reverted analysis intervals. * Updated the l2 and linf errors for the elixir_advection_basic_coupled.jl test to reflect the increased simulation time. * Corrected bracket typo in structured_2d test. * Renamed plural variable names to lists. * Further renaiming plural variable names. * Added convergence_test for elixir_advection_basic_coupled. * Fix coverage for convergence_test * Add test for analysis_callback(sol) * Split timers between systems * fully specialize on rhs and parameters when constructing an ODEProblem * switch example back to OrdinaryDiffEq.jl * Reverted coupled example to use Trixi.solve instead of OrdinaryDiffEq solve. This should fix issues with LoadError: Failed to precompile OrdinaryDiffEq in the thread_legacy test. * Changed Julia version in project toml to 1.9 to fix OrdinaryDiffEq issues on the github test. * Change 1:nsystems(semi) to eachsystem(semi) * Use `get_system_u_ode` * Move all SemidiscretizationCoupled-specific code to semi/semi_coupled.jl * Changed file name name of elixir_advection_basic_coupled.jl to elixir_advection_coupled.jl. * Reverted Julia version to 1.8 in Project toml file. * Apply suggestions from code review * -use type SciMLBase.FullSpecialize instead of instance * Use get_system_u_ode instead of manual view * Reorder elixir ingredients * Make comment reflect code again * Use solve from OrdinaryDiffEq * Use more precise type for array * Test EOCs for each system separately * Allow test to run for the full duration --------- Co-authored-by: SimonCan Co-authored-by: Hendrik Ranocha * Remove unused `total_volume(...)` * Make `save_solution_file` work for SemiEulerGravity again (and make it multi-system aware) * Update src/semidiscretization/semidiscretization_euler_gravity.jl Co-authored-by: Hendrik Ranocha * Apply formatting --------- Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Hendrik Ranocha Co-authored-by: Hendrik Ranocha Co-authored-by: Benjamin Bolm <74359358+bennibolm@users.noreply.github.com> Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> Co-authored-by: Lucas Gemein <74359570+NichtLucas@users.noreply.github.com> --- .../elixir_advection_coupled.jl | 117 ++++ src/Trixi.jl | 8 +- src/auxiliary/special_elixirs.jl | 16 +- src/callbacks_step/analysis.jl | 30 +- src/callbacks_step/save_solution.jl | 91 +-- src/callbacks_step/stepsize.jl | 19 +- src/callbacks_step/summary.jl | 22 +- src/meshes/mesh_io.jl | 8 +- src/semidiscretization/semidiscretization.jl | 6 +- .../semidiscretization_coupled.jl | 610 ++++++++++++++++++ .../semidiscretization_euler_gravity.jl | 17 +- test/test_special_elixirs.jl | 7 + test/test_structured_2d.jl | 13 + 13 files changed, 890 insertions(+), 74 deletions(-) create mode 100644 examples/structured_2d_dgsem/elixir_advection_coupled.jl create mode 100644 src/semidiscretization/semidiscretization_coupled.jl diff --git a/examples/structured_2d_dgsem/elixir_advection_coupled.jl b/examples/structured_2d_dgsem/elixir_advection_coupled.jl new file mode 100644 index 00000000000..1e54e411db6 --- /dev/null +++ b/examples/structured_2d_dgsem/elixir_advection_coupled.jl @@ -0,0 +1,117 @@ +using OrdinaryDiffEq +using Trixi + + +############################################################################### +# Coupled semidiscretization of two linear advection systems, which are connected periodically +# +# In this elixir, we have a square domain that is divided into a left half and a right half. On each +# half of the domain, a completely independent SemidiscretizationHyperbolic is created for the +# linear advection equations. The two systems are coupled in the x-direction and have periodic +# boundaries in the y-direction. For a high-level overview, see also the figure below: +# +# (-1, 1) ( 1, 1) +# ┌────────────────────┬────────────────────┐ +# │ ↑ periodic ↑ │ ↑ periodic ↑ │ +# │ │ │ +# │ │ │ +# │ ========= │ ========= │ +# │ system #1 │ system #2 │ +# │ ========= │ ========= │ +# │ │ │ +# │ │ │ +# │ │ │ +# │ │ │ +# │ coupled -->│<-- coupled │ +# │ │ │ +# │<-- coupled │ coupled -->│ +# │ │ │ +# │ │ │ +# │ ↓ periodic ↓ │ ↓ periodic ↓ │ +# └────────────────────┴────────────────────┘ +# (-1, -1) ( 1, -1) + +advection_velocity = (0.2, -0.7) +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) + +# First mesh is the left half of a [-1,1]^2 square +coordinates_min1 = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) +coordinates_max1 = ( 0.0, 1.0) # maximum coordinates (max(x), max(y)) + +# Define identical resolution as a variable such that it is easier to change from `trixi_include` +cells_per_dimension = (8, 16) + +cells_per_dimension1 = cells_per_dimension + +mesh1 = StructuredMesh(cells_per_dimension1, coordinates_min1, coordinates_max1) + +# A semidiscretization collects data structures and functions for the spatial discretization +semi1 = SemidiscretizationHyperbolic(mesh1, equations, initial_condition_convergence_test, solver, + boundary_conditions=( + # Connect left boundary with right boundary of right mesh + x_neg=BoundaryConditionCoupled(2, (:end, :i_forward), Float64), + # Connect right boundary with left boundary of right mesh + x_pos=BoundaryConditionCoupled(2, (:begin, :i_forward), Float64), + y_neg=boundary_condition_periodic, + y_pos=boundary_condition_periodic)) + + +# Second mesh is the right half of a [-1,1]^2 square +coordinates_min2 = (0.0, -1.0) # minimum coordinates (min(x), min(y)) +coordinates_max2 = (1.0, 1.0) # maximum coordinates (max(x), max(y)) + +cells_per_dimension2 = cells_per_dimension + +mesh2 = StructuredMesh(cells_per_dimension2, coordinates_min2, coordinates_max2) + +semi2 = SemidiscretizationHyperbolic(mesh2, equations, initial_condition_convergence_test, solver, + boundary_conditions=( + # Connect left boundary with right boundary of left mesh + x_neg=BoundaryConditionCoupled(1, (:end, :i_forward), Float64), + # Connect right boundary with left boundary of left mesh + x_pos=BoundaryConditionCoupled(1, (:begin, :i_forward), Float64), + y_neg=boundary_condition_periodic, + y_pos=boundary_condition_periodic)) + +# Create a semidiscretization that bundles semi1 and semi2 +semi = SemidiscretizationCoupled(semi1, semi2) + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span from 0.0 to 2.0 +ode = semidiscretize(semi, (0.0, 2.0)); + +# 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_callback1 = AnalysisCallback(semi1, interval=100) +analysis_callback2 = AnalysisCallback(semi2, interval=100) +analysis_callback = AnalysisCallbackCoupled(semi, analysis_callback1, analysis_callback2) + +# 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.6) + +# 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.0, # 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/src/Trixi.jl b/src/Trixi.jl index d5579aeea33..86e349c7dad 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -117,6 +117,7 @@ include("semidiscretization/semidiscretization.jl") include("semidiscretization/semidiscretization_hyperbolic.jl") include("semidiscretization/semidiscretization_hyperbolic_parabolic.jl") include("semidiscretization/semidiscretization_euler_acoustics.jl") +include("semidiscretization/semidiscretization_coupled.jl") include("callbacks_step/callbacks_step.jl") include("callbacks_stage/callbacks_stage.jl") include("semidiscretization/semidiscretization_euler_gravity.jl") @@ -184,7 +185,8 @@ export boundary_condition_do_nothing, boundary_condition_noslip_wall, boundary_condition_slip_wall, boundary_condition_wall, - BoundaryConditionNavierStokesWall, NoSlip, Adiabatic, Isothermal + BoundaryConditionNavierStokesWall, NoSlip, Adiabatic, Isothermal, + BoundaryConditionCoupled export initial_condition_convergence_test, source_terms_convergence_test export source_terms_harmonic @@ -229,12 +231,14 @@ export SemidiscretizationEulerAcoustics export SemidiscretizationEulerGravity, ParametersEulerGravity, timestep_gravity_erk52_3Sstar!, timestep_gravity_carpenter_kennedy_erk54_2N! +export SemidiscretizationCoupled + export SummaryCallback, SteadyStateCallback, AnalysisCallback, AliveCallback, SaveRestartCallback, SaveSolutionCallback, TimeSeriesCallback, VisualizationCallback, AveragingCallback, AMRCallback, StepsizeCallback, GlmSpeedCallback, LBMCollisionCallback, EulerAcousticsCouplingCallback, - TrivialCallback + TrivialCallback, AnalysisCallbackCoupled export load_mesh, load_time diff --git a/src/auxiliary/special_elixirs.jl b/src/auxiliary/special_elixirs.jl index da73b42e572..25bca8939ce 100644 --- a/src/auxiliary/special_elixirs.jl +++ b/src/auxiliary/special_elixirs.jl @@ -85,9 +85,21 @@ function convergence_test(mod::Module, elixir::AbstractString, iterations; kwarg println("#"^100) end - # number of variables - _, equations, _, _ = mesh_equations_solver_cache(mod.semi) + # Use raw error values to compute EOC + analyze_convergence(errors, iterations, mod.semi) +end + +# Analyze convergence for any semidiscretization +# Note: this intermediate method is to allow dispatching on the semidiscretization +function analyze_convergence(errors, iterations, semi::AbstractSemidiscretization) + _, equations, _, _ = mesh_equations_solver_cache(semi) variablenames = varnames(cons2cons, equations) + analyze_convergence(errors, iterations, variablenames) +end + +# This method is called with the collected error values to actually compute and print the EOC +function analyze_convergence(errors, iterations, + variablenames::Union{Tuple, AbstractArray}) nvariables = length(variablenames) # Reshape errors to get a matrix where the i-th row represents the i-th iteration diff --git a/src/callbacks_step/analysis.jl b/src/callbacks_step/analysis.jl index 2e038401df7..7fa2e21a244 100644 --- a/src/callbacks_step/analysis.jl +++ b/src/callbacks_step/analysis.jl @@ -84,11 +84,13 @@ function Base.show(io::IO, ::MIME"text/plain", end end +# This is the convenience constructor that gets called from the elixirs function AnalysisCallback(semi::AbstractSemidiscretization; kwargs...) mesh, equations, solver, cache = mesh_equations_solver_cache(semi) AnalysisCallback(mesh, equations, solver, cache; kwargs...) end +# This is the actual constructor function AnalysisCallback(mesh, equations::AbstractEquations, solver, cache; interval = 0, save_analysis = false, @@ -132,9 +134,18 @@ function AnalysisCallback(mesh, equations::AbstractEquations, solver, cache; initialize = initialize!) end +# This method gets called from OrdinaryDiffEq's `solve(...)` function initialize!(cb::DiscreteCallback{Condition, Affect!}, u_ode, t, integrator) where {Condition, Affect! <: AnalysisCallback} semi = integrator.p + du_ode = first(get_tmp_cache(integrator)) + initialize!(cb, u_ode, du_ode, t, integrator, semi) +end + +# This is the actual initialization method +# Note: we have this indirection to allow initializing a callback from the AnalysisCallbackCoupled +function initialize!(cb::DiscreteCallback{Condition, Affect!}, u_ode, du_ode, t, + integrator, semi) where {Condition, Affect! <: AnalysisCallback} initial_state_integrals = integrate(u_ode, semi) _, equations, _, _ = mesh_equations_solver_cache(semi) @@ -202,13 +213,21 @@ function initialize!(cb::DiscreteCallback{Condition, Affect!}, u_ode, t, # Note: For details see the actual callback function below analysis_callback.start_gc_time = Base.gc_time_ns() - analysis_callback(integrator) + analysis_callback(u_ode, du_ode, integrator, semi) return nothing end -# TODO: Taal refactor, allow passing an IO object (which could be devnull to avoid cluttering the console) +# This method gets called from OrdinaryDiffEq's `solve(...)` function (analysis_callback::AnalysisCallback)(integrator) semi = integrator.p + du_ode = first(get_tmp_cache(integrator)) + u_ode = integrator.u + analysis_callback(u_ode, du_ode, integrator, semi) +end + +# This method gets called internally as the main entry point to the AnalysiCallback +# TODO: Taal refactor, allow passing an IO object (which could be devnull to avoid cluttering the console) +function (analysis_callback::AnalysisCallback)(u_ode, du_ode, integrator, semi) mesh, equations, solver, cache = mesh_equations_solver_cache(semi) @unpack dt, t = integrator iter = integrator.stats.naccept @@ -300,15 +319,14 @@ function (analysis_callback::AnalysisCallback)(integrator) end # Calculate current time derivative (needed for semidiscrete entropy time derivative, residual, etc.) - du_ode = first(get_tmp_cache(integrator)) # `integrator.f` is usually just a call to `rhs!` # However, we want to allow users to modify the ODE RHS outside of Trixi.jl # and allow us to pass a combined ODE RHS to OrdinaryDiffEq, e.g., for # hyperbolic-parabolic systems. - @notimeit timer() integrator.f(du_ode, integrator.u, semi, t) - u = wrap_array(integrator.u, mesh, equations, solver, cache) + @notimeit timer() integrator.f(du_ode, u_ode, semi, t) + u = wrap_array(u_ode, mesh, equations, solver, cache) du = wrap_array(du_ode, mesh, equations, solver, cache) - l2_error, linf_error = analysis_callback(io, du, u, integrator.u, t, semi) + l2_error, linf_error = analysis_callback(io, du, u, u_ode, t, semi) mpi_println("─"^100) mpi_println() diff --git a/src/callbacks_step/save_solution.jl b/src/callbacks_step/save_solution.jl index 55f17bbc1c7..1fe0d6b1e15 100644 --- a/src/callbacks_step/save_solution.jl +++ b/src/callbacks_step/save_solution.jl @@ -141,14 +141,7 @@ function initialize_save_cb!(solution_callback::SaveSolutionCallback, u, t, inte mpi_isroot() && mkpath(solution_callback.output_directory) semi = integrator.p - mesh, _, _, _ = mesh_equations_solver_cache(semi) - @trixi_timeit timer() "I/O" begin - if mesh.unsaved_changes - mesh.current_filename = save_mesh_file(mesh, - solution_callback.output_directory) - mesh.unsaved_changes = false - end - end + @trixi_timeit timer() "I/O" save_mesh(semi, solution_callback.output_directory) if solution_callback.save_initial_solution solution_callback(integrator) @@ -157,6 +150,16 @@ function initialize_save_cb!(solution_callback::SaveSolutionCallback, u, t, inte return nothing end +# Save mesh for a general semidiscretization (default) +function save_mesh(semi::AbstractSemidiscretization, output_directory, timestep = 0) + mesh, _, _, _ = mesh_equations_solver_cache(semi) + + if mesh.unsaved_changes + mesh.current_filename = save_mesh_file(mesh, output_directory) + mesh.unsaved_changes = false + end +end + # this method is called to determine whether the callback should be activated function (solution_callback::SaveSolutionCallback)(u, t, integrator) @unpack interval_or_dt, save_final_solution = solution_callback @@ -174,41 +177,15 @@ end # this method is called when the callback is activated function (solution_callback::SaveSolutionCallback)(integrator) u_ode = integrator.u - @unpack t, dt = integrator - iter = integrator.stats.naccept semi = integrator.p - mesh, _, _, _ = mesh_equations_solver_cache(semi) + iter = integrator.stats.naccept @trixi_timeit timer() "I/O" begin - @trixi_timeit timer() "save mesh" if mesh.unsaved_changes - mesh.current_filename = save_mesh_file(mesh, - solution_callback.output_directory, - iter) - mesh.unsaved_changes = false - end - - element_variables = Dict{Symbol, Any}() - @trixi_timeit timer() "get element variables" begin - get_element_variables!(element_variables, u_ode, semi) - callbacks = integrator.opts.callback - if callbacks isa CallbackSet - for cb in callbacks.continuous_callbacks - get_element_variables!(element_variables, u_ode, semi, cb; - t = integrator.t, - iter = integrator.stats.naccept) - end - for cb in callbacks.discrete_callbacks - get_element_variables!(element_variables, u_ode, semi, cb; - t = integrator.t, - iter = integrator.stats.naccept) - end - end - end - - @trixi_timeit timer() "save solution" save_solution_file(u_ode, t, dt, iter, - semi, - solution_callback, - element_variables) + # Call high-level functions that dispatch on semidiscretization type + @trixi_timeit timer() "save mesh" save_mesh(semi, + solution_callback.output_directory, + iter) + save_solution_file(semi, u_ode, solution_callback, integrator) end # avoid re-evaluating possible FSAL stages @@ -216,13 +193,43 @@ function (solution_callback::SaveSolutionCallback)(integrator) return nothing end +@inline function save_solution_file(semi::AbstractSemidiscretization, u_ode, + solution_callback, + integrator; system = "") + @unpack t, dt = integrator + iter = integrator.stats.naccept + + element_variables = Dict{Symbol, Any}() + @trixi_timeit timer() "get element variables" begin + get_element_variables!(element_variables, u_ode, semi) + callbacks = integrator.opts.callback + if callbacks isa CallbackSet + for cb in callbacks.continuous_callbacks + get_element_variables!(element_variables, u_ode, semi, cb; + t = integrator.t, iter = iter) + end + for cb in callbacks.discrete_callbacks + get_element_variables!(element_variables, u_ode, semi, cb; + t = integrator.t, iter = iter) + end + end + end + + @trixi_timeit timer() "save solution" save_solution_file(u_ode, t, dt, iter, semi, + solution_callback, + element_variables, + system = system) +end + @inline function save_solution_file(u_ode, t, dt, iter, semi::AbstractSemidiscretization, solution_callback, - element_variables = Dict{Symbol, Any}()) + element_variables = Dict{Symbol, Any}(); + system = "") mesh, equations, solver, cache = mesh_equations_solver_cache(semi) u = wrap_array_native(u_ode, mesh, equations, solver, cache) save_solution_file(u, t, dt, iter, mesh, equations, solver, cache, - solution_callback, element_variables) + solution_callback, + element_variables; system = system) end # TODO: Taal refactor, move save_mesh_file? diff --git a/src/callbacks_step/stepsize.jl b/src/callbacks_step/stepsize.jl index 9e9f2d4885b..8b5cb958318 100644 --- a/src/callbacks_step/stepsize.jl +++ b/src/callbacks_step/stepsize.jl @@ -64,14 +64,11 @@ end t = integrator.t u_ode = integrator.u semi = integrator.p - mesh, equations, solver, cache = mesh_equations_solver_cache(semi) @unpack cfl_number = stepsize_callback - u = wrap_array(u_ode, mesh, equations, solver, cache) - dt = @trixi_timeit timer() "calculate dt" begin - cfl_number * max_dt(u, t, mesh, have_constant_speed(equations), equations, - solver, cache) - end + # Dispatch based on semidiscretization + dt = @trixi_timeit timer() "calculate dt" calculate_dt(u_ode, t, cfl_number, + semi) set_proposed_dt!(integrator, dt) integrator.opts.dtmax = dt @@ -83,6 +80,16 @@ end return nothing end +# General case for a single semidiscretization +function calculate_dt(u_ode, t, cfl_number, semi::AbstractSemidiscretization) + mesh, equations, solver, cache = mesh_equations_solver_cache(semi) + u = wrap_array(u_ode, mesh, equations, solver, cache) + + dt = cfl_number * max_dt(u, t, mesh, + have_constant_speed(equations), equations, + solver, cache) +end + # Time integration methods from the DiffEq ecosystem without adaptive time stepping on their own # such as `CarpenterKennedy2N54` require passing `dt=...` in `solve(ode, ...)`. Since we don't have # an integrator at this stage but only the ODE, this method will be used there. It's called in diff --git a/src/callbacks_step/summary.jl b/src/callbacks_step/summary.jl index a73b2a1913b..08e13d0b98d 100644 --- a/src/callbacks_step/summary.jl +++ b/src/callbacks_step/summary.jl @@ -152,15 +152,7 @@ function initialize_summary_callback(cb::DiscreteCallback, u, t, integrator) :indentation_level => 0) semi = integrator.p - show(io_context, MIME"text/plain"(), semi) - println(io, "\n") - mesh, equations, solver, _ = mesh_equations_solver_cache(semi) - show(io_context, MIME"text/plain"(), mesh) - println(io, "\n") - show(io_context, MIME"text/plain"(), equations) - println(io, "\n") - show(io_context, MIME"text/plain"(), solver) - println(io, "\n") + print_summary_semidiscretization(io_context, semi) callbacks = integrator.opts.callback if callbacks isa CallbackSet @@ -208,6 +200,18 @@ function initialize_summary_callback(cb::DiscreteCallback, u, t, integrator) return nothing end +function print_summary_semidiscretization(io::IO, semi::AbstractSemidiscretization) + show(io, MIME"text/plain"(), semi) + println(io, "\n") + mesh, equations, solver, _ = mesh_equations_solver_cache(semi) + show(io, MIME"text/plain"(), mesh) + println(io, "\n") + show(io, MIME"text/plain"(), equations) + println(io, "\n") + show(io, MIME"text/plain"(), solver) + println(io, "\n") +end + function (cb::DiscreteCallback{Condition, Affect!})(io::IO = stdout) where {Condition, Affect! <: typeof(summary_callback) diff --git a/src/meshes/mesh_io.jl b/src/meshes/mesh_io.jl index b9c462fa15a..ede85d80106 100644 --- a/src/meshes/mesh_io.jl +++ b/src/meshes/mesh_io.jl @@ -95,11 +95,15 @@ end # of the mesh, like its size and the type of boundary mapping function. # Then, within Trixi2Vtk, the StructuredMesh and its node coordinates are reconstructured from # these attributes for plotting purposes -function save_mesh_file(mesh::StructuredMesh, output_directory) +function save_mesh_file(mesh::StructuredMesh, output_directory; system = "") # Create output directory (if it does not exist) mkpath(output_directory) - filename = joinpath(output_directory, "mesh.h5") + if isempty(system) + filename = joinpath(output_directory, "mesh.h5") + else + filename = joinpath(output_directory, @sprintf("mesh_%s.h5", system)) + end # Open file (clobber existing content) h5open(filename, "w") do file diff --git a/src/semidiscretization/semidiscretization.jl b/src/semidiscretization/semidiscretization.jl index 8fef66d261e..ac312c57c89 100644 --- a/src/semidiscretization/semidiscretization.jl +++ b/src/semidiscretization/semidiscretization.jl @@ -76,7 +76,8 @@ function semidiscretize(semi::AbstractSemidiscretization, tspan) # mpi_isparallel() && MPI.Barrier(mpi_comm()) # See https://github.com/trixi-framework/Trixi.jl/issues/328 iip = true # is-inplace, i.e., we modify a vector when calling rhs! - return ODEProblem{iip}(rhs!, u0_ode, tspan, semi) + specialize = SciMLBase.FullSpecialize # specialize on rhs! and parameters (semi) + return ODEProblem{iip, specialize}(rhs!, u0_ode, tspan, semi) end """ @@ -93,7 +94,8 @@ function semidiscretize(semi::AbstractSemidiscretization, tspan, # mpi_isparallel() && MPI.Barrier(mpi_comm()) # See https://github.com/trixi-framework/Trixi.jl/issues/328 iip = true # is-inplace, i.e., we modify a vector when calling rhs! - return ODEProblem{iip}(rhs!, u0_ode, tspan, semi) + specialize = SciMLBase.FullSpecialize # specialize on rhs! and parameters (semi) + return ODEProblem{iip, specialize}(rhs!, u0_ode, tspan, semi) end """ diff --git a/src/semidiscretization/semidiscretization_coupled.jl b/src/semidiscretization/semidiscretization_coupled.jl new file mode 100644 index 00000000000..b7adff78425 --- /dev/null +++ b/src/semidiscretization/semidiscretization_coupled.jl @@ -0,0 +1,610 @@ +""" + SemidiscretizationCoupled + +A struct used to bundle multiple semidiscretizations. +[`semidiscretize`](@ref) will return an `ODEProblem` that synchronizes time steps between the semidiscretizations. +Each call of `rhs!` will call `rhs!` for each semidiscretization individually. +The semidiscretizations can be coupled by gluing meshes together using [`BoundaryConditionCoupled`](@ref). + +!!! warning "Experimental code" + This is an experimental feature and can change any time. +""" +struct SemidiscretizationCoupled{S, Indices, EquationList} <: AbstractSemidiscretization + semis::S + u_indices::Indices # u_ode[u_indices[i]] is the part of u_ode corresponding to semis[i] + performance_counter::PerformanceCounter +end + +""" + SemidiscretizationCoupled(semis...) + +Create a coupled semidiscretization that consists of the semidiscretizations passed as arguments. +""" +function SemidiscretizationCoupled(semis...) + @assert all(semi -> ndims(semi) == ndims(semis[1]), semis) "All semidiscretizations must have the same dimension!" + + # Number of coefficients for each semidiscretization + n_coefficients = zeros(Int, length(semis)) + for i in 1:length(semis) + _, equations, _, _ = mesh_equations_solver_cache(semis[i]) + n_coefficients[i] = ndofs(semis[i]) * nvariables(equations) + end + + # Compute range of coefficients associated with each semidiscretization and allocate coupled BCs + u_indices = Vector{UnitRange{Int}}(undef, length(semis)) + for i in 1:length(semis) + offset = sum(n_coefficients[1:(i - 1)]) + 1 + u_indices[i] = range(offset, length = n_coefficients[i]) + + allocate_coupled_boundary_conditions(semis[i]) + end + + performance_counter = PerformanceCounter() + + SemidiscretizationCoupled{typeof(semis), typeof(u_indices), typeof(performance_counter) + }(semis, u_indices, performance_counter) +end + +function Base.show(io::IO, semi::SemidiscretizationCoupled) + @nospecialize semi # reduce precompilation time + + print(io, "SemidiscretizationCoupled($(semi.semis))") +end + +function Base.show(io::IO, ::MIME"text/plain", semi::SemidiscretizationCoupled) + @nospecialize semi # reduce precompilation time + + if get(io, :compact, false) + show(io, semi) + else + summary_header(io, "SemidiscretizationCoupled") + summary_line(io, "#spatial dimensions", ndims(semi.semis[1])) + summary_line(io, "#systems", nsystems(semi)) + for i in eachsystem(semi) + summary_line(io, "system", i) + mesh, equations, solver, _ = mesh_equations_solver_cache(semi.semis[i]) + summary_line(increment_indent(io), "mesh", mesh |> typeof |> nameof) + summary_line(increment_indent(io), "equations", equations |> typeof |> nameof) + summary_line(increment_indent(io), "initial condition", + semi.semis[i].initial_condition) + # no boundary conditions since that could be too much + summary_line(increment_indent(io), "source terms", semi.semis[i].source_terms) + summary_line(increment_indent(io), "solver", solver |> typeof |> nameof) + end + summary_line(io, "total #DOFs", ndofs(semi)) + summary_footer(io) + end +end + +function print_summary_semidiscretization(io::IO, semi::SemidiscretizationCoupled) + show(io, MIME"text/plain"(), semi) + println(io, "\n") + for i in eachsystem(semi) + mesh, equations, solver, _ = mesh_equations_solver_cache(semi.semis[i]) + summary_header(io, "System #$i") + + summary_line(io, "mesh", mesh |> typeof |> nameof) + show(increment_indent(io), MIME"text/plain"(), mesh) + + summary_line(io, "equations", equations |> typeof |> nameof) + show(increment_indent(io), MIME"text/plain"(), equations) + + summary_line(io, "solver", solver |> typeof |> nameof) + show(increment_indent(io), MIME"text/plain"(), solver) + + summary_footer(io) + println(io, "\n") + end +end + +@inline Base.ndims(semi::SemidiscretizationCoupled) = ndims(semi.semis[1]) + +@inline nsystems(semi::SemidiscretizationCoupled) = length(semi.semis) + +@inline eachsystem(semi::SemidiscretizationCoupled) = Base.OneTo(nsystems(semi)) + +@inline Base.real(semi::SemidiscretizationCoupled) = promote_type(real.(semi.semis)...) + +@inline Base.eltype(semi::SemidiscretizationCoupled) = promote_type(eltype.(semi.semis)...) + +@inline function ndofs(semi::SemidiscretizationCoupled) + sum(ndofs, semi.semis) +end + +@inline function nelements(semi::SemidiscretizationCoupled) + return sum(semi.semis) do semi_ + mesh, equations, solver, cache = mesh_equations_solver_cache(semi_) + + nelements(mesh, solver, cache) + end +end + +function compute_coefficients(t, semi::SemidiscretizationCoupled) + @unpack u_indices = semi + + u_ode = Vector{real(semi)}(undef, u_indices[end][end]) + + for i in eachsystem(semi) + # Call `compute_coefficients` in `src/semidiscretization/semidiscretization.jl` + u_ode[u_indices[i]] .= compute_coefficients(t, semi.semis[i]) + end + + return u_ode +end + +@inline function get_system_u_ode(u_ode, index, semi::SemidiscretizationCoupled) + @view u_ode[semi.u_indices[index]] +end + +function rhs!(du_ode, u_ode, semi::SemidiscretizationCoupled, t) + @unpack u_indices = semi + + time_start = time_ns() + + @trixi_timeit timer() "copy to coupled boundaries" begin + for semi_ in semi.semis + copy_to_coupled_boundary!(semi_.boundary_conditions, u_ode, semi) + end + end + + # Call rhs! for each semidiscretization + for i in eachsystem(semi) + u_loc = get_system_u_ode(u_ode, i, semi) + du_loc = get_system_u_ode(du_ode, i, semi) + + @trixi_timeit timer() "system #$i" rhs!(du_loc, u_loc, semi.semis[i], t) + end + + runtime = time_ns() - time_start + put!(semi.performance_counter, runtime) + + return nothing +end + +################################################################################ +### AnalysisCallback +################################################################################ + +""" + AnalysisCallbackCoupled(semi, callbacks...) + +Combine multiple analysis callbacks for coupled simulations with a +[`SemidiscretizationCoupled`](@ref). For each coupled system, an indididual +[`AnalysisCallback`](@ref) **must** be created and passed to the `AnalysisCallbackCoupled` **in +order**, i.e., in the same sequence as the indidvidual semidiscretizations are stored in the +`SemidiscretizationCoupled`. + +!!! warning "Experimental code" + This is an experimental feature and can change any time. +""" +struct AnalysisCallbackCoupled{CB} + callbacks::CB +end + +function Base.show(io::IO, ::MIME"text/plain", + cb_coupled::DiscreteCallback{<:Any, <:AnalysisCallbackCoupled}) + @nospecialize cb_coupled # reduce precompilation time + + if get(io, :compact, false) + show(io, cb_coupled) + else + analysis_callback_coupled = cb_coupled.affect! + + summary_header(io, "AnalysisCallbackCoupled") + for (i, cb) in enumerate(analysis_callback_coupled.callbacks) + summary_line(io, "Callback #$i", "") + show(increment_indent(io), MIME"text/plain"(), cb) + end + summary_footer(io) + end +end + +# Convenience constructor for the coupled callback that gets called directly from the elixirs +function AnalysisCallbackCoupled(semi_coupled, callbacks...) + if length(callbacks) != nsystems(semi_coupled) + error("an AnalysisCallbackCoupled requires one AnalysisCallback for each semidiscretization") + end + + analysis_callback_coupled = AnalysisCallbackCoupled{typeof(callbacks)}(callbacks) + + # This callback is triggered if any of its subsidiary callbacks' condition is triggered + condition = (u, t, integrator) -> any(callbacks) do callback + callback.condition(u, t, integrator) + end + + DiscreteCallback(condition, analysis_callback_coupled, + save_positions = (false, false), + initialize = initialize!) +end + +# This method gets called during initialization from OrdinaryDiffEq's `solve(...)` +function initialize!(cb_coupled::DiscreteCallback{Condition, Affect!}, u_ode_coupled, t, + integrator) where {Condition, Affect! <: AnalysisCallbackCoupled} + analysis_callback_coupled = cb_coupled.affect! + semi_coupled = integrator.p + du_ode_coupled = first(get_tmp_cache(integrator)) + + # Loop over coupled systems' callbacks and initialize them individually + for i in eachsystem(semi_coupled) + cb = analysis_callback_coupled.callbacks[i] + semi = semi_coupled.semis[i] + u_ode = get_system_u_ode(u_ode_coupled, i, semi_coupled) + du_ode = get_system_u_ode(du_ode_coupled, i, semi_coupled) + initialize!(cb, u_ode, du_ode, t, integrator, semi) + end +end + +# This method gets called from OrdinaryDiffEq's `solve(...)` +function (analysis_callback_coupled::AnalysisCallbackCoupled)(integrator) + semi_coupled = integrator.p + u_ode_coupled = integrator.u + du_ode_coupled = first(get_tmp_cache(integrator)) + + # Loop over coupled systems' callbacks and call them individually + for i in eachsystem(semi_coupled) + @unpack condition = analysis_callback_coupled.callbacks[i] + analysis_callback = analysis_callback_coupled.callbacks[i].affect! + u_ode = get_system_u_ode(u_ode_coupled, i, semi_coupled) + + # Check condition and skip callback if it is not yet its turn + if !condition(u_ode, integrator.t, integrator) + continue + end + + semi = semi_coupled.semis[i] + du_ode = get_system_u_ode(du_ode_coupled, i, semi_coupled) + analysis_callback(u_ode, du_ode, integrator, semi) + end +end + +# used for error checks and EOC analysis +function (cb::DiscreteCallback{Condition, Affect!})(sol) where {Condition, + Affect! <: + AnalysisCallbackCoupled} + semi_coupled = sol.prob.p + u_ode_coupled = sol.u[end] + @unpack callbacks = cb.affect! + + uEltype = real(semi_coupled) + l2_error_collection = uEltype[] + linf_error_collection = uEltype[] + for i in eachsystem(semi_coupled) + analysis_callback = callbacks[i].affect! + @unpack analyzer = analysis_callback + cache_analysis = analysis_callback.cache + + semi = semi_coupled.semis[i] + u_ode = get_system_u_ode(u_ode_coupled, i, semi_coupled) + + l2_error, linf_error = calc_error_norms(u_ode, sol.t[end], analyzer, semi, + cache_analysis) + append!(l2_error_collection, l2_error) + append!(linf_error_collection, linf_error) + end + + (; l2 = l2_error_collection, linf = linf_error_collection) +end + +################################################################################ +### SaveSolutionCallback +################################################################################ + +# Save mesh for a coupled semidiscretization, which contains multiple meshes internally +function save_mesh(semi::SemidiscretizationCoupled, output_directory, timestep = 0) + for i in eachsystem(semi) + mesh, _, _, _ = mesh_equations_solver_cache(semi.semis[i]) + + if mesh.unsaved_changes + mesh.current_filename = save_mesh_file(mesh, output_directory, system = i) + mesh.unsaved_changes = false + end + end +end + +@inline function save_solution_file(semi::SemidiscretizationCoupled, u_ode, + solution_callback, + integrator) + @unpack semis = semi + + for i in eachsystem(semi) + u_ode_slice = get_system_u_ode(u_ode, i, semi) + save_solution_file(semis[i], u_ode_slice, solution_callback, integrator, system = i) + end +end + +################################################################################ +### StepsizeCallback +################################################################################ + +# In case of coupled system, use minimum timestep over all systems +function calculate_dt(u_ode, t, cfl_number, semi::SemidiscretizationCoupled) + dt = minimum(eachsystem(semi)) do i + u_ode_slice = get_system_u_ode(u_ode, i, semi) + calculate_dt(u_ode_slice, t, cfl_number, semi.semis[i]) + end + + return dt +end + +################################################################################ +### Equations +################################################################################ + +""" + BoundaryConditionCoupled(other_semi_index, indices, uEltype) + +Boundary condition to glue two meshes together. Solution values at the boundary +of another mesh will be used as boundary values. This requires the use +of [`SemidiscretizationCoupled`](@ref). The other mesh is specified by `other_semi_index`, +which is the index of the mesh in the tuple of semidiscretizations. + +Note that the elements and nodes of the two meshes at the coupled boundary must coincide. +This is currently only implemented for [`StructuredMesh`](@ref). + +# Arguments +- `other_semi_index`: the index in `SemidiscretizationCoupled` of the semidiscretization + from which the values are copied +- `indices::Tuple`: node/cell indices at the boundary of the mesh in the other + semidiscretization. See examples below. +- `uEltype::Type`: element type of solution + +# Examples +```julia +# Connect the left boundary of mesh 2 to our boundary such that our positive +# boundary direction will match the positive y direction of the other boundary +BoundaryConditionCoupled(2, (:begin, :i), Float64) + +# Connect the same two boundaries oppositely oriented +BoundaryConditionCoupled(2, (:begin, :i_backwards), Float64) + +# Using this as y_neg boundary will connect `our_cells[i, 1, j]` to `other_cells[j, end-i, end]` +BoundaryConditionCoupled(2, (:j, :i_backwards, :end), Float64) +``` + +!!! warning "Experimental code" + This is an experimental feature and can change any time. +""" +mutable struct BoundaryConditionCoupled{NDIMS, NDIMST2M1, uEltype <: Real, Indices} + # NDIMST2M1 == NDIMS * 2 - 1 + # Buffer for boundary values: [variable, nodes_i, nodes_j, cell_i, cell_j] + u_boundary :: Array{uEltype, NDIMST2M1} # NDIMS * 2 - 1 + other_semi_index :: Int + other_orientation :: Int + indices :: Indices + + function BoundaryConditionCoupled(other_semi_index, indices, uEltype) + NDIMS = length(indices) + u_boundary = Array{uEltype, NDIMS * 2 - 1}(undef, ntuple(_ -> 0, NDIMS * 2 - 1)) + + if indices[1] in (:begin, :end) + other_orientation = 1 + elseif indices[2] in (:begin, :end) + other_orientation = 2 + else # indices[3] in (:begin, :end) + other_orientation = 3 + end + + new{NDIMS, NDIMS * 2 - 1, uEltype, typeof(indices)}(u_boundary, other_semi_index, + other_orientation, indices) + end +end + +function Base.eltype(boundary_condition::BoundaryConditionCoupled) + eltype(boundary_condition.u_boundary) +end + +function (boundary_condition::BoundaryConditionCoupled)(u_inner, orientation, direction, + cell_indices, surface_node_indices, + surface_flux_function, equations) + # get_node_vars(boundary_condition.u_boundary, equations, solver, surface_node_indices..., cell_indices...), + # but we don't have a solver here + u_boundary = SVector(ntuple(v -> boundary_condition.u_boundary[v, + surface_node_indices..., + cell_indices...], + Val(nvariables(equations)))) + + # Calculate boundary flux + if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary + flux = surface_flux_function(u_inner, u_boundary, orientation, equations) + else # u_boundary is "left" of boundary, u_inner is "right" of boundary + flux = surface_flux_function(u_boundary, u_inner, orientation, equations) + end + + return flux +end + +function allocate_coupled_boundary_conditions(semi::AbstractSemidiscretization) + n_boundaries = 2 * ndims(semi) + mesh, equations, solver, _ = mesh_equations_solver_cache(semi) + + for direction in 1:n_boundaries + boundary_condition = semi.boundary_conditions[direction] + + allocate_coupled_boundary_condition(boundary_condition, direction, mesh, equations, + solver) + end +end + +# Don't do anything for other BCs than BoundaryConditionCoupled +function allocate_coupled_boundary_condition(boundary_condition, direction, mesh, equations, + solver) + return nothing +end + +# In 2D +function allocate_coupled_boundary_condition(boundary_condition::BoundaryConditionCoupled{2 + }, + direction, mesh, equations, dg::DGSEM) + if direction in (1, 2) + cell_size = size(mesh, 2) + else + cell_size = size(mesh, 1) + end + + uEltype = eltype(boundary_condition) + boundary_condition.u_boundary = Array{uEltype, 3}(undef, nvariables(equations), + nnodes(dg), + cell_size) +end + +# Don't do anything for other BCs than BoundaryConditionCoupled +function copy_to_coupled_boundary!(boundary_condition, u_ode, semi) + return nothing +end + +function copy_to_coupled_boundary!(boundary_conditions::Union{Tuple, NamedTuple}, u_ode, + semi) + for boundary_condition in boundary_conditions + copy_to_coupled_boundary!(boundary_condition, u_ode, semi) + end +end + +# In 2D +function copy_to_coupled_boundary!(boundary_condition::BoundaryConditionCoupled{2}, u_ode, + semi) + @unpack u_indices = semi + @unpack other_semi_index, other_orientation, indices = boundary_condition + + mesh, equations, solver, cache = mesh_equations_solver_cache(semi.semis[other_semi_index]) + u = wrap_array(get_system_u_ode(u_ode, other_semi_index, semi), mesh, equations, solver, + cache) + + linear_indices = LinearIndices(size(mesh)) + + if other_orientation == 1 + cells = axes(mesh, 2) + else # other_orientation == 2 + cells = axes(mesh, 1) + end + + # Copy solution data to the coupled boundary using "delayed indexing" with + # a start value and a step size to get the correct face and orientation. + node_index_range = eachnode(solver) + i_node_start, i_node_step = index_to_start_step_2d(indices[1], node_index_range) + j_node_start, j_node_step = index_to_start_step_2d(indices[2], node_index_range) + + i_cell_start, i_cell_step = index_to_start_step_2d(indices[1], axes(mesh, 1)) + j_cell_start, j_cell_step = index_to_start_step_2d(indices[2], axes(mesh, 2)) + + i_cell = i_cell_start + j_cell = j_cell_start + + for cell in cells + i_node = i_node_start + j_node = j_node_start + + for i in eachnode(solver) + for v in 1:size(u, 1) + boundary_condition.u_boundary[v, i, cell] = u[v, i_node, j_node, + linear_indices[i_cell, + j_cell]] + end + i_node += i_node_step + j_node += j_node_step + end + i_cell += i_cell_step + j_cell += j_cell_step + end +end + +################################################################################ +### DGSEM/structured +################################################################################ + +@inline function calc_boundary_flux_by_direction!(surface_flux_values, u, t, orientation, + boundary_condition::BoundaryConditionCoupled, + mesh::StructuredMesh, equations, + surface_integral, dg::DG, cache, + direction, node_indices, + surface_node_indices, element) + @unpack node_coordinates, contravariant_vectors, inverse_jacobian = cache.elements + @unpack surface_flux = surface_integral + + cell_indices = get_boundary_indices(element, orientation, mesh) + + u_inner = get_node_vars(u, equations, dg, node_indices..., element) + + # If the mapping is orientation-reversing, the contravariant vectors' orientation + # is reversed as well. The normal vector must be oriented in the direction + # from `left_element` to `right_element`, or the numerical flux will be computed + # incorrectly (downwind direction). + sign_jacobian = sign(inverse_jacobian[node_indices..., element]) + + # Contravariant vector Ja^i is the normal vector + normal = sign_jacobian * get_contravariant_vector(orientation, contravariant_vectors, + node_indices..., element) + + # If the mapping is orientation-reversing, the normal vector will be reversed (see above). + # However, the flux now has the wrong sign, since we need the physical flux in normal direction. + flux = sign_jacobian * boundary_condition(u_inner, normal, direction, cell_indices, + surface_node_indices, surface_flux, equations) + + for v in eachvariable(equations) + surface_flux_values[v, surface_node_indices..., direction, element] = flux[v] + end +end + +function get_boundary_indices(element, orientation, mesh::StructuredMesh{2}) + cartesian_indices = CartesianIndices(size(mesh)) + if orientation == 1 + # Get index of element in y-direction + cell_indices = (cartesian_indices[element][2],) + else # orientation == 2 + # Get index of element in x-direction + cell_indices = (cartesian_indices[element][1],) + end + + return cell_indices +end + +################################################################################ +### Special elixirs +################################################################################ + +# Analyze convergence for SemidiscretizationCoupled +function analyze_convergence(errors_coupled, iterations, + semi_coupled::SemidiscretizationCoupled) + # Extract errors: the errors are currently stored as + # | iter 1 sys 1 var 1...n | iter 1 sys 2 var 1...n | ... | iter 2 sys 1 var 1...n | ... + # but for calling `analyze_convergence` below, we need the following layout + # sys n: | iter 1 var 1...n | iter 1 var 1...n | ... | iter 2 var 1...n | ... + # That is, we need to extract and join the data for a single system + errors = Dict{Symbol, Vector{Float64}}[] + for i in eachsystem(semi_coupled) + push!(errors, Dict(:l2 => Float64[], :linf => Float64[])) + end + offset = 0 + for iter in 1:iterations, i in eachsystem(semi_coupled) + # Extract information on current semi + semi = semi_coupled.semis[i] + _, equations, _, _ = mesh_equations_solver_cache(semi) + variablenames = varnames(cons2cons, equations) + + # Compute offset + first = offset + 1 + last = offset + length(variablenames) + offset += length(variablenames) + + # Append errors to appropriate storage + append!(errors[i][:l2], errors_coupled[:l2][first:last]) + append!(errors[i][:linf], errors_coupled[:linf][first:last]) + end + + eoc_mean_values = Vector{Dict{Symbol, Any}}(undef, nsystems(semi_coupled)) + for i in eachsystem(semi_coupled) + # Use visual cues to separate output from multiple systems + println() + println("="^100) + println("# System $i") + println("="^100) + + # Extract information on current semi + semi = semi_coupled.semis[i] + _, equations, _, _ = mesh_equations_solver_cache(semi) + variablenames = varnames(cons2cons, equations) + + eoc_mean_values[i] = analyze_convergence(errors[i], iterations, variablenames) + end + + return eoc_mean_values +end diff --git a/src/semidiscretization/semidiscretization_euler_gravity.jl b/src/semidiscretization/semidiscretization_euler_gravity.jl index 665f2be9bfa..8fe9de1d2b2 100644 --- a/src/semidiscretization/semidiscretization_euler_gravity.jl +++ b/src/semidiscretization/semidiscretization_euler_gravity.jl @@ -477,18 +477,29 @@ end @inline function save_solution_file(u_ode, t, dt, iter, semi::SemidiscretizationEulerGravity, solution_callback, - element_variables = Dict{Symbol, Any}()) + element_variables = Dict{Symbol, Any}(); + system = "") + # If this is called already as part of a multi-system setup (i.e., system is non-empty), + # we build a combined system name + if !isempty(system) + system_euler = system * "_euler" + system_gravity = system * "_gravity" + else + system_euler = "euler" + system_gravity = "gravity" + end + u_euler = wrap_array_native(u_ode, semi.semi_euler) filename_euler = save_solution_file(u_euler, t, dt, iter, mesh_equations_solver_cache(semi.semi_euler)..., solution_callback, element_variables, - system = "euler") + system = system_euler) u_gravity = wrap_array_native(semi.cache.u_ode, semi.semi_gravity) filename_gravity = save_solution_file(u_gravity, t, dt, iter, mesh_equations_solver_cache(semi.semi_gravity)..., solution_callback, element_variables, - system = "gravity") + system = system_gravity) return filename_euler, filename_gravity end diff --git a/test/test_special_elixirs.jl b/test/test_special_elixirs.jl index 742a3abc376..23017059eaa 100644 --- a/test/test_special_elixirs.jl +++ b/test/test_special_elixirs.jl @@ -30,6 +30,12 @@ coverage = occursin("--code-coverage", cmd) && !occursin("--code-coverage=none", @test isapprox(mean_convergence[:l2], [4.0], rtol=0.05) end + @timed_testset "structured_2d_dgsem coupled" begin + mean_convergence = convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "structured_2d_dgsem", "elixir_advection_coupled.jl"), 3) + @test isapprox(mean_convergence[1][:l2], [4.0], rtol=0.05) + @test isapprox(mean_convergence[2][:l2], [4.0], rtol=0.05) + end + @timed_testset "p4est_2d_dgsem" begin # Run convergence test on unrefined mesh no_refine = @cfunction((p4est, which_tree, quadrant) -> Cint(0), Cint, (Ptr{Trixi.p4est_t}, Ptr{Trixi.p4est_topidx_t}, Ptr{Trixi.p4est_quadrant_t})) @@ -57,6 +63,7 @@ coverage = occursin("--code-coverage", cmd) && !occursin("--code-coverage=none", @test_nowarn_mod convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_2d_dgsem", "elixir_advection_basic.jl"), 2, tspan=(0.0, 0.01)) @test_nowarn_mod convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_2d_dgsem", "elixir_advection_extended.jl"), 2, initial_refinement_level=0, tspan=(0.0, 0.1)) @test_nowarn_mod convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "structured_2d_dgsem", "elixir_advection_basic.jl"), 2, tspan=(0.0, 0.01)) + @test_nowarn_mod convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "structured_2d_dgsem", "elixir_advection_coupled.jl"), 2, tspan=(0.0, 0.01)) @test_nowarn_mod convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "structured_2d_dgsem", "elixir_advection_extended.jl"), 2, cells_per_dimension=(1, 1), tspan=(0.0, 0.1)) end end diff --git a/test/test_structured_2d.jl b/test/test_structured_2d.jl index feaf66c4a7f..16fc72f0a46 100644 --- a/test/test_structured_2d.jl +++ b/test/test_structured_2d.jl @@ -19,6 +19,19 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [6.627000273229378e-5]) end + @trixi_testset "elixir_advection_coupled.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_coupled.jl"), + l2 = [7.816742843181738e-6, 7.816742843196112e-6], + linf = [6.314906965543265e-5, 6.314906965410039e-5], + coverage_override = (maxiters=10^5,)) + + @testset "analysis_callback(sol) for AnalysisCallbackCoupled" begin + errors = analysis_callback(sol) + @test errors.l2 ≈ [7.816742843181738e-6, 7.816742843196112e-6] rtol=1.0e-4 + @test errors.linf ≈ [6.314906965543265e-5, 6.314906965410039e-5] rtol=1.0e-4 + end + end + @trixi_testset "elixir_advection_extended.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), l2 = [4.220397559713772e-6], From deb027adefdd88fccf6cec5ce4ca5c76106a0439 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Jun 2023 22:53:10 +0200 Subject: [PATCH 002/263] Bump crate-ci/typos from 1.14.12 to 1.15.0 (#1524) * Bump crate-ci/typos from 1.14.12 to 1.15.0 Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.14.12 to 1.15.0. - [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.14.12...v1.15.0) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Fix typos --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Michael Schlottke-Lakemper --- .github/workflows/SpellCheck.yml | 2 +- docs/src/visualization.md | 2 +- examples/p4est_2d_dgsem/elixir_euler_supersonic_cylinder.jl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/SpellCheck.yml b/.github/workflows/SpellCheck.yml index c4ab3a98557..bc324c689bc 100644 --- a/.github/workflows/SpellCheck.yml +++ b/.github/workflows/SpellCheck.yml @@ -10,4 +10,4 @@ jobs: - name: Checkout Actions Repository uses: actions/checkout@v3 - name: Check spelling - uses: crate-ci/typos@v1.14.12 + uses: crate-ci/typos@v1.15.0 diff --git a/docs/src/visualization.md b/docs/src/visualization.md index e29313cc080..8f72bb4b1c6 100644 --- a/docs/src/visualization.md +++ b/docs/src/visualization.md @@ -339,7 +339,7 @@ create a [`PlotData1D`](@ref) with the keyword argument `curve` set to your list Let's give an example of this with the basic advection equation from above by creating a plot along the circle marked in green: -![2d-plot-along-cirlce](https://user-images.githubusercontent.com/72009492/130951042-e1849447-8e55-4798-9361-c8badb9f3a49.png) +![2d-plot-along-circle](https://user-images.githubusercontent.com/72009492/130951042-e1849447-8e55-4798-9361-c8badb9f3a49.png) We can write a function like this, that outputs a list of points on a circle: ```julia diff --git a/examples/p4est_2d_dgsem/elixir_euler_supersonic_cylinder.jl b/examples/p4est_2d_dgsem/elixir_euler_supersonic_cylinder.jl index 42370e861ce..366be700f9f 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_supersonic_cylinder.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_supersonic_cylinder.jl @@ -3,7 +3,7 @@ # Boundary conditions are supersonic Mach 3 inflow at the left portion of the domain # and supersonic outflow at the right portion of the domain. The top and bottom of the # channel as well as the cylinder are treated as Euler slip wall boundaries. -# This flow results in strong shock refletions / interactions as well as Kelvin-Helmholtz +# This flow results in strong shock reflections / interactions as well as Kelvin-Helmholtz # instabilities at later times as two Mach stems form above and below the cylinder. # # For complete details on the problem setup see Section 5.7 of the paper: From 642da1af9f9cc390f1d3d2a47a5fd07628a632f0 Mon Sep 17 00:00:00 2001 From: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Date: Mon, 19 Jun 2023 09:07:15 +0200 Subject: [PATCH 003/263] Use `Pointerwrapper`s in `P4estMesh` (#1434) * use PointerWrappers * fix typo * fix typo * fixes * fixes * fixes * unsafe_load_sc returns PointerWrapper * bug fixes * bug fixes * bug fixes * add comment about * rename unsafe_load_* to load_pointerwrapper_* * format * fix merge conflicts * fix bad format again * fix * add unsafe_wrap_sc again * fix * fix * Update src/auxiliary/p4est.jl Co-authored-by: Michael Schlottke-Lakemper * introduce generic type PointerOrWrapper{T} * format --------- Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Hendrik Ranocha --- src/auxiliary/p4est.jl | 94 +++++++----- src/callbacks_step/amr.jl | 30 ++-- src/callbacks_step/amr_dg.jl | 3 +- src/callbacks_step/analysis.jl | 2 +- src/meshes/p4est_mesh.jl | 117 +++++++------- src/solvers/dgsem_p4est/containers.jl | 122 +++++++-------- src/solvers/dgsem_p4est/containers_2d.jl | 2 +- src/solvers/dgsem_p4est/containers_3d.jl | 2 +- .../dgsem_p4est/containers_parallel.jl | 145 +++++++++--------- src/solvers/dgsem_p4est/dg_parallel.jl | 80 +++++----- 10 files changed, 311 insertions(+), 286 deletions(-) diff --git a/src/auxiliary/p4est.jl b/src/auxiliary/p4est.jl index 93b5166cd81..968af339cbd 100644 --- a/src/auxiliary/p4est.jl +++ b/src/auxiliary/p4est.jl @@ -24,35 +24,38 @@ function init_p4est() return nothing end +# for convenience to either pass a Ptr or a PointerWrapper +const PointerOrWrapper = Union{Ptr{T}, PointerWrapper{T}} where {T} + # Convert sc_array of type T to Julia array -function unsafe_wrap_sc(::Type{T}, sc_array::Ptr{sc_array}) where {T} - sc_array_obj = unsafe_load(sc_array) +function unsafe_wrap_sc(::Type{T}, sc_array_ptr::Ptr{sc_array}) where {T} + sc_array_obj = unsafe_load(sc_array_ptr) return unsafe_wrap_sc(T, sc_array_obj) end function unsafe_wrap_sc(::Type{T}, sc_array_obj::sc_array) where {T} elem_count = sc_array_obj.elem_count array = sc_array_obj.array - return unsafe_wrap(Array, Ptr{T}(array), elem_count) end -# Load the ith element (1-indexed) of an sc array of type T -function unsafe_load_sc(::Type{T}, sc_array::Ptr{sc_array}, i = 1) where {T} - sc_array_obj = unsafe_load(sc_array) - return unsafe_load_sc(T, sc_array_obj, i) -end +function unsafe_wrap_sc(::Type{T}, sc_array_pw::PointerWrapper{sc_array}) where {T} + elem_count = sc_array_pw.elem_count[] + array = sc_array_pw.array -function unsafe_load_sc(::Type{T}, sc_array_obj::sc_array, i = 1) where {T} - element_size = sc_array_obj.elem_size - @assert element_size == sizeof(T) + return unsafe_wrap(Array, Ptr{T}(pointer(array)), elem_count) +end - return unsafe_load(Ptr{T}(sc_array_obj.array), i) +# Load the ith element (1-indexed) of an sc array of type T as PointerWrapper +function load_pointerwrapper_sc(::Type{T}, sc_array::PointerWrapper{sc_array}, + i::Integer = 1) where {T} + return PointerWrapper(T, pointer(sc_array.array) + (i - 1) * sizeof(T)) end # Create new `p4est` from a p4est_connectivity # 2D -function new_p4est(connectivity::Ptr{p4est_connectivity_t}, initial_refinement_level) +function new_p4est(connectivity::PointerOrWrapper{p4est_connectivity_t}, + initial_refinement_level) comm = P4est.uses_mpi() ? mpi_comm() : 0 # Use Trixi.jl's MPI communicator if p4est supports MPI p4est_new_ext(comm, connectivity, @@ -65,7 +68,8 @@ function new_p4est(connectivity::Ptr{p4est_connectivity_t}, initial_refinement_l end # 3D -function new_p4est(connectivity::Ptr{p8est_connectivity_t}, initial_refinement_level) +function new_p4est(connectivity::PointerOrWrapper{p8est_connectivity_t}, + initial_refinement_level) comm = P4est.uses_mpi() ? mpi_comm() : 0 # Use Trixi.jl's MPI communicator if p4est supports MPI p8est_new_ext(comm, connectivity, 0, initial_refinement_level, true, 2 * sizeof(Int), C_NULL, C_NULL) @@ -73,13 +77,13 @@ end # Save `p4est` data to file # 2D -function save_p4est!(file, p4est::Ptr{p4est_t}) +function save_p4est!(file, p4est::PointerOrWrapper{p4est_t}) # Don't save user data of the quads p4est_save(file, p4est, false) end # 3D -function save_p4est!(file, p8est::Ptr{p8est_t}) +function save_p4est!(file, p8est::PointerOrWrapper{p8est_t}) # Don't save user data of the quads p8est_save(file, p8est, false) end @@ -107,27 +111,33 @@ read_inp_p4est(meshfile, ::Val{3}) = p8est_connectivity_read_inp(meshfile) # Refine `p4est` if refine_fn_c returns 1 # 2D -function refine_p4est!(p4est::Ptr{p4est_t}, recursive, refine_fn_c, init_fn_c) +function refine_p4est!(p4est::PointerOrWrapper{p4est_t}, recursive, refine_fn_c, + init_fn_c) p4est_refine(p4est, recursive, refine_fn_c, init_fn_c) end # 3D -function refine_p4est!(p8est::Ptr{p8est_t}, recursive, refine_fn_c, init_fn_c) +function refine_p4est!(p8est::PointerOrWrapper{p8est_t}, recursive, refine_fn_c, + init_fn_c) p8est_refine(p8est, recursive, refine_fn_c, init_fn_c) end # Refine `p4est` if coarsen_fn_c returns 1 # 2D -function coarsen_p4est!(p4est::Ptr{p4est_t}, recursive, coarsen_fn_c, init_fn_c) +function coarsen_p4est!(p4est::PointerOrWrapper{p4est_t}, recursive, coarsen_fn_c, + init_fn_c) p4est_coarsen(p4est, recursive, coarsen_fn_c, init_fn_c) end # 3D -function coarsen_p4est!(p8est::Ptr{p8est_t}, recursive, coarsen_fn_c, init_fn_c) +function coarsen_p4est!(p8est::PointerOrWrapper{p8est_t}, recursive, coarsen_fn_c, + init_fn_c) p8est_coarsen(p8est, recursive, coarsen_fn_c, init_fn_c) end # Create new ghost layer from p4est, only connections via faces are relevant # 2D -ghost_new_p4est(p4est::Ptr{p4est_t}) = p4est_ghost_new(p4est, P4est.P4EST_CONNECT_FACE) +function ghost_new_p4est(p4est::PointerOrWrapper{p4est_t}) + p4est_ghost_new(p4est, P4est.P4EST_CONNECT_FACE) +end # 3D # In 3D it is not sufficient to use `P8EST_CONNECT_FACE`. Consider the neighbor elements of a mortar # in 3D. We have to determine which MPI ranks are involved in this mortar. @@ -147,28 +157,37 @@ ghost_new_p4est(p4est::Ptr{p4est_t}) = p4est_ghost_new(p4est, P4est.P4EST_CONNEC # `P8EST_CONNECT_FACE`. But if it is not in the ghost layer, it will not be available in # `iterate_p4est` and thus we cannot determine its MPI rank # (see https://github.com/cburstedde/p4est/blob/439bc9aae849555256ddfe4b03d1f9fe8d18ff0e/src/p8est_iterate.h#L66-L72). -ghost_new_p4est(p8est::Ptr{p8est_t}) = p8est_ghost_new(p8est, P4est.P8EST_CONNECT_FULL) +function ghost_new_p4est(p8est::PointerOrWrapper{p8est_t}) + p8est_ghost_new(p8est, P4est.P8EST_CONNECT_FULL) +end # Check if ghost layer is valid # 2D -function ghost_is_valid_p4est(p4est::Ptr{p4est_t}, ghost_layer::Ptr{p4est_ghost_t}) +function ghost_is_valid_p4est(p4est::PointerOrWrapper{p4est_t}, + ghost_layer::Ptr{p4est_ghost_t}) return p4est_ghost_is_valid(p4est, ghost_layer) end # 3D -function ghost_is_valid_p4est(p4est::Ptr{p8est_t}, ghost_layer::Ptr{p8est_ghost_t}) +function ghost_is_valid_p4est(p4est::PointerOrWrapper{p8est_t}, + ghost_layer::Ptr{p8est_ghost_t}) return p8est_ghost_is_valid(p4est, ghost_layer) end # Destroy ghost layer # 2D -ghost_destroy_p4est(ghost_layer::Ptr{p4est_ghost_t}) = p4est_ghost_destroy(ghost_layer) +function ghost_destroy_p4est(ghost_layer::PointerOrWrapper{p4est_ghost_t}) + p4est_ghost_destroy(ghost_layer) +end # 3D -ghost_destroy_p4est(ghost_layer::Ptr{p8est_ghost_t}) = p8est_ghost_destroy(ghost_layer) +function ghost_destroy_p4est(ghost_layer::PointerOrWrapper{p8est_ghost_t}) + p8est_ghost_destroy(ghost_layer) +end # Let `p4est` iterate over each cell volume and cell face. # Call iter_volume_c for each cell and iter_face_c for each face. # 2D -function iterate_p4est(p4est::Ptr{p4est_t}, user_data; ghost_layer = C_NULL, +function iterate_p4est(p4est::PointerOrWrapper{p4est_t}, user_data; + ghost_layer = C_NULL, iter_volume_c = C_NULL, iter_face_c = C_NULL) if user_data === C_NULL user_data_ptr = user_data @@ -191,7 +210,8 @@ function iterate_p4est(p4est::Ptr{p4est_t}, user_data; ghost_layer = C_NULL, end # 3D -function iterate_p4est(p8est::Ptr{p8est_t}, user_data; ghost_layer = C_NULL, +function iterate_p4est(p8est::PointerOrWrapper{p8est_t}, user_data; + ghost_layer = C_NULL, iter_volume_c = C_NULL, iter_face_c = C_NULL) if user_data === C_NULL user_data_ptr = user_data @@ -216,23 +236,25 @@ end # Load i-th element of the sc_array info.sides of the type p[48]est_iter_face_side_t # 2D version -function unsafe_load_side(info::Ptr{p4est_iter_face_info_t}, i = 1) - return unsafe_load_sc(p4est_iter_face_side_t, unsafe_load(info).sides, i) +function load_pointerwrapper_side(info::PointerWrapper{p4est_iter_face_info_t}, + i::Integer = 1) + return load_pointerwrapper_sc(p4est_iter_face_side_t, info.sides, i) end # 3D version -function unsafe_load_side(info::Ptr{p8est_iter_face_info_t}, i = 1) - return unsafe_load_sc(p8est_iter_face_side_t, unsafe_load(info).sides, i) +function load_pointerwrapper_side(info::PointerWrapper{p8est_iter_face_info_t}, + i::Integer = 1) + return load_pointerwrapper_sc(p8est_iter_face_side_t, info.sides, i) end # Load i-th element of the sc_array p4est.trees of the type p[48]est_tree_t # 2D version -function unsafe_load_tree(p4est::Ptr{p4est_t}, i = 1) - return unsafe_load_sc(p4est_tree_t, unsafe_load(p4est).trees, i) +function load_pointerwrapper_tree(p4est::PointerWrapper{p4est_t}, i::Integer = 1) + return load_pointerwrapper_sc(p4est_tree_t, p4est.trees, i) end # 3D version -function unsafe_load_tree(p8est::Ptr{p8est_t}, i = 1) - return unsafe_load_sc(p8est_tree_t, unsafe_load(p8est).trees, i) +function load_pointerwrapper_tree(p8est::PointerWrapper{p8est_t}, i::Integer = 1) + return load_pointerwrapper_sc(p8est_tree_t, p8est.trees, i) end end # @muladd diff --git a/src/callbacks_step/amr.jl b/src/callbacks_step/amr.jl index d6e19b79886..bef49b4c482 100644 --- a/src/callbacks_step/amr.jl +++ b/src/callbacks_step/amr.jl @@ -348,24 +348,24 @@ end # Copy controller values to quad user data storage, will be called below function copy_to_quad_iter_volume(info, user_data) - info_obj = unsafe_load(info) + info_pw = PointerWrapper(info) # Load tree from global trees array, one-based indexing - tree = unsafe_load_tree(info_obj.p4est, info_obj.treeid + 1) + tree_pw = load_pointerwrapper_tree(info_pw.p4est, info_pw.treeid[] + 1) # Quadrant numbering offset of this quadrant - offset = tree.quadrants_offset + offset = tree_pw.quadrants_offset[] # Global quad ID - quad_id = offset + info_obj.quadid + quad_id = offset + info_pw.quadid[] # Access user_data = lambda - user_data_ptr = Ptr{Int}(user_data) + user_data_pw = PointerWrapper(Int, user_data) # Load controller_value = lambda[quad_id + 1] - controller_value = unsafe_load(user_data_ptr, quad_id + 1) + controller_value = user_data_pw[quad_id + 1] # Access quadrant's user data ([global quad ID, controller_value]) - quad_data_ptr = Ptr{Int}(unsafe_load(info_obj.quad.p.user_data)) + quad_data_pw = PointerWrapper(Int, info_pw.quad.p.user_data[]) # Save controller value to quadrant's user data. - unsafe_store!(quad_data_ptr, controller_value, 2) + quad_data_pw[2] = controller_value return nothing end @@ -599,22 +599,22 @@ function current_element_levels(mesh::TreeMesh, solver, cache) end function extract_levels_iter_volume(info, user_data) - info_obj = unsafe_load(info) + info_pw = PointerWrapper(info) # Load tree from global trees array, one-based indexing - tree = unsafe_load_tree(info_obj.p4est, info_obj.treeid + 1) + tree_pw = load_pointerwrapper_tree(info_pw.p4est, info_pw.treeid[] + 1) # Quadrant numbering offset of this quadrant - offset = tree.quadrants_offset + offset = tree_pw.quadrants_offset[] # Global quad ID - quad_id = offset + info_obj.quadid + quad_id = offset + info_pw.quadid[] # Julia element ID element_id = quad_id + 1 - current_level = unsafe_load(info_obj.quad.level) + current_level = info_pw.quad.level[] # Unpack user_data = current_levels and save current element level - ptr = Ptr{Int}(user_data) - unsafe_store!(ptr, current_level, element_id) + pw = PointerWrapper(Int, user_data) + pw[element_id] = current_level return nothing end diff --git a/src/callbacks_step/amr_dg.jl b/src/callbacks_step/amr_dg.jl index 19bbebd9254..1dcfdccdea8 100644 --- a/src/callbacks_step/amr_dg.jl +++ b/src/callbacks_step/amr_dg.jl @@ -9,8 +9,7 @@ function rebalance_solver!(u_ode::AbstractVector, mesh::ParallelP4estMesh, equations, dg::DGSEM, cache, old_global_first_quadrant) # mpi ranks are 0-based, this array uses 1-based indices - global_first_quadrant = unsafe_wrap(Array, - unsafe_load(mesh.p4est).global_first_quadrant, + global_first_quadrant = unsafe_wrap(Array, mesh.p4est.global_first_quadrant, mpi_nranks() + 1) if global_first_quadrant[mpi_rank() + 1] == old_global_first_quadrant[mpi_rank() + 1] && diff --git a/src/callbacks_step/analysis.jl b/src/callbacks_step/analysis.jl index 7fa2e21a244..8cf43a1d15e 100644 --- a/src/callbacks_step/analysis.jl +++ b/src/callbacks_step/analysis.jl @@ -508,7 +508,7 @@ function print_amr_information(callbacks, mesh::P4estMesh, solver, cache) elements_per_level = zeros(P4EST_MAXLEVEL + 1) - for tree in unsafe_wrap_sc(p4est_tree_t, unsafe_load(mesh.p4est).trees) + for tree in unsafe_wrap_sc(p4est_tree_t, mesh.p4est.trees) elements_per_level .+= tree.quadrants_per_level end diff --git a/src/meshes/p4est_mesh.jl b/src/meshes/p4est_mesh.jl index ddd6cf473e4..60db285e04f 100644 --- a/src/meshes/p4est_mesh.jl +++ b/src/meshes/p4est_mesh.jl @@ -13,9 +13,9 @@ to manage trees and mesh refinement. """ mutable struct P4estMesh{NDIMS, RealT <: Real, IsParallel, P, Ghost, NDIMSP2, NNODES} <: AbstractMesh{NDIMS} - p4est::P # Either Ptr{p4est_t} or Ptr{p8est_t} - is_parallel::IsParallel - ghost::Ghost # Either Ptr{p4est_ghost_t} or Ptr{p8est_ghost_t} + p4est :: P # Either PointerWrapper{p4est_t} or PointerWrapper{p8est_t} + is_parallel :: IsParallel + ghost :: Ghost # Either PointerWrapper{p4est_ghost_t} or PointerWrapper{p8est_ghost_t} # Coordinates at the nodes specified by the tensor product of `nodes` (NDIMS times). # This specifies the geometry interpolation for each tree. tree_node_coordinates::Array{RealT, NDIMSP2} # [dimension, i, j, k, tree] @@ -43,18 +43,21 @@ mutable struct P4estMesh{NDIMS, RealT <: Real, IsParallel, P, Ghost, NDIMSP2, NN is_parallel = False() end + p4est_pw = PointerWrapper(p4est) + ghost = ghost_new_p4est(p4est) + ghost_pw = PointerWrapper(ghost) mesh = new{NDIMS, eltype(tree_node_coordinates), typeof(is_parallel), - typeof(p4est), typeof(ghost), NDIMS + 2, length(nodes)}(p4est, - is_parallel, - ghost, - tree_node_coordinates, - nodes, - boundary_names, - current_filename, - unsaved_changes, - p4est_partition_allow_for_coarsening) + typeof(p4est_pw), typeof(ghost_pw), NDIMS + 2, length(nodes)}(p4est_pw, + is_parallel, + ghost_pw, + tree_node_coordinates, + nodes, + boundary_names, + current_filename, + unsaved_changes, + p4est_partition_allow_for_coarsening) # Destroy `p4est` structs when the mesh is garbage collected finalizer(destroy_mesh, mesh) @@ -70,14 +73,14 @@ const ParallelP4estMesh{NDIMS} = P4estMesh{NDIMS, <:Real, <:True} @inline mpi_parallel(mesh::ParallelP4estMesh) = True() function destroy_mesh(mesh::P4estMesh{2}) - connectivity = unsafe_load(mesh.p4est).connectivity + connectivity = mesh.p4est.connectivity p4est_ghost_destroy(mesh.ghost) p4est_destroy(mesh.p4est) p4est_connectivity_destroy(connectivity) end function destroy_mesh(mesh::P4estMesh{3}) - connectivity = unsafe_load(mesh.p4est).connectivity + connectivity = mesh.p4est.connectivity p8est_ghost_destroy(mesh.ghost) p8est_destroy(mesh.p4est) p8est_connectivity_destroy(connectivity) @@ -87,11 +90,10 @@ end @inline Base.real(::P4estMesh{NDIMS, RealT}) where {NDIMS, RealT} = RealT @inline function ntrees(mesh::P4estMesh) - trees = unsafe_load(mesh.p4est).trees - return unsafe_load(trees).elem_count + return mesh.p4est.trees.elem_count[] end # returns Int32 by default which causes a weird method error when creating the cache -@inline ncells(mesh::P4estMesh) = Int(unsafe_load(mesh.p4est).local_num_quadrants) +@inline ncells(mesh::P4estMesh) = Int(mesh.p4est.local_num_quadrants[]) function Base.show(io::IO, mesh::P4estMesh) print(io, "P4estMesh{", ndims(mesh), ", ", real(mesh), "}") @@ -387,14 +389,14 @@ function p4est_mesh_from_hohqmesh_abaqus(meshfile, initial_refinement_level, n_dimensions, RealT) # Create the mesh connectivity using `p4est` connectivity = read_inp_p4est(meshfile, Val(n_dimensions)) - connectivity_obj = unsafe_load(connectivity) + connectivity_pw = PointerWrapper(connectivity) # These need to be of the type Int for unsafe_wrap below to work - n_trees::Int = connectivity_obj.num_trees - n_vertices::Int = connectivity_obj.num_vertices + n_trees::Int = connectivity_pw.num_trees[] + n_vertices::Int = connectivity_pw.num_vertices[] # Extract a copy of the element vertices to compute the tree node coordinates - vertices = unsafe_wrap(Array, connectivity_obj.vertices, (3, n_vertices)) + vertices = unsafe_wrap(Array, connectivity_pw.vertices, (3, n_vertices)) # Readin all the information from the mesh file into a string array file_lines = readlines(open(meshfile)) @@ -445,14 +447,14 @@ function p4est_mesh_from_standard_abaqus(meshfile, mapping, polydeg, initial_refinement_level, n_dimensions, RealT) # Create the mesh connectivity using `p4est` connectivity = read_inp_p4est(meshfile, Val(n_dimensions)) - connectivity_obj = unsafe_load(connectivity) + connectivity_pw = PointerWrapper(connectivity) # These need to be of the type Int for unsafe_wrap below to work - n_trees::Int = connectivity_obj.num_trees - n_vertices::Int = connectivity_obj.num_vertices + n_trees::Int = connectivity_pw.num_trees[] + n_vertices::Int = connectivity_pw.num_vertices[] - vertices = unsafe_wrap(Array, connectivity_obj.vertices, (3, n_vertices)) - tree_to_vertex = unsafe_wrap(Array, connectivity_obj.tree_to_vertex, + vertices = unsafe_wrap(Array, connectivity_pw.vertices, (3, n_vertices)) + tree_to_vertex = unsafe_wrap(Array, connectivity_pw.tree_to_vertex, (2^n_dimensions, n_trees)) basis = LobattoLegendreBasis(RealT, polydeg) @@ -1511,17 +1513,18 @@ end function update_ghost_layer!(mesh::P4estMesh) ghost_destroy_p4est(mesh.ghost) - mesh.ghost = ghost_new_p4est(mesh.p4est) + mesh.ghost = PointerWrapper(ghost_new_p4est(mesh.p4est)) end function init_fn(p4est, which_tree, quadrant) # Unpack quadrant's user data ([global quad ID, controller_value]) - ptr = Ptr{Int}(unsafe_load(quadrant.p.user_data)) + # Use `unsafe_load` here since `quadrant.p.user_data isa Ptr{Ptr{Nothing}}` + # and we only need the first (only!) entry + pw = PointerWrapper(Int, unsafe_load(quadrant.p.user_data)) # Initialize quad ID as -1 and controller_value as 0 (don't refine or coarsen) - unsafe_store!(ptr, -1, 1) - unsafe_store!(ptr, 0, 2) - + pw[1] = -1 + pw[2] = 0 return nothing end @@ -1539,8 +1542,10 @@ end function refine_fn(p4est, which_tree, quadrant) # Controller value has been copied to the quadrant's user data storage before. # Unpack quadrant's user data ([global quad ID, controller_value]). - ptr = Ptr{Int}(unsafe_load(quadrant.p.user_data)) - controller_value = unsafe_load(ptr, 2) + # Use `unsafe_load` here since `quadrant.p.user_data isa Ptr{Ptr{Nothing}}` + # and we only need the first (only!) entry + pw = PointerWrapper(Int, unsafe_load(quadrant.p.user_data)) + controller_value = pw[2] if controller_value > 0 # return true (refine) @@ -1586,9 +1591,9 @@ function coarsen_fn(p4est, which_tree, quadrants_ptr) # Controller value has been copied to the quadrant's user data storage before. # Load controller value from quadrant's user data ([global quad ID, controller_value]). - function controller_value(i) - unsafe_load(Ptr{Int}(unsafe_load(quadrants[i].p.user_data)), 2) - end + # Use `unsafe_load` here since `quadrant.p.user_data isa Ptr{Ptr{Nothing}}` + # and we only need the first (only!) entry + controller_value(i) = PointerWrapper(Int, unsafe_load(quadrants[i].p.user_data))[2] # `p4est` calls this function for each 2^ndims quads that could be coarsened to a single one. # Only coarsen if all these 2^ndims quads have been marked for coarsening. @@ -1671,20 +1676,19 @@ end # Copy global quad ID to quad's user data storage, will be called below function save_original_id_iter_volume(info, user_data) - info_obj = unsafe_load(info) + info_pw = PointerWrapper(info) # Load tree from global trees array, one-based indexing - tree = unsafe_load_tree(info_obj.p4est, info_obj.treeid + 1) + tree_pw = load_pointerwrapper_tree(info_pw.p4est, info_pw.treeid[] + 1) # Quadrant numbering offset of this quadrant - offset = tree.quadrants_offset + offset = tree_pw.quadrants_offset[] # Global quad ID - quad_id = offset + info_obj.quadid + quad_id = offset + info_pw.quadid[] # Unpack quadrant's user data ([global quad ID, controller_value]) - ptr = Ptr{Int}(unsafe_load(info_obj.quad.p.user_data)) + pw = PointerWrapper(Int, info_pw.quad.p.user_data[]) # Save global quad ID - unsafe_store!(ptr, quad_id, 1) - + pw[1] = quad_id return nothing end @@ -1708,24 +1712,23 @@ end # Extract information about which cells have been changed function collect_changed_iter_volume(info, user_data) - info_obj = unsafe_load(info) + info_pw = PointerWrapper(info) # The original element ID has been saved to user_data before. # Load original quad ID from quad's user data ([global quad ID, controller_value]). - quad_data_ptr = Ptr{Int}(unsafe_load(info_obj.quad.p.user_data)) - original_id = unsafe_load(quad_data_ptr, 1) + quad_data_pw = PointerWrapper(Int, info_pw.quad.p.user_data[]) + original_id = quad_data_pw[1] # original_id of cells that have been newly created is -1 if original_id >= 0 # Unpack user_data = original_cells - user_data_ptr = Ptr{Int}(user_data) + user_data_pw = PointerWrapper(Int, user_data) # If quad has an original_id, it existed before refinement/coarsening, # and therefore wasn't changed. # Mark original_id as "not changed during refinement/coarsening" in original_cells - unsafe_store!(user_data_ptr, 0, original_id + 1) + user_data_pw[original_id + 1] = 0 end - return nothing end @@ -1756,29 +1759,27 @@ end # Extract newly created cells function collect_new_iter_volume(info, user_data) - info_obj = unsafe_load(info) + info_pw = PointerWrapper(info) # The original element ID has been saved to user_data before. # Unpack quadrant's user data ([global quad ID, controller_value]). - quad_data_ptr = Ptr{Int}(unsafe_load(info_obj.quad.p.user_data)) - original_id = unsafe_load(quad_data_ptr, 1) + original_id = PointerWrapper(Int, info_pw.quad.p.user_data[])[1] # original_id of cells that have been newly created is -1 if original_id < 0 # Load tree from global trees array, one-based indexing - tree = unsafe_load_tree(info_obj.p4est, info_obj.treeid + 1) + tree_pw = load_pointerwrapper_tree(info_pw.p4est, info_pw.treeid[] + 1) # Quadrant numbering offset of this quadrant - offset = tree.quadrants_offset + offset = tree_pw.quadrants_offset[] # Global quad ID - quad_id = offset + info_obj.quadid + quad_id = offset + info_pw.quadid[] # Unpack user_data = original_cells - user_data_ptr = Ptr{Int}(user_data) + user_data_pw = PointerWrapper(Int, user_data) # Mark cell as "newly created during refinement/coarsening/balancing" - unsafe_store!(user_data_ptr, 1, quad_id + 1) + user_data_pw[quad_id + 1] = 1 end - return nothing end diff --git a/src/solvers/dgsem_p4est/containers.jl b/src/solvers/dgsem_p4est/containers.jl index 9b87de777a6..2b9c6987d24 100644 --- a/src/solvers/dgsem_p4est/containers.jl +++ b/src/solvers/dgsem_p4est/containers.jl @@ -276,18 +276,18 @@ function init_boundaries!(boundaries, mesh::P4estMesh) end # Function barrier for type stability -function init_boundaries_iter_face_inner(info, boundaries, boundary_id, mesh) +function init_boundaries_iter_face_inner(info_pw, boundaries, boundary_id, mesh) # Extract boundary data - side = unsafe_load_side(info) + side_pw = load_pointerwrapper_side(info_pw) # Get local tree, one-based indexing - tree = unsafe_load_tree(mesh.p4est, side.treeid + 1) + tree_pw = load_pointerwrapper_tree(mesh.p4est, side_pw.treeid[] + 1) # Quadrant numbering offset of this quadrant - offset = tree.quadrants_offset + offset = tree_pw.quadrants_offset[] # Verify before accessing is.full, but this should never happen - @assert side.is_hanging == false + @assert side_pw.is_hanging[] == false - local_quad_id = side.is.full.quadid + local_quad_id = side_pw.is.full.quadid[] # Global ID of this quad quad_id = offset + local_quad_id @@ -296,13 +296,13 @@ function init_boundaries_iter_face_inner(info, boundaries, boundary_id, mesh) boundaries.neighbor_ids[boundary_id] = quad_id + 1 # Face at which the boundary lies - face = side.face + face = side_pw.face[] # Save boundaries.node_indices dimension specific in containers_[23]d.jl init_boundary_node_indices!(boundaries, face, boundary_id) # One-based indexing - boundaries.name[boundary_id] = mesh.boundary_names[face + 1, side.treeid + 1] + boundaries.name[boundary_id] = mesh.boundary_names[face + 1, side_pw.treeid[] + 1] return nothing end @@ -479,32 +479,33 @@ end # Function barrier for type stability function init_surfaces_iter_face_inner(info, user_data) @unpack interfaces, mortars, boundaries = user_data - elem_count = unsafe_load(info).sides.elem_count + info_pw = PointerWrapper(info) + elem_count = info_pw.sides.elem_count[] if elem_count == 2 # Two neighboring elements => Interface or mortar # Extract surface data - sides = (unsafe_load_side(info, 1), unsafe_load_side(info, 2)) + sides_pw = (load_pointerwrapper_side(info_pw, 1), + load_pointerwrapper_side(info_pw, 2)) - if sides[1].is_hanging == false && sides[2].is_hanging == false + if sides_pw[1].is_hanging[] == false && sides_pw[2].is_hanging[] == false # No hanging nodes => normal interface if interfaces !== nothing - init_interfaces_iter_face_inner(info, sides, user_data) + init_interfaces_iter_face_inner(info_pw, sides_pw, user_data) end else # Hanging nodes => mortar if mortars !== nothing - init_mortars_iter_face_inner(info, sides, user_data) + init_mortars_iter_face_inner(info_pw, sides_pw, user_data) end end elseif elem_count == 1 # One neighboring elements => boundary if boundaries !== nothing - init_boundaries_iter_face_inner(info, user_data) + init_boundaries_iter_face_inner(info_pw, user_data) end end - return nothing end @@ -519,18 +520,18 @@ function init_surfaces!(interfaces, mortars, boundaries, mesh::P4estMesh) end # Initialization of interfaces after the function barrier -function init_interfaces_iter_face_inner(info, sides, user_data) +function init_interfaces_iter_face_inner(info_pw, sides_pw, user_data) @unpack interfaces, interface_id, mesh = user_data user_data.interface_id += 1 # Get Tuple of local trees, one-based indexing - trees = (unsafe_load_tree(mesh.p4est, sides[1].treeid + 1), - unsafe_load_tree(mesh.p4est, sides[2].treeid + 1)) + trees_pw = (load_pointerwrapper_tree(mesh.p4est, sides_pw[1].treeid[] + 1), + load_pointerwrapper_tree(mesh.p4est, sides_pw[2].treeid[] + 1)) # Quadrant numbering offsets of the quadrants at this interface - offsets = SVector(trees[1].quadrants_offset, - trees[2].quadrants_offset) + offsets = SVector(trees_pw[1].quadrants_offset[], + trees_pw[2].quadrants_offset[]) - local_quad_ids = SVector(sides[1].is.full.quadid, sides[2].is.full.quadid) + local_quad_ids = SVector(sides_pw[1].is.full.quadid[], sides_pw[2].is.full.quadid[]) # Global IDs of the neighboring quads quad_ids = offsets + local_quad_ids @@ -540,31 +541,30 @@ function init_interfaces_iter_face_inner(info, sides, user_data) interfaces.neighbor_ids[2, interface_id] = quad_ids[2] + 1 # Face at which the interface lies - faces = (sides[1].face, sides[2].face) + faces = (sides_pw[1].face[], sides_pw[2].face[]) # Save interfaces.node_indices dimension specific in containers_[23]d.jl - init_interface_node_indices!(interfaces, faces, - unsafe_load(info).orientation, interface_id) + init_interface_node_indices!(interfaces, faces, info_pw.orientation[], interface_id) return nothing end # Initialization of boundaries after the function barrier -function init_boundaries_iter_face_inner(info, user_data) +function init_boundaries_iter_face_inner(info_pw, user_data) @unpack boundaries, boundary_id, mesh = user_data user_data.boundary_id += 1 # Extract boundary data - side = unsafe_load_side(info) + side_pw = load_pointerwrapper_side(info_pw) # Get local tree, one-based indexing - tree = unsafe_load_tree(mesh.p4est, side.treeid + 1) + tree_pw = load_pointerwrapper_tree(mesh.p4est, side_pw.treeid[] + 1) # Quadrant numbering offset of this quadrant - offset = tree.quadrants_offset + offset = tree_pw.quadrants_offset[] # Verify before accessing is.full, but this should never happen - @assert side.is_hanging == false + @assert side_pw.is_hanging[] == false - local_quad_id = side.is.full.quadid + local_quad_id = side_pw.is.full.quadid[] # Global ID of this quad quad_id = offset + local_quad_id @@ -573,52 +573,52 @@ function init_boundaries_iter_face_inner(info, user_data) boundaries.neighbor_ids[boundary_id] = quad_id + 1 # Face at which the boundary lies - face = side.face + face = side_pw.face[] # Save boundaries.node_indices dimension specific in containers_[23]d.jl init_boundary_node_indices!(boundaries, face, boundary_id) # One-based indexing - boundaries.name[boundary_id] = mesh.boundary_names[face + 1, side.treeid + 1] + boundaries.name[boundary_id] = mesh.boundary_names[face + 1, side_pw.treeid[] + 1] return nothing end # Initialization of mortars after the function barrier -function init_mortars_iter_face_inner(info, sides, user_data) +function init_mortars_iter_face_inner(info_pw, sides_pw, user_data) @unpack mortars, mortar_id, mesh = user_data user_data.mortar_id += 1 # Get Tuple of local trees, one-based indexing - trees = (unsafe_load_tree(mesh.p4est, sides[1].treeid + 1), - unsafe_load_tree(mesh.p4est, sides[2].treeid + 1)) + trees_pw = (load_pointerwrapper_tree(mesh.p4est, sides_pw[1].treeid[] + 1), + load_pointerwrapper_tree(mesh.p4est, sides_pw[2].treeid[] + 1)) # Quadrant numbering offsets of the quadrants at this interface - offsets = SVector(trees[1].quadrants_offset, - trees[2].quadrants_offset) + offsets = SVector(trees_pw[1].quadrants_offset[], + trees_pw[2].quadrants_offset[]) - if sides[1].is_hanging == true + if sides_pw[1].is_hanging[] == true # Left is small, right is large - faces = (sides[1].face, sides[2].face) + faces = (sides_pw[1].face[], sides_pw[2].face[]) - local_small_quad_ids = sides[1].is.hanging.quadid + local_small_quad_ids = sides_pw[1].is.hanging.quadid[] # Global IDs of the two small quads small_quad_ids = offsets[1] .+ local_small_quad_ids # Just be sure before accessing is.full - @assert sides[2].is_hanging == false - large_quad_id = offsets[2] + sides[2].is.full.quadid - else # sides[2].is_hanging == true + @assert sides_pw[2].is_hanging[] == false + large_quad_id = offsets[2] + sides_pw[2].is.full.quadid[] + else # sides_pw[2].is_hanging[] == true # Right is small, left is large. # init_mortar_node_indices! below expects side 1 to contain the small elements. - faces = (sides[2].face, sides[1].face) + faces = (sides_pw[2].face[], sides_pw[1].face[]) - local_small_quad_ids = sides[2].is.hanging.quadid + local_small_quad_ids = sides_pw[2].is.hanging.quadid[] # Global IDs of the two small quads small_quad_ids = offsets[2] .+ local_small_quad_ids # Just be sure before accessing is.full - @assert sides[1].is_hanging == false - large_quad_id = offsets[1] + sides[1].is.full.quadid + @assert sides_pw[1].is_hanging[] == false + large_quad_id = offsets[1] + sides_pw[1].is.full.quadid[] end # Write data to mortar container, 1 and 2 are the small elements @@ -627,7 +627,7 @@ function init_mortars_iter_face_inner(info, sides, user_data) # Last entry is the large element mortars.neighbor_ids[end, mortar_id] = large_quad_id + 1 - init_mortar_node_indices!(mortars, faces, unsafe_load(info).orientation, mortar_id) + init_mortar_node_indices!(mortars, faces, info_pw.orientation[], mortar_id) return nothing end @@ -638,34 +638,36 @@ end # - boundaries # and collect the numbers in `user_data` in this order. function count_surfaces_iter_face(info, user_data) - elem_count = unsafe_load(info).sides.elem_count + info_pw = PointerWrapper(info) + elem_count = info_pw.sides.elem_count[] if elem_count == 2 # Two neighboring elements => Interface or mortar # Extract surface data - sides = (unsafe_load_side(info, 1), unsafe_load_side(info, 2)) + sides_pw = (load_pointerwrapper_side(info_pw, 1), + load_pointerwrapper_side(info_pw, 2)) - if sides[1].is_hanging == false && sides[2].is_hanging == false + if sides_pw[1].is_hanging[] == false && sides_pw[2].is_hanging[] == false # No hanging nodes => normal interface # Unpack user_data = [interface_count] and increment interface_count - ptr = Ptr{Int}(user_data) - id = unsafe_load(ptr, 1) - unsafe_store!(ptr, id + 1, 1) + pw = PointerWrapper(Int, user_data) + id = pw[1] + pw[1] = id + 1 else # Hanging nodes => mortar # Unpack user_data = [mortar_count] and increment mortar_count - ptr = Ptr{Int}(user_data) - id = unsafe_load(ptr, 2) - unsafe_store!(ptr, id + 1, 2) + pw = PointerWrapper(Int, user_data) + id = pw[2] + pw[2] = id + 1 end elseif elem_count == 1 # One neighboring elements => boundary # Unpack user_data = [boundary_count] and increment boundary_count - ptr = Ptr{Int}(user_data) - id = unsafe_load(ptr, 3) - unsafe_store!(ptr, id + 1, 3) + pw = PointerWrapper(Int, user_data) + id = pw[3] + pw[3] = id + 1 end return nothing diff --git a/src/solvers/dgsem_p4est/containers_2d.jl b/src/solvers/dgsem_p4est/containers_2d.jl index 4f7d903897a..11747f1f175 100644 --- a/src/solvers/dgsem_p4est/containers_2d.jl +++ b/src/solvers/dgsem_p4est/containers_2d.jl @@ -52,7 +52,7 @@ function calc_node_coordinates!(node_coordinates, p4est_root_len = 1 << P4EST_MAXLEVEL p4est_quadrant_len(l) = 1 << (P4EST_MAXLEVEL - l) - trees = unsafe_wrap_sc(p4est_tree_t, unsafe_load(mesh.p4est).trees) + trees = unsafe_wrap_sc(p4est_tree_t, mesh.p4est.trees) for tree in eachindex(trees) offset = trees[tree].quadrants_offset diff --git a/src/solvers/dgsem_p4est/containers_3d.jl b/src/solvers/dgsem_p4est/containers_3d.jl index 6cdc2cf9611..e9994fe4569 100644 --- a/src/solvers/dgsem_p4est/containers_3d.jl +++ b/src/solvers/dgsem_p4est/containers_3d.jl @@ -43,7 +43,7 @@ function calc_node_coordinates!(node_coordinates, p4est_root_len = 1 << P4EST_MAXLEVEL p4est_quadrant_len(l) = 1 << (P4EST_MAXLEVEL - l) - trees = unsafe_wrap_sc(p8est_tree_t, unsafe_load(mesh.p4est).trees) + trees = unsafe_wrap_sc(p8est_tree_t, mesh.p4est.trees) for tree in eachindex(trees) offset = trees[tree].quadrants_offset diff --git a/src/solvers/dgsem_p4est/containers_parallel.jl b/src/solvers/dgsem_p4est/containers_parallel.jl index 42d6ea44c5e..e7ee1f81478 100644 --- a/src/solvers/dgsem_p4est/containers_parallel.jl +++ b/src/solvers/dgsem_p4est/containers_parallel.jl @@ -311,21 +311,24 @@ function init_surfaces_iter_face_inner(info, # surfaces at once or any subset of them, some of the unpacked values above may be `nothing` if # they're not supposed to be initialized during this call. That is why we need additional # `!== nothing` checks below before initializing individual faces. - if unsafe_load(info).sides.elem_count == 2 + info_pw = PointerWrapper(info) + if info_pw.sides.elem_count[] == 2 # Two neighboring elements => Interface or mortar # Extract surface data - sides = (unsafe_load_side(info, 1), unsafe_load_side(info, 2)) + sides_pw = (load_pointerwrapper_side(info_pw, 1), + load_pointerwrapper_side(info_pw, 2)) - if sides[1].is_hanging == false && sides[2].is_hanging == false + if sides_pw[1].is_hanging[] == false && sides_pw[2].is_hanging[] == false # No hanging nodes => normal interface or MPI interface - if sides[1].is.full.is_ghost == true || sides[2].is.full.is_ghost == true # remote side => MPI interface + if sides_pw[1].is.full.is_ghost[] == true || + sides_pw[2].is.full.is_ghost[] == true # remote side => MPI interface if mpi_interfaces !== nothing - init_mpi_interfaces_iter_face_inner(info, sides, user_data) + init_mpi_interfaces_iter_face_inner(info_pw, sides_pw, user_data) end else if interfaces !== nothing - init_interfaces_iter_face_inner(info, sides, user_data) + init_interfaces_iter_face_inner(info_pw, sides_pw, user_data) end end else @@ -333,18 +336,18 @@ function init_surfaces_iter_face_inner(info, # First, we check which side is hanging, i.e., on which side we have the refined cells. # Then we check if any of the refined cells or the coarse cell are "ghost" cells, i.e., they # belong to another rank. That way we can determine if this is a regular mortar or MPI mortar - if sides[1].is_hanging == true - @assert sides[2].is_hanging == false - if any(sides[1].is.hanging.is_ghost .== true) || - sides[2].is.full.is_ghost == true + if sides_pw[1].is_hanging[] == true + @assert sides_pw[2].is_hanging[] == false + if any(sides_pw[1].is.hanging.is_ghost[] .== true) || + sides_pw[2].is.full.is_ghost[] == true face_has_ghost_side = true else face_has_ghost_side = false end - else # sides[2].is_hanging == true - @assert sides[1].is_hanging == false - if sides[1].is.full.is_ghost == true || - any(sides[2].is.hanging.is_ghost .== true) + else # sides_pw[2].is_hanging[] == true + @assert sides_pw[1].is_hanging[] == false + if sides_pw[1].is.full.is_ghost[] == true || + any(sides_pw[2].is.hanging.is_ghost[] .== true) face_has_ghost_side = true else face_has_ghost_side = false @@ -352,15 +355,15 @@ function init_surfaces_iter_face_inner(info, end # Initialize mortar or MPI mortar if face_has_ghost_side && mpi_mortars !== nothing - init_mpi_mortars_iter_face_inner(info, sides, user_data) + init_mpi_mortars_iter_face_inner(info_pw, sides_pw, user_data) elseif !face_has_ghost_side && mortars !== nothing - init_mortars_iter_face_inner(info, sides, user_data) + init_mortars_iter_face_inner(info_pw, sides_pw, user_data) end end - elseif unsafe_load(info).sides.elem_count == 1 + elseif info_pw.sides.elem_count[] == 1 # One neighboring elements => boundary if boundaries !== nothing - init_boundaries_iter_face_inner(info, user_data) + init_boundaries_iter_face_inner(info_pw, user_data) end end @@ -381,23 +384,23 @@ function init_surfaces!(interfaces, mortars, boundaries, mpi_interfaces, mpi_mor end # Initialization of MPI interfaces after the function barrier -function init_mpi_interfaces_iter_face_inner(info, sides, user_data) +function init_mpi_interfaces_iter_face_inner(info_pw, sides_pw, user_data) @unpack mpi_interfaces, mpi_interface_id, mesh = user_data user_data.mpi_interface_id += 1 - if sides[1].is.full.is_ghost == true + if sides_pw[1].is.full.is_ghost[] == true local_side = 2 - elseif sides[2].is.full.is_ghost == true + elseif sides_pw[2].is.full.is_ghost[] == true local_side = 1 else error("should not happen") end # Get local tree, one-based indexing - tree = unsafe_load_tree(mesh.p4est, sides[local_side].treeid + 1) + tree_pw = load_pointerwrapper_tree(mesh.p4est, sides_pw[local_side].treeid[] + 1) # Quadrant numbering offset of the local quadrant at this interface - offset = tree.quadrants_offset - tree_quad_id = sides[local_side].is.full.quadid # quadid in the local tree + offset = tree_pw.quadrants_offset[] + tree_quad_id = sides_pw[local_side].is.full.quadid[] # quadid in the local tree # ID of the local neighboring quad, cumulative over local trees local_quad_id = offset + tree_quad_id @@ -406,52 +409,52 @@ function init_mpi_interfaces_iter_face_inner(info, sides, user_data) mpi_interfaces.local_sides[mpi_interface_id] = local_side # Face at which the interface lies - faces = (sides[1].face, sides[2].face) + faces = (sides_pw[1].face[], sides_pw[2].face[]) # Save mpi_interfaces.node_indices dimension specific in containers_[23]d_parallel.jl init_mpi_interface_node_indices!(mpi_interfaces, faces, local_side, - unsafe_load(info).orientation, + info_pw.orientation[], mpi_interface_id) return nothing end # Initialization of MPI mortars after the function barrier -function init_mpi_mortars_iter_face_inner(info, sides, user_data) +function init_mpi_mortars_iter_face_inner(info_pw, sides_pw, user_data) @unpack mpi_mortars, mpi_mortar_id, mesh = user_data user_data.mpi_mortar_id += 1 # Get Tuple of adjacent trees, one-based indexing - trees = (unsafe_load_tree(mesh.p4est, sides[1].treeid + 1), - unsafe_load_tree(mesh.p4est, sides[2].treeid + 1)) + trees_pw = (load_pointerwrapper_tree(mesh.p4est, sides_pw[1].treeid[] + 1), + load_pointerwrapper_tree(mesh.p4est, sides_pw[2].treeid[] + 1)) # Quadrant numbering offsets of the quadrants at this mortar - offsets = SVector(trees[1].quadrants_offset, - trees[2].quadrants_offset) + offsets = SVector(trees_pw[1].quadrants_offset[], + trees_pw[2].quadrants_offset[]) - if sides[1].is_hanging == true + if sides_pw[1].is_hanging[] == true hanging_side = 1 full_side = 2 - else # sides[2].is_hanging == true + else # sides_pw[2].is_hanging[] == true hanging_side = 2 full_side = 1 end # Just be sure before accessing is.full or is.hanging later - @assert sides[full_side].is_hanging == false - @assert sides[hanging_side].is_hanging == true + @assert sides_pw[full_side].is_hanging[] == false + @assert sides_pw[hanging_side].is_hanging[] == true # Find small quads that are locally available - local_small_quad_positions = findall(sides[hanging_side].is.hanging.is_ghost .== + local_small_quad_positions = findall(sides_pw[hanging_side].is.hanging.is_ghost[] .== false) # Get id of local small quadrants within their tree # Indexing CBinding.Caccessor via a Vector does not work here -> use map instead - tree_small_quad_ids = map(p -> sides[hanging_side].is.hanging.quadid[p], + tree_small_quad_ids = map(p -> sides_pw[hanging_side].is.hanging.quadid[][p], local_small_quad_positions) local_small_quad_ids = offsets[hanging_side] .+ tree_small_quad_ids # ids cumulative over local trees # Determine if large quadrant is available and if yes, determine its id - if sides[full_side].is.full.is_ghost == false - local_large_quad_id = offsets[full_side] + sides[full_side].is.full.quadid + if sides_pw[full_side].is.full.is_ghost[] == false + local_large_quad_id = offsets[full_side] + sides_pw[full_side].is.full.quadid[] else local_large_quad_id = -1 # large quad is ghost end @@ -470,9 +473,8 @@ function init_mpi_mortars_iter_face_inner(info, sides, user_data) mpi_mortars.local_neighbor_positions[mpi_mortar_id] = local_neighbor_positions # init_mortar_node_indices! expects side 1 to contain small elements - faces = (sides[hanging_side].face, sides[full_side].face) - init_mortar_node_indices!(mpi_mortars, faces, unsafe_load(info).orientation, - mpi_mortar_id) + faces = (sides_pw[hanging_side].face[], sides_pw[full_side].face[]) + init_mortar_node_indices!(mpi_mortars, faces, info_pw.orientation[], mpi_mortar_id) return nothing end @@ -485,42 +487,45 @@ end # - (MPI) mortars at subdomain boundaries # and collect the numbers in `user_data` in this order. function count_surfaces_iter_face_parallel(info, user_data) - if unsafe_load(info).sides.elem_count == 2 + info_pw = PointerWrapper(info) + if info_pw.sides.elem_count[] == 2 # Two neighboring elements => Interface or mortar # Extract surface data - sides = (unsafe_load_side(info, 1), unsafe_load_side(info, 2)) + sides_pw = (load_pointerwrapper_side(info_pw, 1), + load_pointerwrapper_side(info_pw, 2)) - if sides[1].is_hanging == false && sides[2].is_hanging == false + if sides_pw[1].is_hanging[] == false && sides_pw[2].is_hanging[] == false # No hanging nodes => normal interface or MPI interface - if sides[1].is.full.is_ghost == true || sides[2].is.full.is_ghost == true # remote side => MPI interface + if sides_pw[1].is.full.is_ghost[] == true || + sides_pw[2].is.full.is_ghost[] == true # remote side => MPI interface # Unpack user_data = [mpi_interface_count] and increment mpi_interface_count - ptr = Ptr{Int}(user_data) - id = unsafe_load(ptr, 4) - unsafe_store!(ptr, id + 1, 4) + pw = PointerWrapper(Int, user_data) + id = pw[4] + pw[4] = id + 1 else # Unpack user_data = [interface_count] and increment interface_count - ptr = Ptr{Int}(user_data) - id = unsafe_load(ptr, 1) - unsafe_store!(ptr, id + 1, 1) + pw = PointerWrapper(Int, user_data) + id = pw[1] + pw[1] = id + 1 end else # Hanging nodes => mortar or MPI mortar # First, we check which side is hanging, i.e., on which side we have the refined cells. # Then we check if any of the refined cells or the coarse cell are "ghost" cells, i.e., they # belong to another rank. That way we can determine if this is a regular mortar or MPI mortar - if sides[1].is_hanging == true - @assert sides[2].is_hanging == false - if any(sides[1].is.hanging.is_ghost .== true) || - sides[2].is.full.is_ghost == true + if sides_pw[1].is_hanging[] == true + @assert sides_pw[2].is_hanging[] == false + if any(sides_pw[1].is.hanging.is_ghost[] .== true) || + sides_pw[2].is.full.is_ghost[] == true face_has_ghost_side = true else face_has_ghost_side = false end - else # sides[2].is_hanging == true - @assert sides[1].is_hanging == false - if sides[1].is.full.is_ghost == true || - any(sides[2].is.hanging.is_ghost .== true) + else # sides_pw[2].is_hanging[] == true + @assert sides_pw[1].is_hanging[] == false + if sides_pw[1].is.full.is_ghost[] == true || + any(sides_pw[2].is.hanging.is_ghost[] .== true) face_has_ghost_side = true else face_has_ghost_side = false @@ -528,23 +533,23 @@ function count_surfaces_iter_face_parallel(info, user_data) end if face_has_ghost_side # Unpack user_data = [mpi_mortar_count] and increment mpi_mortar_count - ptr = Ptr{Int}(user_data) - id = unsafe_load(ptr, 5) - unsafe_store!(ptr, id + 1, 5) + pw = PointerWrapper(Int, user_data) + id = pw[5] + pw[5] = id + 1 else # Unpack user_data = [mortar_count] and increment mortar_count - ptr = Ptr{Int}(user_data) - id = unsafe_load(ptr, 2) - unsafe_store!(ptr, id + 1, 2) + pw = PointerWrapper(Int, user_data) + id = pw[2] + pw[2] = id + 1 end end - elseif unsafe_load(info).sides.elem_count == 1 + elseif info_pw.sides.elem_count[] == 1 # One neighboring elements => boundary # Unpack user_data = [boundary_count] and increment boundary_count - ptr = Ptr{Int}(user_data) - id = unsafe_load(ptr, 3) - unsafe_store!(ptr, id + 1, 3) + pw = PointerWrapper(Int, user_data) + id = pw[3] + pw[3] = id + 1 end return nothing diff --git a/src/solvers/dgsem_p4est/dg_parallel.jl b/src/solvers/dgsem_p4est/dg_parallel.jl index ac122d048c1..324bc7f3cd6 100644 --- a/src/solvers/dgsem_p4est/dg_parallel.jl +++ b/src/solvers/dgsem_p4est/dg_parallel.jl @@ -263,15 +263,13 @@ function init_mpi_cache!(mpi_cache::P4estMPICache, mesh::ParallelP4estMesh, uEltype) # Determine local and total number of elements - n_elements_global = Int(unsafe_load(mesh.p4est).global_num_quadrants) - n_elements_by_rank = vcat(Int.(unsafe_wrap(Array, - unsafe_load(mesh.p4est).global_first_quadrant, + n_elements_global = Int(mesh.p4est.global_num_quadrants[]) + n_elements_by_rank = vcat(Int.(unsafe_wrap(Array, mesh.p4est.global_first_quadrant, mpi_nranks())), n_elements_global) |> diff # diff sufficient due to 0-based quad indices n_elements_by_rank = OffsetArray(n_elements_by_rank, 0:(mpi_nranks() - 1)) # Account for 1-based indexing in Julia - first_element_global_id = Int(unsafe_load(unsafe_load(mesh.p4est).global_first_quadrant, - mpi_rank() + 1)) + 1 + first_element_global_id = Int(mesh.p4est.global_first_quadrant[mpi_rank() + 1]) + 1 @assert n_elements_global==sum(n_elements_by_rank) "error in total number of elements" # TODO reuse existing structures @@ -379,17 +377,19 @@ function init_neighbor_rank_connectivity_iter_face_inner(info, user_data) @unpack interfaces, interface_id, global_interface_ids, neighbor_ranks_interface, mortars, mortar_id, global_mortar_ids, neighbor_ranks_mortar, mesh = user_data + info_pw = PointerWrapper(info) # Get the global interface/mortar ids and neighbor rank if current face belongs to an MPI # interface/mortar - if unsafe_load(info).sides.elem_count == 2 # MPI interfaces/mortars have two neighboring elements + if info_pw.sides.elem_count[] == 2 # MPI interfaces/mortars have two neighboring elements # Extract surface data - sides = (unsafe_load_side(info, 1), unsafe_load_side(info, 2)) + sides_pw = (load_pointerwrapper_side(info_pw, 1), + load_pointerwrapper_side(info_pw, 2)) - if sides[1].is_hanging == false && sides[2].is_hanging == false # No hanging nodes for MPI interfaces - if sides[1].is.full.is_ghost == true + if sides_pw[1].is_hanging[] == false && sides_pw[2].is_hanging[] == false # No hanging nodes for MPI interfaces + if sides_pw[1].is.full.is_ghost[] == true remote_side = 1 local_side = 2 - elseif sides[2].is.full.is_ghost == true + elseif sides_pw[2].is.full.is_ghost[] == true remote_side = 2 local_side = 1 else # both sides are on this rank -> skip since it's a regular interface @@ -397,16 +397,17 @@ function init_neighbor_rank_connectivity_iter_face_inner(info, user_data) end # Sanity check, current face should belong to current MPI interface - local_tree = unsafe_load_tree(mesh.p4est, sides[local_side].treeid + 1) # one-based indexing - local_quad_id = local_tree.quadrants_offset + - sides[local_side].is.full.quadid + local_tree_pw = load_pointerwrapper_tree(mesh.p4est, + sides_pw[local_side].treeid[] + 1) # one-based indexing + local_quad_id = local_tree_pw.quadrants_offset[] + + sides_pw[local_side].is.full.quadid[] @assert interfaces.local_neighbor_ids[interface_id] == local_quad_id + 1 # one-based indexing # Get neighbor ID from ghost layer proc_offsets = unsafe_wrap(Array, - unsafe_load(unsafe_load(info).ghost_layer).proc_offsets, + info_pw.ghost_layer.proc_offsets, mpi_nranks() + 1) - ghost_id = sides[remote_side].is.full.quadid # indexes the ghost layer, 0-based + ghost_id = sides_pw[remote_side].is.full.quadid[] # indexes the ghost layer, 0-based neighbor_rank = findfirst(r -> proc_offsets[r] <= ghost_id < proc_offsets[r + 1], 1:mpi_nranks()) - 1 # MPI ranks are 0-based @@ -415,21 +416,18 @@ function init_neighbor_rank_connectivity_iter_face_inner(info, user_data) # Global interface id is the globally unique quadrant id of the quadrant on the primary # side (1) multiplied by the number of faces per quadrant plus face if local_side == 1 - offset = unsafe_load(unsafe_load(mesh.p4est).global_first_quadrant, - mpi_rank() + 1) # one-based indexing + offset = mesh.p4est.global_first_quadrant[mpi_rank() + 1] # one-based indexing primary_quad_id = offset + local_quad_id else - offset = unsafe_load(unsafe_load(mesh.p4est).global_first_quadrant, - neighbor_rank + 1) # one-based indexing - primary_quad_id = offset + - unsafe_load(sides[1].is.full.quad.p.piggy3.local_num) + offset = mesh.p4est.global_first_quadrant[neighbor_rank + 1] # one-based indexing + primary_quad_id = offset + sides_pw[1].is.full.quad.p.piggy3.local_num[] end - global_interface_id = 2 * ndims(mesh) * primary_quad_id + sides[1].face + global_interface_id = 2 * ndims(mesh) * primary_quad_id + sides_pw[1].face[] global_interface_ids[interface_id] = global_interface_id user_data.interface_id += 1 else # hanging node - if sides[1].is_hanging == true + if sides_pw[1].is_hanging[] == true hanging_side = 1 full_side = 2 else @@ -437,26 +435,26 @@ function init_neighbor_rank_connectivity_iter_face_inner(info, user_data) full_side = 1 end # Verify before accessing is.full / is.hanging - @assert sides[hanging_side].is_hanging == true && - sides[full_side].is_hanging == false + @assert sides_pw[hanging_side].is_hanging[] == true && + sides_pw[full_side].is_hanging[] == false # If all quadrants are locally available, this is a regular mortar -> skip - if sides[full_side].is.full.is_ghost == false && - all(sides[hanging_side].is.hanging.is_ghost .== false) + if sides_pw[full_side].is.full.is_ghost[] == false && + all(sides_pw[hanging_side].is.hanging.is_ghost[] .== false) return nothing end - trees = (unsafe_load_tree(mesh.p4est, sides[1].treeid + 1), - unsafe_load_tree(mesh.p4est, sides[2].treeid + 1)) + trees_pw = (load_pointerwrapper_tree(mesh.p4est, sides_pw[1].treeid[] + 1), + load_pointerwrapper_tree(mesh.p4est, sides_pw[2].treeid[] + 1)) # Find small quads that are remote and determine which rank owns them - remote_small_quad_positions = findall(sides[hanging_side].is.hanging.is_ghost .== + remote_small_quad_positions = findall(sides_pw[hanging_side].is.hanging.is_ghost[] .== true) proc_offsets = unsafe_wrap(Array, - unsafe_load(unsafe_load(info).ghost_layer).proc_offsets, + info_pw.ghost_layer.proc_offsets, mpi_nranks() + 1) # indices of small remote quads inside the ghost layer, 0-based - ghost_ids = map(pos -> sides[hanging_side].is.hanging.quadid[pos], + ghost_ids = map(pos -> sides_pw[hanging_side].is.hanging.quadid[][pos], remote_small_quad_positions) neighbor_ranks = map(ghost_ids) do ghost_id return findfirst(r -> proc_offsets[r] <= ghost_id < proc_offsets[r + 1], @@ -464,28 +462,26 @@ function init_neighbor_rank_connectivity_iter_face_inner(info, user_data) end # Determine global quad id of large element to determine global MPI mortar id # Furthermore, if large element is ghost, add its owner rank to neighbor_ranks - if sides[full_side].is.full.is_ghost == true - ghost_id = sides[full_side].is.full.quadid + if sides_pw[full_side].is.full.is_ghost[] == true + ghost_id = sides_pw[full_side].is.full.quadid[] large_quad_owner_rank = findfirst(r -> proc_offsets[r] <= ghost_id < proc_offsets[r + 1], 1:mpi_nranks()) - 1 # MPI ranks are 0-based push!(neighbor_ranks, large_quad_owner_rank) - offset = unsafe_load(unsafe_load(mesh.p4est).global_first_quadrant, - large_quad_owner_rank + 1) # one-based indexing + offset = mesh.p4est.global_first_quadrant[large_quad_owner_rank + 1] # one-based indexing large_quad_id = offset + - unsafe_load(sides[full_side].is.full.quad.p.piggy3.local_num) + sides_pw[full_side].is.full.quad.p.piggy3.local_num[] else - offset = unsafe_load(unsafe_load(mesh.p4est).global_first_quadrant, - mpi_rank() + 1) # one-based indexing - large_quad_id = offset + trees[full_side].quadrants_offset + - sides[full_side].is.full.quadid + offset = mesh.p4est.global_first_quadrant[mpi_rank() + 1] # one-based indexing + large_quad_id = offset + trees_pw[full_side].quadrants_offset[] + + sides_pw[full_side].is.full.quadid[] end neighbor_ranks_mortar[mortar_id] = neighbor_ranks # Global mortar id is the globally unique quadrant id of the large quadrant multiplied by the # number of faces per quadrant plus face global_mortar_ids[mortar_id] = 2 * ndims(mesh) * large_quad_id + - sides[full_side].face + sides_pw[full_side].face[] user_data.mortar_id += 1 end From eb4c91a6ba3c1fe1c1f0bbb9c332ab0068171113 Mon Sep 17 00:00:00 2001 From: David Knapp Date: Mon, 19 Jun 2023 10:48:56 +0200 Subject: [PATCH 004/263] Added a dispatchable constructur for DG with TensorProductWedges (#1389) * Added a dispatchable constructur for DG with TensorProductWedges Adapted the timestepping for DGMulti to use the minimal polynomial degree of the tensorproduct * Use the maximal poly-degree * Update src/solvers/dgmulti/types.jl Co-authored-by: Hendrik Ranocha * Change DGMulti-call for Tensorwedges * Adding comment about the polydeg-choice * Adapt constructor * Add an example for TensorWedges * Update example * Update examples/dgmulti_3d/elixir_euler_tensorWedge.jl Co-authored-by: Hendrik Ranocha * Update examples/dgmulti_3d/elixir_euler_tensorWedge.jl Co-authored-by: Hendrik Ranocha * Update examples/dgmulti_3d/elixir_euler_tensorWedge.jl Co-authored-by: Hendrik Ranocha * Readd Gauss Accidentaly deleted during Merge-Conflict resolvement online * Remove explicit load of StartUpDG in elixir * Update max_dt * Apply suggestions from code review Co-authored-by: Hendrik Ranocha * Update comments * Add tensorWedge-test * Update src/solvers/dgmulti/dg.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Renamed tensorwedge elixir * Update testset title * Remove typos * temporal push * fix max_dt dispatch * Update TensorProductWedges-test * Update test * Address CI-Warning * Update dt_polydeg_scaling * Correct dt_polydeg_scaling A previous commit changed it from (polydeg + 1) to polydeg * Update DGMulti-call * Rename file * Change Path in test-file * Apply suggestions from code review Co-authored-by: Hendrik Ranocha * Update examples/dgmulti_3d/elixir_advection_tensor_wedge.jl Co-authored-by: Hendrik Ranocha * Reformat src/Trixi.jl * Format solvers/dgmulti/dg.jl * Formatting --------- Co-authored-by: Knapp Co-authored-by: Hendrik Ranocha Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> Co-authored-by: Jesse Chan --- .../elixir_advection_tensor_wedge.jl | 56 +++++++++++++++++++ src/Trixi.jl | 3 +- src/solvers/dgmulti/dg.jl | 11 ++-- src/solvers/dgmulti/types.jl | 15 +++++ test/test_dgmulti_3d.jl | 6 ++ 5 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 examples/dgmulti_3d/elixir_advection_tensor_wedge.jl diff --git a/examples/dgmulti_3d/elixir_advection_tensor_wedge.jl b/examples/dgmulti_3d/elixir_advection_tensor_wedge.jl new file mode 100644 index 00000000000..4f43f2571a3 --- /dev/null +++ b/examples/dgmulti_3d/elixir_advection_tensor_wedge.jl @@ -0,0 +1,56 @@ +using OrdinaryDiffEq +using Trixi +using LinearAlgebra + +############################################################################### +equations = LinearScalarAdvectionEquation3D(1.0, 1.0, 1.0) + +initial_condition = initial_condition_convergence_test + +# Define the polynomial degrees for the polynoms of the triangular base and the line +# of the tensor-prism +tensor_polydeg = (3, 4) + +dg = DGMulti(element_type = Wedge(), + approximation_type = Polynomial(), + surface_flux = flux_lax_friedrichs, + polydeg = tensor_polydeg) + + +cells_per_dimension = (8, 8, 8) +mesh = DGMultiMesh(dg, + cells_per_dimension, + coordinates_min = (-1.0, -1.0, -1.0), + coordinates_max = (1.0, 1.0, 1.0), + periodicity = true) + + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg, + boundary_conditions=boundary_condition_periodic) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 5.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) + +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +# The StepsizeCallback handles the re-calculation of the maximum Δt after each time step +stepsize_callback = StepsizeCallback(cfl=1.0) + +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, stepsize_callback) + + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, + save_everystep=false, callback=callbacks); + +summary_callback() # print the timer summary \ No newline at end of file diff --git a/src/Trixi.jl b/src/Trixi.jl index 86e349c7dad..66878f4b459 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -83,7 +83,8 @@ import SummationByPartsOperators: integrate, semidiscretize, upwind_operators # DGMulti solvers -@reexport using StartUpDG: StartUpDG, Polynomial, Gauss, SBP, Line, Tri, Quad, Hex, Tet +@reexport using StartUpDG: StartUpDG, Polynomial, Gauss, TensorProductWedge, SBP, Line, Tri, + Quad, Hex, Tet, Wedge using StartUpDG: RefElemData, MeshData, AbstractElemShape # TODO: include_optimized diff --git a/src/solvers/dgmulti/dg.jl b/src/solvers/dgmulti/dg.jl index d51c7cabf9d..bc76aa1a9d2 100644 --- a/src/solvers/dgmulti/dg.jl +++ b/src/solvers/dgmulti/dg.jl @@ -226,6 +226,11 @@ function estimate_dt(mesh::DGMultiMesh, dg::DGMulti) return StartUpDG.estimate_h(rd, mesh.md) / StartUpDG.inverse_trace_constant(rd) end +dt_polydeg_scaling(dg::DGMulti) = inv(dg.basis.N + 1) +function dt_polydeg_scaling(dg::DGMulti{3, <:Wedge, <:TensorProductWedge}) + inv(maximum(dg.basis.N) + 1) +end + # for the stepsize callback function max_dt(u, t, mesh::DGMultiMesh, constant_speed::False, equations, dg::DGMulti{NDIMS}, @@ -247,8 +252,7 @@ function max_dt(u, t, mesh::DGMultiMesh, # `polydeg+1`. This is because `nnodes(dg)` returns the total number of # multi-dimensional nodes for DGMulti solver types, while `nnodes(dg)` returns # the number of 1D nodes for `DGSEM` solvers. - polydeg = rd.N - return 2 * dt_min / (polydeg + 1) + return 2 * dt_min * dt_polydeg_scaling(dg) end function max_dt(u, t, mesh::DGMultiMesh, @@ -270,8 +274,7 @@ function max_dt(u, t, mesh::DGMultiMesh, # `polydeg+1`. This is because `nnodes(dg)` returns the total number of # multi-dimensional nodes for DGMulti solver types, while `nnodes(dg)` returns # the number of 1D nodes for `DGSEM` solvers. - polydeg = rd.N - return 2 * dt_min / (polydeg + 1) + return 2 * dt_min * dt_polydeg_scaling(dg) end # interpolates from solution coefficients to face quadrature points diff --git a/src/solvers/dgmulti/types.jl b/src/solvers/dgmulti/types.jl index c225e334e8e..f1f7b158dec 100644 --- a/src/solvers/dgmulti/types.jl +++ b/src/solvers/dgmulti/types.jl @@ -96,6 +96,21 @@ function DGMulti(; polydeg = nothing, polydeg = polydeg, kwargs...) end +# dispatchable constructor for DGMulti using a TensorProductWedge +function DGMulti(element_type::Wedge, + approximation_type, + volume_integral, + surface_integral; + polydeg::Tuple, + kwargs...) + factor_a = RefElemData(Tri(), approximation_type, polydeg[1]; kwargs...) + factor_b = RefElemData(Line(), approximation_type, polydeg[2]; kwargs...) + + tensor = TensorProductWedge(factor_a, factor_b) + rd = RefElemData(element_type, tensor; kwargs...) + return DG(rd, nothing, surface_integral, volume_integral) +end + # dispatchable constructor for DGMulti to allow for specialization function DGMulti(element_type::AbstractElemShape, approximation_type, diff --git a/test/test_dgmulti_3d.jl b/test/test_dgmulti_3d.jl index 22c0a0fd3ba..68fa1d13304 100644 --- a/test/test_dgmulti_3d.jl +++ b/test/test_dgmulti_3d.jl @@ -135,6 +135,12 @@ isdir(outdir) && rm(outdir, recursive=true) ) end + @trixi_testset "elixir_advection_tensor_wedge.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_tensor_wedge.jl"), + l2 = [2.30487910e-04] , + linf = [6.31795281e-04] ) + end + end # Clean up afterwards: delete Trixi.jl output directory From a837dd7726f25a88c7bab8bed2dc6955f20534bf Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Mon, 19 Jun 2023 14:50:27 +0200 Subject: [PATCH 005/263] Update test values for 1D discontinuous examples (#1511) * set true discontinuous initial conditions for 1D * update Burgers tests * update MHD tests in 1D * update structured_1d_dgsem/elixir_advection_shockcapturing elixir and test * remove workaround in elixir_shallowwater_ec.jl and update test * accidentally removed adjusted tolerance in structured mesh test * remove workaround in elixir_shallowwater_shockcapturing.jl and update test * remove workaround in elixir_shallowwater_well_balanced.jl and update tests * bug fix in energy_total computation for ShallowWaterTwoLayerEquations1D * remove workaround in elixir_shallowwater_twolayer_dam_break.jl and update test * update docs test for adding a nonconservative equation * update Nonconservative terms in 1D (linear advection) test * update all necessary IdealGlmMhdMulticomponentEquations1D tests * update all necessary CompressibleEulerMulticomponentEquations1D tests * update necessary CompressibleEuler1D tests except for neural network shock capturing * Update test values for NN-based SC * add short description to the NEWS.md * add extra test to avoid coverage drop * Update src/solvers/dg.jl Co-authored-by: Hendrik Ranocha --------- Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Hendrik Ranocha --- NEWS.md | 1 + .../files/adding_nonconservative_equation.jl | 2 +- .../elixir_advection_shockcapturing.jl | 6 +- .../tree_1d_dgsem/elixir_burgers_shock.jl | 6 +- ..._eulermulti_two_interacting_blast_waves.jl | 2 +- .../elixir_mhd_briowu_shock_tube.jl | 2 +- examples/tree_1d_dgsem/elixir_mhdmulti_ec.jl | 4 +- examples/tree_1d_dgsem/elixir_mhdmulti_es.jl | 4 +- .../tree_1d_dgsem/elixir_shallowwater_ec.jl | 71 ++++++--------- .../elixir_shallowwater_shock_capturing.jl | 81 +++++++---------- .../elixir_shallowwater_twolayer_dam_break.jl | 77 +++++++---------- .../elixir_shallowwater_well_balanced.jl | 56 +++--------- src/equations/shallow_water_two_layer_1d.jl | 86 +++++++++---------- src/solvers/dg.jl | 9 ++ test/test_structured_1d.jl | 4 +- test/test_tree_1d.jl | 2 +- test/test_tree_1d_burgers.jl | 8 +- test/test_tree_1d_euler.jl | 44 +++++----- test/test_tree_1d_eulermulti.jl | 32 ++++--- test/test_tree_1d_mhd.jl | 12 +-- test/test_tree_1d_mhdmulti.jl | 48 +++++------ test/test_tree_1d_shallowwater.jl | 28 +++--- test/test_tree_1d_shallowwater_twolayer.jl | 6 +- 23 files changed, 267 insertions(+), 324 deletions(-) diff --git a/NEWS.md b/NEWS.md index 9b46ba565fe..35c7039b2ef 100644 --- a/NEWS.md +++ b/NEWS.md @@ -9,6 +9,7 @@ for human readability. #### Added - Experimental support for 3D parabolic diffusion terms has been added. +- Capability to set truly discontinuous initial conditions in 1D. #### Changed diff --git a/docs/literate/src/files/adding_nonconservative_equation.jl b/docs/literate/src/files/adding_nonconservative_equation.jl index 08dd631058e..110fa486070 100644 --- a/docs/literate/src/files/adding_nonconservative_equation.jl +++ b/docs/literate/src/files/adding_nonconservative_equation.jl @@ -147,7 +147,7 @@ plot(sol) # above. error_1 = analysis_callback(sol).l2 |> first -@test isapprox(error_1, 0.0002961027497) #src +@test isapprox(error_1, 0.00029609575838969394) #src # Next, we increase the grid resolution by one refinement level and run the # simulation again. diff --git a/examples/structured_1d_dgsem/elixir_advection_shockcapturing.jl b/examples/structured_1d_dgsem/elixir_advection_shockcapturing.jl index 9a81acfe51c..313812fe08d 100644 --- a/examples/structured_1d_dgsem/elixir_advection_shockcapturing.jl +++ b/examples/structured_1d_dgsem/elixir_advection_shockcapturing.jl @@ -9,7 +9,9 @@ advection_velocity = 1.0 """ initial_condition_composite(x, t, equations::LinearScalarAdvectionEquation1D) -Slight simplification of +Wave form that is a combination of a Gaussian pulse, a square wave, a triangle wave, +and half an ellipse with periodic boundary conditions. +Slight simplification from - Jiang, Shu (1996) Efficient Implementation of Weighted ENO Schemes [DOI: 10.1006/jcph.1996.0130](https://doi.org/10.1006/jcph.1996.0130) @@ -60,7 +62,7 @@ volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; solver = DGSEM(basis, surface_flux, volume_integral) # Create curved mesh -cells_per_dimension = (125,) +cells_per_dimension = (120,) coordinates_min = (-1.0,) # minimum coordinate coordinates_max = (1.0,) # maximum coordinate mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, diff --git a/examples/tree_1d_dgsem/elixir_burgers_shock.jl b/examples/tree_1d_dgsem/elixir_burgers_shock.jl index 987fb320ad6..00b5314e19f 100644 --- a/examples/tree_1d_dgsem/elixir_burgers_shock.jl +++ b/examples/tree_1d_dgsem/elixir_burgers_shock.jl @@ -21,7 +21,7 @@ surface_flux = flux_lax_friedrichs volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; volume_flux_dg=surface_flux, volume_flux_fv=surface_flux) - + solver = DGSEM(basis, surface_flux, volume_integral) coordinate_min = 0.0 @@ -59,7 +59,7 @@ end boundary_conditions = (x_neg=boundary_condition_inflow, x_pos=boundary_condition_outflow) - + initial_condition = initial_condition_shock semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, @@ -79,7 +79,7 @@ analysis_callback = AnalysisCallback(semi, interval=analysis_interval) alive_callback = AliveCallback(analysis_interval=analysis_interval) -stepsize_callback = StepsizeCallback(cfl=0.9) +stepsize_callback = StepsizeCallback(cfl=0.85) callbacks = CallbackSet(summary_callback, diff --git a/examples/tree_1d_dgsem/elixir_eulermulti_two_interacting_blast_waves.jl b/examples/tree_1d_dgsem/elixir_eulermulti_two_interacting_blast_waves.jl index 353093e5f70..81966194180 100644 --- a/examples/tree_1d_dgsem/elixir_eulermulti_two_interacting_blast_waves.jl +++ b/examples/tree_1d_dgsem/elixir_eulermulti_two_interacting_blast_waves.jl @@ -88,7 +88,7 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -analysis_interval = 100 +analysis_interval = 1000 analysis_callback = AnalysisCallback(semi, interval=analysis_interval) diff --git a/examples/tree_1d_dgsem/elixir_mhd_briowu_shock_tube.jl b/examples/tree_1d_dgsem/elixir_mhd_briowu_shock_tube.jl index 1c07fc4fdde..c5727109d92 100644 --- a/examples/tree_1d_dgsem/elixir_mhd_briowu_shock_tube.jl +++ b/examples/tree_1d_dgsem/elixir_mhd_briowu_shock_tube.jl @@ -94,7 +94,7 @@ amr_callback = AMRCallback(semi, amr_controller, adapt_initial_condition=true, adapt_initial_condition_only_refine=true) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl=0.65) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, diff --git a/examples/tree_1d_dgsem/elixir_mhdmulti_ec.jl b/examples/tree_1d_dgsem/elixir_mhdmulti_ec.jl index 34fdce6634e..69ea0551bed 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmulti_ec.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmulti_ec.jl @@ -4,8 +4,8 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealGlmMhdMulticomponentEquations1D(gammas = (2.0, 2.0, 2.0), - gas_constants = (2.0, 2.0, 2.0)) +equations = IdealGlmMhdMulticomponentEquations1D(gammas = (2.0, 2.0, 2.0), + gas_constants = (2.0, 2.0, 2.0)) initial_condition = initial_condition_weak_blast_wave diff --git a/examples/tree_1d_dgsem/elixir_mhdmulti_es.jl b/examples/tree_1d_dgsem/elixir_mhdmulti_es.jl index 8ca32194b9e..93cf3e0fdb2 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmulti_es.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmulti_es.jl @@ -4,8 +4,8 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealGlmMhdMulticomponentEquations1D(gammas = (2.0, 2.0, 2.0), - gas_constants = (2.0, 2.0, 2.0)) +equations = IdealGlmMhdMulticomponentEquations1D(gammas = (2.0, 2.0, 2.0), + gas_constants = (2.0, 2.0, 2.0)) initial_condition = initial_condition_weak_blast_wave diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_ec.jl b/examples/tree_1d_dgsem/elixir_shallowwater_ec.jl index be6a2cb166c..1469afec1ca 100644 --- a/examples/tree_1d_dgsem/elixir_shallowwater_ec.jl +++ b/examples/tree_1d_dgsem/elixir_shallowwater_ec.jl @@ -8,9 +8,34 @@ using Trixi equations = ShallowWaterEquations1D(gravity_constant=9.81) -# 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 +# Initial condition with a truly discontinuous water height, velocity, and bottom +# topography function as an academic testcase for entropy conservation. +# The errors from the analysis callback are not important but `∑∂S/∂U ⋅ Uₜ` should +# be around machine roundoff. +# Works as intended for TreeMesh1D with `initial_refinement_level=4`. If the mesh +# refinement level is changed the initial condition below may need changed as well to +# ensure that the discontinuities lie on an element interface. +function initial_condition_ec_discontinuous_bottom(x, t, equations::ShallowWaterEquations1D) + # Set the background values + H = 4.25 + v = 0.0 + b = sin(x[1]) # arbitrary continuous function + + # Setup the discontinuous water height and velocity + if x[1] >= 0.125 && x[1] <= 0.25 + H = 5.0 + v = 0.1882 + end + + # Setup a discontinuous bottom topography + if x[1] >= -0.25 && x[1] <= -0.125 + b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) + end + + return prim2cons(SVector(H, v, b), equations) +end + +initial_condition = initial_condition_ec_discontinuous_bottom ############################################################################### # Get the DG approximation space @@ -37,46 +62,6 @@ semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) tspan = (0.0, 2.0) 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 TreeMesh1D with `initial_refinement_level=4`. -function initial_condition_ec_discontinuous_bottom(x, t, element_id, equations::ShallowWaterEquations1D) - # Set the background values - H = 4.25 - v = 0.0 - b = sin(x[1]) # arbitrary continuous function - - # setup the discontinuous water height and velocity - if element_id == 10 - H = 5.0 - v = 0.1882 - end - - # Setup a discontinuous bottom topography using the element id number - if element_id == 7 - b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) - end - - return prim2cons(SVector(H, v, 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 i in eachnode(semi.solver) - x_node = Trixi.get_node_coords(semi.cache.elements.node_coordinates, equations, semi.solver, i, 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, element) - end -end - ############################################################################### # Callbacks diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_shock_capturing.jl b/examples/tree_1d_dgsem/elixir_shallowwater_shock_capturing.jl index 50241126a28..62346d7b5ab 100644 --- a/examples/tree_1d_dgsem/elixir_shallowwater_shock_capturing.jl +++ b/examples/tree_1d_dgsem/elixir_shallowwater_shock_capturing.jl @@ -7,24 +7,37 @@ using Trixi equations = ShallowWaterEquations1D(gravity_constant=9.812, H0=1.75) -function initial_condition_stone_throw(x, t, equations::ShallowWaterEquations1D) - # Set up polar coordinates - inicenter = 0.15 - x_norm = x[1] - inicenter[1] - r = abs(x_norm) +# Initial condition with a truly discontinuous velocity and bottom topography. +# Works as intended for TreeMesh1D with `initial_refinement_level=3`. If the mesh +# refinement level is changed the initial condition below may need changed as well to +# ensure that the discontinuities lie on an element interface. +function initial_condition_stone_throw_discontinuous_bottom(x, t, equations::ShallowWaterEquations1D) + + # Calculate primitive variables + + # flat lake + H = equations.H0 + + # Discontinuous velocity + v = 0.0 + if x[1] >= -0.75 && x[1] <= 0.0 + v = -1.0 + elseif x[1] >= 0.0 && x[1] <= 0.75 + v = 1.0 + end - # Calculate primitive variables - H = equations.H0 - # v = 0.0 # for well-balanced test - v = r < 0.6 ? 1.75 : 0.0 # for stone throw + b = ( 1.5 / exp( 0.5 * ((x[1] - 1.0)^2 ) ) + + 0.75 / exp( 0.5 * ((x[1] + 1.0)^2 ) ) ) - b = ( 1.5 / exp( 0.5 * ((x[1] - 1.0)^2 ) ) - + 0.75 / exp( 0.5 * ((x[1] + 1.0)^2 ) ) ) + # Force a discontinuous bottom topography + if x[1] >= -1.5 && x[1] <= 0.0 + b = 0.5 + end - return prim2cons(SVector(H, v, b), equations) + return prim2cons(SVector(H, v, b), equations) end -initial_condition = initial_condition_stone_throw +initial_condition = initial_condition_stone_throw_discontinuous_bottom boundary_condition = boundary_condition_slip_wall @@ -62,49 +75,13 @@ semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions = boundary_condition) ############################################################################### -# ODE solvers, callbacks etc. +# ODE solver tspan = (0.0, 3.0) ode = semidiscretize(semi, tspan) -# Hack in a discontinuous bottom for a more interesting test -function initial_condition_stone_throw_discontinuous_bottom(x, t, element_id, equations::ShallowWaterEquations1D) - - inicenter = 0.15 - x_norm = x[1] - inicenter[1] - r = abs(x_norm) - - # Calculate primitive variables - H = equations.H0 # flat lake - # Discontinuous velocity set via element id number - v = 0.0 - if element_id == 4 - v = -1.0 - elseif element_id == 5 - v = 1.0 - end - - b = ( 1.5 / exp( 0.5 * ((x[1] - 1.0)^2 ) ) - + 0.75 / exp( 0.5 * ((x[1] + 1.0)^2 ) ) ) - - # Setup a discontinuous bottom topography using the element id number - if element_id == 3 || element_id == 4 - b = 0.5 - end - - return prim2cons(SVector(H, v, 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 i in eachnode(semi.solver) - x_node = Trixi.get_node_coords(semi.cache.elements.node_coordinates, equations, semi.solver, i, element) - u_node = initial_condition_stone_throw_discontinuous_bottom(x_node, first(tspan), element, equations) - Trixi.set_node_vars!(u, u_node, equations, semi.solver, i, element) - end -end +############################################################################### +# Callbacks summary_callback = SummaryCallback() diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_dam_break.jl b/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_dam_break.jl index 67c1098b178..60770d158fa 100644 --- a/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_dam_break.jl +++ b/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_dam_break.jl @@ -3,20 +3,34 @@ using OrdinaryDiffEq using Trixi ############################################################################### -# Semidiscretization of the two-layer shallow water equations for a dam break test with a -# discontinuous bottom topography function to test entropy conservation +# Semidiscretization of the two-layer shallow water equations for a dam break +# test with a discontinuous bottom topography function to test entropy conservation equations = ShallowWaterTwoLayerEquations1D(gravity_constant=9.81, H0=2.0, rho_upper=0.9, rho_lower=1.0) -############################################################################### -# Workaround to set a discontinuous bottom topography and initial condition. +# Initial condition of a dam break with a discontinuous water heights and bottom topography. +# Works as intended for TreeMesh1D with `initial_refinement_level=5`. If the mesh +# refinement level is changed the initial condition below may need changed as well to +# ensure that the discontinuities lie on an element interface. +function initial_condition_dam_break(x, t, equations::ShallowWaterTwoLayerEquations1D) + v1_upper = 0.0 + v1_lower = 0.0 + + # Set the discontinuity + if x[1] <= 10.0 + H_lower = 2.0 + H_upper = 4.0 + b = 0.0 + else + H_lower = 1.5 + H_upper = 3.0 + b = 0.5 + end + + return prim2cons(SVector(H_upper, v1_upper, H_lower, v1_lower, b), equations) +end -# This test case uses a special work around to setup a truly discontinuous bottom topography -# function and initial condition for this academic testcase of entropy conservation. First, a -# dummy initial condition is introduced to create the semidiscretization. Then the initial condition -# is reset with the true discontinuous values from initial_condition_dam_break. Note, that this -# initial condition only works for TreeMesh1D with `initial_refinement_level=5`. -initial_condition = initial_condition_convergence_test +initial_condition = initial_condition_dam_break ############################################################################### # Get the DG approximation space @@ -25,7 +39,6 @@ volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) solver = DGSEM(polydeg=3, surface_flux=(flux_fjordholm_etal, flux_nonconservative_fjordholm_etal), volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) - ############################################################################### # Get the TreeMesh and setup a non-periodic mesh @@ -39,54 +52,22 @@ mesh = TreeMesh(coordinates_min, coordinates_max, boundary_condition = boundary_condition_slip_wall # create the semidiscretization object -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions=boundary_condition) ############################################################################### -# ODE solvers, callbacks etc. +# ODE solvers tspan = (0.0,0.4) ode = semidiscretize(semi, tspan) -# Initial conditions dam break test case -function initial_condition_dam_break(x, t, element_id, equations::ShallowWaterTwoLayerEquations1D) - v1_upper = 0.0 - v1_lower = 0.0 - - # Set the discontinuity - if element_id <= 16 - H_lower = 2.0 - H_upper = 4.0 - b = 0.0 - else - H_lower = 1.5 - H_upper = 3.0 - b = 0.5 - end - - return prim2cons(SVector(H_upper, v1_upper, H_lower, v1_lower, 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 i in eachnode(semi.solver) - x_node = Trixi.get_node_coords(semi.cache.elements.node_coordinates, - equations, semi.solver, i, element) - u_node = initial_condition_dam_break(x_node, first(tspan), element, equations) - Trixi.set_node_vars!(u, u_node, equations, semi.solver, i, element) - end -end - - - +############################################################################### +# Callbacks summary_callback = SummaryCallback() analysis_interval = 500 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false, +analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false, extra_analysis_integrals=(energy_total, energy_kinetic, energy_internal,)) stepsize_callback = StepsizeCallback(cfl=1.0) diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_well_balanced.jl b/examples/tree_1d_dgsem/elixir_shallowwater_well_balanced.jl index 83835656839..e07bc04d76a 100644 --- a/examples/tree_1d_dgsem/elixir_shallowwater_well_balanced.jl +++ b/examples/tree_1d_dgsem/elixir_shallowwater_well_balanced.jl @@ -8,21 +8,28 @@ using Trixi equations = ShallowWaterEquations1D(gravity_constant=9.81, H0=3.25) -# An initial condition with constant total water height and zero velocities to test well-balancedness. -# Note, this routine is used to compute errors in the analysis callback but the initialization is -# overwritten by `initial_condition_discontinuous_well_balancedness` below. -function initial_condition_well_balancedness(x, t, equations::ShallowWaterEquations1D) +# Setup a truly discontinuous bottom topography function for this academic +# testcase of well-balancedness. The errors from the analysis callback are +# not important but the error for this lake-at-rest test case +# `∑|H0-(h+b)|` should be around machine roundoff. +# Works as intended for TreeMesh1D with `initial_refinement_level=3`. If the mesh +# refinement level is changed the initial condition below may need changed as well to +# ensure that the discontinuities lie on an element interface. +function initial_condition_discontinuous_well_balancedness(x, t, equations::ShallowWaterEquations1D) # Set the background values H = equations.H0 v = 0.0 + b = 0.0 - # bottom topography inspired by from Pond.control in [HOHQMesh](https://github.com/trixi-framework/HOHQMesh) - b = (1.5 / exp( 0.5 * ((x[1] - 1.0)^2) )+ 0.75 / exp(0.5 * ((x[1] + 1.0)^2))) + # Setup a discontinuous bottom topography + if x[1] >= 0.5 && x[1] <= 0.75 + b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) + end return prim2cons(SVector(H, v, b), equations) end -initial_condition = initial_condition_well_balancedness +initial_condition = initial_condition_discontinuous_well_balancedness ############################################################################### # Get the DG approximation space @@ -50,41 +57,6 @@ semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) tspan = (0.0, 100.0) 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 for this academic testcase of well-balancedness. -# The errors from the analysis callback are not important but the error for this lake at rest test case -# `∑|H0-(h+b)|` 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 TreeMesh1D with `initial_refinement_level=3`. -function initial_condition_discontinuous_well_balancedness(x, t, element_id, equations::ShallowWaterEquations1D) - # Set the background values - H = equations.H0 - v = 0.0 - b = 0.0 - - # Setup a discontinuous bottom topography using the element id number - if element_id == 7 - b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) - end - - return prim2cons(SVector(H, v, 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 i in eachnode(semi.solver) - x_node = Trixi.get_node_coords(semi.cache.elements.node_coordinates, equations, semi.solver, i, element) - u_node = initial_condition_discontinuous_well_balancedness(x_node, first(tspan), element, equations) - Trixi.set_node_vars!(u, u_node, equations, semi.solver, i, element) - end -end - ############################################################################### # Callbacks diff --git a/src/equations/shallow_water_two_layer_1d.jl b/src/equations/shallow_water_two_layer_1d.jl index edf7d5e32ff..02899171509 100644 --- a/src/equations/shallow_water_two_layer_1d.jl +++ b/src/equations/shallow_water_two_layer_1d.jl @@ -11,28 +11,28 @@ Two-Layer Shallow Water equations (2LSWE) in one space dimension. The equations are given by ```math \begin{alignat*}{4} -&\frac{\partial}{\partial t}h_{upper} -&&+ \frac{\partial}{\partial x}\left(h_{upper} v_{1,upper}\right) +&\frac{\partial}{\partial t}h_{upper} +&&+ \frac{\partial}{\partial x}\left(h_{upper} v_{1,upper}\right) &&= 0 \\ -&\frac{\partial}{\partial t}\left(h_{upper}v_{1,upper}\right) -&&+ \frac{\partial}{\partial x}\left(h_{upper}v_{1,upper}^2 + \dfrac{gh_{upper}^2}{2}\right) +&\frac{\partial}{\partial t}\left(h_{upper}v_{1,upper}\right) +&&+ \frac{\partial}{\partial x}\left(h_{upper}v_{1,upper}^2 + \dfrac{gh_{upper}^2}{2}\right) &&= -gh_{upper}\frac{\partial}{\partial x}\left(b+h_{lower}\right)\\ -&\frac{\partial}{\partial t}h_{lower} -&&+ \frac{\partial}{\partial x}\left(h_{lower}v_{1,lower}\right) +&\frac{\partial}{\partial t}h_{lower} +&&+ \frac{\partial}{\partial x}\left(h_{lower}v_{1,lower}\right) &&= 0 \\ -&\frac{\partial}{\partial t}\left(h_{lower}v_{1,lower}\right) -&&+ \frac{\partial}{\partial x}\left(h_{lower}v_{1,lower}^2 + \dfrac{gh_{lower}^2}{2}\right) +&\frac{\partial}{\partial t}\left(h_{lower}v_{1,lower}\right) +&&+ \frac{\partial}{\partial x}\left(h_{lower}v_{1,lower}^2 + \dfrac{gh_{lower}^2}{2}\right) &&= -gh_{lower}\frac{\partial}{\partial x}\left(b+\dfrac{\rho_{upper}}{\rho_{lower}}h_{upper}\right). \end{alignat*} ``` -The unknown quantities of the 2LSWE are the water heights of the {lower} layer ``h_{lower}`` and the -{upper} layer ``h_{upper}`` with respective velocities ``v_{1,upper}`` and ``v_{1,lower}``. The gravitational constant is -denoted by `g`, the layer densitites by ``\rho_{upper}``and ``\rho_{lower}`` and the (possibly) variable -bottom topography function ``b(x)``. The conservative variable water height ``h_{lower}`` is measured -from the bottom topography ``b`` and ``h_{upper}`` relative to ``h_{lower}``, therefore one also defines the +The unknown quantities of the 2LSWE are the water heights of the {lower} layer ``h_{lower}`` and the +{upper} layer ``h_{upper}`` with respective velocities ``v_{1,upper}`` and ``v_{1,lower}``. The gravitational constant is +denoted by `g`, the layer densitites by ``\rho_{upper}``and ``\rho_{lower}`` and the (possibly) variable +bottom topography function ``b(x)``. The conservative variable water height ``h_{lower}`` is measured +from the bottom topography ``b`` and ``h_{upper}`` relative to ``h_{lower}``, therefore one also defines the total water heights as ``H_{upper} = h_{upper} + h_{upper} + b`` and ``H_{lower} = h_{lower} + b``. -The densities must be chosen such that ``\rho_{upper} < \rho_{lower}``, to make sure that the heavier fluid +The densities must be chosen such that ``\rho_{upper} < \rho_{lower}``, to make sure that the heavier fluid ``\rho_{lower}`` is in the bottom layer and the lighter fluid ``\rho_{upper}`` in the {upper} layer. The additional quantity ``H_0`` is also available to store a reference value for the total water @@ -41,13 +41,13 @@ height that is useful to set initial conditions or test the "lake-at-rest" well- The bottom topography function ``b(x)`` is set inside the initial condition routine for a particular problem setup. -In addition to the unknowns, Trixi currently stores the bottom topography values at the -approximation points despite being fixed in time. This is done for convenience of computing the -bottom topography gradients on the fly during the approximation as well as computing auxiliary +In addition to the unknowns, Trixi currently stores the bottom topography values at the +approximation points despite being fixed in time. This is done for convenience of computing the +bottom topography gradients on the fly during the approximation as well as computing auxiliary quantities like the total water height ``H`` or the entropy variables. This affects the implementation and use of these equations in various ways: * The flux values corresponding to the bottom topography must be zero. -* The bottom topography values must be included when defining initial conditions, boundary +* The bottom topography values must be included when defining initial conditions, boundary conditions or source terms. * [`AnalysisCallback`](@ref) analyzes this variable. * Trixi's visualization tools will visualize the bottom topography by default. @@ -101,7 +101,7 @@ end initial_condition_convergence_test(x, t, equations::ShallowWaterTwoLayerEquations1D) A smooth initial condition used for convergence tests in combination with -[`source_terms_convergence_test`](@ref) (and +[`source_terms_convergence_test`](@ref) (and [`BoundaryConditionDirichlet(initial_condition_convergence_test)`](@ref) in non-periodic domains). """ function initial_condition_convergence_test(x, t, @@ -121,9 +121,9 @@ end """ source_terms_convergence_test(u, x, t, equations::ShallowWaterTwoLayerEquations1D) -Source terms used for convergence tests in combination with -[`initial_condition_convergence_test`](@ref) -(and [`BoundaryConditionDirichlet(initial_condition_convergence_test)`](@ref) +Source terms used for convergence tests in combination with +[`initial_condition_convergence_test`](@ref) +(and [`BoundaryConditionDirichlet(initial_condition_convergence_test)`](@ref) in non-periodic domains). """ @inline function source_terms_convergence_test(u, x, t, @@ -167,8 +167,8 @@ the internal value. For details see Section 9.2.5 of the book: - Eleuterio F. Toro (2001) - Shock-Capturing Methods for Free-Surface Shallow Flows - 1st edition + Shock-Capturing Methods for Free-Surface Shallow Flows + 1st edition ISBN 0471987662 """ @inline function boundary_condition_slip_wall(u_inner, orientation_or_normal, direction, @@ -219,7 +219,7 @@ end Non-symmetric two-point volume flux discretizing the nonconservative (source) term that contains the gradient of the bottom topography [`ShallowWaterTwoLayerEquations2D`](@ref) and an -additional term that couples the momentum of both layers. This is a slightly modified version +additional term that couples the momentum of both layers. This is a slightly modified version to account for the additional source term compared to the standard SWE described in the paper. Further details are available in the paper: @@ -238,7 +238,7 @@ Further details are available in the paper: z = zero(eltype(u_ll)) - # Bottom gradient nonconservative term: (0, g*h_upper*(b+h_lower)_x, + # Bottom gradient nonconservative term: (0, g*h_upper*(b+h_lower)_x, # 0, g*h_lower*(b+r*h_upper)_x, 0) f = SVector(z, equations.gravity * h_upper_ll * (b_rr + h_lower_rr), @@ -254,9 +254,9 @@ end !!! warning "Experimental code" This numerical flux is experimental and may change in any future release. - -Non-symmetric two-point surface flux discretizing the nonconservative (source) term that contains -the gradients of the bottom topography and an additional term that couples the momentum of both + +Non-symmetric two-point surface flux discretizing the nonconservative (source) term that contains +the gradients of the bottom topography and an additional term that couples the momentum of both layers [`ShallowWaterTwoLayerEquations2D`](@ref). Further details are available in the paper: @@ -286,7 +286,7 @@ formulation. z = zero(eltype(u_ll)) - # Bottom gradient nonconservative term: (0, g*h_upper*(b+h_lower)_x, + # Bottom gradient nonconservative term: (0, g*h_upper*(b+h_lower)_x, # 0, g*h_lower*(b+r*h_upper)_x, 0) f = SVector(z, g * h_upper_ll * (b_ll + h_lower_ll) + @@ -303,13 +303,13 @@ end flux_fjordholm_etal(u_ll, u_rr, orientation, equations::ShallowWaterTwoLayerEquations1D) -Total energy conservative (mathematical entropy for shallow water equations). When the bottom -topography is nonzero this should only be used as a surface flux otherwise the scheme will not be +Total energy conservative (mathematical entropy for shallow water equations). When the bottom +topography is nonzero this should only be used as a surface flux otherwise the scheme will not be well-balanced. For well-balancedness in the volume flux use [`flux_wintermeyer_etal`](@ref). Details are available in Eq. (4.1) in the paper: - Ulrik S. Fjordholm, Siddhartha Mishra and Eitan Tadmor (2011) - Well-balanced and energy stable schemes for the shallow water equations with discontinuous + Well-balanced and energy stable schemes for the shallow water equations with discontinuous topography [DOI: 10.1016/j.jcp.2011.03.042](https://doi.org/10.1016/j.jcp.2011.03.042) and the application to two layers is shown in the paper: - Ulrik Skre Fjordholm (2012) @@ -348,11 +348,11 @@ end """ flux_wintermeyer_etal(u_ll, u_rr, orientation, equations::ShallowWaterTwoLayerEquations1D) - + Total energy conservative (mathematical entropy for two-layer 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). To obtain the flux for the -two-layer shallow water equations the flux that is described in the paper for the normal shallow +two-layer shallow water equations the flux that is described in the paper for the normal shallow water equations is used within each layer. Further details are available in Theorem 1 of the paper: @@ -391,8 +391,8 @@ end flux_es_fjordholm_etal(u_ll, u_rr, orientation, equations::ShallowWaterTwoLayerEquations1D) -Entropy stable surface flux for the two-layer shallow water equations. Uses the entropy -conservative flux_fjordholm_etal and adds a Lax-Friedrichs type dissipation dependent on the jump +Entropy stable surface flux for the two-layer shallow water equations. Uses the entropy +conservative flux_fjordholm_etal and adds a Lax-Friedrichs type dissipation dependent on the jump of entropy variables. Further details are available in the paper: @@ -460,10 +460,10 @@ formulation. end # Calculate approximation for maximum wave speed for local Lax-Friedrichs-type dissipation as the -# maximum velocity magnitude plus the maximum speed of sound. This function uses approximate -# eigenvalues using the speed of the barotropic mode as there is no simple way to calculate them +# maximum velocity magnitude plus the maximum speed of sound. This function uses approximate +# eigenvalues using the speed of the barotropic mode as there is no simple way to calculate them # analytically. -# +# # A good overview of the derivation is given in: # - Jonas Nycander, Andrew McC. Hogg, Leela M. Frankcombe (2008) # Open boundary conditions for nonlinear channel Flows @@ -488,7 +488,7 @@ end return (max(abs(v_m_ll) + c_ll, abs(v_m_rr) + c_rr)) end -# Specialized `DissipationLocalLaxFriedrichs` to avoid spurious dissipation in the bottom +# Specialized `DissipationLocalLaxFriedrichs` to avoid spurious dissipation in the bottom # topography @inline function (dissipation::DissipationLocalLaxFriedrichs)(u_ll, u_rr, orientation_or_normal_direction, @@ -530,7 +530,7 @@ end end # Convert conservative variables to entropy variables -# Note, only the first four are the entropy variables, the fifth entry still just carries the +# Note, only the first four are the entropy variables, the fifth entry still just carries the # bottom topography values for convenience @inline function cons2entropy(u, equations::ShallowWaterTwoLayerEquations1D) h_upper, _, h_lower, _, b = u @@ -567,7 +567,7 @@ end # Calculate total energy for a conservative state `cons` @inline function energy_total(cons, equations::ShallowWaterTwoLayerEquations1D) - h_upper, h_lower, h_v1_upper, h_v2_lower, b = cons + h_upper, h_v1_upper, h_lower, h_v2_lower, b = cons # Set new variables for better readability g = equations.gravity rho_upper = equations.rho_upper diff --git a/src/solvers/dg.jl b/src/solvers/dg.jl index 838fa2d5819..2536cfe0bf2 100644 --- a/src/solvers/dg.jl +++ b/src/solvers/dg.jl @@ -628,6 +628,15 @@ function compute_coefficients!(u, func, t, mesh::AbstractMesh{1}, equations, dg: for i in eachnode(dg) x_node = get_node_coords(cache.elements.node_coordinates, equations, dg, i, element) + # Changing the node positions passed to the initial condition by the minimum + # amount possible with the current type of floating point numbers allows setting + # discontinuous initial data in a simple way. In particular, a check like `if x < x_jump` + # works if the jump location `x_jump` is at the position of an interface. + if i == 1 + x_node = SVector(nextfloat(x_node[1])) + elseif i == nnodes(dg) + x_node = SVector(prevfloat(x_node[1])) + end u_node = func(x_node, t, equations) set_node_vars!(u, u_node, equations, dg, i, element) end diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index a27d3c219e1..ec8c7a138d5 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -27,8 +27,8 @@ isdir(outdir) && rm(outdir, recursive=true) @trixi_testset "elixir_advection_shockcapturing.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_shockcapturing.jl"), - l2 = [0.08004076716881656], - linf = [0.6342577638501385], + l2 = [0.08015029105233593], + linf = [0.610709468736576], atol = 1.0e-5) end diff --git a/test/test_tree_1d.jl b/test/test_tree_1d.jl index e37e1efc3e6..7737a93a15a 100644 --- a/test/test_tree_1d.jl +++ b/test/test_tree_1d.jl @@ -271,7 +271,7 @@ end sol = solve(ode, Tsit5(), abstol=1.0e-6, reltol=1.0e-6, save_everystep=false, callback=callbacks); - @test analysis_callback(sol).l2 ≈ [0.00029610274971929974, 5.573684084938363e-6] + @test analysis_callback(sol).l2 ≈ [0.00029609575838969394, 5.5681704039507985e-6] end diff --git a/test/test_tree_1d_burgers.jl b/test/test_tree_1d_burgers.jl index 788c7ab4199..8c4cfaa406d 100644 --- a/test/test_tree_1d_burgers.jl +++ b/test/test_tree_1d_burgers.jl @@ -22,14 +22,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @trixi_testset "elixir_burgers_shock.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_shock.jl"), - l2 = [0.4407585104869119], - linf = [1.000000000000001]) + l2 = [0.4422505602587537], + linf = [1.0000000000000009]) end @trixi_testset "elixir_burgers_rarefaction.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_rarefaction.jl"), - l2 = [0.40287062735307044], - linf = [1.0042992585765542]) + l2 = [0.4038224690923722], + linf = [1.0049201454652736]) end end diff --git a/test/test_tree_1d_euler.jl b/test/test_tree_1d_euler.jl index 40f2a38b0e1..5fb74b80bce 100644 --- a/test/test_tree_1d_euler.jl +++ b/test/test_tree_1d_euler.jl @@ -22,8 +22,8 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @trixi_testset "elixir_euler_density_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_density_wave.jl"), - l2 = [0.0011482554820185795, 0.00011482554830363504, 5.741277417754598e-6], - linf = [0.004090978306820037, 0.00040909783134346345, 2.0454891732413216e-5]) + l2 = [0.0011482554820217855, 0.00011482554830323462, 5.741277429325267e-6], + linf = [0.004090978306812376, 0.0004090978313582294, 2.045489210189544e-5]) end @trixi_testset "elixir_euler_density_wave.jl with initial_condition_constant" begin @@ -41,14 +41,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @trixi_testset "elixir_euler_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.11915540925414216, 0.15489191247295198, 0.44543052524765375], - linf = [0.2751485868543495, 0.2712764982000735, 0.9951407418216425]) + l2 = [0.11821957357197649, 0.15330089521538678, 0.4417674632047301], + linf = [0.24280567569982958, 0.29130548795961936, 0.8847009003152442]) end @trixi_testset "elixir_euler_ec.jl with flux_kennedy_gruber" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.07905582221868049, 0.10180958900546237, 0.29596551476711125], - linf = [0.23515297345769826, 0.2958208108392532, 0.8694224308790321], + l2 = [0.07803455838661963, 0.10032577312032283, 0.29228156303827935], + linf = [0.2549869853794955, 0.3376472164661263, 0.9650477546553962], maxiters = 10, surface_flux = flux_kennedy_gruber, volume_flux = flux_kennedy_gruber) @@ -56,8 +56,8 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @trixi_testset "elixir_euler_ec.jl with flux_shima_etal" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.07909267609417114, 0.1018246500951966, 0.2959649187481973], - linf = [0.23631829743146504, 0.2977756307879202, 0.8642794698697331], + l2 = [0.07800654460172655, 0.10030365573277883, 0.2921481199111959], + linf = [0.25408579350400395, 0.3388657679031271, 0.9776486386921928], maxiters = 10, surface_flux = flux_shima_etal, volume_flux = flux_shima_etal) @@ -65,8 +65,8 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @trixi_testset "elixir_euler_ec.jl with flux_chandrashekar" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.07905306555214126, 0.10181180378499956, 0.2959171937479504], - linf = [0.24057642004451651, 0.29691454643616433, 0.886425723870524], + l2 = [0.07801923089205756, 0.10039557434912669, 0.2922210399923278], + linf = [0.2576521982607225, 0.3409717926625057, 0.9772961936567048], maxiters = 10, surface_flux = flux_chandrashekar, volume_flux = flux_chandrashekar) @@ -74,8 +74,8 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @trixi_testset "elixir_euler_ec.jl with flux_hll" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.07959780803600519, 0.10342491934977621, 0.2978851659149904], - linf = [0.19228754121840885, 0.2524152253292552, 0.725604944702432], + l2 = [0.07852272782240548, 0.10209790867523805, 0.293873048809011], + linf = [0.19244768908604093, 0.2515941686151897, 0.7258000837553769], maxiters = 10, surface_flux = flux_hll, volume_flux = flux_ranocha) @@ -83,8 +83,8 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @trixi_testset "elixir_euler_shockcapturing.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing.jl"), - l2 = [0.11665968950973675, 0.15105507394693413, 0.43503082674771115], - linf = [0.1867400345208743, 0.24621854448555328, 0.703826406555577]) + l2 = [0.11606096465319675, 0.15028768943458806, 0.4328230323046703], + linf = [0.18031710091067965, 0.2351582421501841, 0.6776805692092567]) end @trixi_testset "elixir_euler_sedov_blast_wave.jl" begin @@ -96,8 +96,8 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @trixi_testset "elixir_euler_sedov_blast_wave_pure_fv.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov_blast_wave_pure_fv.jl"), - l2 = [1.075075094036344, 0.06766902169711514, 0.9221426570128292], - linf = [3.3941512671408542, 0.16862631133303882, 2.6572394126490315], + l2 = [1.0735456065491455, 0.07131078703089379, 0.9205739468590453], + linf = [3.4296365168219216, 0.17635583964559245, 2.6574584326179505], # Let this test run longer to cover some lines in flux_hllc coverage_override = (maxiters=10^5, tspan=(0.0, 0.1))) end @@ -129,22 +129,22 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @trixi_testset "elixir_euler_blast_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blast_wave.jl"), - l2 = [0.21651329948737183, 0.28091709900008616, 0.5580778880050432], - linf = [1.513525457073142, 1.5328754303137992, 2.0467706106669556], + l2 = [0.21934822867340323, 0.28131919126002686, 0.554361702716662], + linf = [1.5180897390290355, 1.3967085956620369, 2.0663825294019595], maxiters = 30) end @trixi_testset "elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl"), - l2 = [2.13605618e-01, 2.79953055e-01, 5.54424459e-01], - linf = [1.55151701e+00, 1.55696782e+00, 2.05525953e+00], + l2 = [0.21814833203212694, 0.2818328665444332, 0.5528379124720818], + linf = [1.5548653877320868, 1.4474018998129738, 2.071919577393772], maxiters = 30) end @trixi_testset "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl"), - l2 = [2.18148857e-01, 2.83182959e-01, 5.59096194e-01], - linf = [1.62706876e+00, 1.61680275e+00, 2.05876517e+00], + l2 = [0.22054468879127423, 0.2828269190680846, 0.5542369885642424], + linf = [1.5623359741479623, 1.4290121654488288, 2.1040405133123072], maxiters = 30) end end diff --git a/test/test_tree_1d_eulermulti.jl b/test/test_tree_1d_eulermulti.jl index eac54a9372c..e880f98e2d0 100644 --- a/test/test_tree_1d_eulermulti.jl +++ b/test/test_tree_1d_eulermulti.jl @@ -11,39 +11,47 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @trixi_testset "elixir_eulermulti_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_ec.jl"), - l2 = [1.54891912e-01, 4.45430525e-01, 1.70222013e-02, 3.40444026e-02, 6.80888053e-02], - linf = [2.71276498e-01, 9.95140742e-01, 3.93069410e-02, 7.86138820e-02, 1.57227764e-01]) + l2 = [0.15330089521538684, 0.4417674632047301, 0.016888510510282385, 0.03377702102056477, + 0.06755404204112954], + linf = [0.29130548795961864, 0.8847009003152357, 0.034686525099975274, 0.06937305019995055, + 0.1387461003999011]) end @trixi_testset "elixir_eulermulti_es.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_es.jl"), - l2 = [1.53387916e-01, 4.41585576e-01, 3.93605635e-02, 7.87211270e-02], - linf = [2.49632117e-01, 7.21088064e-01, 6.38328770e-02, 1.27665754e-01]) + l2 = [0.1522380497572071, 0.43830846465313206, 0.03907262116499431, 0.07814524232998862], + linf = [0.24939193075537294, 0.7139395740052739, 0.06324208768391237, 0.12648417536782475]) end @trixi_testset "elixir_eulermulti_convergence_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_ec.jl"), - l2 = [8.57523604e-05, 1.63878043e-04, 1.94126993e-05, 3.88253986e-05], - linf = [3.05932773e-04, 6.24480393e-04, 7.25312144e-05, 1.45062429e-04]) + l2 = [8.575236038539227e-5, 0.00016387804318585358, 1.9412699303977585e-5, 3.882539860795517e-5], + linf = [0.00030593277277124464, 0.0006244803933350696, 7.253121435135679e-5, 0.00014506242870271358]) end @trixi_testset "elixir_eulermulti_convergence_es.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_es.jl"), - l2 = [1.8983933794407234e-5, 6.207744299844731e-5, 1.5466205761868047e-6, 3.0932411523736094e-6, 6.186482304747219e-6, 1.2372964609494437e-5], - linf = [0.00012014372605895218, 0.0003313207215800418, 6.50836791016296e-6, 1.301673582032592e-5, 2.603347164065184e-5, 5.206694328130368e-5]) + l2 = [1.8983933794407234e-5, 6.207744299844731e-5, 1.5466205761868047e-6, 3.0932411523736094e-6, + 6.186482304747219e-6, 1.2372964609494437e-5], + linf = [0.00012014372605895218, 0.0003313207215800418, 6.50836791016296e-6, 1.301673582032592e-5, + 2.603347164065184e-5, 5.206694328130368e-5]) end @trixi_testset "elixir_eulermulti_convergence_es.jl with flux_chandrashekar" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_es.jl"), - l2 = [1.88845048e-05, 5.49106005e-05, 9.42673716e-07, 1.88534743e-06, 3.77069486e-06, 7.54138973e-06], - linf = [1.16223512e-04, 3.07922197e-04, 3.21774233e-06, 6.43548465e-06, 1.28709693e-05, 2.57419386e-05], + l2 = [1.888450477353845e-5, 5.4910600482795386e-5, 9.426737161533622e-7, 1.8853474323067245e-6, + 3.770694864613449e-6, 7.541389729226898e-6], + linf = [0.00011622351152063004, 0.0003079221967086099, 3.2177423254231563e-6, 6.435484650846313e-6, + 1.2870969301692625e-5, 2.574193860338525e-5], volume_flux = flux_chandrashekar) end @trixi_testset "elixir_eulermulti_two_interacting_blast_waves.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_two_interacting_blast_waves.jl"), - l2 = [1.28886761e+00, 8.27133526e+01, 3.50680272e-03, 1.36987844e-02, 1.91795185e-02], - linf = [2.96413045e+01, 1.32258448e+03, 9.19191937e-02, 3.10929710e-01, 4.41798976e-01], + l2 = [1.288867611915533, 82.71335258388848, 0.00350680272313187, 0.013698784353152794, + 0.019179518517518084], + linf = [29.6413044707026, 1322.5844802186496, 0.09191919374782143, 0.31092970966717925, + 0.4417989757182038], tspan = (0.0, 0.0001)) end diff --git a/test/test_tree_1d_mhd.jl b/test/test_tree_1d_mhd.jl index 938959831c1..e3a0cda3250 100644 --- a/test/test_tree_1d_mhd.jl +++ b/test/test_tree_1d_mhd.jl @@ -32,14 +32,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @trixi_testset "elixir_mhd_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ec.jl"), - l2 = [5.86009540e-02, 8.16048158e-02, 5.46791194e-02, 5.46791194e-02, 1.54509265e-01, 4.13046273e-17, 5.47637521e-02, 5.47637521e-02], - linf = [1.10014999e-01, 1.81982581e-01, 9.13611439e-02, 9.13611439e-02, 4.23831370e-01, 1.11022302e-16, 9.93731761e-02, 9.93731761e-02]) + l2 = [0.05815183849746399, 0.08166807325621023, 0.054659228513541165, 0.054659228513541165, 0.15578125987042743, 4.130462730494e-17, 0.05465258887150046, 0.05465258887150046], + linf = [0.12165312668363826, 0.1901920742264952, 0.10059813883022554, 0.10059813883022554, 0.44079257431070706, 1.1102230246251565e-16, 0.10528911365809579, 0.10528911365809579]) end @trixi_testset "elixir_mhd_briowu_shock_tube.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_briowu_shock_tube.jl"), - l2 = [0.17764301067932906, 0.19693621875378622, 0.3635136528288642, 0.0, 0.3757321708837591, 8.593007507325741e-16, 0.36473438378159656, 0.0], - linf = [0.5601530250396535, 0.43867368105486537, 1.0960903616351099, 0.0, 1.0551794137886303, 4.107825191113079e-15, 1.5374410890043144, 0.0], + l2 = [0.17477712356961989, 0.19489623595086944, 0.3596546157640463, 0.0, 0.3723215736814466, 1.2060075775846403e-15, 0.36276754492568164, 0.0], + linf = [0.5797109945880677, 0.4372991899547103, 1.0906536287185835, 0.0, 1.0526758874956808, 5.995204332975845e-15, 1.5122922036932964, 0.0], coverage_override = (maxiters=6,)) end @@ -51,8 +51,8 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @trixi_testset "elixir_mhd_ryujones_shock_tube.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ryujones_shock_tube.jl"), - l2 = [2.34809441e-01, 3.92255943e-01, 8.23575546e-02, 1.75599624e-01, 9.61613519e-01, 6.60825891e-17, 2.15346454e-01, 1.07006529e-01], - linf = [6.40732148e-01, 9.44889516e-01, 3.54932707e-01, 8.54060243e-01, 2.07757711e+00, 1.11022302e-16, 4.92584725e-01, 2.49526561e-01], + l2 = [0.23469781891518154, 0.3916675299696121, 0.08245195301016353, 0.1745346945706147, 0.9606363432904367, 6.608258910237605e-17, 0.21542929107153735, 0.10705457908737925], + linf = [0.6447951791685409, 0.9461857095377463, 0.35074627554617605, 0.8515177411529542, 2.0770652030507053, 1.1102230246251565e-16, 0.49670855513788204, 0.24830199967863564], tspan = (0.0, 0.1)) end diff --git a/test/test_tree_1d_mhdmulti.jl b/test/test_tree_1d_mhdmulti.jl index 2985e6d5663..5214ed26d38 100644 --- a/test/test_tree_1d_mhdmulti.jl +++ b/test/test_tree_1d_mhdmulti.jl @@ -11,33 +11,33 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @trixi_testset "elixir_mhdmulti_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmulti_ec.jl"), - l2 = [0.08160481582829862, 0.05467911944326103, 0.05467911944326103, 0.15450926504459692, - 4.130462730494e-17, 0.054763752050210085, 0.054763752050210085, 0.008371564857135208, - 0.016743129714270416, 0.03348625942854083], - linf = [0.18198258075330706, 0.09136114386311774, 0.09136114386311774, 0.423831369951313, - 1.1102230246251565e-16, 0.09937317613143604, 0.09937317613143604, 0.0157164284712992, - 0.0314328569425984, 0.0628657138851968]) + l2 = [0.08166807325620999, 0.054659228513541616, 0.054659228513541616, 0.15578125987042812, + 4.130462730494e-17, 0.054652588871500665, 0.054652588871500665, 0.008307405499637766, + 0.01661481099927553, 0.03322962199855106], + linf = [0.19019207422649645, 0.10059813883022888, 0.10059813883022888, 0.4407925743107146, + 1.1102230246251565e-16, 0.10528911365809623, 0.10528911365809623, 0.01737901809766182, + 0.03475803619532364, 0.06951607239064728]) end @trixi_testset "elixir_mhdmulti_ec.jl with flux_derigs_etal" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmulti_ec.jl"), - l2 = [0.08153372259925547, 0.05464109003345891, 0.05464109003345891, 0.1540576724164453, - 4.130462730494e-17, 0.054734930802131036, 0.054734930802131036, 0.008391254781284321, - 0.016782509562568642, 0.033565019125137284], - linf = [0.17492544007323832, 0.09029632168248182, 0.09029632168248182, 0.40798609353896564, - 1.1102230246251565e-16, 0.09872923637833075, 0.09872923637833075, 0.01609818847160674, - 0.03219637694321348, 0.06439275388642696], + l2 = [0.08151404166186461, 0.054640238302693274, 0.054640238302693274, 0.15536125426328573, + 4.130462730494e-17, 0.054665489963920275, 0.054665489963920275, 0.008308349501359825, + 0.01661669900271965, 0.0332333980054393], + linf = [0.1824424257860952, 0.09734687137001484, 0.09734687137001484, 0.4243089502087325, + 1.1102230246251565e-16, 0.09558639591092555, 0.09558639591092555, 0.017364773041550624, + 0.03472954608310125, 0.0694590921662025], volume_flux = flux_derigs_etal) end @trixi_testset "elixir_mhdmulti_es.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmulti_es.jl"), - l2 = [0.07968782477167513, 0.05398115008116676, 0.05398115008116676, 0.15015281822439228, - 4.130462730494e-17, 0.053629890024921495, 0.053629890024921495, 0.008279068245579706, - 0.016558136491159413, 0.033116272982318826], - linf = [0.14118014632124837, 0.07820697032983395, 0.07820697032983395, 0.3390558674728652, - 1.1102230246251565e-16, 0.06998787893467828, 0.06998787893467828, 0.014943825414763745, - 0.02988765082952749, 0.05977530165905498]) + l2 = [0.07994082660130175, 0.053940174914031976, 0.053940174914031976, 0.15165513559250643, + 4.130462730494e-17, 0.05363207135290325, 0.05363207135290325, 0.008258265884659555, + 0.01651653176931911, 0.03303306353863822], + linf = [0.14101014428198477, 0.07762441749521025, 0.07762441749521025, 0.3381334453289866, + 1.1102230246251565e-16, 0.07003646400675223, 0.07003646400675223, 0.014962483760600165, + 0.02992496752120033, 0.05984993504240066]) end @trixi_testset "elixir_mhdmulti_convergence.jl" begin @@ -52,12 +52,12 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @trixi_testset "elixir_mhdmulti_briowu_shock_tube.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmulti_briowu_shock_tube.jl"), - l2 = [0.1946577804333822, 0.3591196215528672, 0.0, 0.36875476066849383, - 4.7644020131827105e-16, 0.36668249926193885, 0.0, 0.05775369214541893, - 0.11550738429083786], - linf = [0.4345551123140612, 1.0874941615375844, 0.0, 1.0493729052116585, - 3.219646771412954e-15, 1.5160434573973656, 0.0, 0.18616213071936066, - 0.3723242614387213], + l2 = [0.1877830835572639, 0.3455841730726793, 0.0, 0.35413123388836687, + 8.745556626531982e-16, 0.3629920109231055, 0.0, 0.05329005553971236, + 0.10658011107942472], + linf = [0.4288187627971754, 1.0386547815614993, 0.0, 0.9541678878162702, + 5.773159728050814e-15, 1.4595119339458051, 0.0, 0.18201910908829552, + 0.36403821817659104], coverage_override = (maxiters=6,)) end diff --git a/test/test_tree_1d_shallowwater.jl b/test/test_tree_1d_shallowwater.jl index f8901a3dcb6..1c3bac1fab6 100644 --- a/test/test_tree_1d_shallowwater.jl +++ b/test/test_tree_1d_shallowwater.jl @@ -10,22 +10,30 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @testset "Shallow Water" begin @trixi_testset "elixir_shallowwater_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_ec.jl"), - l2 = [0.8122354510732459, 1.01586214815876, 0.43404255061704217], - linf = [1.4883285368551107, 3.8717508164234276, 1.7711213427919539], + l2 = [0.244729018751225, 0.8583565222389505, 0.07330427577586297], + linf = [2.1635021283528504, 3.8717508164234453, 1.7711213427919539], + tspan = (0.0, 0.25)) + end + + @trixi_testset "elixir_shallowwater_ec.jl with initial_condition_weak_blast_wave" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_ec.jl"), + l2 = [0.39464782107209717, 2.03880864210846, 4.1623084150546725e-10], + linf = [0.778905801278281, 3.2409883402608273, 7.419800190922032e-10], + initial_condition=initial_condition_weak_blast_wave, tspan = (0.0, 0.25)) end @trixi_testset "elixir_shallowwater_well_balanced.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced.jl"), - l2 = [1.2427984842961743, 1.0332499675061871e-14, 1.2427984842961741], - linf = [1.619041478244762, 1.266865149831811e-14, 1.6190414782447629], + l2 = [0.10416666834254829, 1.4352935256803184e-14, 0.10416666834254838], + linf = [1.9999999999999996, 3.248036646353028e-14, 2.0], tspan = (0.0, 0.25)) end @trixi_testset "elixir_shallowwater_well_balanced.jl with FluxHydrostaticReconstruction" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced.jl"), - l2 = [1.2427984842961743, 1.2663646513352053e-14, 1.2427984842961741], - linf = [1.619041478244762, 2.4566658711604395e-14, 1.6190414782447629], + l2 = [0.10416666834254835, 1.1891029971551825e-14, 0.10416666834254838], + linf = [2.0000000000000018, 2.4019608337954543e-14, 2.0], surface_flux=(FluxHydrostaticReconstruction(flux_lax_friedrichs, hydrostatic_reconstruction_audusse_etal), flux_nonconservative_audusse_etal), tspan = (0.0, 0.25)) end @@ -59,14 +67,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") tspan = (0.0, 0.025)) end - @trixi_testset "elixir_shallowwater_well_balanced_nonperiodic.jl with dirichlet boundary" begin + @trixi_testset "elixir_shallowwater_well_balanced_nonperiodic.jl with Dirichlet boundary" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced_nonperiodic.jl"), l2 = [1.725964362045055e-8, 5.0427180314307505e-16, 1.7259643530442137e-8], linf = [3.844551077492042e-8, 3.469453422316143e-15, 3.844551077492042e-8], tspan = (0.0, 0.25)) end - @trixi_testset "elixir_shallowwater_well_nonperiodic.jl with wall boundary" begin + @trixi_testset "elixir_shallowwater_well_balanced_nonperiodic.jl with wall boundary" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced_nonperiodic.jl"), l2 = [1.7259643614361866e-8, 3.5519018243195145e-16, 1.7259643530442137e-8], linf = [3.844551010878661e-8, 9.846474508971374e-16, 3.844551077492042e-8], @@ -76,8 +84,8 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @trixi_testset "elixir_shallowwater_shock_capturing.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_shock_capturing.jl"), - l2 = [0.2884024818919076, 0.5252262013521178, 0.2890348477852955], - linf = [0.7565706154863958, 2.076621603471687, 0.8646939843534258], + l2 = [0.07424140641160326, 0.2148642632748155, 0.0372579849000542], + linf = [1.1209754279344226, 1.3230788645853582, 0.8646939843534251], tspan = (0.0, 0.05)) end end diff --git a/test/test_tree_1d_shallowwater_twolayer.jl b/test/test_tree_1d_shallowwater_twolayer.jl index 6c0ad2941cc..0d8a83806f9 100644 --- a/test/test_tree_1d_shallowwater_twolayer.jl +++ b/test/test_tree_1d_shallowwater_twolayer.jl @@ -38,9 +38,9 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @trixi_testset "elixir_shallowwater_twolayer_dam_break.jl with flux_lax_friedrichs" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_twolayer_dam_break.jl"), - l2 = [0.35490827242437256, 1.6715402155795918, 0.6960264969949427, - 0.9351481433409805, 0.7938172946965545], - linf = [0.6417127471419837, 1.9742107034120873, 1.135774587483082, 1.236125279347084, 1.1], + l2 = [0.10010269243463918, 0.5668733957648654, 0.08759617327649398, + 0.4538443183566172, 0.013638618139749523], + linf = [0.5854202777756559, 2.1278930820498934, 0.5193686074348809, 1.8071213168086229, 0.5], surface_flux = (flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), tspan = (0.0, 0.25)) end From 9ea37cce8f510dcc135ad568280fd770a693ba10 Mon Sep 17 00:00:00 2001 From: David Knapp Date: Mon, 19 Jun 2023 16:16:48 +0200 Subject: [PATCH 006/263] Add a pre-commit script and an adapted formatting file (#1534) * Add a pre-commit script and an adapted formatting file * Formatting I am aware of the irony * Fix typo * Added documentation * Fix Typo --- docs/src/styleguide.md | 11 ++++++++++ utils/pre-commit | 40 ++++++++++++++++++++++++++++++++++++ utils/trixi-format-file.jl | 42 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100755 utils/pre-commit create mode 100755 utils/trixi-format-file.jl diff --git a/docs/src/styleguide.md b/docs/src/styleguide.md index de367c086cc..9e6b6a8c265 100644 --- a/docs/src/styleguide.md +++ b/docs/src/styleguide.md @@ -65,3 +65,14 @@ utils/trixi-format.jl ``` You can get more information about using the convenience script by running it with the `--help`/`-h` flag. + +### Checking formatting before committing +It can be convenient to check the formatting of source code automatically before each commit. +We use git-hooks for it and provide a `pre-commit` script in the `utils` folder. The script uses +[JuliaFormatter.jl](https://github.com/domluna/JuliaFormatter.jl) just like formatting script that +runs over the whole Trixi.jl directory. +You can copy the `pre-commit`-script into `.git/hooks/pre-commit` and it will check your formatting +before each commit. If errors are found the commit is aborted and you can add the corrections via +```shell +git add -p +``` \ No newline at end of file diff --git a/utils/pre-commit b/utils/pre-commit new file mode 100755 index 00000000000..2977b9a200b --- /dev/null +++ b/utils/pre-commit @@ -0,0 +1,40 @@ +#!/bin/sh + +# Copy this file into .git/hooks/pre-commit to execute before each commit. +# It checks and corrects the format for each file. +# If incorrect formatting is found you can add the correction via git add -p + +echo "Checking format before committing" + +if git ref-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=280fc57fade28e35046c3e884e587ffef05d3867 +fi + +# Redirect output to stderr. +exec 1>&2 + +# Create a list of files to format. +files=() + +for file in `git diff --cached --name-only` +do + # only indent existing files, this is necessary since if we rename or delete + # a file it is added to the committed files and we thus would try to indent a + # nonexisting file. + if [ ! -e $file ] + then + continue + fi + # We only indent .jl files + FILE_ENDING="${file##*.}" + if [ $FILE_ENDING = "jl" ] + then + files+=($file) + fi +done + +julia utils/trixi-format-file.jl "${files[@]}" diff --git a/utils/trixi-format-file.jl b/utils/trixi-format-file.jl new file mode 100755 index 00000000000..c4d8e7c9032 --- /dev/null +++ b/utils/trixi-format-file.jl @@ -0,0 +1,42 @@ +#!/usr/bin/env julia + +using Pkg +Pkg.activate(; temp = true, io = devnull) +Pkg.add("JuliaFormatter"; preserve = PRESERVE_ALL, io = devnull) + +using JuliaFormatter: format_file + +function main() + # Show help + if "-h" in ARGS || "--help" in ARGS + println("usage: trixi-format.jl PATH [PATH...]") + println() + println("positional arguments:") + println() + println(" PATH One or more paths (directories or files) to format. Default: '.'") + return nothing + end + + file_list = ARGS + if isempty(ARGS) + exit(0) + end + non_formatted_files = Vector{String}() + for file in file_list + println("Checking file " * file) + if !format_file(file) + push!(non_formatted_files, file) + end + end + if isempty(non_formatted_files) + exit(0) + else + @error "Some files have not been formatted! Formatting has been applied, run 'git add -p' to update changes." + for file in non_formatted_files + println(file) + end + exit(1) + end +end + +main() From 11f6fa786340534c10f6356886e19d6291cf618a Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 19 Jun 2023 16:57:26 +0200 Subject: [PATCH 007/263] set version to v0.5.29 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 9d51e4dcffc..303e97d6324 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.5.29-pre" +version = "0.5.29" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From e84946146c022588ef2d4260e4fa4c34b1ab2d9d Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 19 Jun 2023 16:57:48 +0200 Subject: [PATCH 008/263] set development version to v0.5.30-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 303e97d6324..d3983262591 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.5.29" +version = "0.5.30-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 9519c26b2fb88398ab12ddc4f3c6acc62c02a426 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Jun 2023 21:24:37 +0200 Subject: [PATCH 009/263] Bump crate-ci/typos from 1.15.0 to 1.15.1 (#1537) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.15.0 to 1.15.1. - [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.15.0...v1.15.1) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-type: direct:production update-type: version-update:semver-patch ... 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 bc324c689bc..75886465f85 100644 --- a/.github/workflows/SpellCheck.yml +++ b/.github/workflows/SpellCheck.yml @@ -10,4 +10,4 @@ jobs: - name: Checkout Actions Repository uses: actions/checkout@v3 - name: Check spelling - uses: crate-ci/typos@v1.15.0 + uses: crate-ci/typos@v1.15.1 From 830d1d7a5fcc76d9ee205c72abff15f328372d02 Mon Sep 17 00:00:00 2001 From: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Date: Tue, 20 Jun 2023 09:02:05 +0200 Subject: [PATCH 010/263] Fix pre-commit (#1536) * fix pre-commit * consistent indent --- utils/pre-commit | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/utils/pre-commit b/utils/pre-commit index 2977b9a200b..73ad061baef 100755 --- a/utils/pre-commit +++ b/utils/pre-commit @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Copy this file into .git/hooks/pre-commit to execute before each commit. # It checks and corrects the format for each file. @@ -8,10 +8,10 @@ echo "Checking format before committing" if git ref-parse --verify HEAD >/dev/null 2>&1 then - against=HEAD + against=HEAD else - # Initial commit: diff against an empty tree object - against=280fc57fade28e35046c3e884e587ffef05d3867 + # Initial commit: diff against an empty tree object + against=280fc57fade28e35046c3e884e587ffef05d3867 fi # Redirect output to stderr. @@ -22,19 +22,19 @@ files=() for file in `git diff --cached --name-only` do - # only indent existing files, this is necessary since if we rename or delete - # a file it is added to the committed files and we thus would try to indent a - # nonexisting file. - if [ ! -e $file ] - then - continue - fi - # We only indent .jl files - FILE_ENDING="${file##*.}" - if [ $FILE_ENDING = "jl" ] - then - files+=($file) - fi + # only indent existing files, this is necessary since if we rename or delete + # a file it is added to the committed files and we thus would try to indent a + # nonexisting file. + if [ ! -e $file ] + then + continue + fi + # We only indent .jl files + FILE_ENDING="${file##*.}" + if [ $FILE_ENDING = "jl" ] + then + files+=($file) + fi done julia utils/trixi-format-file.jl "${files[@]}" From 196f139069370bd1d450b1d3865170c447c2b74f Mon Sep 17 00:00:00 2001 From: Johannes Markert <10619309+jmark@users.noreply.github.com> Date: Tue, 20 Jun 2023 09:12:02 +0200 Subject: [PATCH 011/263] Update styleguide.md (#1538) Added missing apostrophe. --- docs/src/styleguide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/styleguide.md b/docs/src/styleguide.md index 9e6b6a8c265..c2562a0c651 100644 --- a/docs/src/styleguide.md +++ b/docs/src/styleguide.md @@ -55,7 +55,7 @@ julia -e 'using Pkg; Pkg.add("JuliaFormatter")' ``` You can then recursively format all Julia files in the Trixi.jl repo by executing ```shell -julia -e 'using JuliaFormatter; format(".") +julia -e 'using JuliaFormatter; format(".")' ``` from inside the Trixi.jl repository. For convenience, there is also a script you can directly run from your terminal shell, which will automatically install JuliaFormatter in a @@ -75,4 +75,4 @@ You can copy the `pre-commit`-script into `.git/hooks/pre-commit` and it will ch before each commit. If errors are found the commit is aborted and you can add the corrections via ```shell git add -p -``` \ No newline at end of file +``` From 3303ed8c0b8af262a16e96f2ad6dcd84034bbe7b Mon Sep 17 00:00:00 2001 From: Johannes Markert <10619309+jmark@users.noreply.github.com> Date: Tue, 20 Jun 2023 11:45:41 +0200 Subject: [PATCH 012/263] Update styleguide.md (#1540) * Update styleguide.md Updated the formatting command line fixing the issue https://github.com/trixi-framework/Trixi.jl/issues/1539 * Update styleguide.md Removed superfluous whitespace. --- docs/src/styleguide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/styleguide.md b/docs/src/styleguide.md index c2562a0c651..60e227204ca 100644 --- a/docs/src/styleguide.md +++ b/docs/src/styleguide.md @@ -53,9 +53,9 @@ of your PR), you need to install JuliaFormatter.jl first by running ```shell julia -e 'using Pkg; Pkg.add("JuliaFormatter")' ``` -You can then recursively format all Julia files in the Trixi.jl repo by executing +You can then recursively format the core Julia files in the Trixi.jl repo by executing ```shell -julia -e 'using JuliaFormatter; format(".")' +julia -e 'using JuliaFormatter; format(["benchmark", "ext", "src", "utils"])' ``` from inside the Trixi.jl repository. For convenience, there is also a script you can directly run from your terminal shell, which will automatically install JuliaFormatter in a From 414dafa310738414d43d16d0393ca13588b2c101 Mon Sep 17 00:00:00 2001 From: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Date: Wed, 21 Jun 2023 11:31:35 +0200 Subject: [PATCH 013/263] Fix some typos in docs (#1541) * fix some typos in docs * fix copy mistake * update link --- docs/src/github-git.md | 4 ++-- src/auxiliary/auxiliary.jl | 10 +++++----- src/auxiliary/math.jl | 6 +++++- src/auxiliary/mpi.jl | 4 ++-- src/equations/acoustic_perturbation_2d.jl | 2 +- src/equations/compressible_euler_2d.jl | 2 +- src/equations/compressible_euler_3d.jl | 2 +- src/equations/compressible_euler_multicomponent_1d.jl | 8 ++++---- src/equations/compressible_euler_multicomponent_2d.jl | 8 ++++---- src/equations/compressible_navier_stokes_2d.jl | 8 ++++---- src/equations/compressible_navier_stokes_3d.jl | 4 ++-- src/equations/hyperbolic_diffusion_2d.jl | 2 +- src/equations/hyperbolic_diffusion_3d.jl | 2 +- src/equations/ideal_glm_mhd_3d.jl | 2 +- src/equations/shallow_water_two_layer_1d.jl | 2 +- src/equations/shallow_water_two_layer_2d.jl | 3 ++- src/meshes/structured_mesh.jl | 4 ++-- src/solvers/dgmulti/types.jl | 6 +++--- src/solvers/dgsem_tree/indicators.jl | 2 +- 19 files changed, 43 insertions(+), 38 deletions(-) diff --git a/docs/src/github-git.md b/docs/src/github-git.md index ad5991d87af..57b63073e79 100644 --- a/docs/src/github-git.md +++ b/docs/src/github-git.md @@ -112,7 +112,7 @@ branch, and the corresponding pull request will be updated automatically. Please note that a review has nothing to do with the lack of experience of the person developing changes: We try to review all code before it gets added to `main`, even from the most experienced developers. This is good practice and -helps to keep the error rate low while ensuring the the code is developed in a +helps to keep the error rate low while ensuring that the code is developed in a consistent fashion. Furthermore, do not take criticism of your code personally - we just try to keep Trixi.jl as accessible and easy to use for everyone. @@ -121,7 +121,7 @@ Once your branch is reviewed and declared ready for merging by the reviewer, make sure that all the latest changes have been pushed. Then, one of the developers will merge your PR. If you are one of the developers, you can also go to the pull request page on GitHub and and click on **Merge pull request**. -Voilá, you are done! Your branch will have been merged to +Voilà, you are done! Your branch will have been merged to `main` and the source branch will have been deleted in the GitHub repository (if you are not working in your own fork). diff --git a/src/auxiliary/auxiliary.jl b/src/auxiliary/auxiliary.jl index 115d055c0ca..1f7d30d6aa8 100644 --- a/src/auxiliary/auxiliary.jl +++ b/src/auxiliary/auxiliary.jl @@ -132,7 +132,7 @@ end default_example() Return the path to an example elixir that can be used to quickly see Trixi.jl in action on a -[`TreeMesh`]@(ref). See also [`examples_dir`](@ref) and [`get_examples`](@ref). +[`TreeMesh`](@ref). See also [`examples_dir`](@ref) and [`get_examples`](@ref). """ function default_example() joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_basic.jl") @@ -142,7 +142,7 @@ end default_example_unstructured() Return the path to an example elixir that can be used to quickly see Trixi.jl in action on an -[`UnstructuredMesh2D`]@(ref). This simulation is run on the example curved, unstructured mesh +[`UnstructuredMesh2D`](@ref). This simulation is run on the example curved, unstructured mesh given in the Trixi.jl documentation regarding unstructured meshes. """ function default_example_unstructured() @@ -155,7 +155,7 @@ end Return the default options for OrdinaryDiffEq's `solve`. Pass `ode_default_options()...` to `solve` to only return the solution at the final time and enable **MPI aware** error-based step size control, whenever MPI is used. -For example, use `solve(ode, alg; ode_default_options()...)` +For example, use `solve(ode, alg; ode_default_options()...)`. """ function ode_default_options() if mpi_isparallel() @@ -213,8 +213,8 @@ might be provided by other packages such as [Polyester.jl](https://github.com/Ju This macro does not necessarily work for general `for` loops. For example, it does not necessarily support general iterables such as `eachline(filename)`. -Some discussion can be found at https://discourse.julialang.org/t/overhead-of-threads-threads/53964 -and https://discourse.julialang.org/t/threads-threads-with-one-thread-how-to-remove-the-overhead/58435. +Some discussion can be found at [https://discourse.julialang.org/t/overhead-of-threads-threads/53964](https://discourse.julialang.org/t/overhead-of-threads-threads/53964) +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 diff --git a/src/auxiliary/math.jl b/src/auxiliary/math.jl index 27c1bed5ca4..4ecf7dd3fcc 100644 --- a/src/auxiliary/math.jl +++ b/src/auxiliary/math.jl @@ -51,7 +51,7 @@ Given ε = 1.0e-4, we use the following algorithm. - Agner Fog. Lists of instruction latencies, throughputs and micro-operation breakdowns for Intel, AMD, and VIA CPUs. - https://www.agner.org/optimize/instruction_tables.pdf + [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 @@ -166,8 +166,10 @@ checks necessary in the presence of `NaN`s (or signed zeros). # Examples +```jldoctest julia> max(2, 5, 1) 5 +``` """ @inline max(args...) = @fastmath max(args...) @@ -183,8 +185,10 @@ checks necessary in the presence of `NaN`s (or signed zeros). # Examples +```jldoctest julia> min(2, 5, 1) 1 +``` """ @inline min(args...) = @fastmath min(args...) diff --git a/src/auxiliary/mpi.jl b/src/auxiliary/mpi.jl index 2c485b4832c..c85c23670b0 100644 --- a/src/auxiliary/mpi.jl +++ b/src/auxiliary/mpi.jl @@ -72,7 +72,7 @@ You must pass this function as a keyword argument to OrdinaryDiffEq.jl's `solve` when using error-based step size control with MPI parallel execution of Trixi.jl. -See the "Advanced Adaptive Stepsize Control" section of the [documentation](https://docs.sciml.ai/DiffEqDocs/stable/basics/common_solver_opts/) +See the "Advanced Adaptive Stepsize Control" section of the [documentation](https://docs.sciml.ai/DiffEqDocs/stable/basics/common_solver_opts/). """ ode_norm(u::Number, t) = @fastmath abs(u) function ode_norm(u::AbstractArray, t) @@ -125,6 +125,6 @@ You should pass this function as a keyword argument to OrdinaryDiffEq.jl's `solve` when using error-based step size control with MPI parallel execution of Trixi.jl. -See the "Miscellaneous" section of the [documentation](https://docs.sciml.ai/DiffEqDocs/stable/basics/common_solver_opts/) +See the "Miscellaneous" section of the [documentation](https://docs.sciml.ai/DiffEqDocs/stable/basics/common_solver_opts/). """ ode_unstable_check(dt, u, semi, t) = isnan(dt) diff --git a/src/equations/acoustic_perturbation_2d.jl b/src/equations/acoustic_perturbation_2d.jl index 786630a14c7..f4ce770e1e9 100644 --- a/src/equations/acoustic_perturbation_2d.jl +++ b/src/equations/acoustic_perturbation_2d.jl @@ -145,7 +145,7 @@ function initial_condition_convergence_test(x, t, end """ - source_terms_convergence_test(u, x, t, equations::AcousticPerturbationEquations2D) + source_terms_convergence_test(u, x, t, equations::AcousticPerturbationEquations2D) Source terms used for convergence tests in combination with [`initial_condition_convergence_test`](@ref). diff --git a/src/equations/compressible_euler_2d.jl b/src/equations/compressible_euler_2d.jl index 66e3c7bff84..89f04ef1e05 100644 --- a/src/equations/compressible_euler_2d.jl +++ b/src/equations/compressible_euler_2d.jl @@ -31,7 +31,7 @@ The compressible Euler equations ``` for an ideal gas with ratio of specific heats `gamma` in two space dimensions. -Here, ``\rho`` is the density, ``v_1``,`v_2` the velocities, ``e`` the specific total energy **rather than** specific internal energy, and +Here, ``\rho`` is the density, ``v_1``, ``v_2`` the velocities, ``e`` the specific total energy **rather than** specific internal energy, and ```math p = (\gamma - 1) \left( \rho e - \frac{1}{2} \rho (v_1^2+v_2^2) \right) ``` diff --git a/src/equations/compressible_euler_3d.jl b/src/equations/compressible_euler_3d.jl index c16a454b176..cd081cfc42a 100644 --- a/src/equations/compressible_euler_3d.jl +++ b/src/equations/compressible_euler_3d.jl @@ -36,7 +36,7 @@ The compressible Euler equations ``` for an ideal gas with ratio of specific heats `gamma` in three space dimensions. -Here, ``\rho`` is the density, ``v_1``,`v_2`, `v_3` the velocities, ``e`` the specific total energy **rather than** specific internal energy, and +Here, ``\rho`` is the density, ``v_1``, ``v_2``, ``v_3`` the velocities, ``e`` the specific total energy **rather than** specific internal energy, and ```math p = (\gamma - 1) \left( \rho e - \frac{1}{2} \rho (v_1^2+v_2^2+v_3^2) \right) ``` diff --git a/src/equations/compressible_euler_multicomponent_1d.jl b/src/equations/compressible_euler_multicomponent_1d.jl index 4a50d60471a..23ac222b976 100644 --- a/src/equations/compressible_euler_multicomponent_1d.jl +++ b/src/equations/compressible_euler_multicomponent_1d.jl @@ -44,8 +44,8 @@ specific heat capacity at constant volume of component ``i``. In case of more than one component, the specific heat ratios `gammas` and the gas constants `gas_constants` should be passed as tuples, e.g., `gammas=(1.4, 1.667)`. -The remaining variables like the specific heats at constant volume 'cv' or the specific heats at -constant pressure 'cp' are then calculated considering a calorically perfect gas. +The remaining variables like the specific heats at constant volume `cv` or the specific heats at +constant pressure `cp` are then calculated considering a calorically perfect gas. """ struct CompressibleEulerMulticomponentEquations1D{NVARS, NCOMP, RealT <: Real} <: AbstractCompressibleEulerMulticomponentEquations{1, NVARS, NCOMP} @@ -247,8 +247,8 @@ end Entropy conserving two-point flux by - Ayoub Gouasmi, Karthik Duraisamy (2020) - "Formulation of Entropy-Stable schemes for the multicomponent compressible Euler equations"" - arXiv:1904.00972v3 [math.NA] 4 Feb 2020 + "Formulation of Entropy-Stable schemes for the multicomponent compressible Euler equations" + [arXiv:1904.00972v3](https://arxiv.org/abs/1904.00972) [math.NA] 4 Feb 2020 """ @inline function flux_chandrashekar(u_ll, u_rr, orientation::Integer, equations::CompressibleEulerMulticomponentEquations1D) diff --git a/src/equations/compressible_euler_multicomponent_2d.jl b/src/equations/compressible_euler_multicomponent_2d.jl index 5a015777cb1..7b437f4a1b4 100644 --- a/src/equations/compressible_euler_multicomponent_2d.jl +++ b/src/equations/compressible_euler_multicomponent_2d.jl @@ -48,8 +48,8 @@ specific heat capacity at constant volume of component ``i``. In case of more than one component, the specific heat ratios `gammas` and the gas constants `gas_constants` in [kJ/(kg*K)] should be passed as tuples, e.g., `gammas=(1.4, 1.667)`. -The remaining variables like the specific heats at constant volume 'cv' or the specific heats at -constant pressure 'cp' are then calculated considering a calorically perfect gas. +The remaining variables like the specific heats at constant volume `cv` or the specific heats at +constant pressure `cp` are then calculated considering a calorically perfect gas. """ struct CompressibleEulerMulticomponentEquations2D{NVARS, NCOMP, RealT <: Real} <: AbstractCompressibleEulerMulticomponentEquations{2, NVARS, NCOMP} @@ -275,8 +275,8 @@ end Adaption of the entropy conserving two-point flux by - Ayoub Gouasmi, Karthik Duraisamy (2020) - "Formulation of Entropy-Stable schemes for the multicomponent compressible Euler equations"" - arXiv:1904.00972v3 [math.NA] 4 Feb 2020 + "Formulation of Entropy-Stable schemes for the multicomponent compressible Euler equations" + [arXiv:1904.00972v3](https://arxiv.org/abs/1904.00972) [math.NA] 4 Feb 2020 """ @inline function flux_chandrashekar(u_ll, u_rr, orientation::Integer, equations::CompressibleEulerMulticomponentEquations2D) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 33badba15d9..9b06e0b5abf 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -73,8 +73,8 @@ where w_2 = \frac{\rho v_1}{p},\, w_3 = \frac{\rho v_2}{p},\, w_4 = -\frac{\rho}{p} ``` -#!!! warning "Experimental code" -# This code is experimental and may be changed or removed in any future release. +!!! warning "Experimental code" + This code is experimental and may be changed or removed in any future release. """ struct CompressibleNavierStokesDiffusion2D{GradientVariables, RealT <: Real, E <: AbstractCompressibleEulerEquations{2}} <: @@ -94,8 +94,8 @@ struct CompressibleNavierStokesDiffusion2D{GradientVariables, RealT <: Real, end """ -#!!! warning "Experimental code" -# This code is experimental and may be changed or removed in any future release. +!!! warning "Experimental code" + This code is experimental and may be changed or removed in any future release. `GradientVariablesPrimitive` and `GradientVariablesEntropy` are gradient variable type parameters for `CompressibleNavierStokesDiffusion2D`. By default, the gradient variables are set to be diff --git a/src/equations/compressible_navier_stokes_3d.jl b/src/equations/compressible_navier_stokes_3d.jl index 8930489295d..0b770dff1ca 100644 --- a/src/equations/compressible_navier_stokes_3d.jl +++ b/src/equations/compressible_navier_stokes_3d.jl @@ -73,8 +73,8 @@ where w_2 = \frac{\rho v_1}{p},\, w_3 = \frac{\rho v_2}{p},\, w_4 = \frac{\rho v_3}{p},\, w_5 = -\frac{\rho}{p} ``` -#!!! warning "Experimental code" -# This code is experimental and may be changed or removed in any future release. +!!! warning "Experimental code" + This code is experimental and may be changed or removed in any future release. """ struct CompressibleNavierStokesDiffusion3D{GradientVariables, RealT <: Real, E <: AbstractCompressibleEulerEquations{3}} <: diff --git a/src/equations/hyperbolic_diffusion_2d.jl b/src/equations/hyperbolic_diffusion_2d.jl index 25536a060f8..511d1b8935d 100644 --- a/src/equations/hyperbolic_diffusion_2d.jl +++ b/src/equations/hyperbolic_diffusion_2d.jl @@ -10,7 +10,7 @@ The linear hyperbolic diffusion equations in two space dimensions. A description of this system can be found in Sec. 2.5 of the book "I Do Like CFD, Too: Vol 1". -The book is freely available at http://www.cfdbooks.com/ and further analysis can be found in +The book is freely available at [http://www.cfdbooks.com/](http://www.cfdbooks.com/) and further analysis can be found in the paper by Nishikawa [DOI: 10.1016/j.jcp.2007.07.029](https://doi.org/10.1016/j.jcp.2007.07.029) """ struct HyperbolicDiffusionEquations2D{RealT <: Real} <: diff --git a/src/equations/hyperbolic_diffusion_3d.jl b/src/equations/hyperbolic_diffusion_3d.jl index bf6a00140d4..ed807511b67 100644 --- a/src/equations/hyperbolic_diffusion_3d.jl +++ b/src/equations/hyperbolic_diffusion_3d.jl @@ -10,7 +10,7 @@ The linear hyperbolic diffusion equations in three space dimensions. A description of this system can be found in Sec. 2.5 of the book "I Do Like CFD, Too: Vol 1". -The book is freely available at http://www.cfdbooks.com/ and further analysis can be found in +The book is freely available at [http://www.cfdbooks.com/](http://www.cfdbooks.com/) and further analysis can be found in the paper by Nishikawa [DOI: 10.1016/j.jcp.2007.07.029](https://doi.org/10.1016/j.jcp.2007.07.029) """ struct HyperbolicDiffusionEquations3D{RealT <: Real} <: diff --git a/src/equations/ideal_glm_mhd_3d.jl b/src/equations/ideal_glm_mhd_3d.jl index 401fcd2daf1..2e149d2849f 100644 --- a/src/equations/ideal_glm_mhd_3d.jl +++ b/src/equations/ideal_glm_mhd_3d.jl @@ -41,7 +41,7 @@ end # Set initial conditions at physical location `x` for time `t` """ -initial_condition_constant(x, t, equations::IdealGlmMhdEquations3D) + initial_condition_constant(x, t, equations::IdealGlmMhdEquations3D) A constant initial condition to test free-stream preservation. """ diff --git a/src/equations/shallow_water_two_layer_1d.jl b/src/equations/shallow_water_two_layer_1d.jl index 02899171509..e126eec7c25 100644 --- a/src/equations/shallow_water_two_layer_1d.jl +++ b/src/equations/shallow_water_two_layer_1d.jl @@ -392,7 +392,7 @@ end equations::ShallowWaterTwoLayerEquations1D) Entropy stable surface flux for the two-layer shallow water equations. Uses the entropy -conservative flux_fjordholm_etal and adds a Lax-Friedrichs type dissipation dependent on the jump +conservative [`flux_fjordholm_etal`](@ref) and adds a Lax-Friedrichs type dissipation dependent on the jump of entropy variables. Further details are available in the paper: diff --git a/src/equations/shallow_water_two_layer_2d.jl b/src/equations/shallow_water_two_layer_2d.jl index b5e52d636e4..a54831c711f 100644 --- a/src/equations/shallow_water_two_layer_2d.jl +++ b/src/equations/shallow_water_two_layer_2d.jl @@ -695,8 +695,9 @@ end """ flux_es_fjordholm_etal(u_ll, u_rr, orientation_or_normal_direction, equations::ShallowWaterTwoLayerEquations1D) + Entropy stable surface flux for the two-layer shallow water equations. Uses the entropy conservative -flux_fjordholm_etal and adds a Lax-Friedrichs type dissipation dependent on the jump of entropy +[`flux_fjordholm_etal`](@ref) and adds a Lax-Friedrichs type dissipation dependent on the jump of entropy variables. Further details are available in the paper: diff --git a/src/meshes/structured_mesh.jl b/src/meshes/structured_mesh.jl index 5872681933a..df067db833d 100644 --- a/src/meshes/structured_mesh.jl +++ b/src/meshes/structured_mesh.jl @@ -33,7 +33,7 @@ Create a StructuredMesh of the given size and shape that uses `RealT` as coordin the reference mesh to the physical domain. If no `mapping_as_string` is defined, this function must be defined with the name `mapping` to allow for restarts. - This will be changed in the future, see https://github.com/trixi-framework/Trixi.jl/issues/541. + This will be changed in the future, see [https://github.com/trixi-framework/Trixi.jl/issues/541](https://github.com/trixi-framework/Trixi.jl/issues/541). - `RealT::Type`: the type that should be used for coordinates. - `periodicity`: either a `Bool` deciding if all of the boundaries are periodic or an `NTuple{NDIMS, Bool}` deciding for each dimension if the boundaries in this dimension are periodic. @@ -41,7 +41,7 @@ Create a StructuredMesh of the given size and shape that uses `RealT` as coordin - `mapping_as_string::String`: the code that defines the `mapping`. If `CodeTracking` can't find the function definition, it can be passed directly here. The code string must define the mapping function with the name `mapping`. - This will be changed in the future, see https://github.com/trixi-framework/Trixi.jl/issues/541. + This will be changed in the future, see [https://github.com/trixi-framework/Trixi.jl/issues/541](https://github.com/trixi-framework/Trixi.jl/issues/541). """ function StructuredMesh(cells_per_dimension, mapping; RealT = Float64, periodicity = true, unsaved_changes = true, diff --git a/src/solvers/dgmulti/types.jl b/src/solvers/dgmulti/types.jl index f1f7b158dec..fe6510856b0 100644 --- a/src/solvers/dgmulti/types.jl +++ b/src/solvers/dgmulti/types.jl @@ -180,9 +180,9 @@ GeometricTermsType(mesh_type::Curved, element_type::AbstractElemShape) = NonAffi # other potential mesh types to add later: Polynomial{polydeg_geo}? """ - DGMultiMesh(dg::DGMulti{NDIMS}, vertex_coordinates, EToV; - is_on_boundary=nothing, - periodicity=ntuple(_->false, NDIMS)) where {NDIMS} + DGMultiMesh(dg::DGMulti{NDIMS}, vertex_coordinates, EToV; + is_on_boundary=nothing, + periodicity=ntuple(_->false, NDIMS)) where {NDIMS} - `dg::DGMulti` contains information associated with to the reference element (e.g., quadrature, basis evaluation, differentiation, etc). diff --git a/src/solvers/dgsem_tree/indicators.jl b/src/solvers/dgsem_tree/indicators.jl index 2eb0af87148..b8f8a796f2b 100644 --- a/src/solvers/dgsem_tree/indicators.jl +++ b/src/solvers/dgsem_tree/indicators.jl @@ -159,7 +159,7 @@ and `basis` if this indicator should be used for shock capturing. - Löhner (1987) "An adaptive finite element scheme for transient problems in CFD" [doi: 10.1016/0045-7825(87)90098-3](https://doi.org/10.1016/0045-7825(87)90098-3) -- http://flash.uchicago.edu/site/flashcode/user_support/flash4_ug_4p62/node59.html#SECTION05163100000000000000 +- [https://flash.rochester.edu/site/flashcode/user_support/flash4_ug_4p62/node59.html#SECTION05163100000000000000](https://flash.rochester.edu/site/flashcode/user_support/flash4_ug_4p62/node59.html#SECTION05163100000000000000) """ struct IndicatorLöhner{RealT <: Real, Variable, Cache} <: AbstractIndicator f_wave::RealT # TODO: Taal documentation From 054a917a09127570dabc458f1350550f2ddb6a09 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Wed, 21 Jun 2023 17:56:07 +0200 Subject: [PATCH 014/263] update links to Flash manual (#1544) Co-authored-by: Hendrik Ranocha --- examples/p4est_2d_dgsem/elixir_euler_sedov.jl | 4 ++-- examples/p4est_3d_dgsem/elixir_euler_sedov.jl | 4 ++-- .../elixir_eulergravity_jeans_instability.jl | 6 +++--- .../elixir_eulergravity_sedov_blast_wave.jl | 10 +++++----- examples/structured_1d_dgsem/elixir_euler_sedov.jl | 8 ++++---- examples/structured_2d_dgsem/elixir_euler_sedov.jl | 10 +++++----- examples/structured_3d_dgsem/elixir_euler_sedov.jl | 10 +++++----- examples/tree_1d_dgsem/elixir_euler_positivity.jl | 4 ++-- .../tree_1d_dgsem/elixir_euler_sedov_blast_wave.jl | 4 ++-- .../elixir_euler_sedov_blast_wave_pure_fv.jl | 4 ++-- examples/tree_2d_dgsem/elixir_euler_positivity.jl | 4 ++-- .../tree_2d_dgsem/elixir_euler_sedov_blast_wave.jl | 4 ++-- ...er_sedov_blast_wave_neuralnetwork_perssonperaire.jl | 4 ++-- .../tree_3d_dgsem/elixir_euler_sedov_blast_wave.jl | 6 +++--- examples/unstructured_2d_dgsem/elixir_euler_sedov.jl | 4 ++-- 15 files changed, 43 insertions(+), 43 deletions(-) diff --git a/examples/p4est_2d_dgsem/elixir_euler_sedov.jl b/examples/p4est_2d_dgsem/elixir_euler_sedov.jl index 9f5247e8c4d..d5d8e0c78bf 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_sedov.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_sedov.jl @@ -11,7 +11,7 @@ equations = CompressibleEulerEquations2D(1.4) initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations2D) The Sedov blast wave setup based on Flash -- http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations2D) # Set up polar coordinates @@ -20,7 +20,7 @@ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEq y_norm = x[2] - inicenter[2] r = sqrt(x_norm^2 + y_norm^2) - # Setup based on http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) E = 1.0 p0_inner = 3 * (equations.gamma - 1) * E / (3 * pi * r0^2) diff --git a/examples/p4est_3d_dgsem/elixir_euler_sedov.jl b/examples/p4est_3d_dgsem/elixir_euler_sedov.jl index 00da4132851..6fa285b5565 100644 --- a/examples/p4est_3d_dgsem/elixir_euler_sedov.jl +++ b/examples/p4est_3d_dgsem/elixir_euler_sedov.jl @@ -11,7 +11,7 @@ equations = CompressibleEulerEquations3D(1.4) initial_condition_medium_sedov_blast_wave(x, t, equations::CompressibleEulerEquations3D) The Sedov blast wave setup based on Flash -- http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 with smaller strength of the initial discontinuity. """ function initial_condition_medium_sedov_blast_wave(x, t, equations::CompressibleEulerEquations3D) @@ -22,7 +22,7 @@ function initial_condition_medium_sedov_blast_wave(x, t, equations::Compressible z_norm = x[3] - inicenter[3] r = sqrt(x_norm^2 + y_norm^2 + z_norm^2) - # Setup based on http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) E = 1.0 p0_inner = 3 * (equations.gamma - 1) * E / (4 * pi * r0^2) diff --git a/examples/paper_self_gravitating_gas_dynamics/elixir_eulergravity_jeans_instability.jl b/examples/paper_self_gravitating_gas_dynamics/elixir_eulergravity_jeans_instability.jl index 1774e39513d..fb445616cd4 100644 --- a/examples/paper_self_gravitating_gas_dynamics/elixir_eulergravity_jeans_instability.jl +++ b/examples/paper_self_gravitating_gas_dynamics/elixir_eulergravity_jeans_instability.jl @@ -15,7 +15,7 @@ The classical Jeans instability taken from - Dominik Derigs, Andrew R. Winters, Gregor J. Gassner, Stefanie Walch (2016) A Novel High-Order, Entropy Stable, 3D AMR MHD Solver with Guaranteed Positive Pressure [arXiv: 1605.03572](https://arxiv.org/abs/1605.03572) -- Flash manual https://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel.pdf +- Flash manual https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node189.html#SECTION010131000000000000000 in CGS (centimeter, gram, second) units. """ function initial_condition_jeans_instability(x, t, @@ -32,7 +32,7 @@ function initial_condition_jeans_instability(x, t, pres0 = 1.5e7 # dyn/cm^2 delta0 = 1e-3 # set wave vector values for perturbation (units 1/cm) - # see FLASH manual: https://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel.pdf + # see FLASH manual: https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node189.html#SECTION010131000000000000000 kx = 2.0*pi/0.5 # 2π/λ_x, λ_x = 0.5 ky = 0.0 # 2π/λ_y, λ_y = 1e10 k_dot_x = kx*x[1] + ky*x[2] @@ -49,7 +49,7 @@ function initial_condition_jeans_instability(x, t, equations::HyperbolicDiffusionEquations2D) # gravity equation: -Δϕ = -4πGρ # Constants taken from the FLASH manual - # https://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel.pdf + # https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node189.html#SECTION010131000000000000000 rho0 = 1.5e7 delta0 = 1e-3 diff --git a/examples/paper_self_gravitating_gas_dynamics/elixir_eulergravity_sedov_blast_wave.jl b/examples/paper_self_gravitating_gas_dynamics/elixir_eulergravity_sedov_blast_wave.jl index f7bb5bbb01c..8933224a2c7 100644 --- a/examples/paper_self_gravitating_gas_dynamics/elixir_eulergravity_sedov_blast_wave.jl +++ b/examples/paper_self_gravitating_gas_dynamics/elixir_eulergravity_sedov_blast_wave.jl @@ -15,14 +15,14 @@ Adaptation of the Sedov blast wave with self-gravity taken from A purely hyperbolic discontinuous Galerkin approach for self-gravitating gas dynamics [arXiv: 2008.10593](https://arxiv.org/abs/2008.10593) based on -- http://flash.uchicago.edu/site/flashcode/user_support/flash4_ug_4p62/node184.html#SECTION010114000000000000000 +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114100000000000000 Should be used together with [`boundary_condition_sedov_self_gravity`](@ref). """ function initial_condition_sedov_self_gravity(x, t, equations::CompressibleEulerEquations2D) # Set up polar coordinates r = sqrt(x[1]^2 + x[2]^2) - # Setup based on http://flash.uchicago.edu/site/flashcode/user_support/flash4_ug_4p62/node184.html#SECTION010114000000000000000 + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114100000000000000 r0 = 0.125 # = 4.0 * smallest dx (for domain length=8 and max-ref=8) E = 1.0 p_inner = (equations.gamma - 1) * E / (pi * r0^2) @@ -59,7 +59,7 @@ Adaptation of the Sedov blast wave with self-gravity taken from A purely hyperbolic discontinuous Galerkin approach for self-gravitating gas dynamics [arXiv: 2008.10593](https://arxiv.org/abs/2008.10593) based on -- http://flash.uchicago.edu/site/flashcode/user_support/flash4_ug_4p62/node184.html#SECTION010114000000000000000 +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114100000000000000 Should be used together with [`initial_condition_sedov_self_gravity`](@ref). """ function boundary_condition_sedov_self_gravity(u_inner, orientation, direction, x, t, @@ -122,7 +122,7 @@ Adaptation of the Sedov blast wave with self-gravity taken from A purely hyperbolic discontinuous Galerkin approach for self-gravitating gas dynamics [arXiv: 2008.10593](https://arxiv.org/abs/2008.10593) based on -- http://flash.uchicago.edu/site/flashcode/user_support/flash4_ug_4p62/node184.html#SECTION010114000000000000000 +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114100000000000000 Should be used together with [`boundary_condition_sedov_self_gravity`](@ref). """ function initial_condition_sedov_self_gravity(x, t, equations::HyperbolicDiffusionEquations2D) @@ -143,7 +143,7 @@ Adaptation of the Sedov blast wave with self-gravity taken from A purely hyperbolic discontinuous Galerkin approach for self-gravitating gas dynamics [arXiv: 2008.10593](https://arxiv.org/abs/2008.10593) based on -- http://flash.uchicago.edu/site/flashcode/user_support/flash4_ug_4p62/node184.html#SECTION010114000000000000000 +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114100000000000000 Should be used together with [`initial_condition_sedov_self_gravity`](@ref). """ function boundary_condition_sedov_self_gravity(u_inner, orientation, direction, x, t, diff --git a/examples/structured_1d_dgsem/elixir_euler_sedov.jl b/examples/structured_1d_dgsem/elixir_euler_sedov.jl index ee950b3aaaa..9d7be21a5c1 100644 --- a/examples/structured_1d_dgsem/elixir_euler_sedov.jl +++ b/examples/structured_1d_dgsem/elixir_euler_sedov.jl @@ -11,7 +11,7 @@ equations = CompressibleEulerEquations1D(1.4) initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations1D) The Sedov blast wave setup based on Flash -- http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations1D) # Set up polar coordinates @@ -19,7 +19,7 @@ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEq x_norm = x[1] - inicenter[1] r = abs(x_norm) - # Setup based on http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) # r0 = 0.5 # = more reasonable setup E = 1.0 @@ -78,8 +78,8 @@ save_solution = SaveSolutionCallback(interval=100, stepsize_callback = StepsizeCallback(cfl=0.5) -callbacks = CallbackSet(summary_callback, - analysis_callback, +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, save_solution, stepsize_callback) diff --git a/examples/structured_2d_dgsem/elixir_euler_sedov.jl b/examples/structured_2d_dgsem/elixir_euler_sedov.jl index ed1bfab3be2..efc3b6627c0 100644 --- a/examples/structured_2d_dgsem/elixir_euler_sedov.jl +++ b/examples/structured_2d_dgsem/elixir_euler_sedov.jl @@ -11,7 +11,7 @@ equations = CompressibleEulerEquations2D(1.4) initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations2D) The Sedov blast wave setup based on Flash -- http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations2D) # Set up polar coordinates @@ -20,7 +20,7 @@ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEq y_norm = x[2] - inicenter[2] r = sqrt(x_norm^2 + y_norm^2) - # Setup based on http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) E = 1.0 p0_inner = 3 * (equations.gamma - 1) * E / (3 * pi * r0^2) @@ -59,12 +59,12 @@ function mapping(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 * pi * y)) - + return SVector(x, y) end - + cells_per_dimension = (16, 16) - + mesh = StructuredMesh(cells_per_dimension, mapping, periodicity=true) # create the semidiscretization diff --git a/examples/structured_3d_dgsem/elixir_euler_sedov.jl b/examples/structured_3d_dgsem/elixir_euler_sedov.jl index 8f428495b4f..e0595437c99 100644 --- a/examples/structured_3d_dgsem/elixir_euler_sedov.jl +++ b/examples/structured_3d_dgsem/elixir_euler_sedov.jl @@ -11,7 +11,7 @@ equations = CompressibleEulerEquations3D(1.4) initial_condition_medium_sedov_blast_wave(x, t, equations::CompressibleEulerEquations3D) The Sedov blast wave setup based on Flash -- http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 with smaller strength of the initial discontinuity. """ function initial_condition_medium_sedov_blast_wave(x, t, equations::CompressibleEulerEquations3D) @@ -22,11 +22,11 @@ function initial_condition_medium_sedov_blast_wave(x, t, equations::Compressible z_norm = x[3] - inicenter[3] r = sqrt(x_norm^2 + y_norm^2 + z_norm^2) - # Setup based on http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) E = 1.0 p0_inner = 3 * (equations.gamma - 1) * E / (4 * pi * r0^2) - p0_outer = 1.0e-3 + p0_outer = 1.0e-3 # Calculate primitive variables rho = 1.0 @@ -52,8 +52,8 @@ indicator_sc = IndicatorHennemannGassner(equations, basis, 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) + +solver = DGSEM(polydeg=polydeg, surface_flux=surface_flux, volume_integral=volume_integral) # Mapping as described in https://arxiv.org/abs/2012.12040 function mapping(xi, eta, zeta) diff --git a/examples/tree_1d_dgsem/elixir_euler_positivity.jl b/examples/tree_1d_dgsem/elixir_euler_positivity.jl index 7942937151a..966661e8894 100644 --- a/examples/tree_1d_dgsem/elixir_euler_positivity.jl +++ b/examples/tree_1d_dgsem/elixir_euler_positivity.jl @@ -11,7 +11,7 @@ equations = CompressibleEulerEquations1D(1.4) initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations1D) The Sedov blast wave setup based on Flash -- http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations1D) # Set up polar coordinates @@ -19,7 +19,7 @@ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEq x_norm = x[1] - inicenter[1] r = abs(x_norm) - # Setup based on http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) # r0 = 0.5 # = more reasonable setup E = 1.0 diff --git a/examples/tree_1d_dgsem/elixir_euler_sedov_blast_wave.jl b/examples/tree_1d_dgsem/elixir_euler_sedov_blast_wave.jl index 746a7cf1bac..106ccacf4f5 100644 --- a/examples/tree_1d_dgsem/elixir_euler_sedov_blast_wave.jl +++ b/examples/tree_1d_dgsem/elixir_euler_sedov_blast_wave.jl @@ -11,7 +11,7 @@ equations = CompressibleEulerEquations1D(1.4) initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations1D) The Sedov blast wave setup based on Flash -- http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations1D) # Set up polar coordinates @@ -19,7 +19,7 @@ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEq x_norm = x[1] - inicenter[1] r = abs(x_norm) - # Setup based on http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) # r0 = 0.5 # = more reasonable setup E = 1.0 diff --git a/examples/tree_1d_dgsem/elixir_euler_sedov_blast_wave_pure_fv.jl b/examples/tree_1d_dgsem/elixir_euler_sedov_blast_wave_pure_fv.jl index 00b80dbae92..ebe8fa7cebf 100644 --- a/examples/tree_1d_dgsem/elixir_euler_sedov_blast_wave_pure_fv.jl +++ b/examples/tree_1d_dgsem/elixir_euler_sedov_blast_wave_pure_fv.jl @@ -11,7 +11,7 @@ equations = CompressibleEulerEquations1D(1.4) initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations1D) The Sedov blast wave setup based on Flash -- http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations1D) # Set up polar coordinates @@ -19,7 +19,7 @@ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEq x_norm = x[1] - inicenter[1] r = abs(x_norm) - # Setup based on http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) # r0 = 0.5 # = more reasonable setup E = 1.0 diff --git a/examples/tree_2d_dgsem/elixir_euler_positivity.jl b/examples/tree_2d_dgsem/elixir_euler_positivity.jl index e40dc3b47af..4c7dd7eb6cf 100644 --- a/examples/tree_2d_dgsem/elixir_euler_positivity.jl +++ b/examples/tree_2d_dgsem/elixir_euler_positivity.jl @@ -11,7 +11,7 @@ equations = CompressibleEulerEquations2D(gamma) initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations2D) The Sedov blast wave setup based on Flash -- http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations2D) # Set up polar coordinates @@ -20,7 +20,7 @@ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEq y_norm = x[2] - inicenter[2] r = sqrt(x_norm^2 + y_norm^2) - # Setup based on http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) # r0 = 0.5 # = more reasonable setup E = 1.0 diff --git a/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave.jl b/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave.jl index da7e1d55c91..512e5822374 100644 --- a/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave.jl +++ b/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave.jl @@ -11,7 +11,7 @@ equations = CompressibleEulerEquations2D(gamma) initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations2D) The Sedov blast wave setup based on Flash -- http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations2D) # Set up polar coordinates @@ -20,7 +20,7 @@ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEq y_norm = x[2] - inicenter[2] r = sqrt(x_norm^2 + y_norm^2) - # Setup based on http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) # r0 = 0.5 # = more reasonable setup E = 1.0 diff --git a/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl b/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl index 56715789377..5fd32da2e5c 100644 --- a/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl +++ b/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl @@ -23,7 +23,7 @@ equations = CompressibleEulerEquations2D(gamma) initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations2D) The Sedov blast wave setup based on Flash -- http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations2D) # Set up polar coordinates @@ -32,7 +32,7 @@ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEq y_norm = x[2] - inicenter[2] r = sqrt(x_norm^2 + y_norm^2) - # Setup based on http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) # r0 = 0.5 # = more reasonable setup E = 1.0 diff --git a/examples/tree_3d_dgsem/elixir_euler_sedov_blast_wave.jl b/examples/tree_3d_dgsem/elixir_euler_sedov_blast_wave.jl index 336c09e9212..3641878149a 100644 --- a/examples/tree_3d_dgsem/elixir_euler_sedov_blast_wave.jl +++ b/examples/tree_3d_dgsem/elixir_euler_sedov_blast_wave.jl @@ -15,14 +15,14 @@ Adaptation of the Sedov blast wave with self-gravity taken from A purely hyperbolic discontinuous Galerkin approach for self-gravitating gas dynamics [arXiv: 2008.10593](https://arxiv.org/abs/2008.10593) based on -- http://flash.uchicago.edu/site/flashcode/user_support/flash4_ug_4p62/node184.html#SECTION010114000000000000000 +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 Should be used together with [`boundary_condition_sedov_self_gravity`](@ref). """ function initial_condition_sedov_self_gravity(x, t, equations::CompressibleEulerEquations3D) # Calculate radius as distance from origin r = sqrt(x[1]^2 + x[2]^2 + x[3]^2) - # Setup based on http://flash.uchicago.edu/site/flashcode/user_support/flash4_ug_4p62/node184.html#SECTION010114000000000000000 + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 r0 = 0.25 # = 4.0 * smallest dx (for domain length=8 and max-ref=7) E = 1.0 p_inner = (equations.gamma - 1) * E / (4/3 * pi * r0^3) @@ -60,7 +60,7 @@ Adaptation of the Sedov blast wave with self-gravity taken from A purely hyperbolic discontinuous Galerkin approach for self-gravitating gas dynamics [arXiv: 2008.10593](https://arxiv.org/abs/2008.10593) based on -- http://flash.uchicago.edu/site/flashcode/user_support/flash4_ug_4p62/node184.html#SECTION010114000000000000000 +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 Should be used together with [`initial_condition_sedov_self_gravity`](@ref). """ function boundary_condition_sedov_self_gravity(u_inner, orientation, direction, x, t, diff --git a/examples/unstructured_2d_dgsem/elixir_euler_sedov.jl b/examples/unstructured_2d_dgsem/elixir_euler_sedov.jl index 3d5a391bd90..570a2084691 100644 --- a/examples/unstructured_2d_dgsem/elixir_euler_sedov.jl +++ b/examples/unstructured_2d_dgsem/elixir_euler_sedov.jl @@ -11,7 +11,7 @@ equations = CompressibleEulerEquations2D(1.4) initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations2D) The Sedov blast wave setup based on Flash -- http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations2D) # Set up polar coordinates @@ -20,7 +20,7 @@ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEq y_norm = x[2] - inicenter[2] r = sqrt(x_norm^2 + y_norm^2) - # Setup based on http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) E = 1.0 p0_inner = 3 * (equations.gamma - 1) * E / (3 * pi * r0^2) From bea4bfed27ce896edcfa3dbe79861a4faef4dec7 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Thu, 22 Jun 2023 17:06:19 +0200 Subject: [PATCH 015/263] `splitting_lax_friedrichs` for `LinearScalarAdvection1D` (#1546) * splitting_lax_friedrichs for LinearScalarAdvection1D * Update src/equations/linear_scalar_advection_1d.jl Co-authored-by: Andrew Winters --------- Co-authored-by: Andrew Winters --- .../tree_1d_fdsbp/elixir_advection_upwind.jl | 57 +++++++++++++++++++ src/equations/inviscid_burgers_1d.jl | 2 +- src/equations/linear_scalar_advection_1d.jl | 38 +++++++++++++ test/test_tree_1d_fdsbp.jl | 18 ++++++ 4 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 examples/tree_1d_fdsbp/elixir_advection_upwind.jl diff --git a/examples/tree_1d_fdsbp/elixir_advection_upwind.jl b/examples/tree_1d_fdsbp/elixir_advection_upwind.jl new file mode 100644 index 00000000000..5c50e1a6c64 --- /dev/null +++ b/examples/tree_1d_fdsbp/elixir_advection_upwind.jl @@ -0,0 +1,57 @@ +# !!! warning "Experimental implementation (upwind SBP)" +# This is an experimental feature and may change in future releases. + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear scalar advection equation equation + +equations = LinearScalarAdvectionEquation1D(1.0) + +function initial_condition_sin(x, t, equation::LinearScalarAdvectionEquation1D) + return SVector(sinpi(x[1] - equations.advection_velocity[1] * t)) +end + +D_upw = upwind_operators(SummationByPartsOperators.Mattsson2017, + derivative_order = 1, + accuracy_order = 4, + xmin = -1.0, xmax = 1.0, + N = 16) +flux_splitting = splitting_lax_friedrichs +solver = FDSBP(D_upw, + surface_integral = SurfaceIntegralUpwind(flux_splitting), + volume_integral = VolumeIntegralUpwind(flux_splitting)) + +coordinates_min = -1.0 +coordinates_max = 1.0 +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 4, + n_cells_max = 10_000) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_sin, solver) + + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 2.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) + +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback) + + +############################################################################### +# run the simulation + +sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-6, reltol=1.0e-6, + ode_default_options()..., callback=callbacks); +summary_callback() # print the timer summary diff --git a/src/equations/inviscid_burgers_1d.jl b/src/equations/inviscid_burgers_1d.jl index 8d4410b6ffe..6a2cfb6aa8e 100644 --- a/src/equations/inviscid_burgers_1d.jl +++ b/src/equations/inviscid_burgers_1d.jl @@ -132,7 +132,7 @@ end equations::InviscidBurgersEquation1D) Naive local Lax-Friedrichs style flux splitting of the form `f⁺ = 0.5 (f + λ u)` -and `f⁻ = 0.5 (f - λ u)` where λ = abs(u). +and `f⁻ = 0.5 (f - λ u)` where `λ = abs(u)`. Returns a tuple of the fluxes "minus" (associated with waves going into the negative axis direction) and "plus" (associated with waves going into the diff --git a/src/equations/linear_scalar_advection_1d.jl b/src/equations/linear_scalar_advection_1d.jl index 7769cb61fbf..6c6b9dd3721 100644 --- a/src/equations/linear_scalar_advection_1d.jl +++ b/src/equations/linear_scalar_advection_1d.jl @@ -172,6 +172,44 @@ end return abs.(equation.advection_velocity) end +""" + splitting_lax_friedrichs(u, orientation::Integer, + equations::LinearScalarAdvectionEquation1D) + splitting_lax_friedrichs(u, which::Union{Val{:minus}, Val{:plus}} + orientation::Integer, + equations::LinearScalarAdvectionEquation1D) + +Naive local Lax-Friedrichs style flux splitting of the form `f⁺ = 0.5 (f + λ u)` +and `f⁻ = 0.5 (f - λ u)` where `λ` is the absolute value of the advection +velocity. + +Returns a tuple of the fluxes "minus" (associated with waves going into the +negative axis direction) and "plus" (associated with waves going into the +positive axis direction). If only one of the fluxes is required, use the +function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}()`. + +!!! warning "Experimental implementation (upwind SBP)" + This is an experimental feature and may change in future releases. +""" +@inline function splitting_lax_friedrichs(u, orientation::Integer, + equations::LinearScalarAdvectionEquation1D) + fm = splitting_lax_friedrichs(u, Val{:minus}(), orientation, equations) + fp = splitting_lax_friedrichs(u, Val{:plus}(), orientation, equations) + return fm, fp +end + +@inline function splitting_lax_friedrichs(u, ::Val{:plus}, orientation::Integer, + equations::LinearScalarAdvectionEquation1D) + a = equations.advection_velocity[1] + return a > 0 ? flux(u, orientation, equations) : zero(u) +end + +@inline function splitting_lax_friedrichs(u, ::Val{:minus}, orientation::Integer, + equations::LinearScalarAdvectionEquation1D) + a = equations.advection_velocity[1] + return a < 0 ? flux(u, orientation, equations) : zero(u) +end + # Convert conservative variables to primitive @inline cons2prim(u, equation::LinearScalarAdvectionEquation1D) = u diff --git a/test/test_tree_1d_fdsbp.jl b/test/test_tree_1d_fdsbp.jl index a966b3836f3..118385c34b3 100644 --- a/test/test_tree_1d_fdsbp.jl +++ b/test/test_tree_1d_fdsbp.jl @@ -7,6 +7,24 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_fdsbp") +@testset "Linear scalar advection" begin + @trixi_testset "elixir_advection_upwind.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_upwind.jl"), + l2 = [1.7735637157305526e-6], + linf = [1.0418854521951328e-5], + tspan = (0.0, 0.5)) + + # 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 + @testset "Inviscid Burgers" begin @trixi_testset "elixir_burgers_basic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_basic.jl"), From 6160fe952bd1d6f619fb77627329520f0b586956 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 23 Jun 2023 07:50:05 +0200 Subject: [PATCH 016/263] fix typos in FDSBP elixir comments (#1548) --- examples/tree_2d_fdsbp/elixir_euler_convergence.jl | 3 ++- .../tree_2d_fdsbp/elixir_euler_kelvin_helmholtz_instability.jl | 3 ++- examples/tree_2d_fdsbp/elixir_euler_vortex.jl | 3 ++- examples/tree_3d_fdsbp/elixir_euler_convergence.jl | 1 - 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/tree_2d_fdsbp/elixir_euler_convergence.jl b/examples/tree_2d_fdsbp/elixir_euler_convergence.jl index 0843cece67e..2a6c291f0bf 100644 --- a/examples/tree_2d_fdsbp/elixir_euler_convergence.jl +++ b/examples/tree_2d_fdsbp/elixir_euler_convergence.jl @@ -5,7 +5,8 @@ using OrdinaryDiffEq using Trixi ############################################################################### -# semidiscretization of the linear advection equation +# semidiscretization of the compressible Euler equations + equations = CompressibleEulerEquations2D(1.4) initial_condition = initial_condition_convergence_test diff --git a/examples/tree_2d_fdsbp/elixir_euler_kelvin_helmholtz_instability.jl b/examples/tree_2d_fdsbp/elixir_euler_kelvin_helmholtz_instability.jl index 1e58badf47a..e63343852ab 100644 --- a/examples/tree_2d_fdsbp/elixir_euler_kelvin_helmholtz_instability.jl +++ b/examples/tree_2d_fdsbp/elixir_euler_kelvin_helmholtz_instability.jl @@ -5,7 +5,8 @@ using OrdinaryDiffEq using Trixi ############################################################################### -# semidiscretization of the linear advection equation +# semidiscretization of the compressible Euler equations + equations = CompressibleEulerEquations2D(1.4) function initial_condition_kelvin_helmholtz_instability(x, t, equations::CompressibleEulerEquations2D) diff --git a/examples/tree_2d_fdsbp/elixir_euler_vortex.jl b/examples/tree_2d_fdsbp/elixir_euler_vortex.jl index abaf3d494d4..c1bee8f9c4d 100644 --- a/examples/tree_2d_fdsbp/elixir_euler_vortex.jl +++ b/examples/tree_2d_fdsbp/elixir_euler_vortex.jl @@ -5,7 +5,8 @@ using OrdinaryDiffEq using Trixi ############################################################################### -# semidiscretization of the linear advection equation +# semidiscretization of the compressible Euler equations + equations = CompressibleEulerEquations2D(1.4) """ diff --git a/examples/tree_3d_fdsbp/elixir_euler_convergence.jl b/examples/tree_3d_fdsbp/elixir_euler_convergence.jl index 576a07e6aba..6aafa1b5cc1 100644 --- a/examples/tree_3d_fdsbp/elixir_euler_convergence.jl +++ b/examples/tree_3d_fdsbp/elixir_euler_convergence.jl @@ -6,7 +6,6 @@ using Trixi ############################################################################### # semidiscretization of the compressible Euler equations - equations = CompressibleEulerEquations3D(1.4) initial_condition = initial_condition_convergence_test From d4c556960d6307d6279c698203a9e741c2479c2e Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 23 Jun 2023 07:51:00 +0200 Subject: [PATCH 017/263] set version to v0.5.30 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index d3983262591..e015c90310f 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.5.30-pre" +version = "0.5.30" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 1b69182dc06bddbcb4dd693d7aedb576d68fabc0 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 23 Jun 2023 07:51:14 +0200 Subject: [PATCH 018/263] set development version to v0.5.31-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index e015c90310f..0edba6b681c 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.5.30" +version = "0.5.31-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From b7be5856eba029a3d91257166be4ee62514ae0dd Mon Sep 17 00:00:00 2001 From: Jesse Chan <1156048+jlchan@users.noreply.github.com> Date: Fri, 23 Jun 2023 03:34:22 -0500 Subject: [PATCH 019/263] Add parabolic BCs for `P4estMesh{2}` (#1493) * generalize function signatures to P4estMesh * add specializations for P4estMesh d * add normals * add surface integrals * fix type ambiguity * generalizing `apply_jacobian!` to P4estMesh * resolving type ambiguity with apply_jacobian! d * `apply_jacobian!` -> `apply_jacobian_parabolic!` * `apply_jacobian!` -> `apply_jacobian_parabolic!` * switch to `apply_jacobian_parabolic!` * Update src/solvers/dgsem_tree/dg_1d_parabolic.jl Co-authored-by: Hendrik Ranocha * missed one * draft of prolong2interfaces and calc_interface_flux * cache -> cache_parabolic * adding prolong2boundaries! and calc_boundary_flux_gradients! back * remove todo * variable renaming * extending TreeMesh parabolic functions to P4estMesh * adding elixir * comments * add prolong2boundaries! (untested) * update test * initial commit * fix CI f * Update src/solvers/dgsem_p4est/dg_2d_parabolic.jl Co-authored-by: Hendrik Ranocha * Update src/solvers/dgsem_p4est/dg_2d_parabolic.jl Co-authored-by: Hendrik Ranocha * add "no mortars" check * add curved elixir * fix gradient bug * add curved test * Apply suggestions from code review Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> Co-authored-by: Michael Schlottke-Lakemper * add comment on mapping * reuse P4estMesh{2} code * fix += for muladd * Update examples/p4est_2d_dgsem/elixir_advection_diffusion_periodic_curved.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * comment * comments + remove cruft * add BCs for parabolic P43st * add tests * Update examples/p4est_2d_dgsem/elixir_navierstokes_convergence.jl * formatting * fix CNS convergence elixir and add to tests * update test values --------- Co-authored-by: Hendrik Ranocha Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> Co-authored-by: Michael Schlottke-Lakemper --- ..._advection_diffusion_nonperiodic_curved.jl | 96 ++++++++ .../elixir_navierstokes_convergence.jl | 209 ++++++++++++++++++ .../elixir_navierstokes_lid_driven_cavity.jl | 82 +++++++ src/solvers/dgsem_p4est/dg_2d_parabolic.jl | 133 ++++++++++- test/test_parabolic_2d.jl | 32 +++ 5 files changed, 544 insertions(+), 8 deletions(-) create mode 100644 examples/p4est_2d_dgsem/elixir_advection_diffusion_nonperiodic_curved.jl create mode 100644 examples/p4est_2d_dgsem/elixir_navierstokes_convergence.jl create mode 100644 examples/p4est_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl diff --git a/examples/p4est_2d_dgsem/elixir_advection_diffusion_nonperiodic_curved.jl b/examples/p4est_2d_dgsem/elixir_advection_diffusion_nonperiodic_curved.jl new file mode 100644 index 00000000000..55682f73fce --- /dev/null +++ b/examples/p4est_2d_dgsem/elixir_advection_diffusion_nonperiodic_curved.jl @@ -0,0 +1,96 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear advection-diffusion equation + +diffusivity() = 5.0e-2 +advection_velocity = (1.0, 0.0) +equations = LinearScalarAdvectionEquation2D(advection_velocity) +equations_parabolic = LaplaceDiffusion2D(diffusivity(), equations) + +# Example setup taken from +# - Truman Ellis, Jesse Chan, and Leszek Demkowicz (2016). +# Robust DPG methods for transient convection-diffusion. +# In: Building bridges: connections and challenges in modern approaches +# to numerical partial differential equations. +# [DOI](https://doi.org/10.1007/978-3-319-41640-3_6). +function initial_condition_eriksson_johnson(x, t, equations) + l = 4 + epsilon = diffusivity() # TODO: this requires epsilon < .6 due to sqrt + lambda_1 = (-1 + sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + lambda_2 = (-1 - sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + r1 = (1 + sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + s1 = (1 - sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + u = exp(-l * t) * (exp(lambda_1 * x[1]) - exp(lambda_2 * x[1])) + + cos(pi * x[2]) * (exp(s1 * x[1]) - exp(r1 * x[1])) / (exp(-s1) - exp(-r1)) + return SVector{1}(u) +end +initial_condition = initial_condition_eriksson_johnson + +boundary_conditions = Dict(:x_neg => BoundaryConditionDirichlet(initial_condition), + :y_neg => BoundaryConditionDirichlet(initial_condition), + :y_pos => BoundaryConditionDirichlet(initial_condition), + :x_pos => boundary_condition_do_nothing) + +boundary_conditions_parabolic = Dict(:x_neg => BoundaryConditionDirichlet(initial_condition), + :x_pos => BoundaryConditionDirichlet(initial_condition), + :y_neg => BoundaryConditionDirichlet(initial_condition), + :y_pos => BoundaryConditionDirichlet(initial_condition)) + +# 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) + +coordinates_min = (-1.0, -0.5) +coordinates_max = ( 0.0, 0.5) + +# This maps the domain [-1, 1]^2 to [-1, 0] x [-0.5, 0.5] while also +# introducing a curved warping to interior nodes. +function mapping(xi, eta) + x = xi + 0.1 * sin(pi * xi) * sin(pi * eta) + y = eta + 0.1 * sin(pi * xi) * sin(pi * eta) + return SVector(0.5 * (1 + x) - 1, 0.5 * y) +end + +trees_per_dimension = (4, 4) +mesh = P4estMesh(trees_per_dimension, + polydeg=3, initial_refinement_level=2, + mapping=mapping, periodicity=(false, false)) + +# A semidiscretization collects data structures and functions for the spatial discretization +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver, + boundary_conditions = (boundary_conditions, boundary_conditions_parabolic)) + + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span `tspan` +tspan = (0.0, 1.0) +ode = semidiscretize(semi, tspan); + +# 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_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) + +# The AliveCallback prints short status information in regular intervals +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +# Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) + + +############################################################################### +# run the simulation + +# OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks +time_int_tol = 1.0e-11 +sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, + ode_default_options()..., callback=callbacks) + +# Print the timer summary +summary_callback() diff --git a/examples/p4est_2d_dgsem/elixir_navierstokes_convergence.jl b/examples/p4est_2d_dgsem/elixir_navierstokes_convergence.jl new file mode 100644 index 00000000000..8111df8251a --- /dev/null +++ b/examples/p4est_2d_dgsem/elixir_navierstokes_convergence.jl @@ -0,0 +1,209 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal compressible Navier-Stokes equations + +prandtl_number() = 0.72 +mu() = 0.01 + +equations = CompressibleEulerEquations2D(1.4) +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu=mu(), Prandtl=prandtl_number(), + gradient_variables=GradientVariablesPrimitive()) + +# 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, + volume_integral=VolumeIntegralWeakForm()) + +coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) +coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) + +trees_per_dimension = (4, 4) +mesh = P4estMesh(trees_per_dimension, + polydeg=3, initial_refinement_level=2, + coordinates_min=coordinates_min, coordinates_max=coordinates_max, + periodicity=(true, false)) + +# Note: the initial condition cannot be specialized to `CompressibleNavierStokesDiffusion2D` +# since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesDiffusion2D`) +# and by the initial condition (which passes in `CompressibleEulerEquations2D`). +# This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) +function initial_condition_navier_stokes_convergence_test(x, t, equations) + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0)) ) * cos(pi_t) + v2 = v1 + p = rho^2 + + return prim2cons(SVector(rho, v1, v2, p), equations) +end + +@inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) + y = x[2] + + # TODO: parabolic + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + mu_ = mu() + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) + rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) + rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) + rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + + v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) + v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_y = sin(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_xy = pi * cos(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_yy = (sin(pi_x) * ( 2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) + - A * A * log(y + 2.0) * exp(-A * (y - 1.0)) + - (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_xx = v1_xx + v2_xy = v1_xy + v2_yy = v1_yy + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y + + # Note this simplifies slightly because the ansatz assumes that v1 = v2 + E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) + E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x + E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one / Pr + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y + + # x-momentum equation + du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y + # stress tensor from x-direction + - 4.0 / 3.0 * v1_xx * mu_ + + 2.0 / 3.0 * v2_xy * mu_ + - v1_yy * mu_ + - v2_xy * mu_ ) + # y-momentum equation + du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y + # stress tensor from y-direction + - v1_xy * mu_ + - v2_xx * mu_ + - 4.0 / 3.0 * v2_yy * mu_ + + 2.0 / 3.0 * v1_xy * mu_ ) + # total energy equation + du4 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) + # stress tensor and temperature gradient terms from x-direction + - 4.0 / 3.0 * v1_xx * v1 * mu_ + + 2.0 / 3.0 * v2_xy * v1 * mu_ + - 4.0 / 3.0 * v1_x * v1_x * mu_ + + 2.0 / 3.0 * v2_y * v1_x * mu_ + - v1_xy * v2 * mu_ + - v2_xx * v2 * mu_ + - v1_y * v2_x * mu_ + - v2_x * v2_x * mu_ + - T_const * inv_rho_cubed * ( p_xx * rho * rho + - 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x + - p * rho * rho_xx ) * mu_ + # stress tensor and temperature gradient terms from y-direction + - v1_yy * v1 * mu_ + - v2_xy * v1 * mu_ + - v1_y * v1_y * mu_ + - v2_x * v1_y * mu_ + - 4.0 / 3.0 * v2_yy * v2 * mu_ + + 2.0 / 3.0 * v1_xy * v2 * mu_ + - 4.0 / 3.0 * v2_y * v2_y * mu_ + + 2.0 / 3.0 * v1_x * v2_y * mu_ + - T_const * inv_rho_cubed * ( p_yy * rho * rho + - 2.0 * p_y * rho * rho_y + + 2.0 * p * rho_y * rho_y + - p * rho * rho_yy ) * mu_ ) + + return SVector(du1, du2, du3, du4) +end + +initial_condition = initial_condition_navier_stokes_convergence_test + +# BC types +velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:3]) +heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) +boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, heat_bc_top_bottom) + +# define inviscid boundary conditions +boundary_conditions = Dict(:y_neg => boundary_condition_slip_wall, + :y_pos => boundary_condition_slip_wall) + +# define viscous boundary conditions +boundary_conditions_parabolic = Dict(:y_neg => boundary_condition_top_bottom, + :y_pos => boundary_condition_top_bottom) + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; + boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), + source_terms=source_terms_navier_stokes_convergence_test) + +# ############################################################################### +# # ODE solvers, callbacks etc. + +# Create ODE problem with time span `tspan` +tspan = (0.0, 0.5) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() +alive_callback = AliveCallback(alive_interval=10) +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, + ode_default_options()..., callback=callbacks) +summary_callback() # print the timer summary + diff --git a/examples/p4est_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl b/examples/p4est_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl new file mode 100644 index 00000000000..051f4defe54 --- /dev/null +++ b/examples/p4est_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl @@ -0,0 +1,82 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal compressible Navier-Stokes equations + +# TODO: parabolic; unify names of these accessor functions +prandtl_number() = 0.72 +mu() = 0.001 + +equations = CompressibleEulerEquations2D(1.4) +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu=mu(), + Prandtl=prandtl_number()) + +# 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) + +coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) +coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) + +# Create a uniformly refined mesh +trees_per_dimension = (4, 4) +mesh = P4estMesh(trees_per_dimension, + polydeg=3, initial_refinement_level=2, + coordinates_min=coordinates_min, coordinates_max=coordinates_max, + periodicity=(false, false)) + +function initial_condition_cavity(x, t, equations::CompressibleEulerEquations2D) + Ma = 0.1 + rho = 1.0 + u, v = 0.0, 0.0 + p = 1.0 / (Ma^2 * equations.gamma) + return prim2cons(SVector(rho, u, v, p), equations) +end +initial_condition = initial_condition_cavity + +# BC types +velocity_bc_lid = NoSlip((x, t, equations) -> SVector(1.0, 0.0)) +velocity_bc_cavity = NoSlip((x, t, equations) -> SVector(0.0, 0.0)) +heat_bc = Adiabatic((x, t, equations) -> 0.0) +boundary_condition_lid = BoundaryConditionNavierStokesWall(velocity_bc_lid, heat_bc) +boundary_condition_cavity = BoundaryConditionNavierStokesWall(velocity_bc_cavity, heat_bc) + +# define periodic boundary conditions everywhere +boundary_conditions = Dict( :x_neg => boundary_condition_slip_wall, + :y_neg => boundary_condition_slip_wall, + :y_pos => boundary_condition_slip_wall, + :x_pos => boundary_condition_slip_wall) + +boundary_conditions_parabolic = Dict( :x_neg => boundary_condition_cavity, + :y_neg => boundary_condition_cavity, + :y_pos => boundary_condition_lid, + :x_pos => boundary_condition_cavity) + +# A semidiscretization collects data structures and functions for the spatial discretization +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions=(boundary_conditions, + boundary_conditions_parabolic)) + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span `tspan` +tspan = (0.0, 25.0) +ode = semidiscretize(semi, tspan); + +summary_callback = SummaryCallback() +alive_callback = AliveCallback(alive_interval=100) +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +callbacks = CallbackSet(summary_callback, alive_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, + ode_default_options()..., callback=callbacks) +summary_callback() # print the timer summary + + diff --git a/src/solvers/dgsem_p4est/dg_2d_parabolic.jl b/src/solvers/dgsem_p4est/dg_2d_parabolic.jl index e73a8cda9b8..73ac47ed1e3 100644 --- a/src/solvers/dgsem_p4est/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_p4est/dg_2d_parabolic.jl @@ -365,6 +365,7 @@ function prolong2interfaces!(cache_parabolic, flux_viscous, return nothing end +# This version is used for divergence flux computations function calc_interface_flux!(surface_flux_values, mesh::P4estMesh{2}, equations_parabolic, dg::DG, cache_parabolic) @@ -405,7 +406,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, @@ -446,6 +447,7 @@ function prolong2boundaries!(cache_parabolic, flux_viscous, # a start value and a step size to get the correct face and orientation. element = boundaries.neighbor_ids[boundary] node_indices = boundaries.node_indices[boundary] + direction = indices2direction(node_indices) i_node_start, i_node_step = index_to_start_step_2d(node_indices[1], index_range) j_node_start, j_node_step = index_to_start_step_2d(node_indices[2], index_range) @@ -454,15 +456,12 @@ function prolong2boundaries!(cache_parabolic, flux_viscous, j_node = j_node_start for i in eachnode(dg) # this is the outward normal direction on the primary element - normal_direction = get_normal_direction(primary_direction, - contravariant_vectors, - i_node, j_node, primary_element) + normal_direction = get_normal_direction(direction, contravariant_vectors, + i_node, j_node, element) for v in eachvariable(equations_parabolic) - flux_viscous = SVector(flux_viscous_x[v, i_primary, j_primary, - primary_element], - flux_viscous_y[v, i_primary, j_primary, - primary_element]) + flux_viscous = SVector(flux_viscous_x[v, i_node, j_node, element], + flux_viscous_y[v, i_node, j_node, element]) boundaries.u[v, i, boundary] = dot(flux_viscous, normal_direction) end @@ -470,6 +469,124 @@ function prolong2boundaries!(cache_parabolic, flux_viscous, j_node += j_node_step end end + return nothing +end + +function calc_boundary_flux_gradients!(cache, t, + boundary_condition::Union{BoundaryConditionPeriodic, + BoundaryConditionDoNothing + }, + mesh::P4estMesh, equations, surface_integral, dg::DG) + @assert isempty(eachboundary(dg, cache)) +end + +# Function barrier for type stability +function calc_boundary_flux_gradients!(cache, t, boundary_conditions, mesh::P4estMesh, + equations, surface_integral, dg::DG) + (; boundary_condition_types, boundary_indices) = boundary_conditions + calc_boundary_flux_by_type!(cache, t, boundary_condition_types, boundary_indices, + Gradient(), mesh, equations, surface_integral, dg) return nothing end + +function calc_boundary_flux_divergence!(cache, t, boundary_conditions, mesh::P4estMesh, + equations, surface_integral, dg::DG) + (; boundary_condition_types, boundary_indices) = boundary_conditions + + calc_boundary_flux_by_type!(cache, t, boundary_condition_types, boundary_indices, + Divergence(), mesh, equations, surface_integral, dg) + return nothing +end + +# Iterate over tuples of boundary condition types and associated indices +# in a type-stable way using "lispy tuple programming". +function calc_boundary_flux_by_type!(cache, t, BCs::NTuple{N, Any}, + BC_indices::NTuple{N, Vector{Int}}, + operator_type, + mesh::P4estMesh, + equations, surface_integral, dg::DG) where {N} + # Extract the boundary condition type and index vector + boundary_condition = first(BCs) + boundary_condition_indices = first(BC_indices) + # Extract the remaining types and indices to be processed later + remaining_boundary_conditions = Base.tail(BCs) + remaining_boundary_condition_indices = Base.tail(BC_indices) + + # process the first boundary condition type + calc_boundary_flux!(cache, t, boundary_condition, boundary_condition_indices, + operator_type, mesh, equations, surface_integral, dg) + + # recursively call this method with the unprocessed boundary types + calc_boundary_flux_by_type!(cache, t, remaining_boundary_conditions, + remaining_boundary_condition_indices, + operator_type, + mesh, equations, surface_integral, dg) + + return nothing +end + +# terminate the type-stable iteration over tuples +function calc_boundary_flux_by_type!(cache, t, BCs::Tuple{}, BC_indices::Tuple{}, + operator_type, mesh::P4estMesh, equations, + surface_integral, dg::DG) + nothing +end + +function calc_boundary_flux!(cache, t, + boundary_condition_parabolic, # works with Dict types + boundary_condition_indices, + operator_type, mesh::P4estMesh{2}, + equations_parabolic::AbstractEquationsParabolic, + surface_integral, dg::DG) + (; boundaries) = cache + (; node_coordinates, surface_flux_values) = cache.elements + (; contravariant_vectors) = cache.elements + index_range = eachnode(dg) + + @threaded for local_index in eachindex(boundary_condition_indices) + # Use the local index to get the global boundary index from the pre-sorted list + boundary_index = boundary_condition_indices[local_index] + + # Get information on the adjacent element, compute the surface fluxes, + # and store them + element = boundaries.neighbor_ids[boundary_index] + node_indices = boundaries.node_indices[boundary_index] + direction_index = indices2direction(node_indices) + + i_node_start, i_node_step = index_to_start_step_2d(node_indices[1], index_range) + j_node_start, j_node_step = index_to_start_step_2d(node_indices[2], index_range) + + i_node = i_node_start + j_node = j_node_start + for node_index in eachnode(dg) + # Extract solution data from boundary container + u_inner = get_node_vars(boundaries.u, equations_parabolic, dg, node_index, + boundary_index) + + # Outward-pointing normal direction (not normalized) + normal_direction = get_normal_direction(direction_index, contravariant_vectors, + i_node, j_node, element) + + # TODO: revisit if we want more general boundary treatments. + # This assumes the gradient numerical flux at the boundary is the gradient variable, + # which is consistent with BR1, LDG. + flux_inner = u_inner + + # Coordinates at boundary node + x = get_node_coords(node_coordinates, equations_parabolic, dg, i_node, j_node, + element) + + flux_ = boundary_condition_parabolic(flux_inner, u_inner, normal_direction, + x, t, operator_type, equations_parabolic) + + # Copy flux to element storage in the correct orientation + for v in eachvariable(equations_parabolic) + surface_flux_values[v, node_index, direction_index, element] = flux_[v] + end + + i_node += i_node_step + j_node += j_node_step + end + end +end diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index b0ac63d4ce9..471b976e990 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -200,6 +200,38 @@ isdir(outdir) && rm(outdir, recursive=true) ) end + @trixi_testset "P4estMesh2D: elixir_advection_diffusion_periodic_curved.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_advection_diffusion_periodic_curved.jl"), + trees_per_dimension = (1, 1), initial_refinement_level = 2, tspan=(0.0, 0.5), + l2 = [0.012380458938507371], + linf = [0.10860506906472567] + ) + end + + @trixi_testset "P4estMesh2D: elixir_advection_diffusion_nonperiodic_curved.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_advection_diffusion_nonperiodic_curved.jl"), + trees_per_dimension = (1, 1), initial_refinement_level = 2, tspan=(0.0, 0.5), + l2 = [0.04933902988507035], + linf = [0.2550261714590271] + ) + end + + @trixi_testset "P4estMesh2D: elixir_navierstokes_convergence.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_navierstokes_convergence.jl"), + initial_refinement_level = 1, tspan=(0.0, 0.2), + l2 = [0.0003811978985836709, 0.0005874314969169538, 0.0009142898787923481, 0.0011613918899727263], + linf = [0.0021633623982135752, 0.009484348274135372, 0.004231572066492217, 0.011661660275365193] + ) + end + + @trixi_testset "P4estMesh2D: elixir_navierstokes_lid_driven_cavity.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_navierstokes_lid_driven_cavity.jl"), + initial_refinement_level = 2, tspan=(0.0, 0.5), + l2 = [0.00028716166408816073, 0.08101204560401647, 0.02099595625377768, 0.05008149754143295], + linf = [0.014804500261322406, 0.9513271652357098, 0.7223919625994717, 1.4846907331004786] + ) + end + end # Clean up afterwards: delete Trixi.jl output directory From 87a16931fdcafd488b05d4009d476250f0b98a4f Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 26 Jun 2023 12:08:58 +0200 Subject: [PATCH 020/263] fix some typos in docstrings of flux splittings (#1550) --- src/equations/compressible_euler_1d.jl | 6 +++--- src/equations/compressible_euler_2d.jl | 6 +++--- src/equations/compressible_euler_3d.jl | 2 +- src/equations/inviscid_burgers_1d.jl | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/equations/compressible_euler_1d.jl b/src/equations/compressible_euler_1d.jl index f484f26a588..15f7a2cb4c4 100644 --- a/src/equations/compressible_euler_1d.jl +++ b/src/equations/compressible_euler_1d.jl @@ -374,7 +374,7 @@ Splitting of the compressible Euler flux of Steger and Warming. Returns a tuple of the fluxes "minus" (associated with waves going into the negative axis direction) and "plus" (associated with waves going into the positive axis direction). If only one of the fluxes is required, use the -function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}`. +function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}()`. !!! warning "Experimental implementation (upwind SBP)" This is an experimental feature and may change in future releases. @@ -462,7 +462,7 @@ it proved the most robust in practice. Returns a tuple of the fluxes "minus" (associated with waves going into the negative axis direction) and "plus" (associated with waves going into the positive axis direction). If only one of the fluxes is required, use the -function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}`. +function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}()`. !!! warning "Experimental implementation (upwind SBP)" This is an experimental feature and may change in future releases. @@ -555,7 +555,7 @@ are to handle flows at the low Mach number limit. Returns a tuple of the fluxes "minus" (associated with waves going into the negative axis direction) and "plus" (associated with waves going into the positive axis direction). If only one of the fluxes is required, use the -function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}`. +function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}()`. !!! warning "Experimental implementation (upwind SBP)" This is an experimental feature and may change in future releases. diff --git a/src/equations/compressible_euler_2d.jl b/src/equations/compressible_euler_2d.jl index 89f04ef1e05..05987c510b8 100644 --- a/src/equations/compressible_euler_2d.jl +++ b/src/equations/compressible_euler_2d.jl @@ -694,7 +694,7 @@ Splitting of the compressible Euler flux of Steger and Warming. Returns a tuple of the fluxes "minus" (associated with waves going into the negative axis direction) and "plus" (associated with waves going into the positive axis direction). If only one of the fluxes is required, use the -function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}`. +function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}()`. !!! warning "Experimental implementation (upwind SBP)" This is an experimental feature and may change in future releases. @@ -826,7 +826,7 @@ it proved the most robust in practice. Returns a tuple of the fluxes "minus" (associated with waves going into the negative axis direction) and "plus" (associated with waves going into the positive axis direction). If only one of the fluxes is required, use the -function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}`. +function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}()`. !!! warning "Experimental implementation (upwind SBP)" This is an experimental feature and may change in future releases. @@ -924,7 +924,7 @@ to Burgers' equation. Returns a tuple of the fluxes "minus" (associated with waves going into the negative axis direction) and "plus" (associated with waves going into the positive axis direction). If only one of the fluxes is required, use the -function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}`. +function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}()`. !!! warning "Experimental implementation (upwind SBP)" This is an experimental feature and may change in future releases. diff --git a/src/equations/compressible_euler_3d.jl b/src/equations/compressible_euler_3d.jl index cd081cfc42a..2085811f832 100644 --- a/src/equations/compressible_euler_3d.jl +++ b/src/equations/compressible_euler_3d.jl @@ -770,7 +770,7 @@ Splitting of the compressible Euler flux of Steger and Warming. Returns a tuple of the fluxes "minus" (associated with waves going into the negative axis direction) and "plus" (associated with waves going into the positive axis direction). If only one of the fluxes is required, use the -function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}`. +function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}()`. !!! warning "Experimental implementation (upwind SBP)" This is an experimental feature and may change in future releases. diff --git a/src/equations/inviscid_burgers_1d.jl b/src/equations/inviscid_burgers_1d.jl index 6a2cfb6aa8e..f2387f26ba7 100644 --- a/src/equations/inviscid_burgers_1d.jl +++ b/src/equations/inviscid_burgers_1d.jl @@ -137,7 +137,7 @@ and `f⁻ = 0.5 (f - λ u)` where `λ = abs(u)`. Returns a tuple of the fluxes "minus" (associated with waves going into the negative axis direction) and "plus" (associated with waves going into the positive axis direction). If only one of the fluxes is required, use the -function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}`. +function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}()`. !!! warning "Experimental implementation (upwind SBP)" This is an experimental feature and may change in future releases. From fdccbb17aaddd31a935ee7560fd4ea506a6d93ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 27 Jun 2023 07:43:59 +0200 Subject: [PATCH 021/263] Bump crate-ci/typos from 1.15.1 to 1.15.6 (#1552) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.15.1 to 1.15.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.15.1...v1.15.6) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-type: direct:production update-type: version-update:semver-patch ... 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 75886465f85..93bee1ce4fc 100644 --- a/.github/workflows/SpellCheck.yml +++ b/.github/workflows/SpellCheck.yml @@ -10,4 +10,4 @@ jobs: - name: Checkout Actions Repository uses: actions/checkout@v3 - name: Check spelling - uses: crate-ci/typos@v1.15.1 + uses: crate-ci/typos@v1.15.6 From 13b26a3d5c27c6c8040b56a56cb35b66f0e3bb42 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Jul 2023 03:25:15 +0200 Subject: [PATCH 022/263] Bump crate-ci/typos from 1.15.6 to 1.15.10 (#1559) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.15.6 to 1.15.10. - [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.15.6...v1.15.10) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-type: direct:production update-type: version-update:semver-patch ... 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 93bee1ce4fc..90bd9366b50 100644 --- a/.github/workflows/SpellCheck.yml +++ b/.github/workflows/SpellCheck.yml @@ -10,4 +10,4 @@ jobs: - name: Checkout Actions Repository uses: actions/checkout@v3 - name: Check spelling - uses: crate-ci/typos@v1.15.6 + uses: crate-ci/typos@v1.15.10 From 58fbab4df7bdfaf161fff16214f629a10426532b Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 5 Jul 2023 16:06:48 +0200 Subject: [PATCH 023/263] fix typo in docs (#1560) --- docs/literate/src/files/shock_capturing.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/literate/src/files/shock_capturing.jl b/docs/literate/src/files/shock_capturing.jl index b165f7ec8bd..afa34cbf06a 100644 --- a/docs/literate/src/files/shock_capturing.jl +++ b/docs/literate/src/files/shock_capturing.jl @@ -48,7 +48,7 @@ # with the total energy $\mathbb{E}=\max\big(\frac{m_N^2}{\sum_{j=0}^N m_j^2}, \frac{m_{N-1}^2}{\sum_{j=0}^{N-1} m_j^2}\big)$, # threshold $\mathbb{T}= 0.5 * 10^{-1.8*(N+1)^{1/4}}$ and parameter $s=ln\big(\frac{1-0.0001}{0.0001}\big)\approx 9.21024$. -# For computational efficiency, $\alpha_{min}$ is introduced und used for +# For computational efficiency, $\alpha_{min}$ is introduced and used for # ```math # \tilde{\alpha} = \begin{cases} # 0, & \text{if } \alpha<\alpha_{min}\\ From 3bd55515a03dac926446cbb8ee41edd21d9baec0 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Sat, 8 Jul 2023 06:16:24 +0200 Subject: [PATCH 024/263] set version to v0.5.31 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 0edba6b681c..81657e868db 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.5.31-pre" +version = "0.5.31" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From dc364ebc665c7f0ab74601ba0041618dddbabc18 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Sat, 8 Jul 2023 06:16:45 +0200 Subject: [PATCH 025/263] set development version to v0.5.32-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 81657e868db..828f4778f74 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.5.31" +version = "0.5.32-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 766e3f94465f48608c92d1fe91cd46db4c31c362 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jul 2023 07:14:30 +0200 Subject: [PATCH 026/263] Bump crate-ci/typos from 1.15.10 to 1.16.0 (#1563) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.15.10 to 1.16.0. - [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.15.10...v1.16.0) --- 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 90bd9366b50..bb5a32f72ee 100644 --- a/.github/workflows/SpellCheck.yml +++ b/.github/workflows/SpellCheck.yml @@ -10,4 +10,4 @@ jobs: - name: Checkout Actions Repository uses: actions/checkout@v3 - name: Check spelling - uses: crate-ci/typos@v1.15.10 + uses: crate-ci/typos@v1.16.0 From 5ff677c1d246e7a500ab845201bc328d1d3bde92 Mon Sep 17 00:00:00 2001 From: Lars Christmann Date: Tue, 11 Jul 2023 18:53:25 +0200 Subject: [PATCH 027/263] Implement upwind flux for linearized Euler equations (#1557) * Enable input checks for LEE keyword constructor * Extend LEE implementation to curved meshes * Implement upwind flux for linearized Euler equations * Add upwind flux examples and tests * Fix comments in linearized Euler elixirs * Clarify LEE Gaussian source elixir * Rename `flux_upwind` to `flux_godunov` * Add parentheses around multiline expressions * Add consistency checks for LEE Godunov flux * Explain odd mean values in more detail * Use normalized normal vector to simplify flux * Add docstring for LEE upwind flux * Update examples/p4est_2d_dgsem/elixir_linearizedeuler_gaussian_source.jl Co-authored-by: Michael Schlottke-Lakemper --------- Co-authored-by: Michael Schlottke-Lakemper --- .../elixir_linearizedeuler_gaussian_source.jl | 89 ++++++++ .../elixir_linearizedeuler_gauss_wall.jl | 68 ++++++ src/equations/linearized_euler_2d.jl | 212 +++++++++++++++++- test/test_p4est_2d.jl | 5 + test/test_tree_2d_linearizedeuler.jl | 6 + test/test_unit.jl | 20 ++ 6 files changed, 399 insertions(+), 1 deletion(-) create mode 100644 examples/p4est_2d_dgsem/elixir_linearizedeuler_gaussian_source.jl create mode 100644 examples/tree_2d_dgsem/elixir_linearizedeuler_gauss_wall.jl diff --git a/examples/p4est_2d_dgsem/elixir_linearizedeuler_gaussian_source.jl b/examples/p4est_2d_dgsem/elixir_linearizedeuler_gaussian_source.jl new file mode 100644 index 00000000000..ba2ec827778 --- /dev/null +++ b/examples/p4est_2d_dgsem/elixir_linearizedeuler_gaussian_source.jl @@ -0,0 +1,89 @@ + +using OrdinaryDiffEq +using Trixi + +# Based on the TreeMesh example `elixir_acoustics_gaussian_source.jl`. +# The acoustic perturbation equations have been replaced with the linearized Euler +# equations and instead of the Cartesian `TreeMesh` a rotated `P4estMesh` is used + +# Oscillating Gaussian-shaped source terms +function source_terms_gauss(u, x, t, equations::LinearizedEulerEquations2D) + r = 0.1 + A = 1.0 + f = 2.0 + + # Velocity sources + s2 = 0.0 + s3 = 0.0 + # Density and pressure source + s1 = s4 = exp(-(x[1]^2 + x[2]^2) / (2 * r^2)) * A * sin(2 * pi * f * t) + + return SVector(s1, s2, s3, s4) +end + +initial_condition_zero(x, t, equations::LinearizedEulerEquations2D) = SVector(0.0, 0.0, 0.0, 0.0) + +############################################################################### +# semidiscretization of the linearized Euler equations + +# Create a domain that is a 30° rotated version of [-3, 3]^2 +c = cospi(2 * 30.0 / 360.0) +s = sinpi(2 * 30.0 / 360.0) +rot_mat = Trixi.SMatrix{2, 2}([c -s; s c]) +mapping(xi, eta) = rot_mat * SVector(3.0*xi, 3.0*eta) + +# Mean density and speed of sound are slightly off from 1.0 to allow proper verification of +# curved LEE implementation using this elixir (some things in the LEE cancel if both are 1.0) +equations = LinearizedEulerEquations2D(v_mean_global=Tuple(rot_mat * SVector(-0.5, 0.25)), + c_mean_global=1.02, rho_mean_global=1.01) + +initial_condition = initial_condition_zero + +# Create DG solver with polynomial degree = 3 and upwind flux as surface flux +solver = DGSEM(polydeg=3, surface_flux=flux_godunov) + +# Create a uniformly refined mesh with periodic boundaries +trees_per_dimension = (4, 4) +mesh = P4estMesh(trees_per_dimension, polydeg=1, + mapping=mapping, + periodicity=true, initial_refinement_level=2) + +# A semidiscretization collects data structures and functions for the spatial discretization +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms=source_terms_gauss) + + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span from 0.0 to 2.0 +tspan = (0.0, 2.0) +ode = semidiscretize(semi, tspan) + +# 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) + +# The StepsizeCallback handles the re-calculation of the maximum Δt after each time step +stepsize_callback = StepsizeCallback(cfl=0.5) + +# 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.0, # 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/tree_2d_dgsem/elixir_linearizedeuler_gauss_wall.jl b/examples/tree_2d_dgsem/elixir_linearizedeuler_gauss_wall.jl new file mode 100644 index 00000000000..14fe201a291 --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_linearizedeuler_gauss_wall.jl @@ -0,0 +1,68 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linearized Euler equations + +equations = LinearizedEulerEquations2D(v_mean_global=(0.5, 0.0), c_mean_global=1.0, + rho_mean_global=1.0) + +# Create DG solver with polynomial degree = 5 and upwind flux as surface flux +solver = DGSEM(polydeg=5, surface_flux=flux_godunov) + +coordinates_min = (-100.0, 0.0) # minimum coordinates (min(x), min(y)) +coordinates_max = (100.0, 200.0) # maximum coordinates (max(x), max(y)) + +# Create a uniformly refined mesh with periodic boundaries +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + n_cells_max=100_000, + periodicity=false) + +function initial_condition_gauss_wall(x, t, equations::LinearizedEulerEquations2D) + v1_prime = 0.0 + v2_prime = 0.0 + rho_prime = p_prime = exp(-log(2) * (x[1]^2 + (x[2] - 25)^2) / 25) + return SVector(rho_prime, v1_prime, v2_prime, p_prime) +end +initial_condition = initial_condition_gauss_wall + +# A semidiscretization collects data structures and functions for the spatial discretization +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions=boundary_condition_wall) + + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span from 0.0 to 30.0 +tspan = (0.0, 30.0) +ode = semidiscretize(semi, tspan) + +# 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) + +# The StepsizeCallback handles the re-calculation of the maximum Δt after each time step +stepsize_callback = StepsizeCallback(cfl=0.7) + +# 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.0, # 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/src/equations/linearized_euler_2d.jl b/src/equations/linearized_euler_2d.jl index cd681365cae..e478c32bd29 100644 --- a/src/equations/linearized_euler_2d.jl +++ b/src/equations/linearized_euler_2d.jl @@ -53,7 +53,7 @@ end function LinearizedEulerEquations2D(; v_mean_global::NTuple{2, <:Real}, c_mean_global::Real, rho_mean_global::Real) - return LinearizedEulerEquations2D(SVector(v_mean_global), c_mean_global, + return LinearizedEulerEquations2D(v_mean_global, c_mean_global, rho_mean_global) end @@ -126,6 +126,24 @@ end return SVector(f1, f2, f3, f4) end +# Calculate 1D flux for a single point +@inline function flux(u, normal_direction::AbstractVector, + equations::LinearizedEulerEquations2D) + @unpack v_mean_global, c_mean_global, rho_mean_global = equations + rho_prime, v1_prime, v2_prime, p_prime = u + + v_mean_normal = v_mean_global[1] * normal_direction[1] + + v_mean_global[2] * normal_direction[2] + v_prime_normal = v1_prime * normal_direction[1] + v2_prime * normal_direction[2] + + f1 = v_mean_normal * rho_prime + rho_mean_global * v_prime_normal + f2 = v_mean_normal * v1_prime + normal_direction[1] * p_prime / rho_mean_global + f3 = v_mean_normal * v2_prime + normal_direction[2] * p_prime / rho_mean_global + f4 = v_mean_normal * p_prime + c_mean_global^2 * rho_mean_global * v_prime_normal + + return SVector(f1, f2, f3, f4) +end + @inline have_constant_speed(::LinearizedEulerEquations2D) = True() @inline function max_abs_speeds(equations::LinearizedEulerEquations2D) @@ -143,6 +161,198 @@ end end end +@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, + equations::LinearizedEulerEquations2D) + @unpack v_mean_global, c_mean_global = equations + v_mean_normal = normal_direction[1] * v_mean_global[1] + + normal_direction[2] * v_mean_global[2] + return abs(v_mean_normal) + c_mean_global * norm(normal_direction) +end + +@doc raw""" + flux_godunov(u_ll, u_rr, orientation_or_normal_direction, + equations::LinearizedEulerEquations2D) + +An upwind flux for the linearized Euler equations based on diagonalization of the physical +flux matrix. Given the physical flux ``Au``, ``A=T \Lambda T^{-1}`` with +``\Lambda`` being a diagonal matrix that holds the eigenvalues of ``A``, decompose +``\Lambda = \Lambda^+ + \Lambda^-`` where ``\Lambda^+`` and ``\Lambda^-`` are diagonal +matrices holding the positive and negative eigenvalues of ``A``, respectively. Then for +left and right states ``u_L, u_R``, the numerical flux calculated by this function is given +by ``A^+ u_L + A^- u_R`` where ``A^{\pm} = T \Lambda^{\pm} T^{-1}``. + +The diagonalization of the flux matrix can be found in +- R. F. Warming, Richard M. Beam and B. J. Hyett (1975) + Diagonalization and simultaneous symmetrization of the gas-dynamic matrices + [DOI: 10.1090/S0025-5718-1975-0388967-5](https://doi.org/10.1090/S0025-5718-1975-0388967-5) +""" +@inline function flux_godunov(u_ll, u_rr, orientation::Integer, + equations::LinearizedEulerEquations2D) + @unpack v_mean_global, rho_mean_global, c_mean_global = equations + v1_mean = v_mean_global[1] + v2_mean = v_mean_global[2] + + rho_prime_ll, v1_prime_ll, v2_prime_ll, p_prime_ll = u_ll + rho_prime_rr, v1_prime_rr, v2_prime_rr, p_prime_rr = u_rr + + if orientation == 1 + # Eigenvalues of the flux matrix + lambda1 = v1_mean + lambda2 = v1_mean - c_mean_global + lambda3 = v1_mean + c_mean_global + + 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) + + 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) + + f1p = (lambda1_p * rho_prime_ll + + lambda3m2_half_p / c_mean_global * rho_mean_global * v1_prime_ll + + (lambda2p3_half_p - lambda1_p) / c_mean_global^2 * p_prime_ll) + f2p = (lambda2p3_half_p * v1_prime_ll + + lambda3m2_half_p / c_mean_global * p_prime_ll / rho_mean_global) + f3p = lambda1_p * v2_prime_ll + f4p = (lambda3m2_half_p * c_mean_global * rho_mean_global * v1_prime_ll + + lambda2p3_half_p * p_prime_ll) + + f1m = (lambda1_m * rho_prime_rr + + lambda3m2_half_m / c_mean_global * rho_mean_global * v1_prime_rr + + (lambda2p3_half_m - lambda1_m) / c_mean_global^2 * p_prime_rr) + f2m = (lambda2p3_half_m * v1_prime_rr + + lambda3m2_half_m / c_mean_global * p_prime_rr / rho_mean_global) + f3m = lambda1_m * v2_prime_rr + f4m = (lambda3m2_half_m * c_mean_global * rho_mean_global * v1_prime_rr + + lambda2p3_half_m * p_prime_rr) + + f1 = f1p + f1m + f2 = f2p + f2m + f3 = f3p + f3m + f4 = f4p + f4m + else # orientation == 2 + # Eigenvalues of the flux matrix + lambda1 = v2_mean + lambda2 = v2_mean - c_mean_global + lambda3 = v2_mean + c_mean_global + + 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) + + 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) + + f1p = (lambda1_p * rho_prime_ll + + lambda3m2_half_p / c_mean_global * rho_mean_global * v2_prime_ll + + (lambda2p3_half_p - lambda1_p) / c_mean_global^2 * p_prime_ll) + f2p = lambda1_p * v1_prime_ll + f3p = (lambda2p3_half_p * v2_prime_ll + + lambda3m2_half_p / c_mean_global * p_prime_ll / rho_mean_global) + f4p = (lambda3m2_half_p * c_mean_global * rho_mean_global * v2_prime_ll + + lambda2p3_half_p * p_prime_ll) + + f1m = (lambda1_m * rho_prime_rr + + lambda3m2_half_m / c_mean_global * rho_mean_global * v2_prime_rr + + (lambda2p3_half_m - lambda1_m) / c_mean_global^2 * p_prime_rr) + f2m = lambda1_m * v1_prime_rr + f3m = (lambda2p3_half_m * v2_prime_rr + + lambda3m2_half_m / c_mean_global * p_prime_rr / rho_mean_global) + f4m = (lambda3m2_half_m * c_mean_global * rho_mean_global * v2_prime_rr + + lambda2p3_half_m * p_prime_rr) + + f1 = f1p + f1m + f2 = f2p + f2m + f3 = f3p + f3m + f4 = f4p + f4m + end + + return SVector(f1, f2, f3, f4) +end + +@inline function flux_godunov(u_ll, u_rr, normal_direction::AbstractVector, + equations::LinearizedEulerEquations2D) + @unpack v_mean_global, rho_mean_global, c_mean_global = equations + rho_prime_ll, v1_prime_ll, v2_prime_ll, p_prime_ll = u_ll + rho_prime_rr, v1_prime_rr, v2_prime_rr, p_prime_rr = u_rr + + # Do not use `normalize` since we use `norm_` later to scale the eigenvalues + norm_ = norm(normal_direction) + normal_vector = normal_direction / norm_ + + # Use normalized vector here, scaling is applied via eigenvalues of the flux matrix + v_mean_normal = v_mean_global[1] * normal_vector[1] + + v_mean_global[2] * normal_vector[2] + v_prime_normal_ll = v1_prime_ll * normal_vector[1] + v2_prime_ll * normal_vector[2] + v_prime_normal_rr = v1_prime_rr * normal_vector[1] + v2_prime_rr * normal_vector[2] + + # Eigenvalues of the flux matrix + lambda1 = v_mean_normal * norm_ + lambda2 = (v_mean_normal - c_mean_global) * norm_ + lambda3 = (v_mean_normal + c_mean_global) * norm_ + + 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) + + 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) + + f1p = (lambda1_p * rho_prime_ll + + lambda3m2_half_p / c_mean_global * rho_mean_global * v_prime_normal_ll + + (lambda2p3_half_p - lambda1_p) / c_mean_global^2 * p_prime_ll) + f2p = (((lambda1_p * normal_vector[2]^2 + + lambda2p3_half_p * normal_vector[1]^2) * v1_prime_ll + + (lambda2p3_half_p - lambda1_p) * prod(normal_vector) * v2_prime_ll) + + lambda3m2_half_p / c_mean_global * normal_vector[1] * p_prime_ll / + rho_mean_global) + f3p = (((lambda1_p * normal_vector[1]^2 + + lambda2p3_half_p * normal_vector[2]^2) * v2_prime_ll + + (lambda2p3_half_p - lambda1_p) * prod(normal_vector) * v1_prime_ll) + + lambda3m2_half_p / c_mean_global * normal_vector[2] * p_prime_ll / + rho_mean_global) + f4p = (lambda3m2_half_p * c_mean_global * rho_mean_global * v_prime_normal_ll + + lambda2p3_half_p * p_prime_ll) + + f1m = (lambda1_m * rho_prime_rr + + lambda3m2_half_m / c_mean_global * rho_mean_global * v_prime_normal_rr + + (lambda2p3_half_m - lambda1_m) / c_mean_global^2 * p_prime_rr) + f2m = (((lambda1_m * normal_vector[2]^2 + + lambda2p3_half_m * normal_vector[1]^2) * v1_prime_rr + + (lambda2p3_half_m - lambda1_m) * prod(normal_vector) * v2_prime_rr) + + lambda3m2_half_m / c_mean_global * normal_vector[1] * p_prime_rr / + rho_mean_global) + f3m = (((lambda1_m * normal_vector[1]^2 + + lambda2p3_half_m * normal_vector[2]^2) * v2_prime_rr + + (lambda2p3_half_m - lambda1_m) * prod(normal_vector) * v1_prime_rr) + + lambda3m2_half_m / c_mean_global * normal_vector[2] * p_prime_rr / + rho_mean_global) + f4m = (lambda3m2_half_m * c_mean_global * rho_mean_global * v_prime_normal_rr + + lambda2p3_half_m * p_prime_rr) + + f1 = f1p + f1m + f2 = f2p + f2m + f3 = f3p + f3m + f4 = f4p + f4m + + return SVector(f1, f2, f3, f4) +end + # Convert conservative variables to primitive @inline cons2prim(u, equations::LinearizedEulerEquations2D) = u @inline cons2entropy(u, ::LinearizedEulerEquations2D) = u diff --git a/test/test_p4est_2d.jl b/test/test_p4est_2d.jl index f66664c7a89..c4ce2619e15 100644 --- a/test/test_p4est_2d.jl +++ b/test/test_p4est_2d.jl @@ -164,6 +164,11 @@ isdir(outdir) && rm(outdir, recursive=true) tspan = (0.0, 0.02)) end + @trixi_testset "elixir_linearizedeuler_gaussian_source.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_linearizedeuler_gaussian_source.jl"), + l2 = [0.006047938590548741, 0.0040953286019907035, 0.004222698522497298, 0.006269492499336128], + linf = [0.06386175207349379, 0.0378926444850457, 0.041759728067967065, 0.06430136016259067]) + end end # Clean up afterwards: delete Trixi.jl output directory diff --git a/test/test_tree_2d_linearizedeuler.jl b/test/test_tree_2d_linearizedeuler.jl index 540b3951212..2c5f6dc2cd1 100644 --- a/test/test_tree_2d_linearizedeuler.jl +++ b/test/test_tree_2d_linearizedeuler.jl @@ -13,4 +13,10 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") linf = [0.0011006084408365924, 0.0005788678074691855, 0.0005788678074701847, 0.0011006084408365924] ) end + + @trixi_testset "elixir_linearizedeuler_gauss_wall.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_linearizedeuler_gauss_wall.jl"), + l2 = [0.048185623945503485, 0.01941899333212175, 0.019510224816991825, 0.048185623945503485], + linf = [1.0392165942153189, 0.18188777290819994, 0.1877028372108587, 1.0392165942153189]) + end end diff --git a/test/test_unit.jl b/test/test_unit.jl index 2156e9bac32..b0c3e4205e5 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -670,6 +670,26 @@ isdir(outdir) && rm(outdir, recursive=true) for normal_direction in normal_directions @test flux_godunov(u, u, normal_direction, equation) ≈ flux(u, normal_direction, equation) end + + # Linearized Euler 2D + equation = LinearizedEulerEquations2D(v_mean_global=(0.5, -0.7), c_mean_global=1.1, + rho_mean_global=1.2) + u_values = [SVector(1.0, 0.5, -0.7, 1.0), + SVector(1.5, -0.2, 0.1, 5.0),] + + orientations = [1, 2] + for orientation in orientations, u in u_values + @test flux_godunov(u, u, orientation, equation) ≈ flux(u, orientation, equation) + end + + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + + for normal_direction in normal_directions, u in u_values + @test flux_godunov(u, u, normal_direction, equation) ≈ flux(u, normal_direction, equation) + end end @timed_testset "Consistency check for Engquist-Osher flux" begin From 42732dbd09b21c2e0237ba3f004469b94f3d5600 Mon Sep 17 00:00:00 2001 From: Simon Candelaresi <10759273+SimonCan@users.noreply.github.com> Date: Tue, 11 Jul 2023 22:44:39 +0100 Subject: [PATCH 028/263] Added load_timestep function. (#1528) * Added load_timestep function. Corrected time index in restart simulations. * Changed doc string for load_timestep to clarify that we read the iteration number. * Added reading function for dt. Changed restart example elixir such that they use dt from previous simulation. * Get attribute 'current_filename' when loading an existing mesh. This fixes issues with converting from hdf5 into vtk when rerunning a simulation. * format * Update make.jl to include restart simulation documentation. * Create restart.md. * Added unformatted docs on how to restart a simulation from an old snapshot. * Completed restart tutorial. * Fixed a few typos in the docs for restarting a simulation. * Minor typo. * Added myself to the contributor list. * Update docs/src/restart.md Co-authored-by: Hendrik Ranocha * Update docs/src/restart.md Co-authored-by: Hendrik Ranocha * Update docs/src/restart.md Co-authored-by: Hendrik Ranocha * Update docs/src/restart.md Co-authored-by: Hendrik Ranocha * Update docs/src/restart.md Co-authored-by: Michael Schlottke-Lakemper * Update docs/src/restart.md Co-authored-by: Michael Schlottke-Lakemper * Update restart.md Added a few links to the restart documentation. * Update docs/src/restart.md Co-authored-by: Hendrik Ranocha * Corrected reference file name. * Added reference to save solution callback. --------- Co-authored-by: Hendrik Ranocha Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Hendrik Ranocha --- AUTHORS.md | 1 + docs/make.jl | 1 + docs/src/restart.md | 89 +++++++++++++++++++ .../elixir_advection_restart.jl | 16 +++- .../elixir_advection_restart.jl | 16 +++- .../elixir_advection_restart.jl | 15 +++- .../elixir_advection_restart.jl | 16 +++- .../tree_2d_dgsem/elixir_advection_restart.jl | 16 +++- .../tree_3d_dgsem/elixir_advection_restart.jl | 16 +++- .../elixir_euler_restart.jl | 16 +++- src/Trixi.jl | 2 +- src/callbacks_step/save_restart.jl | 22 +++++ src/meshes/mesh_io.jl | 1 + 13 files changed, 205 insertions(+), 22 deletions(-) create mode 100644 docs/src/restart.md diff --git a/AUTHORS.md b/AUTHORS.md index 973e311920b..abaa3e7e037 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -24,6 +24,7 @@ are listed in alphabetical order: * Maximilian D. Bertrand * Benjamin Bolm +* Simon Candelaresi * Jesse Chan * Lars Christmann * Christof Czernik diff --git a/docs/make.jl b/docs/make.jl index 5069e4dc49a..57629577ddb 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -92,6 +92,7 @@ makedocs( "Getting started" => [ "Overview" => "overview.md", "Visualization" => "visualization.md", + "Restart simulation" => "restart.md", ], "Tutorials" => tutorials, "Basic building blocks" => [ diff --git a/docs/src/restart.md b/docs/src/restart.md new file mode 100644 index 00000000000..d24d93cb297 --- /dev/null +++ b/docs/src/restart.md @@ -0,0 +1,89 @@ +# [Restart simulation](@id restart) + +You can continue running an already finished simulation by first +preparing the simulation for the restart and then performing the restart. +Here we suppose that in the first run your simulation stops at time 1.0 +and then you want it to run further to time 2.0. + +## [Prepare the simulation for a restart](@id restart_preparation) +In you original elixir you need to specify to write out restart files. +Those will later be read for the restart of your simulation. +This is done almost the same way as writing the snapshots using the +[`SaveSolutionCallback`](@ref) callback. +For the restart files it is called [`SaveRestartCallback`](@ref): +```julia +save_restart = SaveRestartCallback(interval=100, + save_final_restart=true) +``` +Make this part of your `CallbackSet`. + +An example is +[```examples/examples/structured_2d_dgsem/elixir_advection_extended.jl```](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/structured_2d_dgsem/elixir_advection_extended.jl). + + +## [Perform the simulation restart](@id restart_perform) +Since all of the information about the simulation can be obtained from the +last snapshot, the restart can be done with relatively few lines +in an extra elixir file. +However, some might prefer to keep everything in one elixir and +conditionals like ```if restart``` with a boolean variable ```restart``` that is user defined. + +First we need to define from which file we want to restart, e.g. +```julia +restart_file = "restart_000021.h5" +restart_filename = joinpath("out", restart_file) +``` + +Then we load the mesh file: +```julia +mesh = load_mesh(restart_filename) +``` + +This is then needed for the semidiscretization: +```julia +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) +``` + +We then define a new time span for the simulation that takes as starting +time the one form the snapshot: +```julia +tspan = (load_time(restart_filename), 2.0) +``` + +We now also take the last ```dt```, so that our solver does not need to first find +one to fulfill the CFL condition: +```julia +dt = load_dt(restart_filename) +``` + +The ODE that we will pass to the solver is now: +```julia +ode = semidiscretize(semi, tspan, restart_filename) +``` + +You should now define a [`SaveSolutionCallback`](@ref) similar to the +[original simulation](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/structured_2d_dgsem/elixir_advection_extended.jl), +but with ```save_initial_solution=false```, otherwise our initial snapshot will be overwritten. +If you are using one file for the original simulation and the restart +you can reuse your [`SaveSolutionCallback`](@ref), but need to set +```julia +save_solution.condition.save_initial_solution = false +``` + +Before we compute the solution using +[OrdinaryDiffEq.jl](https://github.com/SciML/OrdinaryDiffEq.jl) +we need to set the integrator +and its time step number, e.g.: +```julia +integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), + dt=dt, save_everystep=false, callback=callbacks); +integrator.iter = load_timestep(restart_filename) +integrator.stats.naccept = integrator.iter +``` + +Now we can compute the solution: +```julia +sol = solve!(integrator) +``` + +An example is in `[``examples/structured_2d_dgsem/elixir_advection_restart.jl```](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/structured_2d_dgsem/elixir_advection_restart.jl). diff --git a/examples/p4est_2d_dgsem/elixir_advection_restart.jl b/examples/p4est_2d_dgsem/elixir_advection_restart.jl index 1906fb2896e..79a35199b83 100644 --- a/examples/p4est_2d_dgsem/elixir_advection_restart.jl +++ b/examples/p4est_2d_dgsem/elixir_advection_restart.jl @@ -24,13 +24,23 @@ semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions=boundary_conditions) tspan = (load_time(restart_filename), 2.0) +dt = load_dt(restart_filename) ode = semidiscretize(semi, tspan, restart_filename); +# Do not overwrite the initial snapshot written by elixir_advection_extended.jl. +save_solution.condition.save_initial_solution = false + +integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), + dt=dt, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep=false, callback=callbacks); + +# Get the last time index and work with that. +integrator.iter = load_timestep(restart_filename) +integrator.stats.naccept = integrator.iter + ############################################################################### # 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); +sol = solve!(integrator) summary_callback() # print the timer summary diff --git a/examples/p4est_3d_dgsem/elixir_advection_restart.jl b/examples/p4est_3d_dgsem/elixir_advection_restart.jl index 71b37e9f39b..b27eaab62e2 100644 --- a/examples/p4est_3d_dgsem/elixir_advection_restart.jl +++ b/examples/p4est_3d_dgsem/elixir_advection_restart.jl @@ -21,13 +21,23 @@ mesh = load_mesh(restart_filename) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, solver) tspan = (load_time(restart_filename), 2.0) +dt = load_dt(restart_filename) ode = semidiscretize(semi, tspan, restart_filename); +# Do not overwrite the initial snapshot written by elixir_advection_extended.jl. +save_solution.condition.save_initial_solution = false + +integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), + dt=dt, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep=false, callback=callbacks); + +# Get the last time index and work with that. +integrator.iter = load_timestep(restart_filename) +integrator.stats.naccept = integrator.iter + ############################################################################### # 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); +sol = solve!(integrator) summary_callback() # print the timer summary diff --git a/examples/structured_2d_dgsem/elixir_advection_restart.jl b/examples/structured_2d_dgsem/elixir_advection_restart.jl index 2c2a0ef8f51..98c44fac71a 100644 --- a/examples/structured_2d_dgsem/elixir_advection_restart.jl +++ b/examples/structured_2d_dgsem/elixir_advection_restart.jl @@ -23,13 +23,22 @@ mesh = load_mesh(restart_filename) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) tspan = (load_time(restart_filename), 2.0) +dt = load_dt(restart_filename) ode = semidiscretize(semi, tspan, restart_filename); +# Do not overwrite the initial snapshot written by elixir_advection_extended.jl. +save_solution.condition.save_initial_solution = false + +integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), + dt=dt, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep=false, callback=callbacks); + +# Get the last time index and work with that. +integrator.iter = load_timestep(restart_filename) +integrator.stats.naccept = integrator.iter ############################################################################### # 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); +sol = solve!(integrator) summary_callback() # print the timer summary diff --git a/examples/structured_3d_dgsem/elixir_advection_restart.jl b/examples/structured_3d_dgsem/elixir_advection_restart.jl index 39e1a675167..39d28848c77 100644 --- a/examples/structured_3d_dgsem/elixir_advection_restart.jl +++ b/examples/structured_3d_dgsem/elixir_advection_restart.jl @@ -21,13 +21,23 @@ mesh = load_mesh(restart_filename) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, solver) tspan = (load_time(restart_filename), 2.0) +dt = load_dt(restart_filename) ode = semidiscretize(semi, tspan, restart_filename); +# Do not overwrite the initial snapshot written by elixir_advection_extended.jl. +save_solution.condition.save_initial_solution = false + +integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), + dt=dt, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep=false, callback=callbacks); + +# Get the last time index and work with that. +integrator.iter = load_timestep(restart_filename) +integrator.stats.naccept = integrator.iter + ############################################################################### # 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); +sol = solve!(integrator) summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_advection_restart.jl b/examples/tree_2d_dgsem/elixir_advection_restart.jl index 2cb45c0b47e..4ceb5932573 100644 --- a/examples/tree_2d_dgsem/elixir_advection_restart.jl +++ b/examples/tree_2d_dgsem/elixir_advection_restart.jl @@ -20,13 +20,23 @@ mesh = load_mesh(restart_filename) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) tspan = (load_time(restart_filename), 2.0) +dt = load_dt(restart_filename) ode = semidiscretize(semi, tspan, restart_filename); +# Do not overwrite the initial snapshot written by elixir_advection_extended.jl. +save_solution.condition.save_initial_solution = false + +integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), + dt=dt, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep=false, callback=callbacks) + +# Get the last time index and work with that. +integrator.iter = load_timestep(restart_filename) +integrator.stats.naccept = integrator.iter ############################################################################### # 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); +sol = solve!(integrator) + summary_callback() # print the timer summary diff --git a/examples/tree_3d_dgsem/elixir_advection_restart.jl b/examples/tree_3d_dgsem/elixir_advection_restart.jl index 83bf4418b98..3061f165874 100644 --- a/examples/tree_3d_dgsem/elixir_advection_restart.jl +++ b/examples/tree_3d_dgsem/elixir_advection_restart.jl @@ -20,13 +20,23 @@ mesh = load_mesh(restart_filename) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) tspan = (load_time(restart_filename), 2.0) +dt = load_dt(restart_filename) ode = semidiscretize(semi, tspan, restart_filename); +# Do not overwrite the initial snapshot written by elixir_advection_extended.jl. +save_solution.condition.save_initial_solution = false + +integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), + dt=dt, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep=false, callback=callbacks); + +# Get the last time index and work with that. +integrator.iter = load_timestep(restart_filename) +integrator.stats.naccept = integrator.iter + ############################################################################### # 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); +sol = solve!(integrator) summary_callback() # print the timer summary diff --git a/examples/unstructured_2d_dgsem/elixir_euler_restart.jl b/examples/unstructured_2d_dgsem/elixir_euler_restart.jl index 2ac67652023..b85cc2c6d70 100644 --- a/examples/unstructured_2d_dgsem/elixir_euler_restart.jl +++ b/examples/unstructured_2d_dgsem/elixir_euler_restart.jl @@ -22,14 +22,24 @@ semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions=boundary_conditions) tspan = (load_time(restart_filename), 1.0) +dt = load_dt(restart_filename) ode = semidiscretize(semi, tspan, restart_filename); +# Do not overwrite the initial snapshot written by elixir_advection_extended.jl. +save_solution.condition.save_initial_solution = false + +integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), + dt=dt, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep=false, callback=callbacks); + +# Get the last time index and work with that. +integrator.iter = load_timestep(restart_filename) +integrator.stats.naccept = integrator.iter + ############################################################################### # 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); +sol = solve!(integrator) summary_callback() # print the timer summary diff --git a/src/Trixi.jl b/src/Trixi.jl index 66878f4b459..6fc62f50520 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -241,7 +241,7 @@ export SummaryCallback, SteadyStateCallback, AnalysisCallback, AliveCallback, GlmSpeedCallback, LBMCollisionCallback, EulerAcousticsCouplingCallback, TrivialCallback, AnalysisCallbackCoupled -export load_mesh, load_time +export load_mesh, load_time, load_timestep, load_dt export ControllerThreeLevel, ControllerThreeLevelCombined, IndicatorLöhner, IndicatorLoehner, IndicatorMax, diff --git a/src/callbacks_step/save_restart.jl b/src/callbacks_step/save_restart.jl index e23f58f26ea..f567a5c7fda 100644 --- a/src/callbacks_step/save_restart.jl +++ b/src/callbacks_step/save_restart.jl @@ -130,6 +130,28 @@ function load_time(restart_file::AbstractString) end end +""" + load_timestep(restart_file::AbstractString) + +Load the time step number (`iter` in OrdinaryDiffEq.jl) saved in a `restart_file`. +""" +function load_timestep(restart_file::AbstractString) + h5open(restart_file, "r") do file + read(attributes(file)["timestep"]) + end +end + +""" + load_dt(restart_file::AbstractString) + +Load the time step size (`dt` in OrdinaryDiffEq.jl) saved in a `restart_file`. +""" +function load_dt(restart_file::AbstractString) + h5open(restart_file, "r") do file + read(attributes(file)["dt"]) + end +end + function load_restart_file(semi::AbstractSemidiscretization, restart_file) load_restart_file(mesh_equations_solver_cache(semi)..., restart_file) end diff --git a/src/meshes/mesh_io.jl b/src/meshes/mesh_io.jl index ede85d80106..da67fe23e0e 100644 --- a/src/meshes/mesh_io.jl +++ b/src/meshes/mesh_io.jl @@ -286,6 +286,7 @@ function load_mesh_serial(mesh_file::AbstractString; n_cells_max, RealT) mesh = StructuredMesh(size, mapping; RealT = RealT, unsaved_changes = false, mapping_as_string = mapping_as_string) + mesh.current_filename = mesh_file elseif mesh_type == "UnstructuredMesh2D" mesh_filename, periodicity_ = h5open(mesh_file, "r") do file return read(attributes(file)["mesh_filename"]), From a191e39b0d6bc75616aa2113b446b68e3b65ee41 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Thu, 13 Jul 2023 20:28:55 +0200 Subject: [PATCH 029/263] Hll 2 wave improvements non breaking (#1561) * Add Classical and Naive HLL 2 Wave solver to classic Hyperbolic PDEs * Format Code * HLLE wave speeds for SWE * Fix typos * Update tests for HLL * Unit test 1D MHD HLL, HLLE * Add example for classical HLL 2 wave * remove plots * Use lowercase for flux * Use einfeldt for mhd * Use hlle for mhd tets * Missing comma causes failing tests * Correct bug in SWE 2D Roe eigval comp, unit tests * format * Revert "format" This reverts commit 047a5e75b4a5ee4a0f58a7979d58b26f15f24334. * format equations * Add unit tests for HLL naive * Revert default hll flux * Rename min_max_speed to min_max_speed_davis and reduce documentation * Update src/equations/shallow_water_1d.jl: Comments Co-authored-by: Hendrik Ranocha * Add published resource for Roe averages for SWE * Add tests for rotation * Remove breaking portionv from PR * fix copy paste error * Lowercase davis * Update src/equations/numerical_fluxes.jl Co-authored-by: Hendrik Ranocha * Update src/equations/numerical_fluxes.jl Co-authored-by: Hendrik Ranocha * Update src/equations/numerical_fluxes.jl Co-authored-by: Hendrik Ranocha * Update src/equations/numerical_fluxes.jl Co-authored-by: Hendrik Ranocha * Update src/equations/numerical_fluxes.jl Co-authored-by: Hendrik Ranocha * Update src/equations/numerical_fluxes.jl Co-authored-by: Hendrik Ranocha * Update test/test_tree_2d_mhd.jl Co-authored-by: Hendrik Ranocha * Update src/equations/ideal_glm_mhd_1d.jl Co-authored-by: Hendrik Ranocha * Update src/equations/ideal_glm_mhd_2d.jl Co-authored-by: Hendrik Ranocha * Update src/equations/ideal_glm_mhd_3d.jl Co-authored-by: Hendrik Ranocha * Update test/test_tree_3d_mhd.jl Co-authored-by: Hendrik Ranocha * Remove hll_davis test * Split consistency checks * Try to resolve conflict with 5ff677c * Add tests * More tests --------- Co-authored-by: Hendrik Ranocha --- examples/dgmulti_2d/elixir_euler_bilinear.jl | 2 +- examples/dgmulti_2d/elixir_euler_curved.jl | 2 +- .../elixir_euler_triangulate_pkg_mesh.jl | 2 +- examples/dgmulti_2d/elixir_euler_weakform.jl | 2 +- .../elixir_euler_weakform_periodic.jl | 2 +- examples/dgmulti_3d/elixir_euler_curved.jl | 2 +- examples/dgmulti_3d/elixir_euler_weakform.jl | 2 +- .../elixir_euler_weakform_periodic.jl | 2 +- src/Trixi.jl | 2 +- src/equations/compressible_euler_1d.jl | 19 +- src/equations/compressible_euler_2d.jl | 43 +- src/equations/compressible_euler_3d.jl | 50 ++- src/equations/ideal_glm_mhd_1d.jl | 24 +- src/equations/ideal_glm_mhd_2d.jl | 67 ++- src/equations/ideal_glm_mhd_3d.jl | 71 ++++ src/equations/linearized_euler_2d.jl | 38 ++ src/equations/numerical_fluxes.jl | 45 ++- src/equations/shallow_water_1d.jl | 66 ++- src/equations/shallow_water_2d.jl | 147 ++++++- test/test_structured_1d.jl | 8 + test/test_unit.jl | 381 +++++++++++++++++- 21 files changed, 946 insertions(+), 31 deletions(-) diff --git a/examples/dgmulti_2d/elixir_euler_bilinear.jl b/examples/dgmulti_2d/elixir_euler_bilinear.jl index beb5c863971..bdd582610ea 100644 --- a/examples/dgmulti_2d/elixir_euler_bilinear.jl +++ b/examples/dgmulti_2d/elixir_euler_bilinear.jl @@ -2,7 +2,7 @@ using Trixi, OrdinaryDiffEq dg = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = SBP(), - surface_integral = SurfaceIntegralWeakForm(FluxHLL()), + surface_integral = SurfaceIntegralWeakForm(flux_hll), volume_integral = VolumeIntegralFluxDifferencing(flux_ranocha)) equations = CompressibleEulerEquations2D(1.4) diff --git a/examples/dgmulti_2d/elixir_euler_curved.jl b/examples/dgmulti_2d/elixir_euler_curved.jl index 4f1d613b247..a3ba62f1cfb 100644 --- a/examples/dgmulti_2d/elixir_euler_curved.jl +++ b/examples/dgmulti_2d/elixir_euler_curved.jl @@ -2,7 +2,7 @@ using Trixi, OrdinaryDiffEq dg = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = SBP(), - surface_integral = SurfaceIntegralWeakForm(FluxHLL()), + surface_integral = SurfaceIntegralWeakForm(flux_hll), volume_integral = VolumeIntegralFluxDifferencing(flux_ranocha)) equations = CompressibleEulerEquations2D(1.4) diff --git a/examples/dgmulti_2d/elixir_euler_triangulate_pkg_mesh.jl b/examples/dgmulti_2d/elixir_euler_triangulate_pkg_mesh.jl index 1f35a11bf8e..c10b5e46a14 100644 --- a/examples/dgmulti_2d/elixir_euler_triangulate_pkg_mesh.jl +++ b/examples/dgmulti_2d/elixir_euler_triangulate_pkg_mesh.jl @@ -1,7 +1,7 @@ using Trixi, OrdinaryDiffEq dg = DGMulti(polydeg = 3, element_type = Tri(), - surface_integral = SurfaceIntegralWeakForm(FluxHLL()), + surface_integral = SurfaceIntegralWeakForm(flux_hll), volume_integral = VolumeIntegralWeakForm()) equations = CompressibleEulerEquations2D(1.4) diff --git a/examples/dgmulti_2d/elixir_euler_weakform.jl b/examples/dgmulti_2d/elixir_euler_weakform.jl index 1ecc666c8db..486a30b37f1 100644 --- a/examples/dgmulti_2d/elixir_euler_weakform.jl +++ b/examples/dgmulti_2d/elixir_euler_weakform.jl @@ -2,7 +2,7 @@ using Trixi, OrdinaryDiffEq dg = DGMulti(polydeg = 3, element_type = Tri(), approximation_type = Polynomial(), - surface_integral = SurfaceIntegralWeakForm(FluxHLL()), + surface_integral = SurfaceIntegralWeakForm(flux_hll), volume_integral = VolumeIntegralWeakForm()) equations = CompressibleEulerEquations2D(1.4) diff --git a/examples/dgmulti_2d/elixir_euler_weakform_periodic.jl b/examples/dgmulti_2d/elixir_euler_weakform_periodic.jl index 48cc8070857..c4c83fff642 100644 --- a/examples/dgmulti_2d/elixir_euler_weakform_periodic.jl +++ b/examples/dgmulti_2d/elixir_euler_weakform_periodic.jl @@ -2,7 +2,7 @@ using Trixi, OrdinaryDiffEq dg = DGMulti(polydeg = 3, element_type = Tri(), approximation_type = Polynomial(), - surface_integral = SurfaceIntegralWeakForm(FluxHLL()), + surface_integral = SurfaceIntegralWeakForm(flux_hll), volume_integral = VolumeIntegralWeakForm()) equations = CompressibleEulerEquations2D(1.4) diff --git a/examples/dgmulti_3d/elixir_euler_curved.jl b/examples/dgmulti_3d/elixir_euler_curved.jl index 339d6ce0186..d8c4df5dd64 100644 --- a/examples/dgmulti_3d/elixir_euler_curved.jl +++ b/examples/dgmulti_3d/elixir_euler_curved.jl @@ -2,7 +2,7 @@ using Trixi, OrdinaryDiffEq dg = DGMulti(polydeg = 3, element_type = Hex(), approximation_type=SBP(), - surface_integral = SurfaceIntegralWeakForm(FluxHLL()), + surface_integral = SurfaceIntegralWeakForm(flux_hll), volume_integral = VolumeIntegralFluxDifferencing(flux_ranocha)) equations = CompressibleEulerEquations3D(1.4) diff --git a/examples/dgmulti_3d/elixir_euler_weakform.jl b/examples/dgmulti_3d/elixir_euler_weakform.jl index 4ad9f045eb6..b167377af51 100644 --- a/examples/dgmulti_3d/elixir_euler_weakform.jl +++ b/examples/dgmulti_3d/elixir_euler_weakform.jl @@ -2,7 +2,7 @@ using Trixi, OrdinaryDiffEq dg = DGMulti(polydeg = 3, element_type = Tet(), - surface_integral = SurfaceIntegralWeakForm(FluxHLL()), + surface_integral = SurfaceIntegralWeakForm(flux_hll), volume_integral = VolumeIntegralWeakForm()) equations = CompressibleEulerEquations3D(1.4) diff --git a/examples/dgmulti_3d/elixir_euler_weakform_periodic.jl b/examples/dgmulti_3d/elixir_euler_weakform_periodic.jl index f554167df90..6b17d4bba65 100644 --- a/examples/dgmulti_3d/elixir_euler_weakform_periodic.jl +++ b/examples/dgmulti_3d/elixir_euler_weakform_periodic.jl @@ -2,7 +2,7 @@ using Trixi, OrdinaryDiffEq dg = DGMulti(polydeg = 3, element_type = Tet(), approximation_type = Polynomial(), - surface_integral = SurfaceIntegralWeakForm(FluxHLL()), + surface_integral = SurfaceIntegralWeakForm(flux_hll), volume_integral = VolumeIntegralWeakForm()) equations = CompressibleEulerEquations3D(1.4) diff --git a/src/Trixi.jl b/src/Trixi.jl index 6fc62f50520..34a1977d4f5 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -164,7 +164,7 @@ export flux, flux_central, flux_lax_friedrichs, flux_hll, flux_hllc, flux_hlle, hydrostatic_reconstruction_audusse_etal, flux_nonconservative_audusse_etal, FluxPlusDissipation, DissipationGlobalLaxFriedrichs, DissipationLocalLaxFriedrichs, FluxLaxFriedrichs, max_abs_speed_naive, - FluxHLL, min_max_speed_naive, + FluxHLL, min_max_speed_naive, min_max_speed_davis, min_max_speed_einfeldt, FluxLMARS, FluxRotated, flux_shima_etal_turbo, flux_ranocha_turbo, diff --git a/src/equations/compressible_euler_1d.jl b/src/equations/compressible_euler_1d.jl index 15f7a2cb4c4..e4fd0997eae 100644 --- a/src/equations/compressible_euler_1d.jl +++ b/src/equations/compressible_euler_1d.jl @@ -628,7 +628,7 @@ end return SVector(f1m, f2m, f3m) end -# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation as the +# Calculate estimates for maximum wave speed for local Lax-Friedrichs-type dissipation as the # maximum velocity magnitude plus the maximum speed of sound @inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::CompressibleEulerEquations1D) @@ -648,7 +648,7 @@ end λ_max = max(v_mag_ll, v_mag_rr) + max(c_ll, c_rr) end -# Calculate minimum and maximum wave speeds for HLL-type fluxes +# Calculate estimates for minimum and maximum wave speeds for HLL-type fluxes @inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer, equations::CompressibleEulerEquations1D) rho_ll, v1_ll, p_ll = cons2prim(u_ll, equations) @@ -660,6 +660,21 @@ end return λ_min, λ_max end +# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer, + equations::CompressibleEulerEquations1D) + rho_ll, v1_ll, p_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, p_rr = cons2prim(u_rr, equations) + + c_ll = sqrt(equations.gamma * p_ll / rho_ll) + c_rr = sqrt(equations.gamma * p_rr / rho_rr) + + λ_min = min(v1_ll - c_ll, v1_rr - c_rr) + λ_max = max(v1_ll + c_ll, v1_rr + c_rr) + + return λ_min, λ_max +end + """ flux_hllc(u_ll, u_rr, orientation, equations::CompressibleEulerEquations1D) diff --git a/src/equations/compressible_euler_2d.jl b/src/equations/compressible_euler_2d.jl index 05987c510b8..27b92f41953 100644 --- a/src/equations/compressible_euler_2d.jl +++ b/src/equations/compressible_euler_2d.jl @@ -1032,7 +1032,7 @@ end return max(abs(v_ll), abs(v_rr)) + max(c_ll, c_rr) * norm(normal_direction) end -# Calculate minimum and maximum wave speeds for HLL-type fluxes +# Calculate estimate for minimum and maximum wave speeds for HLL-type fluxes @inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer, equations::CompressibleEulerEquations2D) rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations) @@ -1065,6 +1065,47 @@ end return λ_min, λ_max end +# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer, + equations::CompressibleEulerEquations2D) + rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations) + + c_ll = sqrt(equations.gamma * p_ll / rho_ll) + c_rr = sqrt(equations.gamma * p_rr / rho_rr) + + if orientation == 1 # x-direction + λ_min = min(v1_ll - c_ll, v1_rr - c_rr) + λ_max = max(v1_ll + c_ll, v1_rr + c_rr) + else # y-direction + λ_min = min(v2_ll - c_ll, v2_rr - c_rr) + λ_max = max(v2_ll + c_ll, v2_rr + c_rr) + end + + return λ_min, λ_max +end + +# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_davis(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleEulerEquations2D) + rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations) + + norm_ = norm(normal_direction) + + c_ll = sqrt(equations.gamma * p_ll / rho_ll) * norm_ + c_rr = sqrt(equations.gamma * p_rr / rho_rr) * norm_ + + v_normal_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] + v_normal_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] + + # The v_normals are already scaled by the norm + λ_min = min(v_normal_ll - c_ll, v_normal_rr - c_rr) + λ_max = max(v_normal_ll + c_ll, v_normal_rr + c_rr) + + return λ_min, λ_max +end + # Called inside `FluxRotated` in `numerical_fluxes.jl` so the direction # has been normalized prior to this rotation of the state vector @inline function rotate_to_x(u, normal_vector, equations::CompressibleEulerEquations2D) diff --git a/src/equations/compressible_euler_3d.jl b/src/equations/compressible_euler_3d.jl index 2085811f832..7f25bde31fd 100644 --- a/src/equations/compressible_euler_3d.jl +++ b/src/equations/compressible_euler_3d.jl @@ -1070,7 +1070,7 @@ end return max(abs(v_ll), abs(v_rr)) + max(c_ll, c_rr) * norm(normal_direction) end -# Calculate minimum and maximum wave speeds for HLL-type fluxes +# Calculate estimates for minimum and maximum wave speeds for HLL-type fluxes @inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer, equations::CompressibleEulerEquations3D) rho_ll, v1_ll, v2_ll, v3_ll, p_ll = cons2prim(u_ll, equations) @@ -1108,6 +1108,54 @@ end return λ_min, λ_max end +# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer, + equations::CompressibleEulerEquations3D) + rho_ll, v1_ll, v2_ll, v3_ll, p_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr, v3_rr, p_rr = cons2prim(u_rr, equations) + + c_ll = sqrt(equations.gamma * p_ll / rho_ll) + c_rr = sqrt(equations.gamma * p_rr / rho_rr) + + if orientation == 1 # x-direction + λ_min = min(v1_ll - c_ll, v1_rr - c_rr) + λ_max = max(v1_ll + c_ll, v1_rr + c_rr) + elseif orientation == 2 # y-direction + λ_min = min(v2_ll - c_ll, v2_rr - c_rr) + λ_max = max(v2_ll + c_ll, v2_rr + c_rr) + else # z-direction + λ_min = min(v3_ll - c_ll, v3_rr - c_rr) + λ_max = max(v3_ll + c_ll, v3_rr + c_rr) + end + + return λ_min, λ_max +end + +# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_davis(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleEulerEquations3D) + rho_ll, v1_ll, v2_ll, v3_ll, p_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr, v3_rr, p_rr = cons2prim(u_rr, equations) + + norm_ = norm(normal_direction) + + c_ll = sqrt(equations.gamma * p_ll / rho_ll) * norm_ + c_rr = sqrt(equations.gamma * p_rr / rho_rr) * norm_ + + v_normal_ll = v1_ll * normal_direction[1] + + v2_ll * normal_direction[2] + + v3_ll * normal_direction[3] + v_normal_rr = v1_rr * normal_direction[1] + + v2_rr * normal_direction[2] + + v3_rr * normal_direction[3] + + # The v_normals are already scaled by the norm + λ_min = min(v_normal_ll - c_ll, v_normal_rr - c_rr) + λ_max = max(v_normal_ll + c_ll, v_normal_rr + c_rr) + + return λ_min, λ_max +end + # Rotate normal vector to x-axis; normal, tangent1 and tangent2 need to be orthonormal # Called inside `FluxRotated` in `numerical_fluxes.jl` so the directions # has been normalized prior to this rotation of the state vector diff --git a/src/equations/ideal_glm_mhd_1d.jl b/src/equations/ideal_glm_mhd_1d.jl index 4ef593cda53..7e5c94c7bc3 100644 --- a/src/equations/ideal_glm_mhd_1d.jl +++ b/src/equations/ideal_glm_mhd_1d.jl @@ -277,13 +277,33 @@ end λ_max = max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) end +# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdEquations1D) + rho_ll, rho_v1_ll, _ = u_ll + rho_rr, rho_v1_rr, _ = u_rr + + # Calculate primitive variables + v1_ll = rho_v1_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + + # Approximate the left-most and right-most eigenvalues in the Riemann fan + c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations) + c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations) + + λ_min = min(v1_ll - c_f_ll, v1_rr - c_f_rr) + λ_max = max(v1_ll + c_f_ll, v1_rr + c_f_rr) + + return λ_min, λ_max +end + """ - min_max_speed_naive(u_ll, u_rr, orientation, equations::IdealGlmMhdEquations1D) + min_max_speed_naive(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdEquations1D) Calculate minimum and maximum wave speeds for HLL-type fluxes as in - Li (2005) An HLLC Riemann solver for magneto-hydrodynamics - [DOI: 10.1016/j.jcp.2004.08.020](https://doi.org/10.1016/j.jcp.2004.08.020) + [DOI: 10.1016/j.jcp.2004.08.020](https://doi.org/10.1016/j.jcp.2004.08.020). """ @inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdEquations1D) diff --git a/src/equations/ideal_glm_mhd_2d.jl b/src/equations/ideal_glm_mhd_2d.jl index fb3048fe883..8fef1ee22c9 100644 --- a/src/equations/ideal_glm_mhd_2d.jl +++ b/src/equations/ideal_glm_mhd_2d.jl @@ -585,13 +585,70 @@ end return max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) end +# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdEquations2D) + rho_ll, rho_v1_ll, rho_v2_ll, _ = u_ll + rho_rr, rho_v1_rr, rho_v2_rr, _ = u_rr + + # Calculate primitive velocity variables + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + + # Approximate the left-most and right-most eigenvalues in the Riemann fan + if orientation == 1 # x-direction + c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations) + c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations) + + λ_min = min(v1_ll - c_f_ll, v1_rr - c_f_rr) + λ_max = max(v1_ll + c_f_ll, v1_rr + c_f_rr) + else # y-direction + c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations) + c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations) + + λ_min = min(v2_ll - c_f_ll, v2_rr - c_f_rr) + λ_max = max(v2_ll + c_f_ll, v1_rr + c_f_rr) + end + + return λ_min, λ_max +end + +# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_davis(u_ll, u_rr, normal_direction::AbstractVector, + equations::IdealGlmMhdEquations2D) + rho_ll, rho_v1_ll, rho_v2_ll, _ = u_ll + rho_rr, rho_v1_rr, rho_v2_rr, _ = u_rr + + # Calculate primitive velocity variables + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + + v_normal_ll = (v1_ll * normal_direction[1] + v2_ll * normal_direction[2]) + v_normal_rr = (v1_rr * normal_direction[1] + v2_rr * normal_direction[2]) + + c_f_ll = calc_fast_wavespeed(u_ll, normal_direction, equations) + c_f_rr = calc_fast_wavespeed(u_rr, normal_direction, equations) + + # Estimate the min/max eigenvalues in the normal direction + λ_min = min(v_normal_ll - c_f_ll, v_normal_rr - c_f_rr) + λ_max = max(v_normal_ll + c_f_ll, v_normal_rr + c_f_rr) + + return λ_min, λ_max +end + """ - min_max_speed_naive(u_ll, u_rr, orientation, equations::IdealGlmMhdEquations2D) + min_max_speed_naive(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdEquations2D) Calculate minimum and maximum wave speeds for HLL-type fluxes as in - Li (2005) An HLLC Riemann solver for magneto-hydrodynamics - [DOI: 10.1016/j.jcp.2004.08.020](https://doi.org/10.1016/j.jcp.2004.08.020) + [DOI: 10.1016/j.jcp.2004.08.020](https://doi.org/10.1016/j.jcp.2004.08.020). """ @inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdEquations2D) @@ -635,10 +692,8 @@ end v1_rr = rho_v1_rr / rho_rr v2_rr = rho_v2_rr / rho_rr - v_normal_ll = (v1_ll * normal_direction[1] + - v2_ll * normal_direction[2]) - v_normal_rr = (v1_rr * normal_direction[1] + - v2_rr * normal_direction[2]) + v_normal_ll = (v1_ll * normal_direction[1] + v2_ll * normal_direction[2]) + v_normal_rr = (v1_rr * normal_direction[1] + v2_rr * normal_direction[2]) c_f_ll = calc_fast_wavespeed(u_ll, normal_direction, equations) c_f_rr = calc_fast_wavespeed(u_rr, normal_direction, equations) diff --git a/src/equations/ideal_glm_mhd_3d.jl b/src/equations/ideal_glm_mhd_3d.jl index 2e149d2849f..09990837706 100644 --- a/src/equations/ideal_glm_mhd_3d.jl +++ b/src/equations/ideal_glm_mhd_3d.jl @@ -670,6 +670,77 @@ end return max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) end +# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdEquations3D) + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr + + # Calculate primitive variables and speed of sound + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + v3_rr = rho_v3_rr / rho_rr + + # Approximate the left-most and right-most eigenvalues in the Riemann fan + if orientation == 1 # x-direction + c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations) + c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations) + + λ_min = min(v1_ll - c_f_ll, v1_rr - c_f_rr) + λ_max = max(v1_ll + c_f_ll, v1_rr + c_f_rr) + elseif orientation == 2 # y-direction + c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations) + c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations) + + λ_min = min(v2_ll - c_f_ll, v2_rr - c_f_rr) + λ_max = max(v2_ll + c_f_ll, v2_rr + c_f_rr) + else # z-direction + c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations) + c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations) + + λ_min = min(v3_ll - c_f_ll, v3_rr - c_f_rr) + λ_max = max(v3_ll + c_f_ll, v3_rr + c_f_rr) + end + + return λ_min, λ_max +end + +# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_davis(u_ll, u_rr, normal_direction::AbstractVector, + equations::IdealGlmMhdEquations3D) + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr + + # Calculate primitive velocity variables + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + v3_rr = rho_v3_rr / rho_rr + + v_normal_ll = (v1_ll * normal_direction[1] + + v2_ll * normal_direction[2] + + v3_ll * normal_direction[3]) + v_normal_rr = (v1_rr * normal_direction[1] + + v2_rr * normal_direction[2] + + v3_rr * normal_direction[3]) + + c_f_ll = calc_fast_wavespeed(u_ll, normal_direction, equations) + c_f_rr = calc_fast_wavespeed(u_rr, normal_direction, equations) + + # Estimate the min/max eigenvalues in the normal direction + λ_min = min(v_normal_ll - c_f_ll, v_normal_rr - c_f_rr) + λ_max = max(v_normal_ll + c_f_ll, v_normal_rr + c_f_rr) + + return λ_min, λ_max +end + """ min_max_speed_naive(u_ll, u_rr, orientation_or_normal_direction, equations::IdealGlmMhdEquations3D) diff --git a/src/equations/linearized_euler_2d.jl b/src/equations/linearized_euler_2d.jl index e478c32bd29..d497762bf62 100644 --- a/src/equations/linearized_euler_2d.jl +++ b/src/equations/linearized_euler_2d.jl @@ -353,6 +353,44 @@ end return SVector(f1, f2, f3, f4) end +# Calculate estimate for minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer, + equations::LinearizedEulerEquations2D) + min_max_speed_davis(u_ll, u_rr, orientation, equations) +end + +@inline function min_max_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, + equations::LinearizedEulerEquations2D) + min_max_speed_davis(u_ll, u_rr, normal_direction, equations) +end + +# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer, + equations::LinearizedEulerEquations2D) + @unpack v_mean_global, c_mean_global = equations + + λ_min = v_mean_global[orientation] - c_mean_global + λ_max = v_mean_global[orientation] + c_mean_global + + return λ_min, λ_max +end + +@inline function min_max_speed_davis(u_ll, u_rr, normal_direction::AbstractVector, + equations::LinearizedEulerEquations2D) + @unpack v_mean_global, c_mean_global = equations + + norm_ = norm(normal_direction) + + v_normal = v_mean_global[1] * normal_direction[1] + + v_mean_global[2] * normal_direction[2] + + # The v_normals are already scaled by the norm + λ_min = v_normal - c_mean_global * norm_ + λ_max = v_normal + c_mean_global * norm_ + + return λ_min, λ_max +end + # Convert conservative variables to primitive @inline cons2prim(u, equations::LinearizedEulerEquations2D) = u @inline cons2entropy(u, ::LinearizedEulerEquations2D) = u diff --git a/src/equations/numerical_fluxes.jl b/src/equations/numerical_fluxes.jl index 16a83124d14..abd9d66c490 100644 --- a/src/equations/numerical_fluxes.jl +++ b/src/equations/numerical_fluxes.jl @@ -214,6 +214,10 @@ Create an HLL (Harten, Lax, van Leer) numerical flux where the minimum and maxim wave speeds are estimated as `λ_min, λ_max = min_max_speed(u_ll, u_rr, orientation_or_normal_direction, equations)`, defaulting to [`min_max_speed_naive`](@ref). +Original paper: +- Amiram Harten, Peter D. Lax, Bram van Leer (1983) + On Upstream Differencing and Godunov-Type Schemes for Hyperbolic Conservation Laws + [DOI: 10.1137/1025002](https://doi.org/10.1137/1025002) """ struct FluxHLL{MinMaxSpeed} min_max_speed::MinMaxSpeed @@ -222,18 +226,55 @@ end FluxHLL() = FluxHLL(min_max_speed_naive) """ - min_max_speed_naive(u_ll, u_rr, orientation::Integer, equations) + min_max_speed_naive(u_ll, u_rr, orientation::Integer, equations) min_max_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, equations) -Simple and fast estimate of the minimal and maximal wave speed of the Riemann problem with +Simple and fast estimate(!) of the minimal and maximal wave speed of the Riemann problem with left and right states `u_ll, u_rr`, usually based only on the local wave speeds associated to `u_ll` and `u_rr`. - Amiram Harten, Peter D. Lax, Bram van Leer (1983) On Upstream Differencing and Godunov-Type Schemes for Hyperbolic Conservation Laws [DOI: 10.1137/1025002](https://doi.org/10.1137/1025002) + +See also [`FluxHLL`](@ref), [`min_max_speed_davis`](@ref), [`min_max_speed_einfeldt`](@ref). """ function min_max_speed_naive end +""" + min_max_speed_davis(u_ll, u_rr, orientation::Integer, equations) + min_max_speed_davis(u_ll, u_rr, normal_direction::AbstractVector, equations) + +Simple and fast estimates of the minimal and maximal wave speed of the Riemann problem with +left and right states `u_ll, u_rr`, usually based only on the local wave speeds associated to +`u_ll` and `u_rr`. + +- S.F. Davis (1988) + Simplified Second-Order Godunov-Type Methods + [DOI: 10.1137/0909030](https://doi.org/10.1137/0909030) + +See also [`FluxHLL`](@ref), [`min_max_speed_naive`](@ref), [`min_max_speed_einfeldt`](@ref). +""" +function min_max_speed_davis end + +""" + min_max_speed_einfeldt(u_ll, u_rr, orientation::Integer, equations) + min_max_speed_einfeldt(u_ll, u_rr, normal_direction::AbstractVector, equations) + +More advanced mininmal and maximal wave speed computation based on +- Bernd Einfeldt (1988) + On Godunov-type methods for gas dynamics. + [DOI: 10.1137/0725021](https://doi.org/10.1137/0725021) +- Bernd Einfeldt, Claus-Dieter Munz, Philip L. Roe and Björn Sjögreen (1991) + On Godunov-type methods near low densities. + [DOI: 10.1016/0021-9991(91)90211-3](https://doi.org/10.1016/0021-9991(91)90211-3) + +originally developed for the compressible Euler equations. +A compact representation can be found in [this lecture notes, eq. (9.28)](https://metaphor.ethz.ch/x/2019/hs/401-4671-00L/literature/mishra_hyperbolic_pdes.pdf). + +See also [`FluxHLL`](@ref), [`min_max_speed_naive`](@ref), [`min_max_speed_davis`](@ref). +""" +function min_max_speed_einfeldt end + @inline function (numflux::FluxHLL)(u_ll, u_rr, orientation_or_normal_direction, equations) λ_min, λ_max = numflux.min_max_speed(u_ll, u_rr, orientation_or_normal_direction, diff --git a/src/equations/shallow_water_1d.jl b/src/equations/shallow_water_1d.jl index 851cbacdd57..c33b31fca81 100644 --- a/src/equations/shallow_water_1d.jl +++ b/src/equations/shallow_water_1d.jl @@ -460,7 +460,7 @@ end end end -# Calculate minimum and maximum wave speeds for HLL-type fluxes +# Calculate estimate for minimum and maximum wave speeds for HLL-type fluxes @inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer, equations::ShallowWaterEquations1D) h_ll = waterheight(u_ll, equations) @@ -474,6 +474,41 @@ end return λ_min, λ_max end +# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer, + equations::ShallowWaterEquations1D) + h_ll = waterheight(u_ll, equations) + v_ll = velocity(u_ll, equations) + h_rr = waterheight(u_rr, equations) + v_rr = velocity(u_rr, equations) + + c_ll = sqrt(equations.gravity * h_ll) + c_rr = sqrt(equations.gravity * h_rr) + + λ_min = min(v_ll - c_ll, v_rr - c_rr) + λ_max = max(v_rr + c_rr, v_rr + c_rr) + + return λ_min, λ_max +end + +@inline function min_max_speed_einfeldt(u_ll, u_rr, orientation::Integer, + equations::ShallowWaterEquations1D) + h_ll = waterheight(u_ll, equations) + v_ll = velocity(u_ll, equations) + h_rr = waterheight(u_rr, equations) + v_rr = velocity(u_rr, equations) + + c_ll = sqrt(equations.gravity * h_ll) + c_rr = sqrt(equations.gravity * h_rr) + + v_roe, c_roe = calc_wavespeed_roe(u_ll, u_rr, orientation, equations) + + λ_min = min(v_ll - c_ll, v_roe - c_roe) + λ_max = max(v_rr + c_rr, v_roe + c_roe) + + return λ_min, λ_max +end + @inline function max_abs_speeds(u, equations::ShallowWaterEquations1D) h = waterheight(u, equations) v = velocity(u, equations) @@ -547,6 +582,35 @@ end return waterheight(u, equations) * pressure(u, equations) end +""" + calc_wavespeed_roe(u_ll, u_rr, direction::Integer, + equations::ShallowWaterEquations1D) + +Calculate Roe-averaged velocity `v_roe` and wavespeed `c_roe = sqrt{g * h_roe}` +See for instance equation (62) in +- Paul A. Ullrich, Christiane Jablonowski, and Bram van Leer (2010) + High-order finite-volume methods for the shallow-water equations on the sphere + [DOI: 10.1016/j.jcp.2010.04.044](https://doi.org/10.1016/j.jcp.2010.04.044) +Or equation (9.17) in [this lecture notes](https://metaphor.ethz.ch/x/2019/hs/401-4671-00L/literature/mishra_hyperbolic_pdes.pdf). +""" +@inline function calc_wavespeed_roe(u_ll, u_rr, direction::Integer, + equations::ShallowWaterEquations1D) + h_ll = waterheight(u_ll, equations) + v_ll = velocity(u_ll, equations) + h_rr = waterheight(u_rr, equations) + v_rr = velocity(u_rr, equations) + + h_roe = 0.5 * (h_ll + h_rr) + c_roe = sqrt(equations.gravity * h_roe) + + h_ll_sqrt = sqrt(h_ll) + h_rr_sqrt = sqrt(h_rr) + + v_roe = (h_ll_sqrt * v_ll + h_rr_sqrt * v_rr) / (h_ll_sqrt + h_rr_sqrt) + + return v_roe, c_roe +end + # Entropy function for the shallow water equations is the total energy @inline function entropy(cons, equations::ShallowWaterEquations1D) energy_total(cons, equations) diff --git a/src/equations/shallow_water_2d.jl b/src/equations/shallow_water_2d.jl index f9ebbd597f9..9e227cd4a77 100644 --- a/src/equations/shallow_water_2d.jl +++ b/src/equations/shallow_water_2d.jl @@ -725,7 +725,7 @@ end end end -# Calculate minimum and maximum wave speeds for HLL-type fluxes +# Calculate estimates for minimum and maximum wave speeds for HLL-type fluxes @inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer, equations::ShallowWaterEquations2D) h_ll = waterheight(u_ll, equations) @@ -762,6 +762,94 @@ end return λ_min, λ_max end +# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer, + equations::ShallowWaterEquations2D) + h_ll = waterheight(u_ll, equations) + v1_ll, v2_ll = velocity(u_ll, equations) + h_rr = waterheight(u_rr, equations) + v1_rr, v2_rr = velocity(u_rr, equations) + + c_ll = sqrt(equations.gravity * h_ll) + c_rr = sqrt(equations.gravity * h_rr) + + if orientation == 1 # x-direction + λ_min = min(v1_ll - c_ll, v1_rr - c_rr) + λ_max = max(v1_ll + c_ll, v1_rr + c_rr) + else # y-direction + λ_min = min(v2_ll - c_ll, v2_rr - c_rr) + λ_max = max(v2_ll + c_ll, v2_rr + c_rr) + end + + return λ_min, λ_max +end + +@inline function min_max_speed_davis(u_ll, u_rr, normal_direction::AbstractVector, + equations::ShallowWaterEquations2D) + h_ll = waterheight(u_ll, equations) + v1_ll, v2_ll = velocity(u_ll, equations) + h_rr = waterheight(u_rr, equations) + v1_rr, v2_rr = velocity(u_rr, equations) + + norm_ = norm(normal_direction) + c_ll = sqrt(equations.gravity * h_ll) * norm_ + c_rr = sqrt(equations.gravity * h_rr) * norm_ + + v_normal_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] + v_normal_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] + + # The v_normals are already scaled by the norm + λ_min = min(v_normal_ll - c_ll, v_normal_rr - c_rr) + λ_max = max(v_normal_ll + c_ll, v_normal_rr + c_rr) + + return λ_min, λ_max +end + +@inline function min_max_speed_einfeldt(u_ll, u_rr, orientation::Integer, + equations::ShallowWaterEquations2D) + h_ll = waterheight(u_ll, equations) + v1_ll, v2_ll = velocity(u_ll, equations) + h_rr = waterheight(u_rr, equations) + v1_rr, v2_rr = velocity(u_rr, equations) + + c_ll = sqrt(equations.gravity * h_ll) + c_rr = sqrt(equations.gravity * h_rr) + + if orientation == 1 # x-direction + v_roe, c_roe = calc_wavespeed_roe(u_ll, u_rr, orientation, equations) + λ_min = min(v1_ll - c_ll, v_roe - c_roe) + λ_max = max(v1_rr + c_rr, v_roe + c_roe) + else # y-direction + v_roe, c_roe = calc_wavespeed_roe(u_ll, u_rr, orientation, equations) + λ_min = min(v2_ll - c_ll, v_roe - c_roe) + λ_max = max(v2_rr + c_rr, v_roe + c_roe) + end + + return λ_min, λ_max +end + +@inline function min_max_speed_einfeldt(u_ll, u_rr, normal_direction::AbstractVector, + equations::ShallowWaterEquations2D) + h_ll = waterheight(u_ll, equations) + v1_ll, v2_ll = velocity(u_ll, equations) + h_rr = waterheight(u_rr, equations) + v1_rr, v2_rr = velocity(u_rr, equations) + + norm_ = norm(normal_direction) + + c_ll = sqrt(equations.gravity * h_ll) * norm_ + c_rr = sqrt(equations.gravity * h_rr) * norm_ + + v_normal_ll = (v1_ll * normal_direction[1] + v2_ll * normal_direction[2]) + v_normal_rr = (v1_rr * normal_direction[1] + v2_rr * normal_direction[2]) + + v_roe, c_roe = calc_wavespeed_roe(u_ll, u_rr, normal_direction, equations) + λ_min = min(v_normal_ll - c_ll, v_roe - c_roe) + λ_max = max(v_normal_rr + c_rr, v_roe + c_roe) + + return λ_min, λ_max +end + @inline function max_abs_speeds(u, equations::ShallowWaterEquations2D) h = waterheight(u, equations) v1, v2 = velocity(u, equations) @@ -837,6 +925,63 @@ end return waterheight(u, equations) * pressure(u, equations) end +""" + calc_wavespeed_roe(u_ll, u_rr, direction::Integer, + equations::ShallowWaterEquations2D) + +Calculate Roe-averaged velocity `v_roe` and wavespeed `c_roe = sqrt{g * h_roe}` depending on direction. +See for instance equation (62) in +- Paul A. Ullrich, Christiane Jablonowski, and Bram van Leer (2010) + High-order finite-volume methods for the shallow-water equations on the sphere + [DOI: 10.1016/j.jcp.2010.04.044](https://doi.org/10.1016/j.jcp.2010.04.044) +Or [this slides](https://faculty.washington.edu/rjl/classes/am574w2011/slides/am574lecture20nup3.pdf), +slides 8 and 9. +""" +@inline function calc_wavespeed_roe(u_ll, u_rr, orientation::Integer, + equations::ShallowWaterEquations2D) + h_ll = waterheight(u_ll, equations) + v1_ll, v2_ll = velocity(u_ll, equations) + h_rr = waterheight(u_rr, equations) + v1_rr, v2_rr = velocity(u_rr, equations) + + h_roe = 0.5 * (h_ll + h_rr) + c_roe = sqrt(equations.gravity * h_roe) + + h_ll_sqrt = sqrt(h_ll) + h_rr_sqrt = sqrt(h_rr) + + if orientation == 1 # x-direction + v_roe = (h_ll_sqrt * v1_ll + h_rr_sqrt * v1_rr) / (h_ll_sqrt + h_rr_sqrt) + else # y-direction + v_roe = (h_ll_sqrt * v2_ll + h_rr_sqrt * v2_rr) / (h_ll_sqrt + h_rr_sqrt) + end + + return v_roe, c_roe +end + +@inline function calc_wavespeed_roe(u_ll, u_rr, normal_direction::AbstractVector, + equations::ShallowWaterEquations2D) + h_ll = waterheight(u_ll, equations) + v1_ll, v2_ll = velocity(u_ll, equations) + h_rr = waterheight(u_rr, equations) + v1_rr, v2_rr = velocity(u_rr, equations) + + norm_ = norm(normal_direction) + + h_roe = 0.5 * (h_ll + h_rr) + c_roe = sqrt(equations.gravity * h_roe) * norm_ + + h_ll_sqrt = sqrt(h_ll) + h_rr_sqrt = sqrt(h_rr) + + v1_roe = (h_ll_sqrt * v1_ll + h_rr_sqrt * v1_rr) / (h_ll_sqrt + h_rr_sqrt) + v2_roe = (h_ll_sqrt * v2_ll + h_rr_sqrt * v2_rr) / (h_ll_sqrt + h_rr_sqrt) + + v_roe = (v1_roe * normal_direction[1] + v2_roe * normal_direction[2]) + + return v_roe, c_roe +end + # Entropy function for the shallow water equations is the total energy @inline function entropy(cons, equations::ShallowWaterEquations2D) energy_total(cons, equations) diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index ec8c7a138d5..d280e2a5e01 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -39,6 +39,14 @@ isdir(outdir) && rm(outdir, recursive=true) tspan = (0.0, 0.3)) end + @trixi_testset "elixir_euler_sedov_hll_davis.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov.jl"), + l2 = [1.278661029299215, 0.0663853410742763, 0.9585741943783386], + linf = [3.1661064228547255, 0.16256363944708607, 2.667676158812806], + tspan = (0.0, 12.5), + surface_flux = FluxHLL(min_max_speed_davis)) + end + @trixi_testset "elixir_euler_source_terms.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms.jl"), # Expected errors are exactly the same as with TreeMesh! diff --git a/test/test_unit.jl b/test/test_unit.jl index b0c3e4205e5..2ce111b2bf4 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -382,7 +382,7 @@ isdir(outdir) && rm(outdir, recursive=true) @timed_testset "HLL flux with vanishing wave speed estimates (#502)" begin equations = CompressibleEulerEquations1D(1.4) u = SVector(1.0, 0.0, 0.0) - @test !any(isnan, FluxHLL()(u, u, 1, equations)) + @test !any(isnan, flux_hll(u, u, 1, equations)) end @timed_testset "DG L2 mortar container debug output" begin @@ -586,7 +586,265 @@ isdir(outdir) && rm(outdir, recursive=true) @test_throws ArgumentError TimeSeriesCallback(semi, [1.0 1.0 1.0; 2.0 2.0 2.0]) end - @timed_testset "Consistency check for HLLE flux" begin + @timed_testset "Consistency check for HLL flux (naive): CEE" begin + flux_hll = FluxHLL(min_max_speed_naive) + + # Set up equations and dummy conservative variables state + equations = CompressibleEulerEquations1D(1.4) + u = SVector(1.1, 2.34, 5.5) + + orientations = [1] + for orientation in orientations + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + end + + equations = CompressibleEulerEquations2D(1.4) + u = SVector(1.1, -0.5, 2.34, 5.5) + + orientations = [1, 2] + for orientation in orientations + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + end + + equations = CompressibleEulerEquations3D(1.4) + u = SVector(1.1, -0.5, 2.34, 2.4, 5.5) + + orientations = [1, 2, 3] + for orientation in orientations + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + end + end + + @timed_testset "Consistency check for HLL flux (naive): LEE" begin + flux_hll = FluxHLL(min_max_speed_naive) + + equations = LinearizedEulerEquations2D(SVector(1.0, 1.0), 1.0, 1.0) + u = SVector(1.1, -0.5, 2.34, 5.5) + + orientations = [1, 2] + for orientation in orientations + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + end + + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + + for normal_direction in normal_directions + @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + end + end + + @timed_testset "Consistency check for HLL flux (naive): SWE" begin + flux_hll = FluxHLL(min_max_speed_naive) + + equations = ShallowWaterEquations1D(gravity_constant=9.81) + u = SVector(1, 0.5, 0.0) + @test flux_hll(u, u, 1, equations) ≈ flux(u, 1, equations) + + equations = ShallowWaterEquations2D(gravity_constant=9.81) + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + u = SVector(1, 0.5, 0.5, 0.0) + for normal_direction in normal_directions + @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + end + end + + @timed_testset "Consistency check for HLL flux (naive): MHD" begin + flux_hll = FluxHLL(min_max_speed_naive) + + equations = IdealGlmMhdEquations1D(1.4) + u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1), + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2),] + + for u in u_values + @test flux_hll(u, u, 1, equations) ≈ flux(u, 1, equations) + end + + equations = IdealGlmMhdEquations2D(1.4, 5.0 #= c_h =#) + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + orientations = [1, 2] + + u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] + + for u in u_values, orientation in orientations + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + end + + for u in u_values, normal_direction in normal_directions + @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + end + + equations = IdealGlmMhdEquations3D(1.4, 5.0 #= c_h =#) + normal_directions = [SVector(1.0, 0.0, 0.0), + SVector(0.0, 1.0, 0.0), + SVector(0.0, 0.0, 1.0), + SVector(0.5, -0.5, 0.2), + SVector(-1.2, 0.3, 1.4)] + orientations = [1, 2, 3] + + u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] + + for u in u_values, orientation in orientations + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + end + + for u in u_values, normal_direction in normal_directions + @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + end + end + + @timed_testset "Consistency check for HLL flux with Davis wave speed estimates: CEE" begin + flux_hll = FluxHLL(min_max_speed_davis) + + # Set up equations and dummy conservative variables state + equations = CompressibleEulerEquations1D(1.4) + u = SVector(1.1, 2.34, 5.5) + + orientations = [1] + for orientation in orientations + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + end + + equations = CompressibleEulerEquations2D(1.4) + u = SVector(1.1, -0.5, 2.34, 5.5) + + orientations = [1, 2] + for orientation in orientations + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + end + + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + + for normal_direction in normal_directions + @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + end + + equations = CompressibleEulerEquations3D(1.4) + u = SVector(1.1, -0.5, 2.34, 2.4, 5.5) + + orientations = [1, 2, 3] + for orientation in orientations + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + end + + normal_directions = [SVector(1.0, 0.0, 0.0), + SVector(0.0, 1.0, 0.0), + SVector(0.0, 0.0, 1.0), + SVector(0.5, -0.5, 0.2), + SVector(-1.2, 0.3, 1.4)] + + for normal_direction in normal_directions + @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + end + end + + @timed_testset "Consistency check for HLL flux with Davis wave speed estimates: LEE" begin + flux_hll = FluxHLL(min_max_speed_davis) + + equations = LinearizedEulerEquations2D(SVector(1.0, 1.0), 1.0, 1.0) + u = SVector(1.1, -0.5, 2.34, 5.5) + + orientations = [1, 2] + for orientation in orientations + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + end + + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + + for normal_direction in normal_directions + @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + end + end + + @timed_testset "Consistency check for HLL flux with Davis wave speed estimates: SWE" begin + flux_hll = FluxHLL(min_max_speed_davis) + + equations = ShallowWaterEquations1D(gravity_constant=9.81) + u = SVector(1, 0.5, 0.0) + @test flux_hll(u, u, 1, equations) ≈ flux(u, 1, equations) + + equations = ShallowWaterEquations2D(gravity_constant=9.81) + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + u = SVector(1, 0.5, 0.5, 0.0) + for normal_direction in normal_directions + @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + end + + orientations = [1, 2] + for orientation in orientations + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + end + end + + @timed_testset "Consistency check for HLL flux with Davis wave speed estimates: MHD" begin + flux_hll = FluxHLL(min_max_speed_davis) + + equations = IdealGlmMhdEquations1D(1.4) + u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1), + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2),] + + for u in u_values + @test flux_hll(u, u, 1, equations) ≈ flux(u, 1, equations) + end + + equations = IdealGlmMhdEquations2D(1.4, 5.0 #= c_h =#) + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + orientations = [1, 2] + + u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] + + for u in u_values, orientation in orientations + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + end + + for u in u_values, normal_direction in normal_directions + @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + end + + equations = IdealGlmMhdEquations3D(1.4, 5.0 #= c_h =#) + normal_directions = [SVector(1.0, 0.0, 0.0), + SVector(0.0, 1.0, 0.0), + SVector(0.0, 0.0, 1.0), + SVector(0.5, -0.5, 0.2), + SVector(-1.2, 0.3, 1.4)] + orientations = [1, 2, 3] + + u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] + + for u in u_values, orientation in orientations + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + end + + for u in u_values, normal_direction in normal_directions + @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + end + end + + @timed_testset "Consistency check for HLLE flux: CEE" begin # Set up equations and dummy conservative variables state equations = CompressibleEulerEquations1D(1.4) u = SVector(1.1, 2.34, 5.5) @@ -604,6 +862,15 @@ isdir(outdir) && rm(outdir, recursive=true) @test flux_hlle(u, u, orientation, equations) ≈ flux(u, orientation, equations) end + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + + for normal_direction in normal_directions + @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + end + equations = CompressibleEulerEquations3D(1.4) u = SVector(1.1, -0.5, 2.34, 2.4, 5.5) @@ -611,6 +878,92 @@ isdir(outdir) && rm(outdir, recursive=true) for orientation in orientations @test flux_hlle(u, u, orientation, equations) ≈ flux(u, orientation, equations) end + + normal_directions = [SVector(1.0, 0.0, 0.0), + SVector(0.0, 1.0, 0.0), + SVector(0.0, 0.0, 1.0), + SVector(0.5, -0.5, 0.2), + SVector(-1.2, 0.3, 1.4)] + + for normal_direction in normal_directions + @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + end + end + + @timed_testset "Consistency check for HLLE flux: SWE" begin + # Test HLL flux with min_max_speed_einfeldt + flux_hll = FluxHLL(min_max_speed_einfeldt) + + equations = ShallowWaterEquations1D(gravity_constant=9.81) + u = SVector(1, 0.5, 0.0) + @test flux_hll(u, u, 1, equations) ≈ flux(u, 1, equations) + + equations = ShallowWaterEquations2D(gravity_constant=9.81) + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + orientations = [1, 2] + + u = SVector(1, 0.5, 0.5, 0.0) + + for orientation in orientations + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + end + + for normal_direction in normal_directions + @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + end + end + + @timed_testset "Consistency check for HLLE flux: MHD" begin + # Test HLL flux with min_max_speed_einfeldt + flux_hll = FluxHLL(min_max_speed_naive) + + equations = IdealGlmMhdEquations1D(1.4) + u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1), + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2),] + + for u in u_values + @test flux_hll(u, u, 1, equations) ≈ flux(u, 1, equations) + end + + equations = IdealGlmMhdEquations2D(1.4, 5.0 #= c_h =#) + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + orientations = [1, 2] + + u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] + + for u in u_values, orientation in orientations + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + end + + for u in u_values, normal_direction in normal_directions + @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + end + + equations = IdealGlmMhdEquations3D(1.4, 5.0 #= c_h =#) + normal_directions = [SVector(1.0, 0.0, 0.0), + SVector(0.0, 1.0, 0.0), + SVector(0.0, 0.0, 1.0), + SVector(0.5, -0.5, 0.2), + SVector(-1.2, 0.3, 1.4)] + orientations = [1, 2, 3] + + u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] + + for u in u_values, orientation in orientations + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + end + + for u in u_values, normal_direction in normal_directions + @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + end end @timed_testset "Consistency check for Godunov flux" begin @@ -780,7 +1133,8 @@ isdir(outdir) && rm(outdir, recursive=true) SVector(-1.2, 0.3)] u_values = [SVector(1.0, 0.5, -0.7, 1.0), SVector(1.5, -0.2, 0.1, 5.0),] - fluxes = [flux_central, flux_ranocha, flux_shima_etal, flux_kennedy_gruber] + fluxes = [flux_central, flux_ranocha, flux_shima_etal, flux_kennedy_gruber, + flux_hll, FluxHLL(min_max_speed_davis)] for f_std in fluxes f_rot = FluxRotated(f_std) @@ -799,7 +1153,8 @@ isdir(outdir) && rm(outdir, recursive=true) SVector(-1.2, 0.3, 1.4)] u_values = [SVector(1.0, 0.5, -0.7, 0.1, 1.0), SVector(1.5, -0.2, 0.1, 0.2, 5.0),] - fluxes = [flux_central, flux_ranocha, flux_shima_etal, flux_kennedy_gruber, FluxLMARS(340)] + fluxes = [flux_central, flux_ranocha, flux_shima_etal, flux_kennedy_gruber, FluxLMARS(340), + flux_hll, FluxHLL(min_max_speed_davis)] for f_std in fluxes f_rot = FluxRotated(f_std) @@ -809,6 +1164,20 @@ isdir(outdir) && rm(outdir, recursive=true) end end + @timed_testset "ShallowWaterEquations2D" begin + equations = ShallowWaterEquations2D(gravity_constant=9.81) + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + + u = SVector(1, 0.5, 0.5, 0.0) + + fluxes = [flux_central, flux_fjordholm_etal, flux_wintermeyer_etal, + flux_hll, FluxHLL(min_max_speed_davis), FluxHLL(min_max_speed_einfeldt)] + + end + @timed_testset "IdealGlmMhdEquations2D" begin equations = IdealGlmMhdEquations2D(1.4, 5.0 #= c_h =#) normal_directions = [SVector(1.0, 0.0), @@ -817,7 +1186,7 @@ isdir(outdir) && rm(outdir, recursive=true) SVector(-1.2, 0.3)] u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] - fluxes = [flux_central, flux_hindenlang_gassner] + fluxes = [flux_central, flux_hindenlang_gassner, flux_hll, FluxHLL(min_max_speed_davis)] for f_std in fluxes f_rot = FluxRotated(f_std) @@ -836,7 +1205,7 @@ isdir(outdir) && rm(outdir, recursive=true) SVector(-1.2, 0.3, 1.4)] u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] - fluxes = [flux_central, flux_hindenlang_gassner] + fluxes = [flux_central, flux_hindenlang_gassner, flux_hll, FluxHLL(min_max_speed_davis)] for f_std in fluxes f_rot = FluxRotated(f_std) From dd91d7ed7fe99f437d8d0261cf7f9c43eb32c95b Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 14 Jul 2023 07:33:12 +0200 Subject: [PATCH 030/263] set version to v0.5.32 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 828f4778f74..f3ede1c74b4 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.5.32-pre" +version = "0.5.32" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 0816ed0b62679bcd656dc38bad68034843632ba1 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 14 Jul 2023 07:33:26 +0200 Subject: [PATCH 031/263] set development version to v0.5.33-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index f3ede1c74b4..4a289380850 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.5.32" +version = "0.5.33-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 905c8e29ef30bdb2648fa3073166ad0887cd1278 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 14 Jul 2023 17:47:20 +0200 Subject: [PATCH 032/263] Merge wet/dry capability to `main` (#1501) * add dummy commit in order to open a dev to main PR * [WIP] Wet/dry capabilities for 2D shallow water equations (#1340) * HR of Chen and Noelle (1D) and edit SWE struct * Overload limiter (SWE 1D) to cut off waterheight * New indicatorHG (SWE 1D) to apply FV on dry cells * Threshold in rhs! before calculation (SWE 1D) * New lake_at_rest_error for SWE 1D * New wet/dry elixirs for testing scheme for SWE 1D * HR of Chen and Noelle (2D) and edit SWE struct * Overload limiter (SWE 2D) to cut off waterheight * New indicatorHG (SWE 2D) to apply FV on dry cells * Threshold in rhs! before calculation (SWE 2D) * New lake_at_rest_error for SWE 2D * New wet/dry elixirs for testing scheme for SWE 2D * Elixir SWE 2D: 3 mounds, problem with boundaries * Fixed MethodError; apply_thresholds! too strict * Fixed MethodError; apply_thresholds! too strict * Move threshold on volume integral in stage_limiter * Indentation, spacing and comments adjustment * Renaming numerical HLL type flux (SWE 1D) * Move threshold on volume integral in stage_limiter * Renaming numerical HLL type flux (SWE 2D) * Indentation, spacing and comments adjustment * Describing docs for Chen and Noelle HR (SWE 1D) * Edit SWE 1D elixirs, error-based solver and docs * Including tests on new SWE 1D elixirs * Describing docs for Chen and Noelle HR (SWE 2D) * Edit SWE 2D elixirs, error-based solver and docs * Including tests on new SWE 2D elixirs * New/reorganize positivity limiter (SWE 2D) * New/reorganize positivity limiter (SWE 1D) * Editing docs SWE 1D * Editing docs SWE 2D * Rearrange cut off at interfaces, edit tests SWE 1D * Edit docs, add Ref * Edit docs and indenting (SWE 2D) * Rearrange cut off at interfaces, edit tests SWE 2D * Remove tree/structured mesh elixir from repo SWE2D * Create unstructured mesh elixir SWE 2D * Add 1D lake-at-rest-error logic to pass 1D tests * Add 2D lake-at-rest-error logic to pass 2D tests * Fixed typo. Confusing name, but correct math * Correction of comments and docstrings * Correction of comments and docstrings * Rename mesh file in elixir for UnstructuredMesh * Update test_unstructured_2d.jl forgot an end statement for the new test * Fixing typos * fix dispatching error on new lake-at-rest error calculation. See if this fixes broken tests * Editing initial condition in parabolic bowl elixir * Delete unnecessary variable in elixir * adjust lake-at-rest error computation strategy. move specialized version of error into the wet-dry elixir as the new functionality was only needed in this speacial case. update corresponding test values as the bottom is now truly discontinuous * update structured mesh version of the wet-dry well-balancedness test * fix typos * update values in parabolic bowl test on StructuredMesh * update parabolic bowl test on TreeMesh * revert the 1D computation of the lake-at-rest error to the standard way. This will change once the 1D wet/dry merges * Reset lake-at-rest error computation strategy. New version of error only in wet-dry elixir (special case) Update test values as the bottom is now truly discontinuous * Fix typo * Shorten test run for parabolic bowl 1D * Choose lower resolution for parabolic bowl and update test values * Further reduce resolution for parabolic bowl and update test values * adjust special initial conditions and well-balancedness error routines to avoid the need of element IDs * Remove MPI from well-balanced test * simplify workaround to set discontinuous initial data * Simplify workaround to set discontinuity * Change structure of Chen&Noelle flux * Fix typos and indenting * Adjust call of solve and use ode_default_options * Edit docstring * Replace boolean with if, remove set_node_vars Shorten test runs on TreeMesh and UnstructuredMesh * Change structure of Chen&Noelle flux * Fix typos and indenting * Adjust call of solve and use ode_default_options * Edit docstring * Replace boolean with if, remove set_node_vars Shorten test runs on TreeMesh and UnstructuredMesh * Update comment regarding H0 for lake-at-rest error * Add the original source to the parabolic bowl test * Update comment regarding H0 for lake-at-rest error * Add the original source to the parabolic bowl test * New sc indicator especially for SWE * Remove threshold parameter from SWE limiter call * update some docstrings * remove type instability in positivty limiter * typo fix * move safety check for dry state in the new positivity limiter into the same element loop * more docstring updates * remove dummy comment added in the dev initial commit * adjust default threshold values to be precision agnostic * update comment on the default threshold value in the new TreeMesh elixirs * update comments for the three new TreeMesh examples * update IC comment for three mound test * update IC comments for new StructuredMesh2D tests * update comment on shallow water constructor * adjust comments in the shallow_water_2d file * adjust comment regarding threshold_limiter in the new elixirs * fix typos found by SpellCheck * Edit docs * Import Printf macros for printing wb error * Remove type instability in Chen & Noelle HR * Change logic for setting SC indicator to one * Change logic for default values of SWE struct * Outsource HG shock capturing indicator for SWE Create different function to compute indicator Edit comments Change wet/dry clipping to if-else logic * Move limiterthreshold into function & edit docs Threshold was a passed variable in elixir before. Now, it is taken right from the SWE struct in the limiter Edit docs * Move new limiter safety check in same element loop * Adjust default threshold values * Remove type instability * Import Printf package for terminal output * Edit docs * Add Printf package to the test/Project.toml Used for printing lake-at-rest error in well-balancedness test * Add Printf package to the test/Project.toml Used for printing lake-at-rest error in well-balancedness test * Typo fix in elixir_shallowwater_well_balanced_wet_dry.jl * Typo fix in elixir_shallowwater_well_balanced_wet_dry.jl * unify new code with required formatting * fix weird formatting and add 'format: noindent' where missing. fix crashing structured mesh run * add unit test for new show routine * apply JuliaFormatter * simplify elixir as we can set discontinuous ICs in 1D. Also update beach test values * dummy commit to check push access * remove dummy comment * typo fix --------- Co-authored-by: Andrew Winters Co-authored-by: Michael Schlottke-Lakemper * adjust comments and remove duplicate code * add TODOs for code pieces that should move to TrixiShallowWater package * remove accidentally added file * apply formatter to avoid errors with new comments * move TODO comments to avoid errors in Documentation build * Apply suggestions from code review Co-authored-by: Hendrik Ranocha * remove unnecessary analysis quantities from several new elixirs * rename local threshold variable in new indicator to avoid confusion * update NEWS.md with wetting and drying feature * fix fomartting issue from conflict resolution --------- Co-authored-by: svengoldberg <102215246+svengoldberg@users.noreply.github.com> Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Hendrik Ranocha --- NEWS.md | 1 + .../elixir_shallowwater_conical_island.jl | 113 ++++++++ .../elixir_shallowwater_parabolic_bowl.jl | 119 ++++++++ ...ixir_shallowwater_well_balanced_wet_dry.jl | 200 +++++++++++++ .../elixir_shallowwater_beach.jl | 121 ++++++++ .../elixir_shallowwater_parabolic_bowl.jl | 117 ++++++++ ...ixir_shallowwater_well_balanced_wet_dry.jl | 165 +++++++++++ .../elixir_shallowwater_conical_island.jl | 116 ++++++++ .../elixir_shallowwater_parabolic_bowl.jl | 120 ++++++++ ...ixir_shallowwater_well_balanced_wet_dry.jl | 198 +++++++++++++ ...ixir_shallowwater_three_mound_dam_break.jl | 139 +++++++++ src/Trixi.jl | 9 +- src/callbacks_stage/callbacks_stage.jl | 2 + .../positivity_shallow_water.jl | 89 ++++++ .../positivity_shallow_water_dg1d.jl | 89 ++++++ .../positivity_shallow_water_dg2d.jl | 90 ++++++ src/equations/numerical_fluxes.jl | 23 ++ src/equations/shallow_water_1d.jl | 192 ++++++++++++- src/equations/shallow_water_2d.jl | 270 +++++++++++++++++- src/equations/shallow_water_two_layer_1d.jl | 2 + src/equations/shallow_water_two_layer_2d.jl | 96 ++++--- src/solvers/dgsem_tree/indicators.jl | 73 ++++- src/solvers/dgsem_tree/indicators_1d.jl | 109 +++++++ src/solvers/dgsem_tree/indicators_2d.jl | 110 +++++++ test/Project.toml | 1 + test/test_structured_2d.jl | 25 +- test/test_tree_1d_shallowwater.jl | 23 ++ test/test_tree_1d_shallowwater_twolayer.jl | 2 + test/test_tree_2d_shallowwater.jl | 24 ++ test/test_tree_2d_shallowwater_twolayer.jl | 20 +- test/test_unit.jl | 4 + test/test_unstructured_2d.jl | 18 ++ 32 files changed, 2608 insertions(+), 72 deletions(-) create mode 100644 examples/structured_2d_dgsem/elixir_shallowwater_conical_island.jl create mode 100644 examples/structured_2d_dgsem/elixir_shallowwater_parabolic_bowl.jl create mode 100644 examples/structured_2d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl create mode 100644 examples/tree_1d_dgsem/elixir_shallowwater_beach.jl create mode 100644 examples/tree_1d_dgsem/elixir_shallowwater_parabolic_bowl.jl create mode 100644 examples/tree_1d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl create mode 100644 examples/tree_2d_dgsem/elixir_shallowwater_conical_island.jl create mode 100644 examples/tree_2d_dgsem/elixir_shallowwater_parabolic_bowl.jl create mode 100644 examples/tree_2d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl create mode 100644 examples/unstructured_2d_dgsem/elixir_shallowwater_three_mound_dam_break.jl create mode 100644 src/callbacks_stage/positivity_shallow_water.jl create mode 100644 src/callbacks_stage/positivity_shallow_water_dg1d.jl create mode 100644 src/callbacks_stage/positivity_shallow_water_dg2d.jl diff --git a/NEWS.md b/NEWS.md index 35c7039b2ef..8e374d9ce99 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,6 +10,7 @@ for human readability. - Experimental support for 3D parabolic diffusion terms has been added. - Capability to set truly discontinuous initial conditions in 1D. +- Wetting and drying feature and examples for 1D and 2D shallow water equations #### Changed diff --git a/examples/structured_2d_dgsem/elixir_shallowwater_conical_island.jl b/examples/structured_2d_dgsem/elixir_shallowwater_conical_island.jl new file mode 100644 index 00000000000..44bc7a12b35 --- /dev/null +++ b/examples/structured_2d_dgsem/elixir_shallowwater_conical_island.jl @@ -0,0 +1,113 @@ + +using OrdinaryDiffEq +using Trixi + + ############################################################################### + # Semidiscretization of the shallow water equations +# +# TODO: TrixiShallowWater: wet/dry example elixir + +equations = ShallowWaterEquations2D(gravity_constant=9.81, H0=1.4) + +""" + initial_condition_conical_island(x, t, equations::ShallowWaterEquations2D) + +Initial condition for the [`ShallowWaterEquations2D`](@ref) to test the [`hydrostatic_reconstruction_chen_noelle`](@ref) +and its handling of discontinuous water heights at the start in combination with wetting and +drying. The bottom topography is given by a conical island in the middle of the domain. Around that +island, there is a cylindrical water column at t=0 and the rest of the domain is dry. This +discontinuous water height is smoothed by a logistic function. This simulation uses periodic +boundary conditions. +""" +function initial_condition_conical_island(x, t, equations::ShallowWaterEquations2D) + # Set the background values + + v1 = 0.0 + v2 = 0.0 + + x1, x2 = x + b = max(0.1, 1.0 - 4.0 * sqrt(x1^2 + x2^2)) + + # use a logistic function to transfer water height value smoothly + L = equations.H0 # maximum of function + x0 = 0.3 # center point of function + k = -25.0 # sharpness of transfer + + H = max(b, L/(1.0 + exp(-k*(sqrt(x1^2+x2^2) - x0)))) + + # It is mandatory to shift the water level at dry areas to make sure the water height h + # stays positive. The system would not be stable for h set to a hard 0 due to division by h in + # the computation of velocity, e.g., (h v1) / h. Therefore, a small dry state threshold + # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above + # for the ShallowWaterEquations and added to the initial condition if h = 0. + # This default value can be changed within the constructor call depending on the simulation setup. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v1, v2, b), equations) +end + +initial_condition = initial_condition_conical_island + +############################################################################### +# Get the DG approximation space + +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), + flux_nonconservative_chen_noelle) + +basis = LobattoLegendreBasis(4) + +indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, + alpha_max=0.5, + alpha_min=0.001, + alpha_smooth=true, + variable=waterheight_pressure) +volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; + volume_flux_dg=volume_flux, + volume_flux_fv=surface_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + +############################################################################### +# Get the StructuredMesh and setup a periodic mesh + +coordinates_min = (-1.0, -1.0) +coordinates_max = (1.0, 1.0) + +cells_per_dimension = (16, 16) + +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) + +# Create the semi discretization object +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solver + +tspan = (0.0, 10.0) +ode = semidiscretize(semi, tspan) + +############################################################################### +# 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=100, + save_initial_solution=true, + save_final_solution=true) + +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) + +############################################################################### +# run the simulation + +stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) + +sol = solve(ode, SSPRK43(stage_limiter!); + ode_default_options()..., callback=callbacks); + +summary_callback() # print the timer summary \ No newline at end of file diff --git a/examples/structured_2d_dgsem/elixir_shallowwater_parabolic_bowl.jl b/examples/structured_2d_dgsem/elixir_shallowwater_parabolic_bowl.jl new file mode 100644 index 00000000000..15cfe6698fc --- /dev/null +++ b/examples/structured_2d_dgsem/elixir_shallowwater_parabolic_bowl.jl @@ -0,0 +1,119 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# Semidiscretization of the shallow water equations +# +# TODO: TrixiShallowWater: wet/dry example elixir + +equations = ShallowWaterEquations2D(gravity_constant=9.81) + +""" + initial_condition_parabolic_bowl(x, t, equations:: ShallowWaterEquations2D) + +Well-known initial condition to test the [`hydrostatic_reconstruction_chen_noelle`](@ref) and its +wet-dry mechanics. This test has an analytical solution. The initial condition is defined by the +analytical solution at time t=0. The bottom topography defines a bowl and the water level is given +by an oscillating lake. + +The original test and its analytical solution were first presented in +- William C. Thacker (1981) + Some exact solutions to the nonlinear shallow-water wave equations + [DOI: 10.1017/S0022112081001882](https://doi.org/10.1017/S0022112081001882). + +The particular setup below is taken from Section 6.2 of +- Niklas Wintermeyer, Andrew R. Winters, Gregor J. Gassner and Timothy Warburton (2018) + An entropy stable discontinuous Galerkin method for the shallow water equations on + curvilinear meshes with wet/dry fronts accelerated by GPUs + [DOI: 10.1016/j.jcp.2018.08.038](https://doi.org/10.1016/j.jcp.2018.08.038). +""" +function initial_condition_parabolic_bowl(x, t, equations:: ShallowWaterEquations2D) + a = 1.0 + h_0 = 0.1 + sigma = 0.5 + ω = sqrt(2 * equations.gravity * h_0) / a + + v1 = -sigma * ω * sin(ω * t) + v2 = sigma * ω * cos(ω * t) + + b = h_0 * ((x[1])^2 + (x[2])^2) / a^2 + + H = sigma * h_0 / a^2 * (2 * x[1] * cos(ω * t) + 2 * x[2] * sin(ω * t) - sigma) + h_0 + + # It is mandatory to shift the water level at dry areas to make sure the water height h + # stays positive. The system would not be stable for h set to a hard 0 due to division by h in + # the computation of velocity, e.g., (h v1) / h. Therefore, a small dry state threshold + # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above + # for the ShallowWaterEquations and added to the initial condition if h = 0. + # This default value can be changed within the constructor call depending on the simulation setup. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v1, v2, b), equations) +end + +initial_condition = initial_condition_parabolic_bowl + + +############################################################################### +# Get the DG approximation space + +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), + flux_nonconservative_chen_noelle) + +basis = LobattoLegendreBasis(4) + +indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, + alpha_max=0.6, + alpha_min=0.001, + alpha_smooth=true, + variable=waterheight_pressure) +volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; + volume_flux_dg=volume_flux, + volume_flux_fv=surface_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + + +############################################################################### + +coordinates_min = (-2.0, -2.0) +coordinates_max = (2.0, 2.0) + +cells_per_dimension = (150, 150) + +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) + +# create the semi discretization 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 = 1000 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false, + extra_analysis_integrals=(energy_kinetic, + energy_internal)) + +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +save_solution = SaveSolutionCallback(interval=100, + save_initial_solution=true, + save_final_solution=true) + +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) + +stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) + +############################################################################### +# run the simulation + +sol = solve(ode, SSPRK43(stage_limiter!); + ode_default_options()..., callback=callbacks); + +summary_callback() # print the timer summary diff --git a/examples/structured_2d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl b/examples/structured_2d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl new file mode 100644 index 00000000000..b18b02e0b4c --- /dev/null +++ b/examples/structured_2d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl @@ -0,0 +1,200 @@ + +using OrdinaryDiffEq +using Trixi +using Printf: @printf, @sprintf + +############################################################################### +# Semidiscretization of the shallow water equations +# +# TODO: TrixiShallowWater: wet/dry example elixir + + +equations = ShallowWaterEquations2D(gravity_constant=9.812) + +""" + initial_condition_well_balanced_chen_noelle(x, t, equations:: ShallowWaterEquations2D) + +Initial condition with a complex (discontinuous) bottom topography to test the well-balanced +property for the [`hydrostatic_reconstruction_chen_noelle`](@ref) including dry areas within the +domain. The errors from the analysis callback are not important but the error for this +lake-at-rest test case `∑|H0-(h+b)|` should be around machine roundoff. + +The initial condition is taken from Section 5.2 of the paper: +- Guoxian Chen and Sebastian Noelle (2017) + A new hydrostatic reconstruction scheme based on subcell reconstructions + [DOI:10.1137/15M1053074](https://dx.doi.org/10.1137/15M1053074) +""" +function initial_condition_complex_bottom_well_balanced(x, t, equations:: ShallowWaterEquations2D) + v1 = 0 + v2 = 0 + b = sin(4 * pi * x[1]) + 3 + + if x[1] >= 0.5 + b = sin(4 * pi * x[1]) + 1 + end + + H = max(b, 2.5) + + if x[1] >= 0.5 + H = max(b, 1.5) + end + + # It is mandatory to shift the water level at dry areas to make sure the water height h + # stays positive. The system would not be stable for h set to a hard 0 due to division by h in + # the computation of velocity, e.g., (h v1) / h. Therefore, a small dry state threshold + # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above + # for the ShallowWaterEquations and added to the initial condition if h = 0. + # This default value can be changed within the constructor call depending on the simulation setup. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v1, v2, b), equations) +end + +initial_condition = initial_condition_complex_bottom_well_balanced + +############################################################################### +# Get the DG approximation space + +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) + +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), + flux_nonconservative_chen_noelle) + +basis = LobattoLegendreBasis(3) + +indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, + alpha_max=0.5, + alpha_min=0.001, + alpha_smooth=true, + variable=waterheight_pressure) +volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; + volume_flux_dg=volume_flux, + volume_flux_fv=surface_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + + +############################################################################### +# Create the StructuredMesh for the domain [0, 1]^2 + +coordinates_min = (0.0, 0.0) +coordinates_max = (1.0, 1.0) + +cells_per_dimension = (16, 16) + +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) + + +# create the semi discretization object +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 10.0) +ode = semidiscretize(semi, tspan) + +############################################################################### +# Workaround to set a discontinuous water and bottom topography for +# debugging and testing. Essentially, this is a slight augmentation of the +# `compute_coefficients` where the `x` node value passed here is slightly +# perturbed to the left / right in order to set a true discontinuity that avoids +# the doubled value of the LGL nodes at a particular element interface. +# +# Note! The errors from the analysis callback are not important but the error +# for this lake at rest test case `∑|H0-(h+b)|` should be near machine roundoff. + +# 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) + # We know that the discontinuity is a vertical line. Slightly augment the x value by a factor + # of unit roundoff to avoid the repeted value from the LGL nodes at at interface. + if i == 1 + x_node = SVector(nextfloat(x_node[1]) , x_node[2]) + elseif i == nnodes(semi.solver) + x_node = SVector(prevfloat(x_node[1]) , x_node[2]) + end + u_node = initial_condition_complex_bottom_well_balanced(x_node, first(tspan), 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, save_analysis=false) + +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.0) + +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) + +stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) + +############################################################################### +# run the simulation + +sol = solve(ode, SSPRK43(stage_limiter!); dt=1.0, + ode_default_options()..., callback=callbacks, adaptive=false); + +summary_callback() # print the timer summary + +############################################################################### +# Workaround to compute the well-balancedness error for this particular problem +# that has two reference water heights. One for a lake to the left of the +# discontinuous bottom topography `H0_upper = 2.5` and another for a lake to the +# right of the discontinuous bottom topography `H0_lower = 1.5`. + +# Declare a special version of the function to compute the lake-at-rest error +# OBS! The reference water height values are hardcoded for convenience. +function lake_at_rest_error_two_level(u, x, equations::ShallowWaterEquations2D) + h, _, _, b = u + + # For well-balancedness testing with possible wet/dry regions the reference + # water height `H0` accounts for the possibility that the bottom topography + # can emerge out of the water as well as for the threshold offset to avoid + # division by a "hard" zero water heights as well. + if x[1] < 0.5 + H0_wet_dry = max( 2.5 , b + equations.threshold_limiter ) + else + H0_wet_dry = max( 1.5 , b + equations.threshold_limiter ) + end + + return abs(H0_wet_dry - (h + b)) +end + +# point to the data we want to analyze +u = Trixi.wrap_array(sol[end], semi) +# Perform the actual integration of the well-balancedness error over the domain +l1_well_balance_error = Trixi.integrate_via_indices(u, mesh, equations, semi.solver, semi.cache; normalize=true) do u, i, j, element, equations, solver + x_node = Trixi.get_node_coords(semi.cache.elements.node_coordinates, equations, solver, i, j, element) + # We know that the discontinuity is a vertical line. Slightly augment the x value by a factor + # of unit roundoff to avoid the repeted value from the LGL nodes at at interface. + if i == 1 + x_node = SVector(nextfloat(x_node[1]) , x_node[2]) + elseif i == nnodes(semi.solver) + x_node = SVector(prevfloat(x_node[1]) , x_node[2]) + end + u_local = Trixi.get_node_vars(u, equations, solver, i, j, element) + return lake_at_rest_error_two_level(u_local, x_node, equations) +end + +# report the well-balancedness lake-at-rest error to the screen +println("─"^100) +println(" Lake-at-rest error for '", Trixi.get_name(equations), "' with ", summary(solver), + " at final time " * @sprintf("%10.8e", tspan[end])) + +@printf(" %-12s:", Trixi.pretty_form_utf(lake_at_rest_error)) +@printf(" % 10.8e", l1_well_balance_error) +println() +println("─"^100) diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_beach.jl b/examples/tree_1d_dgsem/elixir_shallowwater_beach.jl new file mode 100644 index 00000000000..1288bc5e66a --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_shallowwater_beach.jl @@ -0,0 +1,121 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# Semidiscretization of the shallow water equations +# +# TODO: TrixiShallowWater: wet/dry example elixir + +equations = ShallowWaterEquations1D(gravity_constant=9.812) + +""" + initial_condition_beach(x, t, equations:: ShallowWaterEquations1D) +Initial condition to simulate a wave running towards a beach and crashing. Difficult test +including both wetting and drying in the domain using slip wall boundary conditions. +The bottom topography is altered to be differentiable on the domain [0,8] and +differs from the reference below. + +The water height and speed functions used here, are adapted from the initial condition +found in section 5.2 of the paper: + - Andreas Bollermann, Sebastian Noelle, Maria Lukáčová-Medvid’ová (2011) + Finite volume evolution Galerkin methods for the shallow water equations with dry beds\n + [DOI: 10.4208/cicp.220210.020710a](https://dx.doi.org/10.4208/cicp.220210.020710a) +""" +function initial_condition_beach(x, t, equations:: ShallowWaterEquations1D) + D = 1 + delta = 0.02 + gamma = sqrt((3 * delta) / (4 * D)) + x_a = sqrt((4 * D) / (3 * delta)) * acosh(sqrt(20)) + + f = D + 40 * delta * sech(gamma * (8 * x[1] - x_a))^2 + + # steep curved beach + b = 0.01 + 99 / 409600 * 4^x[1] + + if x[1] >= 6 + H = b + v = 0.0 + else + H = f + v = sqrt(equations.gravity / D) * H + end + + # It is mandatory to shift the water level at dry areas to make sure the water height h + # stays positive. The system would not be stable for h set to a hard 0 due to division by h in + # the computation of velocity, e.g., (h v) / h. Therefore, a small dry state threshold + # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above + # for the ShallowWaterEquations and added to the initial condition if h = 0. + # This default value can be changed within the constructor call depending on the simulation setup. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v, b), equations) +end + +initial_condition = initial_condition_beach +boundary_condition = boundary_condition_slip_wall + +############################################################################### +# Get the DG approximation space + +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), + flux_nonconservative_chen_noelle) + +basis = LobattoLegendreBasis(3) + +indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, + alpha_max=0.5, + alpha_min=0.001, + alpha_smooth=true, + variable=waterheight_pressure) +volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; + volume_flux_dg=volume_flux, + volume_flux_fv=surface_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + +############################################################################### +# Create the TreeMesh for the domain [0, 8] + +coordinates_min = 0.0 +coordinates_max = 8.0 + +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=7, + n_cells_max=10_000, + periodicity=false) + +# create the semi discretization object +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions=boundary_condition) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 10.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false, + extra_analysis_integrals=(energy_kinetic, + energy_internal)) + +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +save_solution = SaveSolutionCallback(dt=0.5, + save_initial_solution=true, + save_final_solution=true) + +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) + +stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) + +############################################################################### +# run the simulation + +sol = solve(ode, SSPRK43(stage_limiter!); + ode_default_options()..., callback=callbacks); + +summary_callback() # print the timer summary \ No newline at end of file diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_parabolic_bowl.jl b/examples/tree_1d_dgsem/elixir_shallowwater_parabolic_bowl.jl new file mode 100644 index 00000000000..916bba76ece --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_shallowwater_parabolic_bowl.jl @@ -0,0 +1,117 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# Semidiscretization of the shallow water equations +# +# TODO: TrixiShallowWater: wet/dry example elixir + +equations = ShallowWaterEquations1D(gravity_constant=9.81) + +""" + initial_condition_parabolic_bowl(x, t, equations:: ShallowWaterEquations1D) + +Well-known initial condition to test the [`hydrostatic_reconstruction_chen_noelle`](@ref) and its +wet-dry mechanics. This test has analytical solutions. The initial condition is defined by the +analytical solution at time t=0. The bottom topography defines a bowl and the water level is given +by an oscillating lake. + +The original test and its analytical solution in two dimensions were first presented in +- William C. Thacker (1981) + Some exact solutions to the nonlinear shallow-water wave equations + [DOI: 10.1017/S0022112081001882](https://doi.org/10.1017/S0022112081001882). + +The particular setup below is taken from Section 6.2 of +- Niklas Wintermeyer, Andrew R. Winters, Gregor J. Gassner and Timothy Warburton (2018) + An entropy stable discontinuous Galerkin method for the shallow water equations on + curvilinear meshes with wet/dry fronts accelerated by GPUs + [DOI: 10.1016/j.jcp.2018.08.038](https://doi.org/10.1016/j.jcp.2018.08.038). +""" +function initial_condition_parabolic_bowl(x, t, equations:: ShallowWaterEquations1D) + a = 1 + h_0 = 0.1 + sigma = 0.5 + ω = sqrt(2 * equations.gravity * h_0) / a + + v = -sigma * ω * sin(ω * t) + + b = h_0 * x[1]^2 / a^2 + + H = sigma * h_0 / a^2 * (2 * x[1] * cos(ω * t) - sigma) + h_0 + + # It is mandatory to shift the water level at dry areas to make sure the water height h + # stays positive. The system would not be stable for h set to a hard 0 due to division by h in + # the computation of velocity, e.g., (h v) / h. Therefore, a small dry state threshold + # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above + # for the ShallowWaterEquations and added to the initial condition if h = 0. + # This default value can be changed within the constructor call depending on the simulation setup. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v, b), equations) +end + +initial_condition = initial_condition_parabolic_bowl + +############################################################################### +# Get the DG approximation space + +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), + flux_nonconservative_chen_noelle) + +basis = LobattoLegendreBasis(5) + +indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, + alpha_max=0.5, + alpha_min=0.001, + alpha_smooth=true, + variable=waterheight_pressure) +volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; + volume_flux_dg=volume_flux, + volume_flux_fv=surface_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + +############################################################################### +# Create the TreeMesh for the domain [-2, 2] + +coordinates_min = -2.0 +coordinates_max = 2.0 + +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=6, + n_cells_max=10_000) + +# create the semi discretization object +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 10.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false, + extra_analysis_integrals=(energy_kinetic, + energy_internal)) + +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, alive_callback, save_solution) + +stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) + +############################################################################### +# run the simulation + +sol = solve(ode, SSPRK43(stage_limiter!); + ode_default_options()..., callback=callbacks); + +summary_callback() # print the timer summary \ No newline at end of file diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl b/examples/tree_1d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl new file mode 100644 index 00000000000..8de46c61794 --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl @@ -0,0 +1,165 @@ + +using OrdinaryDiffEq +using Trixi +using Printf: @printf, @sprintf + +############################################################################### +# Semidiscretization of the shallow water equations +# +# TODO: TrixiShallowWater: wet/dry example elixir + +equations = ShallowWaterEquations1D(gravity_constant=9.812) + +""" + initial_condition_complex_bottom_well_balanced(x, t, equations:: ShallowWaterEquations1D) + +Initial condition with a complex (discontinuous) bottom topography to test the well-balanced +property for the [`hydrostatic_reconstruction_chen_noelle`](@ref) including dry areas within the +domain. The errors from the analysis callback are not important but the error for this +lake-at-rest test case `∑|H0-(h+b)|` should be around machine roundoff. + +The initial condition is taken from Section 5.2 of the paper: +- Guoxian Chen and Sebastian Noelle (2017) + A new hydrostatic reconstruction scheme based on subcell reconstructions + [DOI:10.1137/15M1053074](https://dx.doi.org/10.1137/15M1053074) +""" +function initial_condition_complex_bottom_well_balanced(x, t, equations:: ShallowWaterEquations1D) + v = 0.0 + b = sin(4 * pi * x[1]) + 3 + + if x[1] >= 0.5 + b = sin(4 * pi * x[1]) + 1 + end + + H = max(b, 2.5) + + if x[1] >= 0.5 + H = max(b, 1.5) + end + + # It is mandatory to shift the water level at dry areas to make sure the water height h + # stays positive. The system would not be stable for h set to a hard 0 due to division by h in + # the computation of velocity, e.g., (h v) / h. Therefore, a small dry state threshold + # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above + # for the ShallowWaterEquations and added to the initial condition if h = 0. + # This default value can be changed within the constructor call depending on the simulation setup. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v, b), equations) +end + +initial_condition = initial_condition_complex_bottom_well_balanced + +############################################################################### +# Get the DG approximation space + +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), + flux_nonconservative_chen_noelle) + +basis = LobattoLegendreBasis(3) + +indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, + alpha_max=0.5, + alpha_min=0.001, + alpha_smooth=true, + variable=waterheight_pressure) +volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; + volume_flux_dg=volume_flux, + volume_flux_fv=surface_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + +############################################################################### +# Create the TreeMesh for the domain [0, 1] + +coordinates_min = 0.0 +coordinates_max = 1.0 + +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=6, + n_cells_max=10_000) + +# create the semi discretization object +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 25.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 5000 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false) + +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +save_solution = SaveSolutionCallback(interval=5000, + save_initial_solution=true, + save_final_solution=true) + +stepsize_callback = StepsizeCallback(cfl=1.5) + +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, + stepsize_callback) + +stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) + +############################################################################### +# run the simulation + +sol = solve(ode, SSPRK43(stage_limiter!); dt=1.0, + ode_default_options()..., callback=callbacks, adaptive=false); + +summary_callback() # print the timer summary + +############################################################################### +# Workaround to compute the well-balancedness error for this particular problem +# that has two reference water heights. One for a lake to the left of the +# discontinuous bottom topography `H0_upper = 2.5` and another for a lake to the +# right of the discontinuous bottom topography `H0_lower = 1.5`. + +# Declare a special version of the function to compute the lake-at-rest error +# OBS! The reference water height values are hardcoded for convenience. +function lake_at_rest_error_two_level(u, x, equations::ShallowWaterEquations1D) + h, _, b = u + + # For well-balancedness testing with possible wet/dry regions the reference + # water height `H0` accounts for the possibility that the bottom topography + # can emerge out of the water as well as for the threshold offset to avoid + # division by a "hard" zero water heights as well. + if x[1] < 0.5 + H0_wet_dry = max( 2.5 , b + equations.threshold_limiter ) + else + H0_wet_dry = max( 1.5 , b + equations.threshold_limiter ) + end + + return abs(H0_wet_dry - (h + b)) + end + +# point to the data we want to analyze +u = Trixi.wrap_array(sol[end], semi) +# Perform the actual integration of the well-balancedness error over the domain +l1_well_balance_error = Trixi.integrate_via_indices(u, mesh, equations, semi.solver, semi.cache; normalize=true) do u, i, element, equations, solver + x_node = Trixi.get_node_coords(semi.cache.elements.node_coordinates, equations, solver, i, element) + # We know that the discontinuity is a vertical line. Slightly augment the x value by a factor + # of unit roundoff to avoid the repeted value from the LGL nodes at at interface. + if i == 1 + x_node = SVector(nextfloat(x_node[1])) + elseif i == nnodes(semi.solver) + x_node = SVector(prevfloat(x_node[1])) + end + u_local = Trixi.get_node_vars(u, equations, solver, i, element) + return lake_at_rest_error_two_level(u_local, x_node, equations) +end + +# report the well-balancedness lake-at-rest error to the screen +println("─"^100) +println(" Lake-at-rest error for '", Trixi.get_name(equations), "' with ", summary(solver), + " at final time " * @sprintf("%10.8e", tspan[end])) + +@printf(" %-12s:", Trixi.pretty_form_utf(lake_at_rest_error)) +@printf(" % 10.8e", l1_well_balance_error) +println() +println("─"^100) \ No newline at end of file diff --git a/examples/tree_2d_dgsem/elixir_shallowwater_conical_island.jl b/examples/tree_2d_dgsem/elixir_shallowwater_conical_island.jl new file mode 100644 index 00000000000..7c60e35b03e --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_shallowwater_conical_island.jl @@ -0,0 +1,116 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the shallow water equations +# +# TODO: TrixiShallowWater: wet/dry example elixir + +equations = ShallowWaterEquations2D(gravity_constant=9.81, H0=1.4) + +""" + initial_condition_conical_island(x, t, equations::ShallowWaterEquations2D) + +Initial condition for the [`ShallowWaterEquations2D`](@ref) to test the [`hydrostatic_reconstruction_chen_noelle`](@ref) +and its handling of discontinuous water heights at the start in combination with wetting and +drying. The bottom topography is given by a conical island in the middle of the domain. Around that +island, there is a cylindrical water column at t=0 and the rest of the domain is dry. This +discontinuous water height is smoothed by a logistic function. This simulation uses a Dirichlet +boundary condition with the initial values. Due to the dry cells at the boundary, this has the +effect of an outflow which can be seen in the simulation. +""" +function initial_condition_conical_island(x, t, equations::ShallowWaterEquations2D) + # Set the background values + + v1 = 0.0 + v2 = 0.0 + + x1, x2 = x + b = max(0.1, 1.0 - 4.0 * sqrt(x1^2 + x2^2)) + + # use a logistic function to transfer water height value smoothly + L = equations.H0 # maximum of function + x0 = 0.3 # center point of function + k = -25.0 # sharpness of transfer + + H = max(b, L/(1.0 + exp(-k*(sqrt(x1^2+x2^2) - x0)))) + + # It is mandatory to shift the water level at dry areas to make sure the water height h + # stays positive. The system would not be stable for h set to a hard 0 due to division by h in + # the computation of velocity, e.g., (h v1) / h. Therefore, a small dry state threshold + # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above + # for the ShallowWaterEquations and added to the initial condition if h = 0. + # This default value can be changed within the constructor call depending on the simulation setup. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v1, v2, b), equations) +end + +initial_condition = initial_condition_conical_island +boundary_conditions = BoundaryConditionDirichlet(initial_condition) + +############################################################################### +# Get the DG approximation space + +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), + flux_nonconservative_chen_noelle) + +basis = LobattoLegendreBasis(4) + +indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, + alpha_max=0.5, + alpha_min=0.001, + alpha_smooth=true, + variable=waterheight_pressure) +volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; + volume_flux_dg=volume_flux, + volume_flux_fv=surface_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + +############################################################################### +# Get the TreeMesh and setup a mesh + +coordinates_min = (-1.0, -1.0) +coordinates_max = (1.0, 1.0) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + n_cells_max=10_000, + periodicity=false) + +# Create the semi discretization object +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions=boundary_conditions) + +############################################################################### +# ODE solver + +tspan = (0.0, 10.0) +ode = semidiscretize(semi, tspan) + +############################################################################### +# 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=100, + save_initial_solution=true, + save_final_solution=true) + +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) + +############################################################################### +# run the simulation + +stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) + +sol = solve(ode, SSPRK43(stage_limiter!); + ode_default_options()..., callback=callbacks); + +summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_shallowwater_parabolic_bowl.jl b/examples/tree_2d_dgsem/elixir_shallowwater_parabolic_bowl.jl new file mode 100644 index 00000000000..03dcf017266 --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_shallowwater_parabolic_bowl.jl @@ -0,0 +1,120 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# Semidiscretization of the shallow water equations +# +# TODO: TrixiShallowWater: wet/dry example elixir + +equations = ShallowWaterEquations2D(gravity_constant=9.81) + +""" + initial_condition_parabolic_bowl(x, t, equations:: ShallowWaterEquations2D) + +Well-known initial condition to test the [`hydrostatic_reconstruction_chen_noelle`](@ref) and its +wet-dry mechanics. This test has an analytical solution. The initial condition is defined by the +analytical solution at time t=0. The bottom topography defines a bowl and the water level is given +by an oscillating lake. + +The original test and its analytical solution were first presented in +- William C. Thacker (1981) + Some exact solutions to the nonlinear shallow-water wave equations + [DOI: 10.1017/S0022112081001882](https://doi.org/10.1017/S0022112081001882). + +The particular setup below is taken from Section 6.2 of +- Niklas Wintermeyer, Andrew R. Winters, Gregor J. Gassner and Timothy Warburton (2018) + An entropy stable discontinuous Galerkin method for the shallow water equations on + curvilinear meshes with wet/dry fronts accelerated by GPUs + [DOI: 10.1016/j.jcp.2018.08.038](https://doi.org/10.1016/j.jcp.2018.08.038). +""" +function initial_condition_parabolic_bowl(x, t, equations:: ShallowWaterEquations2D) + a = 1.0 + h_0 = 0.1 + sigma = 0.5 + ω = sqrt(2 * equations.gravity * h_0) / a + + v1 = -sigma * ω * sin(ω * t) + v2 = sigma * ω * cos(ω * t) + + b = h_0 * ((x[1])^2 + (x[2])^2) / a^2 + + H = sigma * h_0 / a^2 * (2 * x[1] * cos(ω * t) + 2 * x[2] * sin(ω * t) - sigma) + h_0 + + # It is mandatory to shift the water level at dry areas to make sure the water height h + # stays positive. The system would not be stable for h set to a hard 0 due to division by h in + # the computation of velocity, e.g., (h v1) / h. Therefore, a small dry state threshold + # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above + # for the ShallowWaterEquations and added to the initial condition if h = 0. + # This default value can be changed within the constructor call depending on the simulation setup. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v1, v2, b), equations) +end + +initial_condition = initial_condition_parabolic_bowl +############################################################################### +# Get the DG approximation space + +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), + flux_nonconservative_chen_noelle) + +basis = LobattoLegendreBasis(7) + +indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, + alpha_max=0.6, + alpha_min=0.001, + alpha_smooth=true, + variable=waterheight_pressure) +volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; + volume_flux_dg=volume_flux, + volume_flux_fv=surface_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + + +############################################################################### +# Create the TreeMesh for the domain [-2, 2]^2 + +coordinates_min = (-2.0, -2.0) +coordinates_max = (2.0, 2.0) + +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=5, + n_cells_max=10_000) + +# create the semi discretization 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 = 1000 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false, + extra_analysis_integrals=(energy_kinetic, + energy_internal)) + +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +save_solution = SaveSolutionCallback(interval=100, + save_initial_solution=true, + save_final_solution=true) + +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) + +stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) + +############################################################################### +# run the simulation + +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) + +sol = solve(ode, SSPRK43(stage_limiter!); + ode_default_options()..., callback=callbacks); + +summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl b/examples/tree_2d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl new file mode 100644 index 00000000000..6fede2fa4ea --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl @@ -0,0 +1,198 @@ + +using OrdinaryDiffEq +using Trixi +using Printf: @printf, @sprintf + +############################################################################### +# Semidiscretization of the shallow water equations +# +# TODO: TrixiShallowWater: wet/dry example elixir + +equations = ShallowWaterEquations2D(gravity_constant=9.812) + +""" + initial_condition_well_balanced_chen_noelle(x, t, equations:: ShallowWaterEquations2D) + +Initial condition with a complex (discontinuous) bottom topography to test the well-balanced +property for the [`hydrostatic_reconstruction_chen_noelle`](@ref) including dry areas within the +domain. The errors from the analysis callback are not important but the error for this +lake-at-rest test case `∑|H0-(h+b)|` should be around machine roundoff. + +The initial condition is taken from Section 5.2 of the paper: +- Guoxian Chen and Sebastian Noelle (2017) + A new hydrostatic reconstruction scheme based on subcell reconstructions + [DOI:10.1137/15M1053074](https://dx.doi.org/10.1137/15M1053074) +""" +function initial_condition_complex_bottom_well_balanced(x, t, equations::ShallowWaterEquations2D) + v1 = 0 + v2 = 0 + b = sin(4 * pi * x[1]) + 3 + + if x[1] >= 0.5 + b = sin(4 * pi * x[1]) + 1 + end + + H = max(b, 2.5) + if x[1] >= 0.5 + H = max(b, 1.5) + end + + # It is mandatory to shift the water level at dry areas to make sure the water height h + # stays positive. The system would not be stable for h set to a hard 0 due to division by h in + # the computation of velocity, e.g., (h v1) / h. Therefore, a small dry state threshold + # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above + # for the ShallowWaterEquations and added to the initial condition if h = 0. + # This default value can be changed within the constructor call depending on the simulation setup. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v1, v2, b), equations) +end + +initial_condition = initial_condition_complex_bottom_well_balanced + +############################################################################### +# Get the DG approximation space + +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), + flux_nonconservative_chen_noelle) + +basis = LobattoLegendreBasis(3) + +indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, + alpha_max=0.5, + alpha_min=0.001, + alpha_smooth=true, + variable=waterheight_pressure) +volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; + volume_flux_dg=volume_flux, + volume_flux_fv=surface_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + +############################################################################### +# Create the TreeMesh for the domain [0, 1]^2 + +coordinates_min = (0.0, 0.0) +coordinates_max = (1.0, 1.0) + +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=3, + n_cells_max=10_000) + +# create the semi discretization object +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 50.0) +ode = semidiscretize(semi, tspan) + +############################################################################### +# Workaround to set a discontinuous water and bottom topography for +# debugging and testing. Essentially, this is a slight augmentation of the +# `compute_coefficients` where the `x` node value passed here is slightly +# perturbed to the left / right in order to set a true discontinuity that avoids +# the doubled value of the LGL nodes at a particular element interface. +# +# Note! The errors from the analysis callback are not important but the error +# for this lake at rest test case `∑|H0-(h+b)|` should be near machine roundoff. + +# 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) + # We know that the discontinuity is a vertical line. Slightly augment the x value by a factor + # of unit roundoff to avoid the repeted value from the LGL nodes at at interface. + if i == 1 + x_node = SVector(nextfloat(x_node[1]) , x_node[2]) + elseif i == nnodes(semi.solver) + x_node = SVector(prevfloat(x_node[1]) , x_node[2]) + end + u_node = initial_condition_complex_bottom_well_balanced(x_node, first(tspan), 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, save_analysis=false) + +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +save_solution = SaveSolutionCallback(interval=1000, + save_initial_solution=true, + save_final_solution=true) + +stepsize_callback = StepsizeCallback(cfl=2.0) + + +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, + stepsize_callback) + +stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) + +############################################################################### +# run the simulation + +sol = solve(ode, SSPRK43(stage_limiter!); dt=1.0, + ode_default_options()..., callback=callbacks, adaptive=false); + +summary_callback() # print the timer summary + +############################################################################### +# Workaround to compute the well-balancedness error for this particular problem +# that has two reference water heights. One for a lake to the left of the +# discontinuous bottom topography `H0_upper = 2.5` and another for a lake to the +# right of the discontinuous bottom topography `H0_lower = 1.5`. + +# Declare a special version of the function to compute the lake-at-rest error +# OBS! The reference water height values are hardcoded for convenience. +function lake_at_rest_error_two_level(u, x, equations::ShallowWaterEquations2D) + h, _, _, b = u + + # For well-balancedness testing with possible wet/dry regions the reference + # water height `H0` accounts for the possibility that the bottom topography + # can emerge out of the water as well as for the threshold offset to avoid + # division by a "hard" zero water heights as well. + + if x[1] < 0.5 + H0_wet_dry = max( 2.5 , b + equations.threshold_limiter ) + else + H0_wet_dry = max( 1.5 , b + equations.threshold_limiter ) + end + + return abs(H0_wet_dry - (h + b)) +end + +# point to the data we want to analyze +u = Trixi.wrap_array(sol[end], semi) +# Perform the actual integration of the well-balancedness error over the domain +l1_well_balance_error = Trixi.integrate_via_indices(u, mesh, equations, semi.solver, semi.cache; normalize=true) do u, i, j, element, equations, solver + x_node = Trixi.get_node_coords(semi.cache.elements.node_coordinates, equations, solver, i, j, element) + # We know that the discontinuity is a vertical line. Slightly augment the x value by a factor + # of unit roundoff to avoid the repeted value from the LGL nodes at at interface. + if i == 1 + x_node = SVector(nextfloat(x_node[1]) , x_node[2]) + elseif i == nnodes(semi.solver) + x_node = SVector(prevfloat(x_node[1]) , x_node[2]) + end + u_local = Trixi.get_node_vars(u, equations, solver, i, j, element) + return lake_at_rest_error_two_level(u_local, x_node, equations) +end + +# report the well-balancedness lake-at-rest error to the screen +println("─"^100) +println(" Lake-at-rest error for '", Trixi.get_name(equations), "' with ", summary(solver), + " at final time " * @sprintf("%10.8e", tspan[end])) + +@printf(" %-12s:", Trixi.pretty_form_utf(lake_at_rest_error)) +@printf(" % 10.8e", l1_well_balance_error) +println() +println("─"^100) diff --git a/examples/unstructured_2d_dgsem/elixir_shallowwater_three_mound_dam_break.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_three_mound_dam_break.jl new file mode 100644 index 00000000000..65b0fcae462 --- /dev/null +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_three_mound_dam_break.jl @@ -0,0 +1,139 @@ + +using Downloads: download +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the shallow water equations +# +# TODO: TrixiShallowWater: wet/dry example elixir + + +equations = ShallowWaterEquations2D(gravity_constant=9.81, H0=1.875, + threshold_limiter=1e-12, threshold_wet=1e-14) + + +""" + initial_condition_three_mounds(x, t, equations::ShallowWaterEquations2D) + +Initial condition simulating a dam break. The bottom topography is given by one large and two smaller +mounds. The mounds are flooded by the water for t > 0. To smooth the discontinuity, a logistic function +is applied. + +The initial conditions is taken from Section 6.3 of the paper: +- Niklas Wintermeyer, Andrew R. Winters, Gregor J. Gassner and Timothy Warburton (2018) + An entropy stable discontinuous Galerkin method for the shallow water equations on + curvilinear meshes with wet/dry fronts accelerated by GPUs\n + [DOI: 10.1016/j.jcp.2018.08.038](https://doi.org/10.1016/j.jcp.2018.08.038) +""" +function initial_condition_three_mounds(x, t, equations::ShallowWaterEquations2D) + + # Set the background values + v1 = 0.0 + v2 = 0.0 + + x1, x2 = x + M_1 = 1 - 0.1 * sqrt( (x1 - 30.0)^2 + (x2 - 22.5)^2 ) + M_2 = 1 - 0.1 * sqrt( (x1 - 30.0)^2 + (x2 - 7.5)^2 ) + M_3 = 2.8 - 0.28 * sqrt( (x1 - 47.5)^2 + (x2 - 15.0)^2 ) + + b = max(0.0, M_1, M_2, M_3) + + # use a logistic function to transfer water height value smoothly + L = equations.H0 # maximum of function + x0 = 8 # center point of function + k = -75.0 # sharpness of transfer + + H = max(b, L / (1.0 + exp(-k * (x1 - x0)))) + + # Avoid division by zero by adjusting the initial condition with a small dry state threshold + # that defaults to 500*eps() ≈ 1e-13 in double precision and is set in the constructor above + # for the ShallowWaterEquations struct. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v1, v2, b), equations) +end + +initial_condition = initial_condition_three_mounds + +function boundary_condition_outflow(u_inner, normal_direction::AbstractVector, x, t, + surface_flux_function, equations::ShallowWaterEquations2D) + # Impulse and bottom from inside, height from external state + u_outer = SVector(equations.threshold_wet, u_inner[2], u_inner[3], u_inner[4]) + + # calculate the boundary flux + flux = surface_flux_function(u_inner, u_outer, normal_direction, equations) + + return flux +end + +boundary_conditions = Dict( :Bottom => boundary_condition_slip_wall, + :Top => boundary_condition_slip_wall, + :Right => boundary_condition_outflow, + :Left => boundary_condition_slip_wall ) + +############################################################################### +# Get the DG approximation space + +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), + flux_nonconservative_chen_noelle) + +basis = LobattoLegendreBasis(4) + +indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, + alpha_max=0.5, + alpha_min=0.001, + alpha_smooth=true, + variable=waterheight_pressure) +volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; + volume_flux_dg=volume_flux, + volume_flux_fv=surface_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + +############################################################################### +# Get the unstructured quad mesh from a file (downloads the file if not available locally) + +default_meshfile = joinpath(@__DIR__, "mesh_three_mound.mesh") + +isfile(default_meshfile) || download("https://gist.githubusercontent.com/svengoldberg/c3c87fecb3fc6e46be7f0d1c7cb35f83/raw/e817ecd9e6c4686581d63c46128f9b6468d396d3/mesh_three_mound.mesh", + default_meshfile) + +meshfile = default_meshfile + +mesh = UnstructuredMesh2D(meshfile) + +# Create the semi discretization object +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver; + boundary_conditions=boundary_conditions) + +############################################################################### +# ODE solver + +tspan = (0.0, 20.0) +ode = semidiscretize(semi, tspan) + +############################################################################### +# 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=100, + save_initial_solution=true, + save_final_solution=true) + +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) + +############################################################################### +# run the simulation + +stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) + +sol = solve(ode, SSPRK43(stage_limiter!); + ode_default_options()..., callback=callbacks); +summary_callback() # print the timer summary diff --git a/src/Trixi.jl b/src/Trixi.jl index 34a1977d4f5..cf6158e29eb 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -162,9 +162,13 @@ export flux, flux_central, flux_lax_friedrichs, flux_hll, flux_hllc, flux_hlle, flux_fjordholm_etal, flux_nonconservative_fjordholm_etal, flux_es_fjordholm_etal, flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal, hydrostatic_reconstruction_audusse_etal, flux_nonconservative_audusse_etal, +# TODO: TrixiShallowWater: move anything with "chen_noelle" to new file + hydrostatic_reconstruction_chen_noelle, flux_nonconservative_chen_noelle, + flux_hll_chen_noelle, FluxPlusDissipation, DissipationGlobalLaxFriedrichs, DissipationLocalLaxFriedrichs, FluxLaxFriedrichs, max_abs_speed_naive, FluxHLL, min_max_speed_naive, min_max_speed_davis, min_max_speed_einfeldt, + min_max_speed_chen_noelle, FluxLMARS, FluxRotated, flux_shima_etal_turbo, flux_ranocha_turbo, @@ -215,6 +219,8 @@ export DG, VolumeIntegralFluxDifferencing, VolumeIntegralPureLGLFiniteVolume, VolumeIntegralShockCapturingHG, IndicatorHennemannGassner, +# TODO: TrixiShallowWater: move new indicator + IndicatorHennemannGassnerShallowWater, VolumeIntegralUpwind, SurfaceIntegralWeakForm, SurfaceIntegralStrongForm, SurfaceIntegralUpwind, @@ -248,7 +254,8 @@ export ControllerThreeLevel, ControllerThreeLevelCombined, IndicatorNeuralNetwork, NeuralNetworkPerssonPeraire, NeuralNetworkRayHesthaven, NeuralNetworkCNN -export PositivityPreservingLimiterZhangShu +# TODO: TrixiShallowWater: move new limiter +export PositivityPreservingLimiterZhangShu, PositivityPreservingLimiterShallowWater export trixi_include, examples_dir, get_examples, default_example, default_example_unstructured, ode_default_options diff --git a/src/callbacks_stage/callbacks_stage.jl b/src/callbacks_stage/callbacks_stage.jl index 7609f9b341d..ab0f34efb78 100644 --- a/src/callbacks_stage/callbacks_stage.jl +++ b/src/callbacks_stage/callbacks_stage.jl @@ -6,4 +6,6 @@ #! format: noindent include("positivity_zhang_shu.jl") +# TODO: TrixiShallowWater: move specific limiter file +include("positivity_shallow_water.jl") end # @muladd diff --git a/src/callbacks_stage/positivity_shallow_water.jl b/src/callbacks_stage/positivity_shallow_water.jl new file mode 100644 index 00000000000..36276026fe9 --- /dev/null +++ b/src/callbacks_stage/positivity_shallow_water.jl @@ -0,0 +1,89 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +# TODO: TrixiShallowWater: generic wet/dry limiter + +""" + PositivityPreservingLimiterShallowWater(; variables) + +The limiter is specifically designed for the shallow water equations. +It is applied to all scalar `variables` in their given order +using the defined `threshold_limiter` from the [`ShallowWaterEquations1D`](@ref) struct +or the [`ShallowWaterEquations2D`](@ref) struct to determine the minimal acceptable values. +The order of the `variables` is important and might have a strong influence +on the robustness. + +As opposed to the standard version of the [`PositivityPreservingLimiterZhangShu`](@ref), +nodes with a water height below the `threshold_limiter` are treated in a special way. +To avoid numerical problems caused by velocities close to zero, +the velocity is cut off, such that the node can be identified as "dry". The special feature of the +`ShallowWaterEquations` used here is that the bottom topography is stored as an additional +quantity in the solution vector `u`. However, the value of the bottom topography +should not be changed. That is why, it is not limited. + +After the limiting process is applied to all degrees of freedom, for safety reasons, +the `threshold_limiter` is applied again on all the DG nodes in order to avoid water height below. +In the case where the cell mean value is below the threshold before applying the limiter, +there could still be dry nodes afterwards due to the logic of the limiter. + +This fully-discrete positivity-preserving limiter is based on the work of +- Zhang, Shu (2011) + Maximum-principle-satisfying and positivity-preserving high-order schemes + for conservation laws: survey and new developments + [doi: 10.1098/rspa.2011.0153](https://doi.org/10.1098/rspa.2011.0153) +""" +struct PositivityPreservingLimiterShallowWater{N, Variables <: NTuple{N, Any}} + variables::Variables +end + +function PositivityPreservingLimiterShallowWater(; variables) + PositivityPreservingLimiterShallowWater(variables) +end + +function (limiter!::PositivityPreservingLimiterShallowWater)(u_ode, integrator, + semi::AbstractSemidiscretization, + t) + u = wrap_array(u_ode, semi) + @trixi_timeit timer() "positivity-preserving limiter" limiter_shallow_water!(u, + limiter!.variables, + mesh_equations_solver_cache(semi)...) +end + +# Iterate over tuples in a type-stable way using "lispy tuple programming", +# similar to https://stackoverflow.com/a/55849398: +# Iterating over tuples of different functions isn't type-stable in general +# but accessing the first element of a tuple is type-stable. Hence, it's good +# to process one element at a time and replace iteration by recursion here. +# Note that you shouldn't use this with too many elements per tuple since the +# compile times can increase otherwise - but a handful of elements per tuple +# is definitely fine. +function limiter_shallow_water!(u, variables::NTuple{N, Any}, + mesh, + equations::Union{ShallowWaterEquations1D, + ShallowWaterEquations2D}, + solver, cache) where {N} + variable = first(variables) + remaining_variables = Base.tail(variables) + + limiter_shallow_water!(u, equations.threshold_limiter, variable, mesh, equations, + solver, cache) + limiter_shallow_water!(u, remaining_variables, mesh, equations, solver, cache) + return nothing +end + +# terminate the type-stable iteration over tuples +function limiter_shallow_water!(u, variables::Tuple{}, + mesh, + equations::Union{ShallowWaterEquations1D, + ShallowWaterEquations2D}, + solver, cache) + nothing +end + +include("positivity_shallow_water_dg1d.jl") +include("positivity_shallow_water_dg2d.jl") +end # @muladd diff --git a/src/callbacks_stage/positivity_shallow_water_dg1d.jl b/src/callbacks_stage/positivity_shallow_water_dg1d.jl new file mode 100644 index 00000000000..13c6866e895 --- /dev/null +++ b/src/callbacks_stage/positivity_shallow_water_dg1d.jl @@ -0,0 +1,89 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +# TODO: TrixiShallowWater: 1D wet/dry limiter should move + +function limiter_shallow_water!(u, threshold::Real, variable, + mesh::AbstractMesh{1}, + equations::ShallowWaterEquations1D, + dg::DGSEM, cache) + @unpack weights = dg.basis + + @threaded for element in eachelement(dg, cache) + # determine minimum value + value_min = typemax(eltype(u)) + for i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, element) + value_min = min(value_min, variable(u_node, equations)) + end + + # detect if limiting is necessary + value_min < threshold || continue + + # compute mean value + u_mean = zero(get_node_vars(u, equations, dg, 1, element)) + for i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, element) + u_mean += u_node * weights[i] + end + # note that the reference element is [-1,1]^ndims(dg), thus the weights sum to 2 + u_mean = u_mean / 2^ndims(mesh) + + # We compute the value directly with the mean values, as we assume that + # Jensen's inequality holds (e.g. pressure for compressible Euler equations). + value_mean = variable(u_mean, equations) + theta = (value_mean - threshold) / (value_mean - value_min) + for i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, element) + + # Cut off velocity in case that the waterheight is smaller than the threshold + + h_node, h_v_node, b_node = u_node + h_mean, h_v_mean, _ = u_mean # b_mean is not used as b_node must not be overwritten + + # Set them both to zero to apply linear combination correctly + if h_node <= threshold + h_v_node = zero(eltype(u)) + h_v_mean = zero(eltype(u)) + end + + u_node = SVector(h_node, h_v_node, b_node) + u_mean = SVector(h_mean, h_v_mean, b_node) + + # When velocity is cut off, the only averaged value is the waterheight, + # because the velocity is set to zero and this value is passed. + # Otherwise, the velocity is averaged, as well. + # Note that the auxiliary bottom topography variable `b` is never limited. + set_node_vars!(u, theta * u_node + (1 - theta) * u_mean, + equations, dg, i, element) + end + end + + # "Safety" application of the wet/dry thresholds over all the DG nodes + # on the current `element` after the limiting above in order to avoid dry nodes. + # If the value_mean < threshold before applying limiter, there + # could still be dry nodes afterwards due to logic of the limiting + @threaded for element in eachelement(dg, cache) + for i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, element) + + h, hv, b = u_node + + if h <= threshold + h = threshold + hv = zero(eltype(u)) + end + + u_node = SVector(h, hv, b) + + set_node_vars!(u, u_node, equations, dg, i, element) + end + end + + return nothing +end +end # @muladd diff --git a/src/callbacks_stage/positivity_shallow_water_dg2d.jl b/src/callbacks_stage/positivity_shallow_water_dg2d.jl new file mode 100644 index 00000000000..da3a25fdcf4 --- /dev/null +++ b/src/callbacks_stage/positivity_shallow_water_dg2d.jl @@ -0,0 +1,90 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +# TODO: TrixiShallowWater: 2D wet/dry limiter should move + +function limiter_shallow_water!(u, threshold::Real, variable, + mesh::AbstractMesh{2}, + equations::ShallowWaterEquations2D, dg::DGSEM, cache) + @unpack weights = dg.basis + + @threaded for element in eachelement(dg, cache) + # determine minimum value + value_min = typemax(eltype(u)) + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, j, element) + value_min = min(value_min, variable(u_node, equations)) + end + + # detect if limiting is necessary + value_min < threshold || continue + + # compute mean value + u_mean = zero(get_node_vars(u, equations, dg, 1, 1, element)) + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, j, element) + u_mean += u_node * weights[i] * weights[j] + end + # note that the reference element is [-1,1]^ndims(dg), thus the weights sum to 2 + u_mean = u_mean / 2^ndims(mesh) + + # We compute the value directly with the mean values, as we assume that + # Jensen's inequality holds (e.g. pressure for compressible Euler equations). + value_mean = variable(u_mean, equations) + theta = (value_mean - threshold) / (value_mean - value_min) + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, j, element) + + # Cut off velocity in case that the water height is smaller than the threshold + + h_node, h_v1_node, h_v2_node, b_node = u_node + h_mean, h_v1_mean, h_v2_mean, _ = u_mean # b_mean is not used as it must not be overwritten + + if h_node <= threshold + h_v1_node = zero(eltype(u)) + h_v2_node = zero(eltype(u)) + h_v1_mean = zero(eltype(u)) + h_v2_mean = zero(eltype(u)) + end + + u_node = SVector(h_node, h_v1_node, h_v2_node, b_node) + u_mean = SVector(h_mean, h_v1_mean, h_v2_mean, b_node) + + # When velocities are cut off, the only averaged value is the water height, + # because the velocities are set to zero and this value is passed. + # Otherwise, the velocities are averaged, as well. + # Note that the auxiliary bottom topography variable `b` is never limited. + set_node_vars!(u, theta * u_node + (1 - theta) * u_mean, + equations, dg, i, j, element) + end + end + + # "Safety" application of the wet/dry thresholds over all the DG nodes + # on the current `element` after the limiting above in order to avoid dry nodes. + # If the value_mean < threshold before applying limiter, there + # could still be dry nodes afterwards due to logic of the limiting + @threaded for element in eachelement(dg, cache) + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, j, element) + + h, h_v1, h_v2, b = u_node + + if h <= threshold + h = threshold + h_v1 = zero(eltype(u)) + h_v2 = zero(eltype(u)) + end + + u_node = SVector(h, h_v1, h_v2, b) + + set_node_vars!(u, u_node, equations, dg, i, j, element) + end + end + + return nothing +end +end # @muladd diff --git a/src/equations/numerical_fluxes.jl b/src/equations/numerical_fluxes.jl index abd9d66c490..87010275f2c 100644 --- a/src/equations/numerical_fluxes.jl +++ b/src/equations/numerical_fluxes.jl @@ -304,6 +304,29 @@ See [`FluxHLL`](@ref). """ const flux_hll = FluxHLL() +# TODO: TrixiShallowWater: move the chen_noelle flux structure to the new package + +# An empty version of the `min_max_speed_chen_noelle` function is declared here +# in order to create a dimension agnostic version of `flux_hll_chen_noelle`. +# The full description of this wave speed estimate can be found in the docstrings +# for `min_max_speed_chen_noelle` in `shallow_water_1d.jl` or `shallow_water_2d.jl`. +function min_max_speed_chen_noelle end + +""" + flux_hll_chen_noelle = FluxHLL(min_max_speed_chen_noelle) + +An instance of [`FluxHLL`](@ref) specific to the shallow water equations that +uses the wave speed estimates from [`min_max_speed_chen_noelle`](@ref). +This HLL flux is guaranteed to have zero numerical mass flux out of a "dry" element, +maintain positivity of the water height, and satisfy an entropy inequality. + +For complete details see Section 2.4 of the following reference +- Guoxian Chen and Sebastian Noelle (2017) + A new hydrostatic reconstruction scheme based on subcell reconstructions + [DOI: 10.1137/15M1053074](https://doi.org/10.1137/15M1053074) +""" +const flux_hll_chen_noelle = FluxHLL(min_max_speed_chen_noelle) + """ flux_shima_etal_turbo(u_ll, u_rr, orientation_or_normal_direction, equations) diff --git a/src/equations/shallow_water_1d.jl b/src/equations/shallow_water_1d.jl index c33b31fca81..57bcb1212e1 100644 --- a/src/equations/shallow_water_1d.jl +++ b/src/equations/shallow_water_1d.jl @@ -6,7 +6,7 @@ #! format: noindent @doc raw""" - ShallowWaterEquations1D(gravity, H0) + ShallowWaterEquations1D(; gravity, H0 = 0, threshold_limiter = nothing threshold_wet = nothing) Shallow water equations (SWE) in one space dimension. The equations are given by ```math @@ -24,6 +24,12 @@ also defines the total water height as ``H = h + b``. The additional quantity ``H_0`` is also available to store a reference value for the total water height that is useful to set initial conditions or test the "lake-at-rest" well-balancedness. +Also, there are two thresholds which prevent numerical problems as well as instabilities. Both of them do not +have to be passed, as default values are defined within the struct. The first one, `threshold_limiter`, is +used in [`PositivityPreservingLimiterShallowWater`](@ref) on the water height, as a (small) shift on the initial +condition and cutoff before the next time step. The second one, `threshold_wet`, is applied on the water height to +define when the flow is "wet" before calculating the numerical flux. + The bottom topography function ``b(x)`` is set inside the initial condition routine for a particular problem setup. To test the conservative form of the SWE one can set the bottom topography variable `b` to zero. @@ -45,16 +51,35 @@ References for the SWE are many but a good introduction is available in Chapter [DOI: 10.1017/CBO9780511791253](https://doi.org/10.1017/CBO9780511791253) """ struct ShallowWaterEquations1D{RealT <: Real} <: AbstractShallowWaterEquations{1, 3} + # TODO: TrixiShallowWater: where should the `threshold_limiter` and `threshold_wet` live? + # how to "properly" export these constants across the two packages? gravity::RealT # gravitational constant H0::RealT # constant "lake-at-rest" total water height + # `threshold_limiter` used in `PositivityPreservingLimiterShallowWater` on water height, + # as a (small) shift on the initial condition and cutoff before the next time step. + # Default is 500*eps() which in double precision is ≈1e-13. + threshold_limiter::RealT + # `threshold_wet` applied on water height to define when the flow is "wet" + # before calculating the numerical flux. + # Default is 5*eps() which in double precision is ≈1e-15. + threshold_wet::RealT end # Allow for flexibility to set the gravitational constant within an elixir depending on the # application where `gravity_constant=1.0` or `gravity_constant=9.81` are common values. # The reference total water height H0 defaults to 0.0 but is used for the "lake-at-rest" -# well-balancedness test cases -function ShallowWaterEquations1D(; gravity_constant, H0 = 0.0) - ShallowWaterEquations1D(gravity_constant, H0) +# well-balancedness test cases. +# Strict default values for thresholds that performed well in many numerical experiments +function ShallowWaterEquations1D(; gravity_constant, H0 = zero(gravity_constant), + threshold_limiter = nothing, threshold_wet = nothing) + T = promote_type(typeof(gravity_constant), typeof(H0)) + if threshold_limiter === nothing + threshold_limiter = 500 * eps(T) + end + if threshold_wet === nothing + threshold_wet = 5 * eps(T) + end + ShallowWaterEquations1D(gravity_constant, H0, threshold_limiter, threshold_wet) end have_nonconservative_terms(::ShallowWaterEquations1D) = True() @@ -307,6 +332,54 @@ Further details on the hydrostatic reconstruction and its motivation can be foun z) end +# TODO: TrixiShallowWater: move wet/dry specific routine +""" + flux_nonconservative_chen_noelle(u_ll, u_rr, + orientation::Integer, + equations::ShallowWaterEquations1D) + +Non-symmetric two-point surface flux that discretizes the nonconservative (source) term. +The discretization uses the `hydrostatic_reconstruction_chen_noelle` on the conservative +variables. + +Should be used together with [`FluxHydrostaticReconstruction`](@ref) and +[`hydrostatic_reconstruction_chen_noelle`](@ref) in the surface flux to ensure consistency. + +Further details on the hydrostatic reconstruction and its motivation can be found in +- Guoxian Chen and Sebastian Noelle (2017) + A new hydrostatic reconstruction scheme based on subcell reconstructions + [DOI:10.1137/15M1053074](https://dx.doi.org/10.1137/15M1053074) +""" +@inline function flux_nonconservative_chen_noelle(u_ll, u_rr, + orientation::Integer, + equations::ShallowWaterEquations1D) + + # Pull the water height and bottom topography on the left + h_ll, _, b_ll = u_ll + h_rr, _, b_rr = u_rr + + H_ll = h_ll + b_ll + H_rr = h_rr + b_rr + + b_star = min(max(b_ll, b_rr), min(H_ll, H_rr)) + + # Create the hydrostatic reconstruction for the left solution state + u_ll_star, _ = hydrostatic_reconstruction_chen_noelle(u_ll, u_rr, equations) + + # Copy the reconstructed water height for easier to read code + h_ll_star = u_ll_star[1] + + z = zero(eltype(u_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_ll` and `h_ll_star` to handle discontinuous bathymetry + return SVector(z, + equations.gravity * h_ll * b_ll - + equations.gravity * (h_ll_star + h_ll) * (b_ll - b_star), + z) +end + """ flux_fjordholm_etal(u_ll, u_rr, orientation, equations::ShallowWaterEquations1D) @@ -381,7 +454,7 @@ end A particular type of hydrostatic reconstruction on the water height to guarantee well-balancedness for a general bottom topography [`ShallowWaterEquations1D`](@ref). The reconstructed solution states -`u_ll_star` and `u_rr_star` variables are used to evaluate the surface numerical flux at the interface. +`u_ll_star` and `u_rr_star` variables are then used to evaluate the surface numerical flux at the interface. Use in combination with the generic numerical flux routine [`FluxHydrostaticReconstruction`](@ref). Further details on this hydrostatic reconstruction and its motivation can be found in @@ -410,6 +483,67 @@ Further details on this hydrostatic reconstruction and its motivation can be fou return u_ll_star, u_rr_star end +# TODO: TrixiShallowWater: move wet/dry specific routine +""" + hydrostatic_reconstruction_chen_noelle(u_ll, u_rr, orientation::Integer, + equations::ShallowWaterEquations1D) + +A particular type of hydrostatic reconstruction of the water height to guarantee well-balancedness +for a general bottom topography of the [`ShallowWaterEquations1D`](@ref). The reconstructed solution states +`u_ll_star` and `u_rr_star` variables are used to evaluate the surface numerical flux at the interface. +The key idea is a linear reconstruction of the bottom and water height at the interfaces using subcells. +Use in combination with the generic numerical flux routine [`FluxHydrostaticReconstruction`](@ref). + +Further details on this hydrostatic reconstruction and its motivation can be found in +- Guoxian Chen and Sebastian Noelle (2017) + A new hydrostatic reconstruction scheme based on subcell reconstructions + [DOI:10.1137/15M1053074](https://dx.doi.org/10.1137/15M1053074) +""" +@inline function hydrostatic_reconstruction_chen_noelle(u_ll, u_rr, + equations::ShallowWaterEquations1D) + # Unpack left and right water heights and bottom topographies + h_ll, _, b_ll = u_ll + h_rr, _, b_rr = u_rr + + # Get the velocities on either side + v_ll = velocity(u_ll, equations) + v_rr = velocity(u_rr, equations) + + H_ll = b_ll + h_ll + H_rr = b_rr + h_rr + + b_star = min(max(b_ll, b_rr), min(H_ll, H_rr)) + + # Compute the reconstructed water heights + h_ll_star = min(H_ll - b_star, h_ll) + h_rr_star = min(H_rr - b_star, h_rr) + + # Set the water height to be at least the value stored in the variable threshold after + # the hydrostatic reconstruction is applied and before the numerical flux is calculated + # to avoid numerical problem with arbitrary small values. Interfaces with a water height + # lower or equal to the threshold can be declared as dry. + # The default value for `threshold_wet` is ≈ 5*eps(), or 1e-15 in double precision, is set + # in the `ShallowWaterEquations1D` struct. This threshold value can be changed in the constructor + # call of this equation struct in an elixir. + threshold = equations.threshold_wet + + if (h_ll_star <= threshold) + h_ll_star = threshold + v_ll = zero(v_ll) + end + + if (h_rr_star <= threshold) + h_rr_star = threshold + v_rr = zero(v_rr) + end + + # Create the conservative variables using the reconstruted water heights + u_ll_star = SVector(h_ll_star, h_ll_star * v_ll, b_ll) + u_rr_star = SVector(h_rr_star, h_rr_star * v_rr, b_rr) + + return u_ll_star, u_rr_star +end + # Calculate maximum wave speed for local Lax-Friedrichs-type dissipation as the # maximum velocity magnitude plus the maximum speed of sound @inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, @@ -474,6 +608,39 @@ end return λ_min, λ_max end +# TODO: TrixiShallowWater: move wet/dry specific routine +""" + min_max_speed_chen_noelle(u_ll, u_rr, orientation::Integer, + equations::ShallowWaterEquations1D) + +The approximated speeds for the HLL type numerical flux used by Chen and Noelle for their +hydrostatic reconstruction. As they state in the paper, these speeds are chosen for the numerical +flux to ensure positivity and to satisfy an entropy inequality. + +Further details on this hydrostatic reconstruction and its motivation can be found in +- Guoxian Chen and Sebastian Noelle (2017) + A new hydrostatic reconstruction scheme based on subcell reconstructions + [DOI:10.1137/15M1053074](https://dx.doi.org/10.1137/15M1053074) +""" +@inline function min_max_speed_chen_noelle(u_ll, u_rr, orientation::Integer, + equations::ShallowWaterEquations1D) + # Get the velocity quantities + v_ll = velocity(u_ll, equations) + v_rr = velocity(u_rr, equations) + + # Calculate the wave celerity on the left and right + h_ll = waterheight(u_ll, equations) + h_rr = waterheight(u_rr, equations) + + a_ll = sqrt(equations.gravity * h_ll) + a_rr = sqrt(equations.gravity * h_rr) + + λ_min = min(v_ll - a_ll, v_rr - a_rr, zero(eltype(u_ll))) + λ_max = max(v_ll + a_ll, v_rr + a_rr, zero(eltype(u_ll))) + + return λ_min, λ_max +end + # More refined estimates for minimum and maximum wave speeds for HLL-type fluxes @inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer, equations::ShallowWaterEquations1D) @@ -636,9 +803,20 @@ end end # Calculate the error for the "lake-at-rest" test case where H = h+b should -# be a constant value over time +# be a constant value over time. Note, assumes there is a single reference +# water height `H0` with which to compare. +# +# TODO: TrixiShallowWater: where should `threshold_limiter` live? May need +# to modify or have different versions of the `lake_at_rest_error` function @inline function lake_at_rest_error(u, equations::ShallowWaterEquations1D) h, _, b = u - return abs(equations.H0 - (h + b)) + + # For well-balancedness testing with possible wet/dry regions the reference + # water height `H0` accounts for the possibility that the bottom topography + # can emerge out of the water as well as for the threshold offset to avoid + # division by a "hard" zero water heights as well. + H0_wet_dry = max(equations.H0, b + equations.threshold_limiter) + + return abs(H0_wet_dry - (h + b)) end end # @muladd diff --git a/src/equations/shallow_water_2d.jl b/src/equations/shallow_water_2d.jl index 9e227cd4a77..a81fddeed49 100644 --- a/src/equations/shallow_water_2d.jl +++ b/src/equations/shallow_water_2d.jl @@ -6,7 +6,7 @@ #! format: noindent @doc raw""" - ShallowWaterEquations2D(gravity, H0) + ShallowWaterEquations2D(; gravity, H0 = 0, threshold_limiter = nothing, threshold_wet = nothing) Shallow water equations (SWE) in two space dimensions. The equations are given by ```math @@ -27,6 +27,12 @@ also defines the total water height as ``H = h + b``. The additional quantity ``H_0`` is also available to store a reference value for the total water height that is useful to set initial conditions or test the "lake-at-rest" well-balancedness. +Also, there are two thresholds which prevent numerical problems as well as instabilities. Both of them do not +have to be passed, as default values are defined within the struct. The first one, `threshold_limiter`, is +used in [`PositivityPreservingLimiterShallowWater`](@ref) on the water height, as a (small) shift on the initial +condition and cutoff before the next time step. The second one, `threshold_wet`, is applied on the water height to +define when the flow is "wet" before calculating the numerical flux. + The bottom topography function ``b(x,y)`` is set inside the initial condition routine for a particular problem setup. To test the conservative form of the SWE one can set the bottom topography variable `b` to zero. @@ -48,16 +54,35 @@ References for the SWE are many but a good introduction is available in Chapter [DOI: 10.1017/CBO9780511791253](https://doi.org/10.1017/CBO9780511791253) """ struct ShallowWaterEquations2D{RealT <: Real} <: AbstractShallowWaterEquations{2, 4} + # TODO: TrixiShallowWater: where should the `threshold_limiter` and `threshold_wet` live? + # how to "properly" export these constants across the two packages? gravity::RealT # gravitational constant H0::RealT # constant "lake-at-rest" total water height + # `threshold_limiter` used in `PositivityPreservingLimiterShallowWater` on water height, + # as a (small) shift on the initial condition and cutoff before the next time step. + # Default is 500*eps() which in double precision is ≈1e-13. + threshold_limiter::RealT + # `threshold_wet` applied on water height to define when the flow is "wet" + # before calculating the numerical flux. + # Default is 5*eps() which in double precision is ≈1e-15. + threshold_wet::RealT end # Allow for flexibility to set the gravitational constant within an elixir depending on the # application where `gravity_constant=1.0` or `gravity_constant=9.81` are common values. # The reference total water height H0 defaults to 0.0 but is used for the "lake-at-rest" -# well-balancedness test cases -function ShallowWaterEquations2D(; gravity_constant, H0 = 0.0) - ShallowWaterEquations2D(gravity_constant, H0) +# well-balancedness test cases. +# Strict default values for thresholds that performed well in many numerical experiments +function ShallowWaterEquations2D(; gravity_constant, H0 = zero(gravity_constant), + threshold_limiter = nothing, threshold_wet = nothing) + T = promote_type(typeof(gravity_constant), typeof(H0)) + if threshold_limiter === nothing + threshold_limiter = 500 * eps(T) + end + if threshold_wet === nothing + threshold_wet = 5 * eps(T) + end + ShallowWaterEquations2D(gravity_constant, H0, threshold_limiter, threshold_wet) end have_nonconservative_terms(::ShallowWaterEquations2D) = True() @@ -431,6 +456,69 @@ Further details for the hydrostatic reconstruction and its motivation can be fou return u_ll_star, u_rr_star end +# TODO: TrixiShallowWater: move wet/dry specific routine +""" + hydrostatic_reconstruction_chen_noelle(u_ll, u_rr, orientation::Integer, + equations::ShallowWaterEquations2D) + +A particular type of hydrostatic reconstruction of the water height to guarantee well-balancedness +for a general bottom topography of the [`ShallowWaterEquations2D`](@ref). The reconstructed solution states +`u_ll_star` and `u_rr_star` variables are then used to evaluate the surface numerical flux at the interface. +The key idea is a linear reconstruction of the bottom and water height at the interfaces using subcells. +Use in combination with the generic numerical flux routine [`FluxHydrostaticReconstruction`](@ref). + +Further details on this hydrostatic reconstruction and its motivation can be found in +- Guoxian Chen and Sebastian Noelle (2017) + A new hydrostatic reconstruction scheme based on subcell reconstructions + [DOI:10.1137/15M1053074](https://dx.doi.org/10.1137/15M1053074) +""" +@inline function hydrostatic_reconstruction_chen_noelle(u_ll, u_rr, + equations::ShallowWaterEquations2D) + # Unpack left and right water heights and bottom topographies + h_ll, _, _, b_ll = u_ll + h_rr, _, _, b_rr = u_rr + + # Get the velocities on either side + v1_ll, v2_ll = velocity(u_ll, equations) + v1_rr, v2_rr = velocity(u_rr, equations) + + H_ll = b_ll + h_ll + H_rr = b_rr + h_rr + + b_star = min(max(b_ll, b_rr), min(H_ll, H_rr)) + + # Compute the reconstructed water heights + h_ll_star = min(H_ll - b_star, h_ll) + h_rr_star = min(H_rr - b_star, h_rr) + + # Set the water height to be at least the value stored in the variable threshold after + # the hydrostatic reconstruction is applied and before the numerical flux is calculated + # to avoid numerical problem with arbitrary small values. Interfaces with a water height + # lower or equal to the threshold can be declared as dry. + # The default value for `threshold_wet` is ≈5*eps(), or 1e-15 in double precision, is set + # in the `ShallowWaterEquations2D` struct. This threshold value can be changed in the constructor + # call of this equation struct in an elixir. + threshold = equations.threshold_wet + + if (h_ll_star <= threshold) + h_ll_star = threshold + v1_ll = zero(v1_ll) + v2_ll = zero(v2_ll) + end + + if (h_rr_star <= threshold) + h_rr_star = threshold + v1_rr = zero(v1_rr) + v2_rr = zero(v2_rr) + end + + # Create the conservative variables using the reconstruted water heights + u_ll_star = SVector(h_ll_star, h_ll_star * v1_ll, h_ll_star * v2_ll, b_ll) + u_rr_star = SVector(h_rr_star, h_rr_star * v1_rr, h_rr_star * v2_rr, b_rr) + + return u_ll_star, u_rr_star +end + """ flux_nonconservative_audusse_etal(u_ll, u_rr, orientation::Integer, equations::ShallowWaterEquations2D) @@ -516,6 +604,104 @@ end return SVector(f1, f2, f3, f4) end +# TODO: TrixiShallowWater: move wet/dry specific routine +""" + flux_nonconservative_chen_noelle(u_ll, u_rr, + orientation::Integer, + equations::ShallowWaterEquations2D) + flux_nonconservative_chen_noelle(u_ll, u_rr, + normal_direction_ll ::AbstractVector, + normal_direction_average ::AbstractVector, + equations::ShallowWaterEquations2D) + +Non-symmetric two-point surface flux that discretizes the nonconservative (source) term. +The discretization uses the [`hydrostatic_reconstruction_chen_noelle`](@ref) on the conservative +variables. + +Should be used together with [`FluxHydrostaticReconstruction`](@ref) and +[`hydrostatic_reconstruction_chen_noelle`](@ref) in the surface flux to ensure consistency. + +Further details on the hydrostatic reconstruction and its motivation can be found in +- Guoxian Chen and Sebastian Noelle (2017) + A new hydrostatic reconstruction scheme based on subcell reconstructions + [DOI:10.1137/15M1053074](https://dx.doi.org/10.1137/15M1053074) +""" +@inline function flux_nonconservative_chen_noelle(u_ll, u_rr, orientation::Integer, + equations::ShallowWaterEquations2D) + # Pull the water height and bottom topography on the left + h_ll, _, _, b_ll = u_ll + h_rr, _, _, b_rr = u_rr + + H_ll = h_ll + b_ll + H_rr = h_rr + b_rr + + b_star = min(max(b_ll, b_rr), min(H_ll, H_rr)) + + # Create the hydrostatic reconstruction for the left solution state + u_ll_star, _ = hydrostatic_reconstruction_chen_noelle(u_ll, u_rr, equations) + + # Copy the reconstructed water height for easier to read code + h_ll_star = u_ll_star[1] + + z = zero(eltype(u_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_ll` and `h_ll_star` to handle discontinuous bathymetry + g = equations.gravity + if orientation == 1 + f = SVector(z, + g * h_ll * b_ll - g * (h_ll_star + h_ll) * (b_ll - b_star), + z, z) + else # orientation == 2 + f = SVector(z, z, + g * h_ll * b_ll - g * (h_ll_star + h_ll) * (b_ll - b_star), + z) + end + + return f +end + +@inline function flux_nonconservative_chen_noelle(u_ll, u_rr, + normal_direction_ll::AbstractVector, + normal_direction_average::AbstractVector, + equations::ShallowWaterEquations2D) + # Pull the water height and bottom topography on the left + h_ll, _, _, b_ll = u_ll + h_rr, _, _, b_rr = u_rr + + H_ll = h_ll + b_ll + H_rr = h_rr + b_rr + + b_star = min(max(b_ll, b_rr), min(H_ll, H_rr)) + + # Create the hydrostatic reconstruction for the left solution state + u_ll_star, _ = hydrostatic_reconstruction_chen_noelle(u_ll, u_rr, equations) + + # 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_star + h_ll) * + (b_ll - b_star) + f3 -= normal_direction_ll[2] * equations.gravity * (h_ll_star + h_ll) * + (b_ll - b_star) + + # First and last equations do not have a nonconservative flux + f1 = f4 = zero(eltype(u_ll)) + + return SVector(f1, f2, f3, f4) +end + """ flux_fjordholm_etal(u_ll, u_rr, orientation_or_normal_direction, equations::ShallowWaterEquations2D) @@ -762,6 +948,67 @@ end return λ_min, λ_max end +# TODO: TrixiShallowWater: move wet/dry specific routine +""" + min_max_speed_chen_noelle(u_ll, u_rr, orientation::Integer, + equations::ShallowWaterEquations2D) + min_max_speed_chen_noelle(u_ll, u_rr, normal_direction::AbstractVector, + equations::ShallowWaterEquations2D) + +Special estimate of the minimal and maximal wave speed of the shallow water equations for +the left and right states `u_ll, u_rr`. These approximate speeds are used for the HLL-type +numerical flux [`flux_hll_chen_noelle`](@ref). These wave speed estimates +together with a particular hydrostatic reconstruction technique guarantee +that the numerical flux is positive and satisfies an entropy inequality. + +Further details on this hydrostatic reconstruction and its motivation can be found in +the reference below. The definition of the wave speeds are given in Equation (2.20). +- Guoxian Chen and Sebastian Noelle (2017) + A new hydrostatic reconstruction scheme based on subcell reconstructions + [DOI:10.1137/15M1053074](https://dx.doi.org/10.1137/15M1053074) +""" +@inline function min_max_speed_chen_noelle(u_ll, u_rr, orientation::Integer, + equations::ShallowWaterEquations2D) + h_ll = waterheight(u_ll, equations) + v1_ll, v2_ll = velocity(u_ll, equations) + h_rr = waterheight(u_rr, equations) + v1_rr, v2_rr = velocity(u_rr, equations) + + a_ll = sqrt(equations.gravity * h_ll) + a_rr = sqrt(equations.gravity * h_rr) + + if orientation == 1 # x-direction + λ_min = min(v1_ll - a_ll, v1_rr - a_rr, zero(eltype(u_ll))) + λ_max = max(v1_ll + a_ll, v1_rr + a_rr, zero(eltype(u_ll))) + else # y-direction + λ_min = min(v2_ll - a_ll, v2_rr - a_rr, zero(eltype(u_ll))) + λ_max = max(v2_ll + a_ll, v2_rr + a_rr, zero(eltype(u_ll))) + end + + return λ_min, λ_max +end + +@inline function min_max_speed_chen_noelle(u_ll, u_rr, normal_direction::AbstractVector, + equations::ShallowWaterEquations2D) + h_ll = waterheight(u_ll, equations) + v1_ll, v2_ll = velocity(u_ll, equations) + h_rr = waterheight(u_rr, equations) + v1_rr, v2_rr = velocity(u_rr, equations) + + v_normal_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] + v_normal_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] + + norm_ = norm(normal_direction) + + a_ll = sqrt(equations.gravity * h_ll) * norm_ + a_rr = sqrt(equations.gravity * h_rr) * norm_ + + λ_min = min(v_normal_ll - a_ll, v_normal_rr - a_rr, zero(eltype(u_ll))) + λ_max = max(v_normal_ll + a_ll, v_normal_rr + a_rr, zero(eltype(u_ll))) + + return λ_min, λ_max +end + # More refined estimates for minimum and maximum wave speeds for HLL-type fluxes @inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer, equations::ShallowWaterEquations2D) @@ -1008,9 +1255,20 @@ end end # Calculate the error for the "lake-at-rest" test case where H = h+b should -# be a constant value over time +# be a constant value over time. Note, assumes there is a single reference +# water height `H0` with which to compare. +# +# TODO: TrixiShallowWater: where should `threshold_limiter` live? May need +# to modify or have different versions of the `lake_at_rest_error` function @inline function lake_at_rest_error(u, equations::ShallowWaterEquations2D) h, _, _, b = u - return abs(equations.H0 - (h + b)) + + # For well-balancedness testing with possible wet/dry regions the reference + # water height `H0` accounts for the possibility that the bottom topography + # can emerge out of the water as well as for the threshold offset to avoid + # division by a "hard" zero water heights as well. + H0_wet_dry = max(equations.H0, b + equations.threshold_limiter) + + return abs(H0_wet_dry - (h + b)) end end # @muladd diff --git a/src/equations/shallow_water_two_layer_1d.jl b/src/equations/shallow_water_two_layer_1d.jl index e126eec7c25..4b64481cca3 100644 --- a/src/equations/shallow_water_two_layer_1d.jl +++ b/src/equations/shallow_water_two_layer_1d.jl @@ -5,6 +5,8 @@ @muladd begin #! format: noindent +# TODO: TrixiShallowWater: 1D two layer equations should move to new package + @doc raw""" ShallowWaterTwoLayerEquations1D(gravity, H0, rho_upper, rho_lower) diff --git a/src/equations/shallow_water_two_layer_2d.jl b/src/equations/shallow_water_two_layer_2d.jl index a54831c711f..87249e91948 100644 --- a/src/equations/shallow_water_two_layer_2d.jl +++ b/src/equations/shallow_water_two_layer_2d.jl @@ -5,48 +5,50 @@ @muladd begin #! format: noindent +# TODO: TrixiShallowWater: 2D two layer equations should move to new package + @doc raw""" ShallowWaterTwoLayerEquations2D(gravity, H0, rho_upper, rho_lower) Two-Layer Shallow water equations (2LSWE) in two space dimension. The equations are given by ```math \begin{alignat*}{8} -&\frac{\partial}{\partial t}h_{upper} +&\frac{\partial}{\partial t}h_{upper} &&+ \frac{\partial}{\partial x}\left(h_{upper} v_{1,upper}\right) -&&+ \frac{\partial}{\partial y}\left(h_{upper} v_{2,upper}\right) \quad +&&+ \frac{\partial}{\partial y}\left(h_{upper} v_{2,upper}\right) \quad &&= \quad 0 \\ -&\frac{\partial}{\partial t}\left(h_{upper} v_{1,upper}\right) -&&+ \frac{\partial}{\partial x}\left(h_{upper} v_{1,upper}^2 + \frac{gh_{upper}^2}{2}\right) -&&+ \frac{\partial}{\partial y}\left(h_{upper} v_{1,upper} v_{2,upper}\right) \quad +&\frac{\partial}{\partial t}\left(h_{upper} v_{1,upper}\right) +&&+ \frac{\partial}{\partial x}\left(h_{upper} v_{1,upper}^2 + \frac{gh_{upper}^2}{2}\right) +&&+ \frac{\partial}{\partial y}\left(h_{upper} v_{1,upper} v_{2,upper}\right) \quad &&= -gh_{upper}\frac{\partial}{\partial x}\left(b+h_{lower}\right) \\ -&\frac{\partial}{\partial t}\left(h_{upper} v_{2,upper}\right) -&&+ \frac{\partial}{\partial x}\left(h_{upper} v_{1,upper} v_{2,upper}\right) -&&+ \frac{\partial}{\partial y}\left(h_{upper} v_{2,upper}^2 + \frac{gh_{upper}^2}{2}\right) +&\frac{\partial}{\partial t}\left(h_{upper} v_{2,upper}\right) +&&+ \frac{\partial}{\partial x}\left(h_{upper} v_{1,upper} v_{2,upper}\right) +&&+ \frac{\partial}{\partial y}\left(h_{upper} v_{2,upper}^2 + \frac{gh_{upper}^2}{2}\right) &&= -gh_{upper}\frac{\partial}{\partial y}\left(b+h_{lower}\right)\\ -&\frac{\partial}{\partial t}h_{lower} -&&+ \frac{\partial}{\partial x}\left(h_{lower} v_{1,lower}\right) -&&+ \frac{\partial}{\partial y}\left(h_{lower} v_{2,lower}\right) +&\frac{\partial}{\partial t}h_{lower} +&&+ \frac{\partial}{\partial x}\left(h_{lower} v_{1,lower}\right) +&&+ \frac{\partial}{\partial y}\left(h_{lower} v_{2,lower}\right) &&= \quad 0 \\ -&\frac{\partial}{\partial t}\left(h_{lower} v_{1,lower}\right) -&&+ \frac{\partial}{\partial x}\left(h_{lower} v_{1,lower}^2 + \frac{gh_{lower}^2}{2}\right) -&&+ \frac{\partial}{\partial y}\left(h_{lower} v_{1,lower} v_{2,lower}\right) +&\frac{\partial}{\partial t}\left(h_{lower} v_{1,lower}\right) +&&+ \frac{\partial}{\partial x}\left(h_{lower} v_{1,lower}^2 + \frac{gh_{lower}^2}{2}\right) +&&+ \frac{\partial}{\partial y}\left(h_{lower} v_{1,lower} v_{2,lower}\right) &&= -gh_{lower}\frac{\partial}{\partial x}\left(b+\frac{\rho_{upper}}{\rho_{lower}} h_{upper}\right)\\ -&\frac{\partial}{\partial t}\left(h_{lower} v_{2,lower}\right) -&&+ \frac{\partial}{\partial x}\left(h_{lower} v_{1,lower} v_{2,lower}\right) -&&+ \frac{\partial}{\partial y}\left(h_{lower} v_{2,lower}^2 + \frac{gh_{lower}^2}{2}\right) +&\frac{\partial}{\partial t}\left(h_{lower} v_{2,lower}\right) +&&+ \frac{\partial}{\partial x}\left(h_{lower} v_{1,lower} v_{2,lower}\right) +&&+ \frac{\partial}{\partial y}\left(h_{lower} v_{2,lower}^2 + \frac{gh_{lower}^2}{2}\right) &&= -gh_{lower}\frac{\partial}{\partial y}\left(b+\frac{\rho_{upper}}{\rho_{lower}} h_{upper}\right) \end{alignat*} ``` -The unknown quantities of the 2LSWE are the water heights of the lower layer ``h_{lower}`` and the -upper +The unknown quantities of the 2LSWE are the water heights of the lower layer ``h_{lower}`` and the +upper layer ``h_{upper}`` and the respective velocities in x-direction ``v_{1,lower}`` and ``v_{1,upper}`` and in y-direction -``v_{2,lower}`` and ``v_{2,upper}``. The gravitational constant is denoted by `g`, the layer densitites by -``\rho_{upper}``and ``\rho_{lower}`` and the (possibly) variable bottom topography function by ``b(x)``. -Conservative variable water height ``h_{lower}`` is measured from the bottom topography ``b`` and ``h_{upper}`` -relative to ``h_{lower}``, therefore one also defines the total water heights as ``H_{lower} = h_{lower} + b`` and +``v_{2,lower}`` and ``v_{2,upper}``. The gravitational constant is denoted by `g`, the layer densitites by +``\rho_{upper}``and ``\rho_{lower}`` and the (possibly) variable bottom topography function by ``b(x)``. +Conservative variable water height ``h_{lower}`` is measured from the bottom topography ``b`` and ``h_{upper}`` +relative to ``h_{lower}``, therefore one also defines the total water heights as ``H_{lower} = h_{lower} + b`` and ``H_{upper} = h_{upper} + h_{lower} + b``. -The densities must be chosen such that ``\rho_{upper} < \rho_{lower}``, to make sure that the heavier fluid +The densities must be chosen such that ``\rho_{upper} < \rho_{lower}``, to make sure that the heavier fluid ``\rho_{lower}`` is in the bottom layer and the lighter fluid ``\rho_{upper}`` in the upper layer. The additional quantity ``H_0`` is also available to store a reference value for the total water @@ -55,13 +57,13 @@ height that is useful to set initial conditions or test the "lake-at-rest" well- The bottom topography function ``b(x)`` is set inside the initial condition routine for a particular problem setup. -In addition to the unknowns, Trixi currently stores the bottom topography values at the -approximation points despite being fixed in time. This is done for convenience of computing the -bottom topography gradients on the fly during the approximation as well as computing auxiliary +In addition to the unknowns, Trixi currently stores the bottom topography values at the +approximation points despite being fixed in time. This is done for convenience of computing the +bottom topography gradients on the fly during the approximation as well as computing auxiliary quantities like the total water height ``H`` or the entropy variables. This affects the implementation and use of these equations in various ways: * The flux values corresponding to the bottom topography must be zero. -* The bottom topography values must be included when defining initial conditions, boundary +* The bottom topography values must be included when defining initial conditions, boundary conditions or source terms. * [`AnalysisCallback`](@ref) analyzes this variable. * Trixi's visualization tools will visualize the bottom topography by default. @@ -113,7 +115,7 @@ end initial_condition_convergence_test(x, t, equations::ShallowWaterTwoLayerEquations2D) A smooth initial condition used for convergence tests in combination with -[`source_terms_convergence_test`](@ref). Constants must be set to ``rho_{upper} = 0.9``, +[`source_terms_convergence_test`](@ref). Constants must be set to ``rho_{upper} = 0.9``, ``rho_{lower} = 1.0``, ``g = 10.0``. """ function initial_condition_convergence_test(x, t, @@ -141,7 +143,7 @@ Source terms used for convergence tests in combination with """ @inline function source_terms_convergence_test(u, x, t, equations::ShallowWaterTwoLayerEquations2D) - # Same settings as in `initial_condition_convergence_test`. + # Same settings as in `initial_condition_convergence_test`. # some constants are chosen such that the function is periodic on the domain [0,sqrt(2)]^2] ω = 2.0 * pi * sqrt(2.0) @@ -325,7 +327,7 @@ end Non-symmetric two-point volume flux discretizing the nonconservative (source) term that contains the gradient of the bottom topography [`ShallowWaterTwoLayerEquations2D`](@ref) and an -additional term that couples the momentum of both layers. This is a slightly modified version +additional term that couples the momentum of both layers. This is a slightly modified version to account for the additional source term compared to the standard SWE described in the paper. Further details are available in the paper: @@ -345,7 +347,7 @@ Further details are available in the paper: z = zero(eltype(u_ll)) # Bottom gradient nonconservative term: (0, g*h_upper*(b + h_lower)_x, g*h_upper*(b + h_lower)_y , - # 0, g*h_lower*(b + r*h_upper)_x, + # 0, g*h_lower*(b + r*h_upper)_x, # g*h_lower*(b + r*h_upper)_y, 0) if orientation == 1 f = SVector(z, @@ -397,8 +399,8 @@ end !!! warning "Experimental code" This numerical flux is experimental and may change in any future release. -Non-symmetric two-point surface flux discretizing the nonconservative (source) term that contains -the gradients of the bottom topography and an additional term that couples the momentum of both +Non-symmetric two-point surface flux discretizing the nonconservative (source) term that contains +the gradients of the bottom topography and an additional term that couples the momentum of both layers [`ShallowWaterTwoLayerEquations2D`](@ref). Further details are available in the paper: @@ -506,13 +508,13 @@ end flux_fjordholm_etal(u_ll, u_rr, orientation, equations::ShallowWaterTwoLayerEquations2D) -Total energy conservative (mathematical entropy for two-layer shallow water equations). When the -bottom topography is nonzero this should only be used as a surface flux otherwise the scheme will +Total energy conservative (mathematical entropy for two-layer shallow water equations). When the +bottom topography is nonzero this should only be used as a surface flux otherwise the scheme will not be well-balanced. For well-balancedness in the volume flux use [`flux_wintermeyer_etal`](@ref). Details are available in Eq. (4.1) in the paper: - Ulrik S. Fjordholm, Siddhartha Mishra and Eitan Tadmor (2011) - Well-balanced and energy stable schemes for the shallow water equations with discontinuous + Well-balanced and energy stable schemes for the shallow water equations with discontinuous topography [DOI: 10.1016/j.jcp.2011.03.042](https://doi.org/10.1016/j.jcp.2011.03.042) and the application to two layers is shown in the paper: - Ulrik Skre Fjordholm (2012) @@ -606,11 +608,11 @@ end """ flux_wintermeyer_etal(u_ll, u_rr, orientation, equations::ShallowWaterTwoLayerEquations2D) - + Total energy conservative (mathematical entropy for two-layer 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). To obtain the flux for the -two-layer shallow water equations the flux that is described in the paper for the normal shallow +two-layer shallow water equations the flux that is described in the paper for the normal shallow water equations is used within each layer. Further details are available in Theorem 1 of the paper: @@ -696,9 +698,9 @@ end flux_es_fjordholm_etal(u_ll, u_rr, orientation_or_normal_direction, equations::ShallowWaterTwoLayerEquations1D) -Entropy stable surface flux for the two-layer shallow water equations. Uses the entropy conservative +Entropy stable surface flux for the two-layer shallow water equations. Uses the entropy conservative [`flux_fjordholm_etal`](@ref) and adds a Lax-Friedrichs type dissipation dependent on the jump of entropy -variables. +variables. Further details are available in the paper: - Ulrik Skre Fjordholm (2012) @@ -723,7 +725,7 @@ formulation. q_rr = cons2entropy(u_rr, equations) q_ll = cons2entropy(u_ll, equations) - # Average values from left and right + # Average values from left and right u_avg = (u_ll + u_rr) / 2 # Introduce variables for better readability @@ -791,10 +793,10 @@ formulation. end # Calculate approximation for maximum wave speed for local Lax-Friedrichs-type dissipation as the -# maximum velocity magnitude plus the maximum speed of sound. This function uses approximate -# eigenvalues using the speed of the barotropic mode as there is no simple way to calculate them -# analytically. -# +# maximum velocity magnitude plus the maximum speed of sound. This function uses approximate +# eigenvalues using the speed of the barotropic mode as there is no simple way to calculate them +# analytically. +# # A good overview of the derivation is given in: # - Jonas Nycander, Andrew McC. Hogg, Leela M. Frankcombe (2008) # Open boundary conditions for nonlinear channel Flows @@ -914,7 +916,7 @@ end # Convert conservative variables to entropy variables # Note, only the first four are the entropy variables, the fifth entry still just carries the bottom -# topography values for convenience. +# topography values for convenience. # In contrast to general usage the entropy variables are denoted with q instead of w, because w is # already used for velocity in y-Direction @inline function cons2entropy(u, equations::ShallowWaterTwoLayerEquations2D) diff --git a/src/solvers/dgsem_tree/indicators.jl b/src/solvers/dgsem_tree/indicators.jl index b8f8a796f2b..4b83e9c1a9e 100644 --- a/src/solvers/dgsem_tree/indicators.jl +++ b/src/solvers/dgsem_tree/indicators.jl @@ -92,6 +92,77 @@ end function Base.show(io::IO, ::MIME"text/plain", indicator::IndicatorHennemannGassner) @nospecialize indicator # reduce precompilation time + setup = [ + "indicator variable" => indicator.variable, + "max. α" => indicator.alpha_max, + "min. α" => indicator.alpha_min, + "smooth α" => (indicator.alpha_smooth ? "yes" : "no"), + ] + summary_box(io, "IndicatorHennemannGassner", setup) +end + +# TODO: TrixiShallowWater: move the new indicator and all associated routines to the new package +""" + IndicatorHennemannGassnerShallowWater(equations::AbstractEquations, basis; + alpha_max=0.5, + alpha_min=0.001, + alpha_smooth=true, + variable) + +Modified version of the [`IndicatorHennemannGassner`](@ref) +indicator used for shock-capturing for shallow water equations. After +the element-wise values for the blending factors are computed an additional check +is made to see if the element is partially wet. In this case, partially wet elements +are set to use the pure finite volume scheme that is guaranteed to be well-balanced +for this wet/dry transition state of the flow regime. + +See also [`VolumeIntegralShockCapturingHG`](@ref). + +## References + +- Hennemann, Gassner (2020) + "A provably entropy stable subcell shock capturing approach for high order split form DG" + [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) +""" +struct IndicatorHennemannGassnerShallowWater{RealT <: Real, Variable, Cache} <: + AbstractIndicator + alpha_max::RealT + alpha_min::RealT + alpha_smooth::Bool + variable::Variable + cache::Cache +end + +# this method is used when the indicator is constructed as for shock-capturing volume integrals +# of the shallow water equations +# It modifies the shock-capturing indicator to use full FV method in dry cells +function IndicatorHennemannGassnerShallowWater(equations::AbstractShallowWaterEquations, + basis; + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable) + alpha_max, alpha_min = promote(alpha_max, alpha_min) + cache = create_cache(IndicatorHennemannGassner, equations, basis) + IndicatorHennemannGassnerShallowWater{typeof(alpha_max), typeof(variable), + typeof(cache)}(alpha_max, alpha_min, + alpha_smooth, variable, cache) +end + +function Base.show(io::IO, indicator::IndicatorHennemannGassnerShallowWater) + @nospecialize indicator # reduce precompilation time + + print(io, "IndicatorHennemannGassnerShallowWater(") + print(io, indicator.variable) + print(io, ", alpha_max=", indicator.alpha_max) + print(io, ", alpha_min=", indicator.alpha_min) + print(io, ", alpha_smooth=", indicator.alpha_smooth) + print(io, ")") +end + +function Base.show(io::IO, ::MIME"text/plain", + indicator::IndicatorHennemannGassnerShallowWater) + @nospecialize indicator # reduce precompilation time if get(io, :compact, false) show(io, indicator) @@ -102,7 +173,7 @@ function Base.show(io::IO, ::MIME"text/plain", indicator::IndicatorHennemannGass "min. α" => indicator.alpha_min, "smooth α" => (indicator.alpha_smooth ? "yes" : "no"), ] - summary_box(io, "IndicatorHennemannGassner", setup) + summary_box(io, "IndicatorHennemannGassnerShallowWater", setup) end end diff --git a/src/solvers/dgsem_tree/indicators_1d.jl b/src/solvers/dgsem_tree/indicators_1d.jl index e722584bb2e..8b57348861c 100644 --- a/src/solvers/dgsem_tree/indicators_1d.jl +++ b/src/solvers/dgsem_tree/indicators_1d.jl @@ -24,6 +24,115 @@ function create_cache(typ::Type{IndicatorHennemannGassner}, mesh, create_cache(typ, equations, dg.basis) end +# Modified indicator for ShallowWaterEquations1D to apply full FV method on cells +# containing some "dry" LGL nodes. That is, if an element is partially "wet" then it becomes a +# full FV element. +# +# TODO: TrixiShallowWater: move new indicator type +function (indicator_hg::IndicatorHennemannGassnerShallowWater)(u::AbstractArray{<:Any, 3 + }, + mesh, + equations::ShallowWaterEquations1D, + dg::DGSEM, cache; + kwargs...) + @unpack alpha_max, alpha_min, alpha_smooth, variable = indicator_hg + @unpack alpha, alpha_tmp, indicator_threaded, modal_threaded = indicator_hg.cache + # TODO: Taal refactor, when to `resize!` stuff changed possibly by AMR? + # Shall we implement `resize!(semi::AbstractSemidiscretization, new_size)` + # or just `resize!` whenever we call the relevant methods as we do now? + resize!(alpha, nelements(dg, cache)) + if alpha_smooth + resize!(alpha_tmp, nelements(dg, cache)) + end + + # magic parameters + threshold = 0.5 * 10^(-1.8 * (nnodes(dg))^0.25) + parameter_s = log((1 - 0.0001) / 0.0001) + + # If the water height `h` at one LGL node is lower than `threshold_partially_wet` + # the indicator sets the element-wise blending factor alpha[element] = 1 + # via the local variable `indicator_wet`. In turn, this ensures that a pure + # FV method is used in partially wet cells and guarantees the well-balanced property. + # + # Hard-coded cut-off value of `threshold_partially_wet = 1e-4` was determined through many numerical experiments. + # Overall idea is to increase robustness when computing the velocity on (nearly) dry cells which + # could be "dangerous" due to division of conservative variables, e.g., v = hv / h. + # Here, the impact of the threshold on the number of cells being updated with FV is not that + # significant. However, its impact on the robustness is very significant. + # The value can be seen as a trade-off between accuracy and stability. + # Well-balancedness of the scheme on partially wet cells with hydrostatic reconstruction + # can only be proven for the FV method (see Chen and Noelle). + # Therefore we set alpha to one regardless of its given maximum value. + threshold_partially_wet = 1e-4 + + @threaded for element in eachelement(dg, cache) + indicator = indicator_threaded[Threads.threadid()] + modal = modal_threaded[Threads.threadid()] + + # (Re-)set dummy variable for alpha_dry + indicator_wet = 1 + + # Calculate indicator variables at Gauss-Lobatto nodes + for i in eachnode(dg) + u_local = get_node_vars(u, equations, dg, i, element) + h, _, _ = u_local + + if h <= threshold_partially_wet + indicator_wet = 0 + end + + indicator[i] = indicator_hg.variable(u_local, equations) + end + + # Convert to modal representation + multiply_scalar_dimensionwise!(modal, dg.basis.inverse_vandermonde_legendre, + indicator) + + # Calculate total energies for all modes, without highest, without two highest + total_energy = zero(eltype(modal)) + for i in 1:nnodes(dg) + total_energy += modal[i]^2 + end + total_energy_clip1 = zero(eltype(modal)) + for i in 1:(nnodes(dg) - 1) + total_energy_clip1 += modal[i]^2 + end + total_energy_clip2 = zero(eltype(modal)) + for i in 1:(nnodes(dg) - 2) + total_energy_clip2 += modal[i]^2 + end + + # Calculate energy in higher modes + energy = max((total_energy - total_energy_clip1) / total_energy, + (total_energy_clip1 - total_energy_clip2) / total_energy_clip1) + + alpha_element = 1 / (1 + exp(-parameter_s / threshold * (energy - threshold))) + + # Take care of the case close to pure DG + if alpha_element < alpha_min + alpha_element = zero(alpha_element) + end + + # Take care of the case close to pure FV + if alpha_element > 1 - alpha_min + alpha_element = one(alpha_element) + end + + # Clip the maximum amount of FV allowed or set to one depending on indicator_wet + if indicator_wet == 0 + alpha[element] = 1 + else # Element is not defined as dry but wet + alpha[element] = min(alpha_max, alpha_element) + end + end + + if alpha_smooth + apply_smoothing!(mesh, alpha, alpha_tmp, dg, cache) + end + + return alpha +end + # Use this function barrier and unpack inside to avoid passing closures to Polyester.jl # with @batch (@threaded). # Otherwise, @threaded does not work here with Julia ARM on macOS. diff --git a/src/solvers/dgsem_tree/indicators_2d.jl b/src/solvers/dgsem_tree/indicators_2d.jl index 085cb71ad0c..f7c78547174 100644 --- a/src/solvers/dgsem_tree/indicators_2d.jl +++ b/src/solvers/dgsem_tree/indicators_2d.jl @@ -28,6 +28,116 @@ function create_cache(typ::Type{IndicatorHennemannGassner}, mesh, create_cache(typ, equations, dg.basis) end +# Modified indicator for ShallowWaterEquations2D to apply full FV method on cells +# containing some "dry" LGL nodes. That is, if an element is partially "wet" then it becomes a +# full FV element. +# +# TODO: TrixiShallowWater: move new indicator type +function (indicator_hg::IndicatorHennemannGassnerShallowWater)(u::AbstractArray{<:Any, 4 + }, + mesh, + equations::ShallowWaterEquations2D, + dg::DGSEM, cache; + kwargs...) + @unpack alpha_max, alpha_min, alpha_smooth, variable = indicator_hg + @unpack alpha, alpha_tmp, indicator_threaded, modal_threaded, modal_tmp1_threaded = indicator_hg.cache + # TODO: Taal refactor, when to `resize!` stuff changed possibly by AMR? + # Shall we implement `resize!(semi::AbstractSemidiscretization, new_size)` + # or just `resize!` whenever we call the relevant methods as we do now? + resize!(alpha, nelements(dg, cache)) + if alpha_smooth + resize!(alpha_tmp, nelements(dg, cache)) + end + + # magic parameters + threshold = 0.5 * 10^(-1.8 * (nnodes(dg))^0.25) + parameter_s = log((1 - 0.0001) / 0.0001) + + # If the water height `h` at one LGL node is lower than `threshold_partially_wet` + # the indicator sets the element-wise blending factor alpha[element] = 1 + # via the local variable `indicator_wet`. In turn, this ensures that a pure + # FV method is used in partially wet cells and guarantees the well-balanced property. + # + # Hard-coded cut-off value of `threshold_partially_wet = 1e-4` was determined through many numerical experiments. + # Overall idea is to increase robustness when computing the velocity on (nearly) dry cells which + # could be "dangerous" due to division of conservative variables, e.g., v1 = hv1 / h. + # Here, the impact of the threshold on the number of cells being updated with FV is not that + # significant. However, its impact on the robustness is very significant. + # The value can be seen as a trade-off between accuracy and stability. + # Well-balancedness of the scheme on partially wet cells with hydrostatic reconstruction + # can only be proven for the FV method (see Chen and Noelle). + # Therefore we set alpha to be one regardless of its given value from the modal indicator. + threshold_partially_wet = 1e-4 + + @threaded for element in eachelement(dg, cache) + indicator = indicator_threaded[Threads.threadid()] + modal = modal_threaded[Threads.threadid()] + modal_tmp1 = modal_tmp1_threaded[Threads.threadid()] + + # (Re-)set dummy variable for alpha_dry + indicator_wet = 1 + + # Calculate indicator variables at Gauss-Lobatto nodes + for j in eachnode(dg), i in eachnode(dg) + u_local = get_node_vars(u, equations, dg, i, j, element) + h, _, _, _ = u_local + + if h <= threshold_partially_wet + indicator_wet = 0 + end + + indicator[i, j] = indicator_hg.variable(u_local, equations) + end + + # Convert to modal representation + multiply_scalar_dimensionwise!(modal, dg.basis.inverse_vandermonde_legendre, + indicator, modal_tmp1) + + # Calculate total energies for all modes, without highest, without two highest + total_energy = zero(eltype(modal)) + for j in 1:nnodes(dg), i in 1:nnodes(dg) + total_energy += modal[i, j]^2 + end + total_energy_clip1 = zero(eltype(modal)) + for j in 1:(nnodes(dg) - 1), i in 1:(nnodes(dg) - 1) + total_energy_clip1 += modal[i, j]^2 + end + total_energy_clip2 = zero(eltype(modal)) + for j in 1:(nnodes(dg) - 2), i in 1:(nnodes(dg) - 2) + total_energy_clip2 += modal[i, j]^2 + end + + # Calculate energy in higher modes + energy = max((total_energy - total_energy_clip1) / total_energy, + (total_energy_clip1 - total_energy_clip2) / total_energy_clip1) + + alpha_element = 1 / (1 + exp(-parameter_s / threshold * (energy - threshold))) + + # Take care of the case close to pure DG + if alpha_element < alpha_min + alpha_element = zero(alpha_element) + end + + # Take care of the case close to pure FV + if alpha_element > 1 - alpha_min + alpha_element = one(alpha_element) + end + + # Clip the maximum amount of FV allowed or set to 1 depending on indicator_wet + if indicator_wet == 0 + alpha[element] = 1 + else # Element is not defined as dry but wet + alpha[element] = min(alpha_max, alpha_element) + end + end + + if alpha_smooth + apply_smoothing!(mesh, alpha, alpha_tmp, dg, cache) + end + + return alpha +end + # Use this function barrier and unpack inside to avoid passing closures to Polyester.jl # with @batch (@threaded). # Otherwise, @threaded does not work here with Julia ARM on macOS. diff --git a/test/Project.toml b/test/Project.toml index 7d386415227..cae1d4ff396 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -17,6 +17,7 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/test/test_structured_2d.jl b/test/test_structured_2d.jl index 16fc72f0a46..75937ba82ad 100644 --- a/test/test_structured_2d.jl +++ b/test/test_structured_2d.jl @@ -1,5 +1,7 @@ module TestExamplesStructuredMesh2D +# TODO: TrixiShallowWater: move any wet/dry tests to new package + using Test using Trixi @@ -20,7 +22,7 @@ isdir(outdir) && rm(outdir, recursive=true) end @trixi_testset "elixir_advection_coupled.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_coupled.jl"), + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_coupled.jl"), l2 = [7.816742843181738e-6, 7.816742843196112e-6], linf = [6.314906965543265e-5, 6.314906965410039e-5], coverage_override = (maxiters=10^5,)) @@ -270,6 +272,27 @@ isdir(outdir) && rm(outdir, recursive=true) tspan = (0.0, 0.25)) end + @trixi_testset "elixir_shallowwater_well_balanced_wet_dry.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced_wet_dry.jl"), + l2 = [0.019731646454942086, 1.0694532773278277e-14, 1.1969913383405568e-14, 0.0771517260037954], + linf = [0.4999999999998892, 6.067153702623552e-14, 4.4849667259339357e-14, 1.9999999999999993], + tspan = (0.0, 0.25)) + end + + @trixi_testset "elixir_shallowwater_conical_island.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_conical_island.jl"), + l2 = [0.04593154164306353, 0.1644534881916908, 0.16445348819169076, 0.0011537702354532122], + linf = [0.21100717610846442, 0.9501592344310412, 0.950159234431041, 0.021790250683516296], + tspan = (0.0, 0.025)) + end + + @trixi_testset "elixir_shallowwater_parabolic_bowl.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_parabolic_bowl.jl"), + l2 = [0.00015285369980313484, 1.9536806395943226e-5, 9.936906607758672e-5, 5.0686313334616055e-15], + linf = [0.003316119030459211, 0.0005075409427972817, 0.001986721761060583, 4.701794509287538e-14], + tspan = (0.0, 0.025), cells_per_dimension = (40, 40)) + end + @trixi_testset "elixir_mhd_ec_shockcapturing.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ec_shockcapturing.jl"), l2 = [0.0364192725149364, 0.0426667193422069, 0.04261673001449095, 0.025884071405646924, diff --git a/test/test_tree_1d_shallowwater.jl b/test/test_tree_1d_shallowwater.jl index 1c3bac1fab6..cafa17edd4c 100644 --- a/test/test_tree_1d_shallowwater.jl +++ b/test/test_tree_1d_shallowwater.jl @@ -1,5 +1,7 @@ module TestExamples1DShallowWater +# TODO: TrixiShallowWater: move any wet/dry tests to new package + using Test using Trixi @@ -38,6 +40,13 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") tspan = (0.0, 0.25)) end + @trixi_testset "elixir_shallowwater_well_balanced_wet_dry.jl with FluxHydrostaticReconstruction" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced_wet_dry.jl"), + l2 = [0.00965787167169024, 5.345454081916856e-14, 0.03857583749209928], + linf = [0.4999999999998892, 2.2447689894899726e-13, 1.9999999999999714], + tspan = (0.0, 0.25)) + end + @trixi_testset "elixir_shallowwater_source_terms.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), l2 = [0.0022363707373868713, 0.01576799981934617, 4.436491725585346e-5], @@ -88,6 +97,20 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") linf = [1.1209754279344226, 1.3230788645853582, 0.8646939843534251], tspan = (0.0, 0.05)) end + + @trixi_testset "elixir_shallowwater_beach.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_beach.jl"), + l2 = [0.17979210479598923, 1.2377495706611434, 6.289818963361573e-8], + linf = [0.845938394800688, 3.3740800777086575, 4.4541473087633676e-7], + tspan = (0.0, 0.05)) + end + + @trixi_testset "elixir_shallowwater_parabolic_bowl.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_parabolic_bowl.jl"), + l2 = [8.965981683033589e-5, 1.8565707397810857e-5, 4.1043039226164336e-17], + linf = [0.00041080213807871235, 0.00014823261488938177, 2.220446049250313e-16], + tspan = (0.0, 0.05)) + end end end # module diff --git a/test/test_tree_1d_shallowwater_twolayer.jl b/test/test_tree_1d_shallowwater_twolayer.jl index 0d8a83806f9..8372d0d4676 100644 --- a/test/test_tree_1d_shallowwater_twolayer.jl +++ b/test/test_tree_1d_shallowwater_twolayer.jl @@ -1,5 +1,7 @@ module TestExamples1DShallowWaterTwoLayer +# TODO: TrixiShallowWater: move two layer tests to new package + using Test using Trixi diff --git a/test/test_tree_2d_shallowwater.jl b/test/test_tree_2d_shallowwater.jl index f465a177a67..7670d28f43a 100644 --- a/test/test_tree_2d_shallowwater.jl +++ b/test/test_tree_2d_shallowwater.jl @@ -1,5 +1,7 @@ module TestExamples2DShallowWater +# TODO: TrixiShallowWater: move any wet/dry tests to new package + using Test using Trixi @@ -37,6 +39,13 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") tspan = (0.0, 0.25)) end + @trixi_testset "elixir_shallowwater_well_balanced_wet_dry.jl with FluxHydrostaticReconstruction" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced_wet_dry.jl"), + l2 = [0.030186039395610056, 2.513287752536758e-14, 1.3631397744897607e-16, 0.10911781485920438], + linf = [0.49999999999993505, 5.5278950497971455e-14, 7.462550826772548e-16, 2.0], + tspan = (0.0, 0.25)) + end + @trixi_testset "elixir_shallowwater_source_terms.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), l2 = [0.001868474306068482, 0.01731687445878443, 0.017649083171490863, 6.274146767717023e-5], @@ -57,6 +66,21 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") linf = [0.015156105797771602, 0.07964811135780492, 0.0839787097210376, 0.0001819675955490041], tspan = (0.0, 0.025), surface_flux=(flux_hll, flux_nonconservative_fjordholm_etal)) end + + @trixi_testset "elixir_shallowwater_conical_island.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_conical_island.jl"), + l2 = [0.0459315416430658, 0.1644534881916991, 0.16445348819169914, 0.0011537702354532694], + linf = [0.21100717610846464, 0.9501592344310412, 0.9501592344310417, 0.021790250683516282], + tspan = (0.0, 0.025)) + end + + @trixi_testset "elixir_shallowwater_parabolic_bowl.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_parabolic_bowl.jl"), + l2 = [0.00025345501281482687, 4.4525120338817177e-5, 0.00015991819160294247, 7.750412064917294e-15], + linf = [0.004664246019836723, 0.0004972780116736669, 0.0028735707270457628, 6.866729407306593e-14], + tspan = (0.0, 0.025), + basis = LobattoLegendreBasis(3)) + end end end # module diff --git a/test/test_tree_2d_shallowwater_twolayer.jl b/test/test_tree_2d_shallowwater_twolayer.jl index 4bb45064714..7ad5b0f7316 100644 --- a/test/test_tree_2d_shallowwater_twolayer.jl +++ b/test/test_tree_2d_shallowwater_twolayer.jl @@ -1,5 +1,7 @@ module TestExamples2DShallowWaterTwoLayer +# TODO: TrixiShallowWater: move two layer tests to new package + using Test using Trixi @@ -19,10 +21,10 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") @trixi_testset "elixir_shallowwater_twolayer_convergence.jl with flux_es_fjordholm_etal" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_twolayer_convergence.jl"), - l2 = [0.00024709443131137236, 0.0019215286339769443, 0.0023833298173254447, + l2 = [0.00024709443131137236, 0.0019215286339769443, 0.0023833298173254447, 0.00021258247976270914, 0.0011299428031136195, 0.0009191313765262401, - 8.873630921431545e-6], - linf = [0.0016099763244645793, 0.007659242165565017, 0.009123320235427057, + 8.873630921431545e-6], + linf = [0.0016099763244645793, 0.007659242165565017, 0.009123320235427057, 0.0013496983982568267, 0.0035573687287770994, 0.00296823235874899, 3.361991620143279e-5], surface_flux = (flux_es_fjordholm_etal, flux_nonconservative_fjordholm_etal), @@ -31,19 +33,19 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") @trixi_testset "elixir_shallowwater_twolayer_well_balanced.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_twolayer_well_balanced.jl"), - l2 = [3.2935164267930016e-16, 4.6800825611195103e-17, 4.843057532147818e-17, - 0.0030769233188015013, 1.4809161150389857e-16, 1.509071695038043e-16, + l2 = [3.2935164267930016e-16, 4.6800825611195103e-17, 4.843057532147818e-17, + 0.0030769233188015013, 1.4809161150389857e-16, 1.509071695038043e-16, 0.0030769233188014935], - linf = [2.248201624865942e-15, 2.346382070278936e-16, 2.208565017494899e-16, - 0.026474051138910493, 9.237568031609006e-16, 7.520758026187046e-16, + linf = [2.248201624865942e-15, 2.346382070278936e-16, 2.208565017494899e-16, + 0.026474051138910493, 9.237568031609006e-16, 7.520758026187046e-16, 0.026474051138910267], tspan = (0.0, 0.25)) end @trixi_testset "elixir_shallowwater_twolayer_well_balanced with flux_lax_friedrichs.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_twolayer_well_balanced.jl"), - l2 = [2.0525741072929735e-16, 6.000589392730905e-17, 6.102759428478984e-17, - 0.0030769233188014905, 1.8421386173122792e-16, 1.8473184927121752e-16, + l2 = [2.0525741072929735e-16, 6.000589392730905e-17, 6.102759428478984e-17, + 0.0030769233188014905, 1.8421386173122792e-16, 1.8473184927121752e-16, 0.0030769233188014935], linf = [7.355227538141662e-16, 2.960836949170518e-16, 4.2726562436938764e-16, 0.02647405113891016, 1.038795478061861e-15, 1.0401789378532516e-15, diff --git a/test/test_unit.jl b/test/test_unit.jl index 2ce111b2bf4..e70a9be6a4a 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -402,6 +402,10 @@ isdir(outdir) && rm(outdir, recursive=true) indicator_hg = IndicatorHennemannGassner(1.0, 0.0, true, "variable", "cache") @test_nowarn show(stdout, indicator_hg) + # TODO: TrixiShallowWater: move unit test + indicator_hg_swe = IndicatorHennemannGassnerShallowWater(1.0, 0.0, true, "variable", "cache") + @test_nowarn show(stdout, indicator_hg_swe) + indicator_loehner = IndicatorLöhner(1.0, "variable", (; cache=nothing)) @test_nowarn show(stdout, indicator_loehner) diff --git a/test/test_unstructured_2d.jl b/test/test_unstructured_2d.jl index d4b0d150ca1..fbe88a2a0a3 100644 --- a/test/test_unstructured_2d.jl +++ b/test/test_unstructured_2d.jl @@ -1,5 +1,7 @@ module TestExamplesUnstructuredMesh2D +# TODO: TrixiShallowWater: move any wet/dry and two layer tests + using Test using Trixi @@ -134,6 +136,14 @@ isdir(outdir) && rm(outdir, recursive=true) tspan = (0.0, 0.025)) end + @trixi_testset "elixir_shallowwater_source_terms.jl with flux_hll" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), + l2 = [0.0011197139793938727, 0.015430259691311309, 0.017081031802719554, 5.089218476759981e-6], + linf = [0.014300809338967824, 0.12783372461224918, 0.17625472321993918, 2.6407324614341476e-5], + surface_flux=(flux_hll, flux_nonconservative_fjordholm_etal), + tspan = (0.0, 0.025)) + end + @trixi_testset "elixir_shallowwater_dirichlet.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_dirichlet.jl"), l2 = [1.1577518608940115e-5, 4.867189932537344e-13, 4.647273240470541e-13, 1.1577518608933468e-5], @@ -155,6 +165,14 @@ isdir(outdir) && rm(outdir, recursive=true) tspan = (0.0, 0.25)) end + @trixi_testset "elixir_shallowwater_three_mound_dam_break.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_three_mound_dam_break.jl"), + l2 = [0.0892957892027502, 0.30648836484407915, 2.28712547616214e-15, 0.0008778654298684622], + linf = [0.850329472915091, 2.330631694956507, 5.783660020252348e-14, 0.04326237921249021], + basis = LobattoLegendreBasis(3), + tspan = (0.0, 0.25)) + end + @trixi_testset "elixir_shallowwater_twolayer_convergence.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_twolayer_convergence.jl"), l2 = [0.0007953969898161991, 0.00882074628714633, 0.0024322572528892934, From c97eb8c47a0a092ab73889c8ce7c838ba7864127 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Sat, 15 Jul 2023 06:51:23 +0200 Subject: [PATCH 033/263] set version to v0.5.33 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 4a289380850..9dd7ecd023f 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.5.33-pre" +version = "0.5.33" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 10e0fa93320cd8722d482a89a0e944955b0c23ee Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Sat, 15 Jul 2023 06:51:38 +0200 Subject: [PATCH 034/263] set development version to v0.5.34-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 9dd7ecd023f..6c3c7fa0208 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.5.33" +version = "0.5.34-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 07981c3e50943a9bdb1a845f918a4e8831714338 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Sat, 15 Jul 2023 12:52:38 +0200 Subject: [PATCH 035/263] throw better error message with MPI for TreeMesh1D (#1569) --- src/meshes/tree_mesh.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/meshes/tree_mesh.jl b/src/meshes/tree_mesh.jl index 34794ded852..93ba982bce9 100644 --- a/src/meshes/tree_mesh.jl +++ b/src/meshes/tree_mesh.jl @@ -125,9 +125,9 @@ function TreeMesh(coordinates_min::NTuple{NDIMS, Real}, # TODO: MPI, create nice interface for a parallel tree/mesh if mpi_isparallel() - if mpi_isroot() && NDIMS == 3 + if mpi_isroot() && NDIMS != 2 println(stderr, - "ERROR: TreeMesh3D does not support parallel execution with MPI") + "ERROR: The TreeMesh supports parallel execution with MPI only in 2 dimensions") MPI.Abort(mpi_comm(), 1) end TreeType = ParallelTree{NDIMS} From 932f43358acba90e3de7909c2bd18c8b630c66b9 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Sat, 15 Jul 2023 16:36:48 +0200 Subject: [PATCH 036/263] allow periodic FDSBP operators (#1570) * enable fully periodic upwind SBP oeprators * 2D and 3D tests * comment on PeriodicFDSBP --- Project.toml | 2 +- .../tree_1d_fdsbp/elixir_advection_upwind.jl | 3 +- .../elixir_advection_upwind_periodic.jl | 57 +++++++++++++++++++ src/solvers/fdsbp_tree/fdsbp.jl | 3 + src/solvers/fdsbp_tree/fdsbp_1d.jl | 28 ++++++++- src/solvers/fdsbp_tree/fdsbp_2d.jl | 28 ++++++++- src/solvers/fdsbp_tree/fdsbp_3d.jl | 28 ++++++++- test/test_tree_1d_fdsbp.jl | 15 +++++ test/test_tree_2d_fdsbp.jl | 18 ++++++ test/test_tree_3d_fdsbp.jl | 23 +++++++- 10 files changed, 196 insertions(+), 9 deletions(-) create mode 100644 examples/tree_1d_fdsbp/elixir_advection_upwind_periodic.jl diff --git a/Project.toml b/Project.toml index 6c3c7fa0208..a49cfb2e254 100644 --- a/Project.toml +++ b/Project.toml @@ -79,7 +79,7 @@ StaticArrayInterface = "1.4" StaticArrays = "1" StrideArrays = "0.1.18" StructArrays = "0.6" -SummationByPartsOperators = "0.5.25" +SummationByPartsOperators = "0.5.41" TimerOutputs = "0.5" Triangulate = "2.0" TriplotBase = "0.1" diff --git a/examples/tree_1d_fdsbp/elixir_advection_upwind.jl b/examples/tree_1d_fdsbp/elixir_advection_upwind.jl index 5c50e1a6c64..18dd818e3ca 100644 --- a/examples/tree_1d_fdsbp/elixir_advection_upwind.jl +++ b/examples/tree_1d_fdsbp/elixir_advection_upwind.jl @@ -27,7 +27,8 @@ coordinates_min = -1.0 coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, initial_refinement_level = 4, - n_cells_max = 10_000) + n_cells_max = 10_000, + periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_sin, solver) diff --git a/examples/tree_1d_fdsbp/elixir_advection_upwind_periodic.jl b/examples/tree_1d_fdsbp/elixir_advection_upwind_periodic.jl new file mode 100644 index 00000000000..3eb805095f4 --- /dev/null +++ b/examples/tree_1d_fdsbp/elixir_advection_upwind_periodic.jl @@ -0,0 +1,57 @@ +# !!! warning "Experimental implementation (upwind SBP)" +# This is an experimental feature and may change in future releases. + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear scalar advection equation equation + +equations = LinearScalarAdvectionEquation1D(1.0) + +function initial_condition_sin(x, t, equation::LinearScalarAdvectionEquation1D) + return SVector(sinpi(x[1] - equations.advection_velocity[1] * t)) +end + +D_upw = upwind_operators(SummationByPartsOperators.periodic_derivative_operator, + accuracy_order = 4, + xmin = -1.0, xmax = 1.0, + N = 64) +flux_splitting = splitting_lax_friedrichs +solver = FDSBP(D_upw, + surface_integral = SurfaceIntegralUpwind(flux_splitting), + volume_integral = VolumeIntegralUpwind(flux_splitting)) + +coordinates_min = -1.0 +coordinates_max = 1.0 +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 0, + n_cells_max = 10_000, + periodicity = true) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_sin, solver) + + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 2.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) + +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback) + + +############################################################################### +# run the simulation + +sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-6, reltol=1.0e-6, + ode_default_options()..., callback=callbacks); +summary_callback() # print the timer summary diff --git a/src/solvers/fdsbp_tree/fdsbp.jl b/src/solvers/fdsbp_tree/fdsbp.jl index cbb6fd16243..11b09c6df9c 100644 --- a/src/solvers/fdsbp_tree/fdsbp.jl +++ b/src/solvers/fdsbp_tree/fdsbp.jl @@ -27,6 +27,9 @@ The other arguments have the same meaning as in [`DG`](@ref) or [`DGSEM`](@ref). """ const FDSBP = DG{Basis} where {Basis <: AbstractDerivativeOperator} +# Internal abbreviation for easier-to-read dispatch (not exported) +const PeriodicFDSBP = FDSBP{Basis} where {Basis <: AbstractPeriodicDerivativeOperator} + function FDSBP(D_SBP::AbstractDerivativeOperator; surface_integral, volume_integral) # `nothing` is passed as `mortar` return DG(D_SBP, nothing, surface_integral, volume_integral) diff --git a/src/solvers/fdsbp_tree/fdsbp_1d.jl b/src/solvers/fdsbp_tree/fdsbp_1d.jl index c7712074940..0de0cff4851 100644 --- a/src/solvers/fdsbp_tree/fdsbp_1d.jl +++ b/src/solvers/fdsbp_tree/fdsbp_1d.jl @@ -165,6 +165,14 @@ function calc_surface_integral!(du, u, mesh::TreeMesh{1}, return nothing end +# Periodic FDSBP operators need to use a single element without boundaries +function calc_surface_integral!(du, u, mesh::TreeMesh1D, + equations, surface_integral::SurfaceIntegralStrongForm, + dg::PeriodicFDSBP, cache) + @assert nelements(dg, cache) == 1 + return nothing +end + # Specialized interface flux computation because the upwind solver does # not require a standard numerical flux (Riemann solver). The flux splitting # already separates the solution information into right-traveling and @@ -239,13 +247,25 @@ function calc_surface_integral!(du, u, mesh::TreeMesh{1}, return nothing end +# Periodic FDSBP operators need to use a single element without boundaries +function calc_surface_integral!(du, u, mesh::TreeMesh1D, + equations, surface_integral::SurfaceIntegralUpwind, + dg::PeriodicFDSBP, cache) + @assert nelements(dg, cache) == 1 + return nothing +end + # AnalysisCallback function integrate_via_indices(func::Func, u, mesh::TreeMesh{1}, equations, dg::FDSBP, cache, args...; normalize = true) where {Func} # TODO: FD. This is rather inefficient right now and allocates... - weights = diag(SummationByPartsOperators.mass_matrix(dg.basis)) + M = SummationByPartsOperators.mass_matrix(dg.basis) + if M isa UniformScaling + M = M(nnodes(dg)) + end + weights = diag(M) # Initialize integral with zeros of the right shape integral = zero(func(u, 1, 1, equations, dg, args...)) @@ -271,7 +291,11 @@ function calc_error_norms(func, u, t, analyzer, mesh::TreeMesh{1}, equations, initial_condition, dg::FDSBP, cache, cache_analysis) # TODO: FD. This is rather inefficient right now and allocates... - weights = diag(SummationByPartsOperators.mass_matrix(dg.basis)) + M = SummationByPartsOperators.mass_matrix(dg.basis) + if M isa UniformScaling + M = M(nnodes(dg)) + end + weights = diag(M) @unpack node_coordinates = cache.elements # Set up data structures diff --git a/src/solvers/fdsbp_tree/fdsbp_2d.jl b/src/solvers/fdsbp_tree/fdsbp_2d.jl index 241e0d95342..beff605629a 100644 --- a/src/solvers/fdsbp_tree/fdsbp_2d.jl +++ b/src/solvers/fdsbp_tree/fdsbp_2d.jl @@ -201,6 +201,14 @@ function calc_surface_integral!(du, u, mesh::TreeMesh{2}, return nothing end +# Periodic FDSBP operators need to use a single element without boundaries +function calc_surface_integral!(du, u, mesh::TreeMesh2D, + equations, surface_integral::SurfaceIntegralStrongForm, + dg::PeriodicFDSBP, cache) + @assert nelements(dg, cache) == 1 + return nothing +end + # Specialized interface flux computation because the upwind solver does # not require a standard numerical flux (Riemann solver). The flux splitting # already separates the solution information into right-traveling and @@ -295,12 +303,24 @@ function calc_surface_integral!(du, u, mesh::TreeMesh{2}, return nothing end +# Periodic FDSBP operators need to use a single element without boundaries +function calc_surface_integral!(du, u, mesh::TreeMesh2D, + equations, surface_integral::SurfaceIntegralUpwind, + dg::PeriodicFDSBP, cache) + @assert nelements(dg, cache) == 1 + return nothing +end + # AnalysisCallback function integrate_via_indices(func::Func, u, mesh::TreeMesh{2}, equations, dg::FDSBP, cache, args...; normalize = true) where {Func} # TODO: FD. This is rather inefficient right now and allocates... - weights = diag(SummationByPartsOperators.mass_matrix(dg.basis)) + M = SummationByPartsOperators.mass_matrix(dg.basis) + if M isa UniformScaling + M = M(nnodes(dg)) + end + weights = diag(M) # Initialize integral with zeros of the right shape integral = zero(func(u, 1, 1, 1, equations, dg, args...)) @@ -326,7 +346,11 @@ function calc_error_norms(func, u, t, analyzer, mesh::TreeMesh{2}, equations, initial_condition, dg::FDSBP, cache, cache_analysis) # TODO: FD. This is rather inefficient right now and allocates... - weights = diag(SummationByPartsOperators.mass_matrix(dg.basis)) + M = SummationByPartsOperators.mass_matrix(dg.basis) + if M isa UniformScaling + M = M(nnodes(dg)) + end + weights = diag(M) @unpack node_coordinates = cache.elements # Set up data structures diff --git a/src/solvers/fdsbp_tree/fdsbp_3d.jl b/src/solvers/fdsbp_tree/fdsbp_3d.jl index a4f69d3d481..0c3f18b6d6e 100644 --- a/src/solvers/fdsbp_tree/fdsbp_3d.jl +++ b/src/solvers/fdsbp_tree/fdsbp_3d.jl @@ -237,6 +237,14 @@ function calc_surface_integral!(du, u, mesh::TreeMesh{3}, return nothing end +# Periodic FDSBP operators need to use a single element without boundaries +function calc_surface_integral!(du, u, mesh::TreeMesh3D, + equations, surface_integral::SurfaceIntegralStrongForm, + dg::PeriodicFDSBP, cache) + @assert nelements(dg, cache) == 1 + return nothing +end + # Specialized interface flux computation because the upwind solver does # not require a standard numerical flux (Riemann solver). The flux splitting # already separates the solution information into right-traveling and @@ -346,13 +354,25 @@ function calc_surface_integral!(du, u, mesh::TreeMesh{3}, return nothing end +# Periodic FDSBP operators need to use a single element without boundaries +function calc_surface_integral!(du, u, mesh::TreeMesh3D, + equations, surface_integral::SurfaceIntegralUpwind, + dg::PeriodicFDSBP, cache) + @assert nelements(dg, cache) == 1 + return nothing +end + # AnalysisCallback function integrate_via_indices(func::Func, u, mesh::TreeMesh{3}, equations, dg::FDSBP, cache, args...; normalize = true) where {Func} # TODO: FD. This is rather inefficient right now and allocates... - weights = diag(SummationByPartsOperators.mass_matrix(dg.basis)) + M = SummationByPartsOperators.mass_matrix(dg.basis) + if M isa UniformScaling + M = M(nnodes(dg)) + end + weights = diag(M) # Initialize integral with zeros of the right shape integral = zero(func(u, 1, 1, 1, 1, equations, dg, args...)) @@ -378,7 +398,11 @@ function calc_error_norms(func, u, t, analyzer, mesh::TreeMesh{3}, equations, initial_condition, dg::FDSBP, cache, cache_analysis) # TODO: FD. This is rather inefficient right now and allocates... - weights = diag(SummationByPartsOperators.mass_matrix(dg.basis)) + M = SummationByPartsOperators.mass_matrix(dg.basis) + if M isa UniformScaling + M = M(nnodes(dg)) + end + weights = diag(M) @unpack node_coordinates = cache.elements # Set up data structures diff --git a/test/test_tree_1d_fdsbp.jl b/test/test_tree_1d_fdsbp.jl index 118385c34b3..ce0ca660d35 100644 --- a/test/test_tree_1d_fdsbp.jl +++ b/test/test_tree_1d_fdsbp.jl @@ -23,6 +23,21 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_fdsbp") @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 end end + + @trixi_testset "elixir_advection_upwind_periodic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_upwind_periodic.jl"), + l2 = [1.1672962783692568e-5], + linf = [1.650514414558435e-5]) + + # 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 @testset "Inviscid Burgers" begin diff --git a/test/test_tree_2d_fdsbp.jl b/test/test_tree_2d_fdsbp.jl index 7c58ef89a6c..e81c82f3f34 100644 --- a/test/test_tree_2d_fdsbp.jl +++ b/test/test_tree_2d_fdsbp.jl @@ -23,6 +23,24 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_fdsbp") @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 end end + + @trixi_testset "elixir_advection_extended.jl with periodic operators" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), + l2 = [1.1239649404463432e-5], + linf = [1.5895264629195438e-5], + D_SBP = SummationByPartsOperators.periodic_derivative_operator( + derivative_order = 1, accuracy_order = 4, xmin = 0.0, xmax = 1.0, N = 40), + initial_refinement_level = 0) + + # 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 @testset "Compressible Euler" begin diff --git a/test/test_tree_3d_fdsbp.jl b/test/test_tree_3d_fdsbp.jl index 9dceab38031..106dd007b09 100644 --- a/test/test_tree_3d_fdsbp.jl +++ b/test/test_tree_3d_fdsbp.jl @@ -7,7 +7,7 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_fdsbp") -@testset "Compressible Euler" begin +@testset "Linear scalar advection" begin @trixi_testset "elixir_advection_extended.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), l2 = [0.005355755365412444], @@ -23,6 +23,27 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_fdsbp") end end + @trixi_testset "elixir_advection_extended.jl with periodic operators" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), + l2 = [1.3819894522373702e-8], + linf = [3.381866298113323e-8], + D_SBP = SummationByPartsOperators.periodic_derivative_operator( + derivative_order = 1, accuracy_order = 4, xmin = 0.0, xmax = 1.0, N = 10), + initial_refinement_level = 0, + tspan = (0.0, 5.0)) + + # 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 + +@testset "Compressible Euler" begin @trixi_testset "elixir_euler_convergence.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), l2 = [2.247522803543667e-5, 2.2499169224681058e-5, 2.24991692246826e-5, 2.2499169224684707e-5, 5.814121361417382e-5], From fd239da5af1ba619fa2457c6318a5f3ab3be59b3 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Sun, 16 Jul 2023 06:11:40 +0200 Subject: [PATCH 037/263] set version to v0.5.34 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index a49cfb2e254..7f2a52b0aaf 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.5.34-pre" +version = "0.5.34" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From d96514f6d58e48b33816f58e02959d167954fdea Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Sun, 16 Jul 2023 06:11:55 +0200 Subject: [PATCH 038/263] set development version to v0.5.35-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 7f2a52b0aaf..4c187ed38ff 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.5.34" +version = "0.5.35-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 75d70fdf5706ccdc5290303675bcd5ad1cf7d462 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Jul 2023 19:15:37 +0200 Subject: [PATCH 039/263] Bump crate-ci/typos from 1.16.0 to 1.16.1 (#1573) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.16.0 to 1.16.1. - [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.16.0...v1.16.1) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-type: direct:production update-type: version-update:semver-patch ... 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 bb5a32f72ee..f72c3b0947b 100644 --- a/.github/workflows/SpellCheck.yml +++ b/.github/workflows/SpellCheck.yml @@ -10,4 +10,4 @@ jobs: - name: Checkout Actions Repository uses: actions/checkout@v3 - name: Check spelling - uses: crate-ci/typos@v1.16.0 + uses: crate-ci/typos@v1.16.1 From a12f82da43a16d59db16063557fef245c87b6c0e Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 18 Jul 2023 05:52:17 +0200 Subject: [PATCH 040/263] fix typos in comments (#1572) --- examples/tree_1d_fdsbp/elixir_advection_upwind.jl | 2 +- examples/tree_1d_fdsbp/elixir_advection_upwind_periodic.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/tree_1d_fdsbp/elixir_advection_upwind.jl b/examples/tree_1d_fdsbp/elixir_advection_upwind.jl index 18dd818e3ca..1f2498e0866 100644 --- a/examples/tree_1d_fdsbp/elixir_advection_upwind.jl +++ b/examples/tree_1d_fdsbp/elixir_advection_upwind.jl @@ -5,7 +5,7 @@ using OrdinaryDiffEq using Trixi ############################################################################### -# semidiscretization of the linear scalar advection equation equation +# semidiscretization of the linear scalar advection equation equations = LinearScalarAdvectionEquation1D(1.0) diff --git a/examples/tree_1d_fdsbp/elixir_advection_upwind_periodic.jl b/examples/tree_1d_fdsbp/elixir_advection_upwind_periodic.jl index 3eb805095f4..035d3568a80 100644 --- a/examples/tree_1d_fdsbp/elixir_advection_upwind_periodic.jl +++ b/examples/tree_1d_fdsbp/elixir_advection_upwind_periodic.jl @@ -5,7 +5,7 @@ using OrdinaryDiffEq using Trixi ############################################################################### -# semidiscretization of the linear scalar advection equation equation +# semidiscretization of the linear scalar advection equation equations = LinearScalarAdvectionEquation1D(1.0) From 375384659cb57a80e253c5e685db8ec298e30d8c Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Wed, 19 Jul 2023 07:39:37 +0200 Subject: [PATCH 041/263] Add talk announcement for JuliaCon 2023 (#1575) --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index ccd70b6daf8..7eaee8750dd 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,16 @@

+*** +**Trixi.jl at JuliaCon 2023**
+At this year's JuliaCon, we will be present with an online contribution that involves Trixi.jl: + +* [Scaling Trixi.jl to more than 10,000 cores using MPI](https://pretalx.com/juliacon2023/talk/PC8PZ8/), + 27th July 2023, 10:30–11:30 (US/Eastern), 32-G449 (Kiva) + +We are looking forward to seeing you there ♥️ +*** + **Trixi.jl** is a numerical simulation framework for hyperbolic conservation laws written in [Julia](https://julialang.org). A key objective for the framework is to be useful to both scientists and students. Therefore, next to From b0ec66ea004c84d8487c4318a54933da8c827c92 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 19 Jul 2023 12:16:53 +0200 Subject: [PATCH 042/263] fix GC time percentage output (#1576) --- src/callbacks_step/analysis.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/callbacks_step/analysis.jl b/src/callbacks_step/analysis.jl index 8cf43a1d15e..7c453aab633 100644 --- a/src/callbacks_step/analysis.jl +++ b/src/callbacks_step/analysis.jl @@ -267,7 +267,7 @@ function (analysis_callback::AnalysisCallback)(u_ode, du_ode, integrator, semi) gc_time_absolute = 1.0e-9 * (Base.gc_time_ns() - analysis_callback.start_gc_time) # Compute the percentage of total time that was spent in garbage collection - gc_time_percentage = gc_time_absolute / runtime_absolute + gc_time_percentage = gc_time_absolute / runtime_absolute * 100 # Obtain the current memory usage of the Julia garbage collector, in MiB, i.e., the total size of # objects in memory that have been allocated by the JIT compiler or the user code. From e0aad3cad1a2581eb79cf4fd1d06e7d7fb2c6379 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 19 Jul 2023 14:11:35 +0200 Subject: [PATCH 043/263] set version to v0.5.35 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 4c187ed38ff..1818d1c56c9 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.5.35-pre" +version = "0.5.35" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 67d137d6712f28bbe99ffef3d003afe96c47aade Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 19 Jul 2023 14:11:46 +0200 Subject: [PATCH 044/263] set development version to v0.5.36-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 1818d1c56c9..07c4fe55ad4 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.5.35" +version = "0.5.36-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 1aec5fa7e17a8011baf77bfa1822491693e1986d Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 21 Jul 2023 11:56:38 +0200 Subject: [PATCH 045/263] test threaded time integration (#1581) * test threaded time integration * link to upstream issue in comment --- examples/dgmulti_2d/elixir_euler_curved.jl | 3 +- .../elixir_advection_diffusion.jl | 3 +- .../tree_2d_dgsem/elixir_advection_restart.jl | 3 +- test/Project.toml | 6 ++-- test/test_threaded.jl | 28 +++++++++++++++++++ 5 files changed, 37 insertions(+), 6 deletions(-) diff --git a/examples/dgmulti_2d/elixir_euler_curved.jl b/examples/dgmulti_2d/elixir_euler_curved.jl index a3ba62f1cfb..39e3a0a0360 100644 --- a/examples/dgmulti_2d/elixir_euler_curved.jl +++ b/examples/dgmulti_2d/elixir_euler_curved.jl @@ -42,7 +42,8 @@ callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-6, reltol=1.0e-6, +alg = RDPK3SpFSAL49() +sol = solve(ode, alg; abstol=1.0e-6, reltol=1.0e-6, ode_default_options()..., callback=callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_advection_diffusion.jl b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl index e96e1b5a171..a716bd278b8 100644 --- a/examples/tree_2d_dgsem/elixir_advection_diffusion.jl +++ b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl @@ -75,8 +75,9 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) # run the simulation # OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks +alg = RDPK3SpFSAL49() time_int_tol = 1.0e-11 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, +sol = solve(ode, alg; abstol=time_int_tol, reltol=time_int_tol, ode_default_options()..., callback=callbacks) # Print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_advection_restart.jl b/examples/tree_2d_dgsem/elixir_advection_restart.jl index 4ceb5932573..72efb7d0c84 100644 --- a/examples/tree_2d_dgsem/elixir_advection_restart.jl +++ b/examples/tree_2d_dgsem/elixir_advection_restart.jl @@ -26,7 +26,8 @@ ode = semidiscretize(semi, tspan, restart_filename); # Do not overwrite the initial snapshot written by elixir_advection_extended.jl. save_solution.condition.save_initial_solution = false -integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), +alg = CarpenterKennedy2N54(williamson_condition=false) +integrator = init(ode, alg, dt=dt, # solve needs some value here but it will be overwritten by the stepsize_callback save_everystep=false, callback=callbacks) diff --git a/test/Project.toml b/test/Project.toml index cae1d4ff396..7115a19b441 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -24,9 +24,9 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [preferences.OrdinaryDiffEq] PrecompileAutoSpecialize = false PrecompileAutoSwitch = false -PrecompileDefaultSpecialize = true +PrecompileDefaultSpecialize = false PrecompileFunctionWrapperSpecialize = false -PrecompileLowStorage = true +PrecompileLowStorage = false PrecompileNoSpecialize = false -PrecompileNonStiff = true +PrecompileNonStiff = false PrecompileStiff = false diff --git a/test/test_threaded.jl b/test/test_threaded.jl index 1e750707981..323d12d7091 100644 --- a/test/test_threaded.jl +++ b/test/test_threaded.jl @@ -18,6 +18,14 @@ Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) linf = [6.314906965243505e-5]) end + @trixi_testset "elixir_advection_restart.jl with threaded time integration" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_restart.jl"), + alg = CarpenterKennedy2N54(williamson_condition = false, thread = OrdinaryDiffEq.True()), + # Expected errors are exactly the same as in the serial test! + l2 = [7.81674284320524e-6], + linf = [6.314906965243505e-5]) + end + @trixi_testset "elixir_advection_amr_refine_twice.jl" begin @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_amr_refine_twice.jl"), l2 = [0.00020547512522578292], @@ -42,6 +50,15 @@ Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) l2 = [0.061751715597716854, 0.05018223615408711, 0.05018989446443463, 0.225871559730513], linf = [0.29347582879608825, 0.31081249232844693, 0.3107380389947736, 1.0540358049885143]) end + + @trixi_testset "elixir_advection_diffusion.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_diffusion.jl"), + initial_refinement_level = 2, tspan = (0.0, 0.4), polydeg = 5, + alg = RDPK3SpFSAL49(thread = OrdinaryDiffEq.True()), + l2 = [4.0915532997994255e-6], + linf = [2.3040850347877395e-5] + ) + end end @@ -108,6 +125,17 @@ Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) ) end + @trixi_testset "elixir_euler_curved.jl with threaded time integration" begin + @test_broken false + # TODO: This is currently broken and needs to be fixed upstream + # See https://github.com/JuliaSIMD/StrideArrays.jl/issues/77 + # @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_euler_curved.jl"), + # alg = RDPK3SpFSAL49(thread = OrdinaryDiffEq.True()), + # l2 = [1.720476068165337e-5, 1.592168205710526e-5, 1.592168205812963e-5, 4.894094865697305e-5], + # linf = [0.00010525416930584619, 0.00010003778091061122, 0.00010003778085621029, 0.00036426282101720275] + # ) + end + @trixi_testset "elixir_euler_triangulate_pkg_mesh.jl" begin @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_euler_triangulate_pkg_mesh.jl"), l2 = [2.344080455438114e-6, 1.8610038753097983e-6, 2.4095165666095305e-6, 6.373308158814308e-6], From 036eaed82b92be9376c5b610d8d40eddf45ca1fa Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 24 Jul 2023 13:26:16 +0200 Subject: [PATCH 046/263] reset threads in semidiscretize (#1584) I added the option to reset the threads from Polyester.jl in semidiscretize. However, I did not document it in the docstring since we have not documented that we use Polyester.jl threads in general - and the resetting is specific to Polyester.jl. I was not sure whether we still would like to keep the option to change the threading backend any time - although I do not see a good reason why we should do so. --- Project.toml | 2 +- src/Trixi.jl | 2 +- src/semidiscretization/semidiscretization.jl | 20 +++++++++++++++++-- ...semidiscretization_hyperbolic_parabolic.jl | 10 +++++++++- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/Project.toml b/Project.toml index 07c4fe55ad4..00bf2718d8b 100644 --- a/Project.toml +++ b/Project.toml @@ -65,7 +65,7 @@ MuladdMacro = "0.2.2" Octavian = "0.3.5" OffsetArrays = "1.3" P4est = "0.4" -Polyester = "0.3.4, 0.5, 0.6, 0.7" +Polyester = "0.7.5" PrecompileTools = "1.1" RecipesBase = "1.1" Reexport = "1.0" diff --git a/src/Trixi.jl b/src/Trixi.jl index cf6158e29eb..b0c872b1904 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -51,7 +51,7 @@ using LoopVectorization: LoopVectorization, @turbo, indices using StaticArrayInterface: static_length # used by LoopVectorization using MuladdMacro: @muladd using Octavian: Octavian, matmul! -using Polyester: @batch # You know, the cheapest threads you can find... +using Polyester: Polyester, @batch # You know, the cheapest threads you can find... using OffsetArrays: OffsetArray, OffsetVector using P4est using Setfield: @set diff --git a/src/semidiscretization/semidiscretization.jl b/src/semidiscretization/semidiscretization.jl index ac312c57c89..fbdcd73e2a8 100644 --- a/src/semidiscretization/semidiscretization.jl +++ b/src/semidiscretization/semidiscretization.jl @@ -70,7 +70,15 @@ end Wrap the semidiscretization `semi` as an ODE problem in the time interval `tspan` that can be passed to `solve` from the [SciML ecosystem](https://diffeq.sciml.ai/latest/). """ -function semidiscretize(semi::AbstractSemidiscretization, tspan) +function semidiscretize(semi::AbstractSemidiscretization, tspan; + reset_threads = true) + # Optionally reset Polyester.jl threads. See + # https://github.com/trixi-framework/Trixi.jl/issues/1583 + # https://github.com/JuliaSIMD/Polyester.jl/issues/30 + if reset_threads + Polyester.reset_threads!() + end + u0_ode = compute_coefficients(first(tspan), semi) # TODO: MPI, do we want to synchronize loading and print debug statements, e.g. using # mpi_isparallel() && MPI.Barrier(mpi_comm()) @@ -88,7 +96,15 @@ that can be passed to `solve` from the [SciML ecosystem](https://diffeq.sciml.ai The initial condition etc. is taken from the `restart_file`. """ function semidiscretize(semi::AbstractSemidiscretization, tspan, - restart_file::AbstractString) + restart_file::AbstractString; + reset_threads = true) + # Optionally reset Polyester.jl threads. See + # https://github.com/trixi-framework/Trixi.jl/issues/1583 + # https://github.com/JuliaSIMD/Polyester.jl/issues/30 + if reset_threads + Polyester.reset_threads!() + end + u0_ode = load_restart_file(semi, restart_file) # TODO: MPI, do we want to synchronize loading and print debug statements, e.g. using # mpi_isparallel() && MPI.Barrier(mpi_comm()) diff --git a/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl b/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl index f54bc744164..8f1e38c891b 100644 --- a/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl +++ b/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl @@ -274,7 +274,15 @@ The parabolic right-hand side is the first function of the split ODE problem and will be used by default by the implicit part of IMEX methods from the SciML ecosystem. """ -function semidiscretize(semi::SemidiscretizationHyperbolicParabolic, tspan) +function semidiscretize(semi::SemidiscretizationHyperbolicParabolic, tspan; + reset_threads = true) + # Optionally reset Polyester.jl threads. See + # https://github.com/trixi-framework/Trixi.jl/issues/1583 + # https://github.com/JuliaSIMD/Polyester.jl/issues/30 + if reset_threads + Polyester.reset_threads!() + end + u0_ode = compute_coefficients(first(tspan), semi) # TODO: MPI, do we want to synchronize loading and print debug statements, e.g. using # mpi_isparallel() && MPI.Barrier(mpi_comm()) From 253f63ef042ef3f10ca15c5d21327a3b6ce4bcdc Mon Sep 17 00:00:00 2001 From: Jesse Chan <1156048+jlchan@users.noreply.github.com> Date: Mon, 24 Jul 2023 22:46:27 -0500 Subject: [PATCH 047/263] Fix CI failures related to Makie (#1586) * unrelated cleanup * fix CI issues? --- ext/TrixiMakieExt.jl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ext/TrixiMakieExt.jl b/ext/TrixiMakieExt.jl index 1eb11f6a422..8cd7576a6e5 100644 --- a/ext/TrixiMakieExt.jl +++ b/ext/TrixiMakieExt.jl @@ -335,7 +335,7 @@ end # ================== new Makie plot recipes ==================== # This initializes a Makie recipe, which creates a new type definition which Makie uses to create -# custom `trixiheatmap` plots. See also https://makie.juliaplots.org/stable/recipes.html +# custom `trixiheatmap` plots. See also https://docs.makie.org/stable/documentation/recipes/ Makie.@recipe(TrixiHeatmap, plot_data_series) do scene Makie.Theme(colormap = default_Makie_colormap()) end @@ -346,9 +346,8 @@ function Makie.plot!(myplot::TrixiHeatmap) plotting_mesh = global_plotting_triangulation_makie(pds; set_z_coordinate_zero = true) - @unpack variable_id = pds pd = pds.plot_data - solution_z = vec(StructArrays.component(pd.data, variable_id)) + solution_z = vec(StructArrays.component(pd.data, pds.variable_id)) Makie.mesh!(myplot, plotting_mesh, color = solution_z, shading = false, colormap = myplot[:colormap]) myplot.colorrange = extrema(solution_z) @@ -411,7 +410,7 @@ function Makie.plot!(fig, pd::PlotData2DTriangulated; row = row_list[variable_to_plot] col = col_list[variable_to_plot] - Makie.Colorbar(fig[row, col][1, 2], plt) + Makie.Colorbar(fig[row, col][1, 2], colormap = colormap) ax.aspect = Makie.DataAspect() # equal aspect ratio ax.title = variable_name From 6e7e3b5bfb4e4a232f04a9b0d3c711ad414a56c2 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 25 Jul 2023 07:08:05 +0200 Subject: [PATCH 048/263] activate previously broken test and add allocation tests (#1582) * activate previously broken test and add allocation tests * fix allocations in prolong2interfaces! * fix allocations in calc_sources! * fix allocations in apply_jacobian! * fixed FDSBP, elixir_euler_convergence.jl * elixir_euler_triangulate_pkg_mesh.jl is only broken with multithreading * Update test_threaded.jl * Update test_threaded.jl --- src/solvers/dgsem_tree/dg_1d.jl | 20 ++-- src/solvers/dgsem_tree/dg_2d.jl | 25 +++-- src/solvers/dgsem_tree/dg_3d.jl | 29 +++--- test/test_threaded.jl | 175 ++++++++++++++++++++++++++++++-- 4 files changed, 212 insertions(+), 37 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_1d.jl b/src/solvers/dgsem_tree/dg_1d.jl index c66f427cce3..b5bb076f3b7 100644 --- a/src/solvers/dgsem_tree/dg_1d.jl +++ b/src/solvers/dgsem_tree/dg_1d.jl @@ -385,15 +385,17 @@ end function prolong2interfaces!(cache, u, mesh::TreeMesh{1}, equations, surface_integral, dg::DG) @unpack interfaces = cache + @unpack neighbor_ids = interfaces + interfaces_u = interfaces.u @threaded for interface in eachinterface(dg, cache) - left_element = interfaces.neighbor_ids[1, interface] - right_element = interfaces.neighbor_ids[2, interface] + left_element = neighbor_ids[1, interface] + right_element = neighbor_ids[2, interface] # interface in x-direction for v in eachvariable(equations) - interfaces.u[1, v, interface] = u[v, nnodes(dg), left_element] - interfaces.u[2, v, interface] = u[v, 1, right_element] + interfaces_u[1, v, interface] = u[v, nnodes(dg), left_element] + interfaces_u[2, v, interface] = u[v, 1, right_element] end end @@ -621,8 +623,10 @@ end function apply_jacobian!(du, mesh::Union{TreeMesh{1}, StructuredMesh{1}}, equations, dg::DG, cache) + @unpack inverse_jacobian = cache.elements + @threaded for element in eachelement(dg, cache) - factor = -cache.elements.inverse_jacobian[element] + factor = -inverse_jacobian[element] for i in eachnode(dg) for v in eachvariable(equations) @@ -642,11 +646,13 @@ end function calc_sources!(du, u, t, source_terms, equations::AbstractEquations{1}, dg::DG, cache) + @unpack node_coordinates = cache.elements + @threaded for element in eachelement(dg, cache) for i in eachnode(dg) u_local = get_node_vars(u, equations, dg, i, element) - x_local = get_node_coords(cache.elements.node_coordinates, equations, dg, i, - element) + x_local = get_node_coords(node_coordinates, equations, dg, + i, element) du_local = source_terms(u_local, x_local, t, equations) add_to_node_vars!(du, du_local, equations, dg, i, element) end diff --git a/src/solvers/dgsem_tree/dg_2d.jl b/src/solvers/dgsem_tree/dg_2d.jl index d3227710686..6c5e0cee0cf 100644 --- a/src/solvers/dgsem_tree/dg_2d.jl +++ b/src/solvers/dgsem_tree/dg_2d.jl @@ -529,23 +529,24 @@ end function prolong2interfaces!(cache, u, mesh::TreeMesh{2}, equations, surface_integral, dg::DG) @unpack interfaces = cache - @unpack orientations = interfaces + @unpack orientations, neighbor_ids = interfaces + interfaces_u = interfaces.u @threaded for interface in eachinterface(dg, cache) - left_element = interfaces.neighbor_ids[1, interface] - right_element = interfaces.neighbor_ids[2, interface] + left_element = neighbor_ids[1, interface] + right_element = neighbor_ids[2, interface] if orientations[interface] == 1 # interface in x-direction for j in eachnode(dg), v in eachvariable(equations) - interfaces.u[1, v, j, interface] = u[v, nnodes(dg), j, left_element] - interfaces.u[2, v, j, interface] = u[v, 1, j, right_element] + interfaces_u[1, v, j, interface] = u[v, nnodes(dg), j, left_element] + interfaces_u[2, v, j, interface] = u[v, 1, j, right_element] end else # if orientations[interface] == 2 # interface in y-direction for i in eachnode(dg), v in eachvariable(equations) - interfaces.u[1, v, i, interface] = u[v, i, nnodes(dg), left_element] - interfaces.u[2, v, i, interface] = u[v, i, 1, right_element] + interfaces_u[1, v, i, interface] = u[v, i, nnodes(dg), left_element] + interfaces_u[2, v, i, interface] = u[v, i, 1, right_element] end end end @@ -1116,8 +1117,10 @@ end function apply_jacobian!(du, mesh::TreeMesh{2}, equations, dg::DG, cache) + @unpack inverse_jacobian = cache.elements + @threaded for element in eachelement(dg, cache) - factor = -cache.elements.inverse_jacobian[element] + factor = -inverse_jacobian[element] for j in eachnode(dg), i in eachnode(dg) for v in eachvariable(equations) @@ -1137,11 +1140,13 @@ end function calc_sources!(du, u, t, source_terms, equations::AbstractEquations{2}, dg::DG, cache) + @unpack node_coordinates = cache.elements + @threaded for element in eachelement(dg, cache) for j in eachnode(dg), i in eachnode(dg) u_local = get_node_vars(u, equations, dg, i, j, element) - x_local = get_node_coords(cache.elements.node_coordinates, equations, dg, i, - j, element) + x_local = get_node_coords(node_coordinates, equations, dg, + i, j, element) du_local = source_terms(u_local, x_local, t, equations) add_to_node_vars!(du, du_local, equations, dg, i, j, element) end diff --git a/src/solvers/dgsem_tree/dg_3d.jl b/src/solvers/dgsem_tree/dg_3d.jl index 95abb2595e5..acdab900cd1 100644 --- a/src/solvers/dgsem_tree/dg_3d.jl +++ b/src/solvers/dgsem_tree/dg_3d.jl @@ -598,32 +598,33 @@ end function prolong2interfaces!(cache, u, mesh::TreeMesh{3}, equations, surface_integral, dg::DG) @unpack interfaces = cache - @unpack orientations = interfaces + @unpack orientations, neighbor_ids = interfaces + interfaces_u = interfaces.u @threaded for interface in eachinterface(dg, cache) - left_element = interfaces.neighbor_ids[1, interface] - right_element = interfaces.neighbor_ids[2, interface] + left_element = neighbor_ids[1, interface] + right_element = neighbor_ids[2, interface] if orientations[interface] == 1 # interface in x-direction for k in eachnode(dg), j in eachnode(dg), v in eachvariable(equations) - interfaces.u[1, v, j, k, interface] = u[v, nnodes(dg), j, k, + interfaces_u[1, v, j, k, interface] = u[v, nnodes(dg), j, k, left_element] - interfaces.u[2, v, j, k, interface] = u[v, 1, j, k, right_element] + interfaces_u[2, v, j, k, interface] = u[v, 1, j, k, right_element] end elseif orientations[interface] == 2 # interface in y-direction for k in eachnode(dg), i in eachnode(dg), v in eachvariable(equations) - interfaces.u[1, v, i, k, interface] = u[v, i, nnodes(dg), k, + interfaces_u[1, v, i, k, interface] = u[v, i, nnodes(dg), k, left_element] - interfaces.u[2, v, i, k, interface] = u[v, i, 1, k, right_element] + interfaces_u[2, v, i, k, interface] = u[v, i, 1, k, right_element] end else # if orientations[interface] == 3 # interface in z-direction for j in eachnode(dg), i in eachnode(dg), v in eachvariable(equations) - interfaces.u[1, v, i, j, interface] = u[v, i, j, nnodes(dg), + interfaces_u[1, v, i, j, interface] = u[v, i, j, nnodes(dg), left_element] - interfaces.u[2, v, i, j, interface] = u[v, i, j, 1, right_element] + interfaces_u[2, v, i, j, interface] = u[v, i, j, 1, right_element] end end end @@ -1350,8 +1351,10 @@ end function apply_jacobian!(du, mesh::TreeMesh{3}, equations, dg::DG, cache) + @unpack inverse_jacobian = cache.elements + @threaded for element in eachelement(dg, cache) - factor = -cache.elements.inverse_jacobian[element] + factor = -inverse_jacobian[element] for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg) for v in eachvariable(equations) @@ -1371,11 +1374,13 @@ end function calc_sources!(du, u, t, source_terms, equations::AbstractEquations{3}, dg::DG, cache) + @unpack node_coordinates = cache.elements + @threaded for element in eachelement(dg, cache) for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg) u_local = get_node_vars(u, equations, dg, i, j, k, element) - x_local = get_node_coords(cache.elements.node_coordinates, equations, dg, i, - j, k, element) + x_local = get_node_coords(node_coordinates, equations, dg, + i, j, k, element) du_local = source_terms(u_local, x_local, t, equations) add_to_node_vars!(du, du_local, equations, dg, i, j, k, element) end diff --git a/test/test_threaded.jl b/test/test_threaded.jl index 323d12d7091..77fa16ad33e 100644 --- a/test/test_threaded.jl +++ b/test/test_threaded.jl @@ -16,6 +16,15 @@ Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) # Expected errors are exactly the same as in the serial test! l2 = [7.81674284320524e-6], linf = [6.314906965243505e-5]) + + # 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)) < 5000 + end end @trixi_testset "elixir_advection_restart.jl with threaded time integration" begin @@ -30,12 +39,30 @@ Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_amr_refine_twice.jl"), l2 = [0.00020547512522578292], linf = [0.007831753383083506]) + + # 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)) < 5000 + end end @trixi_testset "elixir_advection_amr_coarsen_twice.jl" begin @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_amr_coarsen_twice.jl"), l2 = [0.0014321062757891826], linf = [0.0253454486893413]) + + # 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)) < 5000 + end end @trixi_testset "elixir_euler_source_terms_nonperiodic.jl" begin @@ -43,12 +70,30 @@ Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) l2 = [2.259440511766445e-6, 2.318888155713922e-6, 2.3188881557894307e-6, 6.3327863238858925e-6], linf = [1.498738264560373e-5, 1.9182011928187137e-5, 1.918201192685487e-5, 6.0526717141407005e-5], rtol = 0.001) + + # 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)) < 5000 + end end @trixi_testset "elixir_euler_ec.jl" begin @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_euler_ec.jl"), l2 = [0.061751715597716854, 0.05018223615408711, 0.05018989446443463, 0.225871559730513], linf = [0.29347582879608825, 0.31081249232844693, 0.3107380389947736, 1.0540358049885143]) + + # 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)) < 5000 + end end @trixi_testset "elixir_advection_diffusion.jl" begin @@ -58,6 +103,47 @@ Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) l2 = [4.0915532997994255e-6], linf = [2.3040850347877395e-5] ) + + # 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)) < 5000 + end + end + + @trixi_testset "FDSBP, elixir_advection_extended.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_fdsbp", "elixir_advection_extended.jl"), + l2 = [2.898644263922225e-6], + linf = [8.491517930142578e-6], + rtol = 1.0e-7) # These results change a little bit and depend on the CI system + + # 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)) < 5000 + end + end + + @trixi_testset "FDSBP, elixir_euler_convergence.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_fdsbp", "elixir_euler_convergence.jl"), + l2 = [1.7088389997042244e-6, 1.7437997855125774e-6, 1.7437997855350776e-6, 5.457223460127621e-6], + linf = [9.796504903736292e-6, 9.614745892783105e-6, 9.614745892783105e-6, 4.026107182575345e-5], + tspan = (0.0, 0.1)) + + # 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)) < 5000 + end end end @@ -70,6 +156,15 @@ Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) rtol = 5.0e-5, # Higher tolerance to make tests pass in CI (in particular with macOS) elixir_file="elixir_advection_waving_flag.jl", restart_file="restart_000021.h5") + + # 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)) < 5000 + end end @trixi_testset "elixir_mhd_ec.jl" begin @@ -81,6 +176,15 @@ Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) 0.9757376320946505, 0.12123736788315098, 0.12837436699267113, 0.17793825293524734, 0.03460761690059514], tspan = (0.0, 0.3)) + + # 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)) < 5000 + end end end @@ -93,6 +197,15 @@ Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) linf = [0.36236334472179443, 0.3690785638275256, 0.8475748723784078, 0.0, 8.881784197001252e-16, 1.7763568394002505e-15, 1.7763568394002505e-15], tspan = (0.0, 5.0)) + + # 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)) < 5000 + end end end @@ -102,6 +215,15 @@ Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), l2 = [0.0034516244508588046, 0.0023420334036925493, 0.0024261923964557187, 0.004731710454271893], linf = [0.04155789011775046, 0.024772109862748914, 0.03759938693042297, 0.08039824959535657]) + + # 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)) < 5000 + end end @trixi_testset "elixir_eulergravity_convergence.jl" begin @@ -123,17 +245,32 @@ Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) l2 = [0.006400337855843578, 0.005303799804137764, 0.005303799804119745, 0.013204169007030144], linf = [0.03798302318566282, 0.05321027922532284, 0.05321027922605448, 0.13392025411839015], ) + + # 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)) < 5000 + end end @trixi_testset "elixir_euler_curved.jl with threaded time integration" begin - @test_broken false - # TODO: This is currently broken and needs to be fixed upstream - # See https://github.com/JuliaSIMD/StrideArrays.jl/issues/77 - # @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_euler_curved.jl"), - # alg = RDPK3SpFSAL49(thread = OrdinaryDiffEq.True()), - # l2 = [1.720476068165337e-5, 1.592168205710526e-5, 1.592168205812963e-5, 4.894094865697305e-5], - # linf = [0.00010525416930584619, 0.00010003778091061122, 0.00010003778085621029, 0.00036426282101720275] - # ) + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_euler_curved.jl"), + alg = RDPK3SpFSAL49(thread = OrdinaryDiffEq.True()), + l2 = [1.720476068165337e-5, 1.592168205710526e-5, 1.592168205812963e-5, 4.894094865697305e-5], + linf = [0.00010525416930584619, 0.00010003778091061122, 0.00010003778085621029, 0.00036426282101720275] + ) + + # 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)) < 5000 + end end @trixi_testset "elixir_euler_triangulate_pkg_mesh.jl" begin @@ -141,6 +278,19 @@ Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) l2 = [2.344080455438114e-6, 1.8610038753097983e-6, 2.4095165666095305e-6, 6.373308158814308e-6], linf = [2.5099852761334418e-5, 2.2683684021362893e-5, 2.6180448559287584e-5, 5.5752932611508044e-5] ) + + # 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) + if (Threads.nthreads() < 2) || (VERSION < v"1.9") + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 5000 + else + @test_broken (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 5000 + end + end end @trixi_testset "elixir_euler_fdsbp_periodic.jl" begin @@ -148,6 +298,15 @@ Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) l2 = [1.3333320340010056e-6, 2.044834627970641e-6, 2.044834627855601e-6, 5.282189803559564e-6], linf = [2.7000151718858945e-6, 3.988595028259212e-6, 3.9885950273710336e-6, 8.848583042286862e-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)) < 5000 + end end end end From 3dd2cb60d0798a5a9a327c73e6150382636c7845 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 25 Jul 2023 08:59:37 +0200 Subject: [PATCH 049/263] set version to v0.5.36 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 00bf2718d8b..2017290c785 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.5.36-pre" +version = "0.5.36" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 41b56ef71c535321fca8c99fe9d7b2098b70025d Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 25 Jul 2023 08:59:47 +0200 Subject: [PATCH 050/263] set development version to v0.5.37-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 2017290c785..94c47a35ac1 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.5.36" +version = "0.5.37-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From fe6a818a8459d6beef3969c1fd2d5cc7ddf596df Mon Sep 17 00:00:00 2001 From: Ahmad Peyvan <115842305+apey236@users.noreply.github.com> Date: Tue, 25 Jul 2023 04:17:42 -0400 Subject: [PATCH 051/263] Adding parabolic terms for `P4estMesh{3}` (#1555) * Adding parabolic terms for 3D P4est mesh * Adding parabolic terms for 3D P4estMesh * Adding working parabolic terms for `P4estMesh{3}` * Formatting * Addin TGV example and test to `P4estMesh{3}` * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl Co-authored-by: Hendrik Ranocha * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl Co-authored-by: Hendrik Ranocha * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl Co-authored-by: Hendrik Ranocha * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl Co-authored-by: Hendrik Ranocha * Removing comments * Removed comments * Adding TGV test for `P4estMesh{3}` * Correcting the format * Format correction * Remove .toml file * Format correction * Optimized loop for speed --------- Co-authored-by: Hendrik Ranocha Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> --- .../elixir_navierstokes_convergence.jl | 263 +++++++ ...elixir_navierstokes_taylor_green_vortex.jl | 82 +++ src/callbacks_step/analysis_dg3d.jl | 2 +- src/solvers/dgsem_p4est/dg.jl | 1 + src/solvers/dgsem_p4est/dg_2d_parabolic.jl | 2 +- src/solvers/dgsem_p4est/dg_3d_parabolic.jl | 691 ++++++++++++++++++ src/solvers/dgsem_tree/dg_3d_parabolic.jl | 13 +- test/test_parabolic_3d.jl | 19 +- 8 files changed, 1063 insertions(+), 10 deletions(-) create mode 100644 examples/p4est_3d_dgsem/elixir_navierstokes_convergence.jl create mode 100644 examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex.jl create mode 100644 src/solvers/dgsem_p4est/dg_3d_parabolic.jl diff --git a/examples/p4est_3d_dgsem/elixir_navierstokes_convergence.jl b/examples/p4est_3d_dgsem/elixir_navierstokes_convergence.jl new file mode 100644 index 00000000000..c426fe95f5b --- /dev/null +++ b/examples/p4est_3d_dgsem/elixir_navierstokes_convergence.jl @@ -0,0 +1,263 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal compressible Navier-Stokes equations + +prandtl_number() = 0.72 +mu() = 0.01 + +equations = CompressibleEulerEquations3D(1.4) +equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu=mu(), Prandtl=prandtl_number(), + gradient_variables=GradientVariablesPrimitive()) + +# 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, + volume_integral=VolumeIntegralWeakForm()) + +coordinates_min = (-1.0, -1.0, -1.0) # minimum coordinates (min(x), min(y), min(z)) +coordinates_max = ( 1.0, 1.0, 1.0) # maximum coordinates (max(x), max(y), max(z)) + +trees_per_dimension = (2, 2, 2) + +mesh = P4estMesh(trees_per_dimension, polydeg=3, + coordinates_min=coordinates_min, coordinates_max=coordinates_max, + periodicity=(true, false, true), initial_refinement_level=2) + +# Note: the initial condition cannot be specialized to `CompressibleNavierStokesDiffusion3D` +# since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesDiffusion3D`) +# and by the initial condition (which passes in `CompressibleEulerEquations3D`). +# This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) +function initial_condition_navier_stokes_convergence_test(x, t, equations) + # Constants. OBS! Must match those in `source_terms_navier_stokes_convergence_test` + c = 2.0 + A1 = 0.5 + A2 = 1.0 + A3 = 0.5 + + # Convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_z = pi * x[3] + pi_t = 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.0) * (1.0 - exp(-A3 * (x[2] - 1.0))) * sin(pi_z) * cos(pi_t) + v2 = v1 + v3 = v1 + p = rho^2 + + return prim2cons(SVector(rho, v1, v2, v3, p), equations) +end + +@inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) + # TODO: parabolic + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + mu_ = mu() + + # Constants. OBS! Must match those in `initial_condition_navier_stokes_convergence_test` + c = 2.0 + A1 = 0.5 + A2 = 1.0 + A3 = 0.5 + + # Convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_z = pi * x[3] + pi_t = pi * t + + # Define auxiliary functions for the strange function of the y variable + # to make expressions easier to read + g = log(x[2] + 2.0) * (1.0 - exp(-A3 * (x[2] - 1.0))) + g_y = ( A3 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0)) + + (1.0 - exp(-A3 * (x[2] - 1.0))) / (x[2] + 2.0) ) + g_yy = ( 2.0 * A3 * exp(-A3 * (x[2] - 1.0)) / (x[2] + 2.0) + - (1.0 - exp(-A3 * (x[2] - 1.0))) / ((x[2] + 2.0)^2) + - A3^2 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0)) ) + + # Density and its derivatives + rho = c + A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t) + rho_t = -pi * A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * sin(pi_t) + rho_x = pi * A1 * cos(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t) + rho_y = -pi * A1 * sin(pi_x) * sin(pi_y) * sin(pi_z) * cos(pi_t) + rho_z = pi * A1 * sin(pi_x) * cos(pi_y) * cos(pi_z) * cos(pi_t) + rho_xx = -pi^2 * (rho - c) + rho_yy = -pi^2 * (rho - c) + rho_zz = -pi^2 * (rho - c) + + # Velocities and their derivatives + # v1 terms + v1 = A2 * sin(pi_x) * g * sin(pi_z) * cos(pi_t) + v1_t = -pi * A2 * sin(pi_x) * g * sin(pi_z) * sin(pi_t) + v1_x = pi * A2 * cos(pi_x) * g * sin(pi_z) * cos(pi_t) + v1_y = A2 * sin(pi_x) * g_y * sin(pi_z) * cos(pi_t) + v1_z = pi * A2 * sin(pi_x) * g * cos(pi_z) * cos(pi_t) + v1_xx = -pi^2 * v1 + v1_yy = A2 * sin(pi_x) * g_yy * sin(pi_z) * cos(pi_t) + v1_zz = -pi^2 * v1 + v1_xy = pi * A2 * cos(pi_x) * g_y * sin(pi_z) * cos(pi_t) + v1_xz = pi^2 * A2 * cos(pi_x) * g * cos(pi_z) * cos(pi_t) + v1_yz = pi * A2 * sin(pi_x) * g_y * cos(pi_z) * cos(pi_t) + # v2 terms (simplifies from ansatz) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_z = v1_z + v2_xx = v1_xx + v2_yy = v1_yy + v2_zz = v1_zz + v2_xy = v1_xy + v2_yz = v1_yz + # v3 terms (simplifies from ansatz) + v3 = v1 + v3_t = v1_t + v3_x = v1_x + v3_y = v1_y + v3_z = v1_z + v3_xx = v1_xx + v3_yy = v1_yy + v3_zz = v1_zz + v3_xz = v1_xz + v3_yz = v1_yz + + # Pressure and its derivatives + p = rho^2 + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_z = 2.0 * rho * rho_z + + # Total energy and its derivatives; simiplifies from ansatz that v2 = v1 and v3 = v1 + E = p * inv_gamma_minus_one + 1.5 * rho * v1^2 + E_t = p_t * inv_gamma_minus_one + 1.5 * rho_t * v1^2 + 3.0 * rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + 1.5 * rho_x * v1^2 + 3.0 * rho * v1 * v1_x + E_y = p_y * inv_gamma_minus_one + 1.5 * rho_y * v1^2 + 3.0 * rho * v1 * v1_y + E_z = p_z * inv_gamma_minus_one + 1.5 * rho_z * v1^2 + 3.0 * rho * v1 * v1_z + + # Divergence of Fick's law ∇⋅∇q = kappa ∇⋅∇T; simplifies because p = rho², so T = p/rho = rho + kappa = equations.gamma * inv_gamma_minus_one / Pr + q_xx = kappa * rho_xx # kappa T_xx + q_yy = kappa * rho_yy # kappa T_yy + q_zz = kappa * rho_zz # kappa T_zz + + # Stress tensor and its derivatives (exploit symmetry) + tau11 = 4.0 / 3.0 * v1_x - 2.0 / 3.0 * (v2_y + v3_z) + tau12 = v1_y + v2_x + tau13 = v1_z + v3_x + tau22 = 4.0 / 3.0 * v2_y - 2.0 / 3.0 * (v1_x + v3_z) + tau23 = v2_z + v3_y + tau33 = 4.0 / 3.0 * v3_z - 2.0 / 3.0 * (v1_x + v2_y) + + tau11_x = 4.0 / 3.0 * v1_xx - 2.0 / 3.0 * (v2_xy + v3_xz) + tau12_x = v1_xy + v2_xx + tau13_x = v1_xz + v3_xx + + tau12_y = v1_yy + v2_xy + tau22_y = 4.0 / 3.0 * v2_yy - 2.0 / 3.0 * (v1_xy + v3_yz) + tau23_y = v2_yz + v3_yy + + tau13_z = v1_zz + v3_xz + tau23_z = v2_zz + v3_yz + tau33_z = 4.0 / 3.0 * v3_zz - 2.0 / 3.0 * (v1_xz + v2_yz) + + # Compute the source terms + # Density equation + du1 = ( rho_t + rho_x * v1 + rho * v1_x + + rho_y * v2 + rho * v2_y + + rho_z * v3 + rho * v3_z ) + # x-momentum equation + du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y + + rho_z * v1 * v3 + + rho * v1_z * v3 + + rho * v1 * v3_z + - mu_ * (tau11_x + tau12_y + tau13_z) ) + # y-momentum equation + du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y + + rho_z * v2 * v3 + + rho * v2_z * v3 + + rho * v2 * v3_z + - mu_ * (tau12_x + tau22_y + tau23_z) ) + # z-momentum equation + du4 = ( rho_t * v3 + rho * v3_t + p_z + rho_x * v1 * v3 + + rho * v1_x * v3 + + rho * v1 * v3_x + + rho_y * v2 * v3 + + rho * v2_y * v3 + + rho * v2 * v3_y + + rho_z * v3^2 + + 2.0 * rho * v3 * v3_z + - mu_ * (tau13_x + tau23_y + tau33_z) ) + # Total energy equation + du5 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) + + v3_z * (E + p) + v3 * (E_z + p_z) + # stress tensor and temperature gradient from x-direction + - mu_ * ( q_xx + v1_x * tau11 + v2_x * tau12 + v3_x * tau13 + + v1 * tau11_x + v2 * tau12_x + v3 * tau13_x) + # stress tensor and temperature gradient terms from y-direction + - mu_ * ( q_yy + v1_y * tau12 + v2_y * tau22 + v3_y * tau23 + + v1 * tau12_y + v2 * tau22_y + v3 * tau23_y) + # stress tensor and temperature gradient terms from z-direction + - mu_ * ( q_zz + v1_z * tau13 + v2_z * tau23 + v3_z * tau33 + + v1 * tau13_z + v2 * tau23_z + v3 * tau33_z) ) + + return SVector(du1, du2, du3, du4, du5) +end + +initial_condition = initial_condition_navier_stokes_convergence_test + +# BC types +velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:4]) +heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) +boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, heat_bc_top_bottom) + +# define inviscid boundary conditions +boundary_conditions = Dict( + :y_neg => boundary_condition_slip_wall, + :y_pos => boundary_condition_slip_wall + ) + +# define viscous boundary conditions +boundary_conditions_parabolic = Dict( + :y_neg => boundary_condition_top_bottom, + :y_pos => boundary_condition_top_bottom + ) + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; + boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), + source_terms=source_terms_navier_stokes_convergence_test) + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span `tspan` +tspan = (0.0, 0.2) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() +alive_callback = AliveCallback(alive_interval=10) +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, + ode_default_options()..., callback=callbacks) +summary_callback() # print the timer summary + diff --git a/examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex.jl b/examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex.jl new file mode 100644 index 00000000000..c5b9ccf2e38 --- /dev/null +++ b/examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex.jl @@ -0,0 +1,82 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Navier-Stokes equations + +# TODO: parabolic; unify names of these accessor functions +prandtl_number() = 0.72 +mu() = 6.25e-4 # equivalent to Re = 1600 + +equations = CompressibleEulerEquations3D(1.4) +equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu=mu(), + Prandtl=prandtl_number()) + +""" + initial_condition_taylor_green_vortex(x, t, equations::CompressibleEulerEquations3D) + +The classical inviscid Taylor-Green vortex. +""" +function initial_condition_taylor_green_vortex(x, t, equations::CompressibleEulerEquations3D) + A = 1.0 # magnitude of speed + Ms = 0.1 # maximum Mach number + + rho = 1.0 + v1 = A * sin(x[1]) * cos(x[2]) * cos(x[3]) + v2 = -A * cos(x[1]) * sin(x[2]) * cos(x[3]) + v3 = 0.0 + p = (A / Ms)^2 * rho / equations.gamma # scaling to get Ms + p = p + 1.0/16.0 * A^2 * rho * (cos(2*x[1])*cos(2*x[3]) + 2*cos(2*x[2]) + 2*cos(2*x[1]) + cos(2*x[2])*cos(2*x[3])) + + return prim2cons(SVector(rho, v1, v2, v3, p), equations) +end +initial_condition = initial_condition_taylor_green_vortex + +volume_flux = flux_ranocha +solver = DGSEM(polydeg=3, surface_flux=flux_hll, + volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = (-1.0, -1.0, -1.0) .* pi +coordinates_max = ( 1.0, 1.0, 1.0) .* pi + +trees_per_dimension = (2, 2, 2) + +mesh = P4estMesh(trees_per_dimension, polydeg=3, + coordinates_min=coordinates_min, coordinates_max=coordinates_max, + periodicity=(true, true, true), initial_refinement_level=2) + + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 20.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 50 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=true, + extra_analysis_integrals=(energy_kinetic, + energy_internal, + enstrophy)) +save_solution = SaveSolutionCallback(interval=100, + save_initial_solution=true, + save_final_solution=true, + solution_variables=cons2prim) +alive_callback = AliveCallback(analysis_interval=analysis_interval,) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback,save_solution) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, + ode_default_options()..., callback=callbacks) +summary_callback() # print the timer summary diff --git a/src/callbacks_step/analysis_dg3d.jl b/src/callbacks_step/analysis_dg3d.jl index 76aba813fab..3d9b38fd2a5 100644 --- a/src/callbacks_step/analysis_dg3d.jl +++ b/src/callbacks_step/analysis_dg3d.jl @@ -228,7 +228,7 @@ function integrate(func::Func, u, end function integrate(func::Func, u, - mesh::TreeMesh{3}, + mesh::Union{TreeMesh{3}, P4estMesh{3}}, equations, equations_parabolic, dg::DGSEM, cache, cache_parabolic; normalize = true) where {Func} diff --git a/src/solvers/dgsem_p4est/dg.jl b/src/solvers/dgsem_p4est/dg.jl index a7cc1eee04d..ec50627d3ef 100644 --- a/src/solvers/dgsem_p4est/dg.jl +++ b/src/solvers/dgsem_p4est/dg.jl @@ -50,5 +50,6 @@ include("dg_2d.jl") include("dg_2d_parabolic.jl") include("dg_3d.jl") +include("dg_3d_parabolic.jl") include("dg_parallel.jl") end # @muladd diff --git a/src/solvers/dgsem_p4est/dg_2d_parabolic.jl b/src/solvers/dgsem_p4est/dg_2d_parabolic.jl index 73ac47ed1e3..7e90a83a9ca 100644 --- a/src/solvers/dgsem_p4est/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_p4est/dg_2d_parabolic.jl @@ -1,7 +1,7 @@ # This method is called when a SemidiscretizationHyperbolicParabolic is constructed. # It constructs the basic `cache` used throughout the simulation to compute # the RHS etc. -function create_cache_parabolic(mesh::P4estMesh, equations_hyperbolic::AbstractEquations, +function create_cache_parabolic(mesh::P4estMesh{2}, equations_hyperbolic::AbstractEquations, equations_parabolic::AbstractEquationsParabolic, dg::DG, parabolic_scheme, RealT, uEltype) balance!(mesh) diff --git a/src/solvers/dgsem_p4est/dg_3d_parabolic.jl b/src/solvers/dgsem_p4est/dg_3d_parabolic.jl new file mode 100644 index 00000000000..5370c927e05 --- /dev/null +++ b/src/solvers/dgsem_p4est/dg_3d_parabolic.jl @@ -0,0 +1,691 @@ +# This method is called when a SemidiscretizationHyperbolicParabolic is constructed. +# It constructs the basic `cache` used throughout the simulation to compute +# the RHS etc. +function create_cache_parabolic(mesh::P4estMesh{3}, equations_hyperbolic::AbstractEquations, + equations_parabolic::AbstractEquationsParabolic, + dg::DG, parabolic_scheme, RealT, uEltype) + balance!(mesh) + + elements = init_elements(mesh, equations_hyperbolic, dg.basis, uEltype) + interfaces = init_interfaces(mesh, equations_hyperbolic, dg.basis, elements) + boundaries = init_boundaries(mesh, equations_hyperbolic, dg.basis, elements) + + n_vars = nvariables(equations_hyperbolic) + n_elements = nelements(elements) + n_nodes = nnodes(dg.basis) # nodes in one direction + u_transformed = Array{uEltype}(undef, n_vars, n_nodes, n_nodes, n_nodes, n_elements) + gradients = ntuple(_ -> similar(u_transformed), ndims(mesh)) + flux_viscous = ntuple(_ -> similar(u_transformed), ndims(mesh)) + + cache = (; elements, interfaces, boundaries, gradients, flux_viscous, u_transformed) + + return cache +end + +function calc_gradient!(gradients, u_transformed, t, + mesh::P4estMesh{3}, equations_parabolic, + boundary_conditions_parabolic, dg::DG, + cache, cache_parabolic) + gradients_x, gradients_y, gradients_z = gradients + + # Reset du + @trixi_timeit timer() "reset gradients" begin + reset_du!(gradients_x, dg, cache) + reset_du!(gradients_y, dg, cache) + reset_du!(gradients_z, dg, cache) + end + + # Calculate volume integral + @trixi_timeit timer() "volume integral" begin + (; derivative_dhat) = dg.basis + (; contravariant_vectors) = cache.elements + + @threaded for element in eachelement(dg, cache) + + # Calculate gradients with respect to reference coordinates in one element + for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u_transformed, equations_parabolic, dg, i, j, k, + element) + + for ii in eachnode(dg) + multiply_add_to_node_vars!(gradients_x, derivative_dhat[ii, i], + u_node, equations_parabolic, dg, ii, j, + k, element) + end + + for jj in eachnode(dg) + multiply_add_to_node_vars!(gradients_y, derivative_dhat[jj, j], + u_node, equations_parabolic, dg, i, jj, + k, element) + end + + for kk in eachnode(dg) + multiply_add_to_node_vars!(gradients_z, derivative_dhat[kk, k], + u_node, equations_parabolic, dg, i, j, + kk, element) + end + end + + # now that the reference coordinate gradients are computed, transform them node-by-node to physical gradients + # using the contravariant vectors + for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg) + Ja11, Ja12, Ja13 = get_contravariant_vector(1, contravariant_vectors, + i, j, k, element) + Ja21, Ja22, Ja23 = get_contravariant_vector(2, contravariant_vectors, + i, j, k, element) + Ja31, Ja32, Ja33 = get_contravariant_vector(3, contravariant_vectors, + i, j, k, element) + + gradients_reference_1 = get_node_vars(gradients_x, equations_parabolic, dg, + i, j, k, element) + gradients_reference_2 = get_node_vars(gradients_y, equations_parabolic, dg, + i, j, k, element) + gradients_reference_3 = get_node_vars(gradients_z, equations_parabolic, dg, + i, j, k, element) + + # note that the contravariant vectors are transposed compared with computations of flux + # divergences in `calc_volume_integral!`. See + # https://github.com/trixi-framework/Trixi.jl/pull/1490#discussion_r1213345190 + # for a more detailed discussion. + gradient_x_node = Ja11 * gradients_reference_1 + + Ja21 * gradients_reference_2 + + Ja31 * gradients_reference_3 + gradient_y_node = Ja12 * gradients_reference_1 + + Ja22 * gradients_reference_2 + + Ja32 * gradients_reference_3 + gradient_z_node = Ja13 * gradients_reference_1 + + Ja23 * gradients_reference_2 + + Ja33 * gradients_reference_3 + + set_node_vars!(gradients_x, gradient_x_node, equations_parabolic, dg, + i, j, k, element) + set_node_vars!(gradients_y, gradient_y_node, equations_parabolic, dg, + i, j, k, element) + set_node_vars!(gradients_z, gradient_z_node, equations_parabolic, dg, + i, j, k, element) + end + end + end + + # Prolong solution to interfaces + @trixi_timeit timer() "prolong2interfaces" begin + prolong2interfaces!(cache_parabolic, u_transformed, mesh, + equations_parabolic, dg.surface_integral, dg) + end + + # Calculate interface fluxes for the gradient. This reuses P4est `calc_interface_flux!` along with a + # specialization for AbstractEquationsParabolic. + @trixi_timeit timer() "interface flux" begin + calc_interface_flux!(cache_parabolic.elements.surface_flux_values, + mesh, False(), # False() = no nonconservative terms + equations_parabolic, dg.surface_integral, dg, cache_parabolic) + end + + # Prolong solution to boundaries + @trixi_timeit timer() "prolong2boundaries" begin + prolong2boundaries!(cache_parabolic, u_transformed, mesh, + equations_parabolic, dg.surface_integral, dg) + end + + # Calculate boundary fluxes + @trixi_timeit timer() "boundary flux" begin + calc_boundary_flux_gradients!(cache_parabolic, t, boundary_conditions_parabolic, + mesh, equations_parabolic, dg.surface_integral, dg) + end + + # TODO: parabolic; mortars + @assert nmortars(dg, cache) == 0 + + # Calculate surface integrals + @trixi_timeit timer() "surface integral" begin + (; boundary_interpolation) = dg.basis + (; surface_flux_values) = cache_parabolic.elements + (; contravariant_vectors) = cache.elements + + # Access the factors only once before beginning the loop to increase performance. + # We also use explicit assignments instead of `+=` to let `@muladd` turn these + # into FMAs (see comment at the top of the file). + factor_1 = boundary_interpolation[1, 1] + factor_2 = boundary_interpolation[nnodes(dg), 2] + @threaded for element in eachelement(dg, cache) + for l in eachnode(dg), m in eachnode(dg) + for v in eachvariable(equations_parabolic) + for dim in 1:3 + grad = gradients[dim] + # surface at -x + normal_direction = get_normal_direction(1, contravariant_vectors, + 1, l, m, element) + grad[v, 1, l, m, element] = (grad[v, 1, l, m, element] + + surface_flux_values[v, l, m, 1, + element] * + factor_1 * normal_direction[dim]) + + # surface at +x + normal_direction = get_normal_direction(2, contravariant_vectors, + nnodes(dg), l, m, element) + grad[v, nnodes(dg), l, m, element] = (grad[v, nnodes(dg), l, m, + element] + + surface_flux_values[v, l, m, + 2, + element] * + factor_2 * + normal_direction[dim]) + + # surface at -y + normal_direction = get_normal_direction(3, contravariant_vectors, + l, m, 1, element) + grad[v, l, 1, m, element] = (grad[v, l, 1, m, element] + + surface_flux_values[v, l, m, 3, + element] * + factor_1 * normal_direction[dim]) + + # surface at +y + normal_direction = get_normal_direction(4, contravariant_vectors, + l, nnodes(dg), m, element) + grad[v, l, nnodes(dg), m, element] = (grad[v, l, nnodes(dg), m, + element] + + surface_flux_values[v, l, m, + 4, + element] * + factor_2 * + normal_direction[dim]) + + # surface at -z + normal_direction = get_normal_direction(5, contravariant_vectors, + l, m, 1, element) + grad[v, l, m, 1, element] = (grad[v, l, m, 1, element] + + surface_flux_values[v, l, m, 5, + element] * + factor_1 * normal_direction[dim]) + + # surface at +z + normal_direction = get_normal_direction(6, contravariant_vectors, + l, m, nnodes(dg), element) + grad[v, l, m, nnodes(dg), element] = (grad[v, l, m, nnodes(dg), + element] + + surface_flux_values[v, l, m, + 6, + element] * + factor_2 * + normal_direction[dim]) + end + end + end + end + end + + # Apply Jacobian from mapping to reference element + @trixi_timeit timer() "Jacobian" begin + apply_jacobian_parabolic!(gradients_x, mesh, equations_parabolic, dg, + cache_parabolic) + apply_jacobian_parabolic!(gradients_y, mesh, equations_parabolic, dg, + cache_parabolic) + apply_jacobian_parabolic!(gradients_z, mesh, equations_parabolic, dg, + cache_parabolic) + end + + return nothing +end + +# This version is used for parabolic gradient computations +@inline function calc_interface_flux!(surface_flux_values, mesh::P4estMesh{3}, + nonconservative_terms::False, + equations::AbstractEquationsParabolic, + surface_integral, dg::DG, cache, + interface_index, normal_direction, + primary_i_node_index, primary_j_node_index, + primary_direction_index, primary_element_index, + secondary_i_node_index, secondary_j_node_index, + secondary_direction_index, + secondary_element_index) + @unpack u = cache.interfaces + @unpack surface_flux = surface_integral + + u_ll, u_rr = get_surface_node_vars(u, equations, dg, primary_i_node_index, + primary_j_node_index, + interface_index) + + flux_ = 0.5 * (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. + for v in eachvariable(equations) + surface_flux_values[v, primary_i_node_index, primary_j_node_index, primary_direction_index, primary_element_index] = flux_[v] + surface_flux_values[v, secondary_i_node_index, secondary_j_node_index, secondary_direction_index, secondary_element_index] = flux_[v] + end +end + +# This is the version used when calculating the divergence of the viscous fluxes +function calc_volume_integral!(du, flux_viscous, + mesh::P4estMesh{3}, + equations_parabolic::AbstractEquationsParabolic, + dg::DGSEM, cache) + (; derivative_dhat) = dg.basis + (; contravariant_vectors) = cache.elements + flux_viscous_x, flux_viscous_y, flux_viscous_z = flux_viscous + + @threaded for element in eachelement(dg, cache) + # Calculate volume terms in one element + for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg) + flux1 = get_node_vars(flux_viscous_x, equations_parabolic, dg, i, j, k, element) + flux2 = get_node_vars(flux_viscous_y, equations_parabolic, dg, i, j, k, element) + flux3 = get_node_vars(flux_viscous_z, equations_parabolic, dg, i, j, k, element) + + # Compute the contravariant flux by taking the scalar product of the + # first contravariant vector Ja^1 and the flux vector + Ja11, Ja12, Ja13 = get_contravariant_vector(1, contravariant_vectors, i, j, k, + element) + contravariant_flux1 = Ja11 * flux1 + Ja12 * flux2 + Ja13 * flux3 + for ii in eachnode(dg) + multiply_add_to_node_vars!(du, derivative_dhat[ii, i], contravariant_flux1, + equations_parabolic, dg, ii, j, k, element) + end + + # Compute the contravariant flux by taking the scalar product of the + # second contravariant vector Ja^2 and the flux vector + Ja21, Ja22, Ja23 = get_contravariant_vector(2, contravariant_vectors, i, j, k, + element) + contravariant_flux2 = Ja21 * flux1 + Ja22 * flux2 + Ja23 * flux3 + for jj in eachnode(dg) + multiply_add_to_node_vars!(du, derivative_dhat[jj, j], contravariant_flux2, + equations_parabolic, dg, i, jj, k, element) + end + + # Compute the contravariant flux by taking the scalar product of the + # second contravariant vector Ja^2 and the flux vector + Ja31, Ja32, Ja33 = get_contravariant_vector(3, contravariant_vectors, i, j, k, + element) + contravariant_flux3 = Ja31 * flux1 + Ja32 * flux2 + Ja33 * flux3 + for kk in eachnode(dg) + multiply_add_to_node_vars!(du, derivative_dhat[kk, k], contravariant_flux3, + equations_parabolic, dg, i, j, kk, element) + end + end + end + + return nothing +end + +# This is the version used when calculating the divergence of the viscous fluxes +# We pass the `surface_integral` argument solely for dispatch +function prolong2interfaces!(cache_parabolic, flux_viscous, + mesh::P4estMesh{3}, + equations_parabolic::AbstractEquationsParabolic, + surface_integral, dg::DG, cache) + (; interfaces) = cache_parabolic + (; contravariant_vectors) = cache_parabolic.elements + index_range = eachnode(dg) + flux_viscous_x, flux_viscous_y, flux_viscous_z = flux_viscous + + @threaded for interface in eachinterface(dg, cache) + # Copy solution data from the primary element using "delayed indexing" with + # a start value and a step size to get the correct face and orientation. + # Note that in the current implementation, the interface will be + # "aligned at the primary element", i.e., the index of the primary side + # will always run forwards. + primary_element = interfaces.neighbor_ids[1, interface] + primary_indices = interfaces.node_indices[1, interface] + primary_direction = indices2direction(primary_indices) + + i_primary_start, i_primary_step_i, i_primary_step_j = index_to_start_step_3d(primary_indices[1], + index_range) + j_primary_start, j_primary_step_i, j_primary_step_j = index_to_start_step_3d(primary_indices[2], + index_range) + k_primary_start, k_primary_step_i, k_primary_step_j = index_to_start_step_3d(primary_indices[3], + index_range) + + i_primary = i_primary_start + j_primary = j_primary_start + k_primary = k_primary_start + + for j in eachnode(dg) + for i in eachnode(dg) + # this is the outward normal direction on the primary element + normal_direction = get_normal_direction(primary_direction, + contravariant_vectors, + i_primary, j_primary, k_primary, + primary_element) + + for v in eachvariable(equations_parabolic) + # OBS! `interfaces.u` stores the interpolated *fluxes* and *not the solution*! + flux_viscous = SVector(flux_viscous_x[v, i_primary, j_primary, + k_primary, + primary_element], + flux_viscous_y[v, i_primary, j_primary, + k_primary, + primary_element], + flux_viscous_z[v, i_primary, j_primary, + k_primary, + primary_element]) + + interfaces.u[1, v, i, j, interface] = dot(flux_viscous, + normal_direction) + end + i_primary += i_primary_step_i + j_primary += j_primary_step_i + k_primary += k_primary_step_i + end + i_primary += i_primary_step_j + j_primary += j_primary_step_j + k_primary += k_primary_step_j + end + + # Copy solution data from the secondary element using "delayed indexing" with + # a start value and a step size to get the correct face and orientation. + secondary_element = interfaces.neighbor_ids[2, interface] + secondary_indices = interfaces.node_indices[2, interface] + secondary_direction = indices2direction(secondary_indices) + + i_secondary_start, i_secondary_step_i, i_secondary_step_j = index_to_start_step_3d(secondary_indices[1], + index_range) + j_secondary_start, j_secondary_step_i, j_secondary_step_j = index_to_start_step_3d(secondary_indices[2], + index_range) + k_secondary_start, k_secondary_step_i, k_secondary_step_j = index_to_start_step_3d(secondary_indices[3], + index_range) + + i_secondary = i_secondary_start + j_secondary = j_secondary_start + k_secondary = k_secondary_start + for j in eachnode(dg) + for i in eachnode(dg) + # This is the outward normal direction on the secondary element. + # Here, we assume that normal_direction on the secondary element is + # the negative of normal_direction on the primary element. + normal_direction = get_normal_direction(secondary_direction, + contravariant_vectors, + i_secondary, j_secondary, + k_secondary, + secondary_element) + + for v in eachvariable(equations_parabolic) + # OBS! `interfaces.u` stores the interpolated *fluxes* and *not the solution*! + flux_viscous = SVector(flux_viscous_x[v, i_secondary, j_secondary, + k_secondary, + secondary_element], + flux_viscous_y[v, i_secondary, j_secondary, + k_secondary, + secondary_element], + flux_viscous_z[v, i_secondary, j_secondary, + k_secondary, + secondary_element]) + # store the normal flux with respect to the primary normal direction + interfaces.u[2, v, i, j, interface] = -dot(flux_viscous, + normal_direction) + end + i_secondary += i_secondary_step_i + j_secondary += j_secondary_step_i + k_secondary += k_secondary_step_i + end + i_secondary += i_secondary_step_j + j_secondary += j_secondary_step_j + k_secondary += k_secondary_step_j + end + end + + return nothing +end + +# This version is used for divergence flux computations +function calc_interface_flux!(surface_flux_values, + mesh::P4estMesh{3}, equations_parabolic, + dg::DG, cache_parabolic) + (; neighbor_ids, node_indices) = cache_parabolic.interfaces + index_range = eachnode(dg) + + @threaded for interface in eachinterface(dg, cache_parabolic) + # Get element and side index information on the primary element + primary_element = neighbor_ids[1, interface] + primary_indices = node_indices[1, interface] + primary_direction_index = indices2direction(primary_indices) + + i_primary_start, i_primary_step_i, i_primary_step_j = index_to_start_step_3d(primary_indices[1], + index_range) + j_primary_start, j_primary_step_i, j_primary_step_j = index_to_start_step_3d(primary_indices[2], + index_range) + k_primary_start, k_primary_step_i, k_primary_step_j = index_to_start_step_3d(primary_indices[3], + index_range) + + i_primary = i_primary_start + j_primary = j_primary_start + k_primary = k_primary_start + + # Get element and side index information on the secondary element + secondary_element = neighbor_ids[2, interface] + secondary_indices = node_indices[2, interface] + secondary_direction_index = indices2direction(secondary_indices) + secondary_surface_indices = surface_indices(secondary_indices) + + # Initiate the secondary index to be used in the surface for loop. + # This index on the primary side will always run forward but + # the secondary index might need to run backwards for flipped sides. + # Get the surface indexing on the secondary element. + # Note that the indices of the primary side will always run forward but + # the secondary indices might need to run backwards for flipped sides. + i_secondary_start, i_secondary_step_i, i_secondary_step_j = index_to_start_step_3d(secondary_surface_indices[1], + index_range) + j_secondary_start, j_secondary_step_i, j_secondary_step_j = index_to_start_step_3d(secondary_surface_indices[2], + index_range) + i_secondary = i_secondary_start + j_secondary = j_secondary_start + + for j in eachnode(dg) + for i in eachnode(dg) + # 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, + dg, + i, j, + interface) + + flux = 0.5 * (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] + surface_flux_values[v, i_secondary, j_secondary, secondary_direction_index, secondary_element] = -flux[v] + end + + # Increment the primary element indices + i_primary += i_primary_step_i + j_primary += j_primary_step_i + k_primary += k_primary_step_i + # Increment the secondary element surface indices + i_secondary += i_secondary_step_i + j_secondary += j_secondary_step_i + end + # Increment the primary element indices + i_primary += i_primary_step_j + j_primary += j_primary_step_j + k_primary += k_primary_step_j + # Increment the secondary element surface indices + i_secondary += i_secondary_step_j + j_secondary += j_secondary_step_j + end + end + + return nothing +end + +# TODO: parabolic, finish implementing `calc_boundary_flux_gradients!` and `calc_boundary_flux_divergence!` +function prolong2boundaries!(cache_parabolic, flux_viscous, + mesh::P4estMesh{3}, + equations_parabolic::AbstractEquationsParabolic, + surface_integral, dg::DG, cache) + (; boundaries) = cache_parabolic + (; contravariant_vectors) = cache_parabolic.elements + index_range = eachnode(dg) + + flux_viscous_x, flux_viscous_y, flux_viscous_z = flux_viscous + + @threaded for boundary in eachboundary(dg, cache_parabolic) + # Copy solution data from the element using "delayed indexing" with + # a start value and a step size to get the correct face and orientation. + element = boundaries.neighbor_ids[boundary] + node_indices = boundaries.node_indices[boundary] + direction = indices2direction(node_indices) + + i_node_start, i_node_step_i, i_node_step_j = index_to_start_step_3d(node_indices[1], + index_range) + j_node_start, j_node_step_i, j_node_step_j = index_to_start_step_3d(node_indices[2], + index_range) + k_node_start, k_node_step_i, k_node_step_j = index_to_start_step_3d(node_indices[3], + index_range) + + i_node = i_node_start + j_node = j_node_start + k_node = k_node_start + + for j in eachnode(dg) + for i in eachnode(dg) + # this is the outward normal direction on the primary element + normal_direction = get_normal_direction(direction, contravariant_vectors, + i_node, j_node, k_node, element) + + for v in eachvariable(equations_parabolic) + flux_viscous = SVector(flux_viscous_x[v, i_node, j_node, k_node, + element], + flux_viscous_y[v, i_node, j_node, k_node, + element], + flux_viscous_z[v, i_node, j_node, k_node, + element]) + + boundaries.u[v, i, j, boundary] = dot(flux_viscous, normal_direction) + end + i_node += i_node_step_i + j_node += j_node_step_i + k_node += k_node_step_i + end + i_node += i_node_step_j + j_node += j_node_step_j + k_node += k_node_step_j + end + end + return nothing +end + +# # Function barrier for type stability +# !!! TODO: Figure out why this cannot removed eventhough it exists in the dg_2d_parabolic.jl file +function calc_boundary_flux_gradients!(cache, t, boundary_conditions, mesh::P4estMesh, + equations, surface_integral, dg::DG) + (; boundary_condition_types, boundary_indices) = boundary_conditions + + calc_boundary_flux_by_type!(cache, t, boundary_condition_types, boundary_indices, + Gradient(), mesh, equations, surface_integral, dg) + return nothing +end + +function calc_boundary_flux_divergence!(cache, t, boundary_conditions, mesh::P4estMesh, + equations, surface_integral, dg::DG) + (; boundary_condition_types, boundary_indices) = boundary_conditions + + calc_boundary_flux_by_type!(cache, t, boundary_condition_types, boundary_indices, + Divergence(), mesh, equations, surface_integral, dg) + return nothing +end + +# Iterate over tuples of boundary condition types and associated indices +# in a type-stable way using "lispy tuple programming". +function calc_boundary_flux_by_type!(cache, t, BCs::NTuple{N, Any}, + BC_indices::NTuple{N, Vector{Int}}, + operator_type, + mesh::P4estMesh, + equations, surface_integral, dg::DG) where {N} + # Extract the boundary condition type and index vector + boundary_condition = first(BCs) + boundary_condition_indices = first(BC_indices) + # Extract the remaining types and indices to be processed later + remaining_boundary_conditions = Base.tail(BCs) + remaining_boundary_condition_indices = Base.tail(BC_indices) + + # process the first boundary condition type + calc_boundary_flux!(cache, t, boundary_condition, boundary_condition_indices, + operator_type, mesh, equations, surface_integral, dg) + + # recursively call this method with the unprocessed boundary types + calc_boundary_flux_by_type!(cache, t, remaining_boundary_conditions, + remaining_boundary_condition_indices, + operator_type, + mesh, equations, surface_integral, dg) + + return nothing +end + +# terminate the type-stable iteration over tuples +function calc_boundary_flux_by_type!(cache, t, BCs::Tuple{}, BC_indices::Tuple{}, + operator_type, mesh::P4estMesh, equations, + surface_integral, dg::DG) + nothing +end + +function calc_boundary_flux!(cache, t, + boundary_condition_parabolic, # works with Dict types + boundary_condition_indices, + operator_type, mesh::P4estMesh{3}, + equations_parabolic::AbstractEquationsParabolic, + surface_integral, dg::DG) + (; boundaries) = cache + (; node_coordinates, surface_flux_values) = cache.elements + (; contravariant_vectors) = cache.elements + index_range = eachnode(dg) + + @threaded for local_index in eachindex(boundary_condition_indices) + # Use the local index to get the global boundary index from the pre-sorted list + boundary_index = boundary_condition_indices[local_index] + + # Get information on the adjacent element, compute the surface fluxes, + # and store them + element = boundaries.neighbor_ids[boundary_index] + node_indices = boundaries.node_indices[boundary_index] + direction_index = indices2direction(node_indices) + + i_node_start, i_node_step_i, i_node_step_j = index_to_start_step_3d(node_indices[1], + index_range) + j_node_start, j_node_step_i, j_node_step_j = index_to_start_step_3d(node_indices[2], + index_range) + k_node_start, k_node_step_i, k_node_step_j = index_to_start_step_3d(node_indices[3], + index_range) + + i_node = i_node_start + j_node = j_node_start + k_node = k_node_start + + for j in eachnode(dg) + for i in eachnode(dg) + # Extract solution data from boundary container + u_inner = get_node_vars(boundaries.u, equations_parabolic, dg, i, j, + boundary_index) + + # Outward-pointing normal direction (not normalized) + normal_direction = get_normal_direction(direction_index, + contravariant_vectors, + i_node, j_node, k_node, element) + + # TODO: revisit if we want more general boundary treatments. + # This assumes the gradient numerical flux at the boundary is the gradient variable, + # which is consistent with BR1, LDG. + flux_inner = u_inner + + # Coordinates at boundary node + x = get_node_coords(node_coordinates, equations_parabolic, dg, i_node, + j_node, k_node, + element) + + flux_ = boundary_condition_parabolic(flux_inner, u_inner, normal_direction, + x, t, operator_type, + equations_parabolic) + + # Copy flux to element storage in the correct orientation + for v in eachvariable(equations_parabolic) + surface_flux_values[v, i, j, direction_index, element] = flux_[v] + end + + i_node += i_node_step_i + j_node += j_node_step_i + k_node += k_node_step_i + end + i_node += i_node_step_j + j_node += j_node_step_j + k_node += k_node_step_j + end + end +end diff --git a/src/solvers/dgsem_tree/dg_3d_parabolic.jl b/src/solvers/dgsem_tree/dg_3d_parabolic.jl index d6d74637021..5b63b971cd8 100644 --- a/src/solvers/dgsem_tree/dg_3d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_3d_parabolic.jl @@ -13,7 +13,7 @@ # 2. compute f(u, grad(u)) # 3. compute div(f(u, grad(u))) (i.e., the "regular" rhs! call) # boundary conditions will be applied to both grad(u) and div(f(u, grad(u))). -function rhs_parabolic!(du, u, t, mesh::TreeMesh{3}, +function rhs_parabolic!(du, u, t, mesh::Union{TreeMesh{3}, P4estMesh{3}}, equations_parabolic::AbstractEquationsParabolic, initial_condition, boundary_conditions_parabolic, source_terms, dg::DG, parabolic_scheme, cache, cache_parabolic) @@ -105,7 +105,7 @@ end # Transform solution variables prior to taking the gradient # (e.g., conservative to primitive variables). Defaults to doing nothing. # TODO: can we avoid copying data? -function transform_variables!(u_transformed, u, mesh::TreeMesh{3}, +function transform_variables!(u_transformed, u, mesh::Union{TreeMesh{3}, P4estMesh{3}}, equations_parabolic::AbstractEquationsParabolic, dg::DG, parabolic_scheme, cache, cache_parabolic) @threaded for element in eachelement(dg, cache) @@ -325,7 +325,8 @@ function prolong2boundaries!(cache_parabolic, flux_viscous, return nothing end -function calc_viscous_fluxes!(flux_viscous, gradients, u_transformed, mesh::TreeMesh{3}, +function calc_viscous_fluxes!(flux_viscous, gradients, u_transformed, + mesh::Union{TreeMesh{3}, P4estMesh{3}}, equations_parabolic::AbstractEquationsParabolic, dg::DG, cache, cache_parabolic) gradients_x, gradients_y, gradients_z = gradients @@ -379,7 +380,7 @@ end function calc_boundary_flux_gradients!(cache, t, boundary_conditions_parabolic::BoundaryConditionPeriodic, - mesh::TreeMesh{3}, + mesh::Union{TreeMesh{3}, P4estMesh{3}}, equations_parabolic::AbstractEquationsParabolic, surface_integral, dg::DG) return nothing @@ -387,7 +388,7 @@ end function calc_boundary_flux_divergence!(cache, t, boundary_conditions_parabolic::BoundaryConditionPeriodic, - mesh::TreeMesh{3}, + mesh::Union{TreeMesh{3}, P4estMesh{3}}, equations_parabolic::AbstractEquationsParabolic, surface_integral, dg::DG) return nothing @@ -806,7 +807,7 @@ end # This is because the parabolic fluxes are assumed to be of the form # `du/dt + df/dx = dg/dx + source(x,t)`, # where f(u) is the inviscid flux and g(u) is the viscous flux. -function apply_jacobian_parabolic!(du, mesh::TreeMesh{3}, +function apply_jacobian_parabolic!(du, mesh::Union{TreeMesh{3}, P4estMesh{3}}, equations::AbstractEquationsParabolic, dg::DG, cache) @threaded for element in eachelement(dg, cache) factor = cache.elements.inverse_jacobian[element] diff --git a/test/test_parabolic_3d.jl b/test/test_parabolic_3d.jl index 1ae5eed44ae..67a27238969 100644 --- a/test/test_parabolic_3d.jl +++ b/test/test_parabolic_3d.jl @@ -86,9 +86,24 @@ isdir(outdir) && rm(outdir, recursive=true) ) end -end + @trixi_testset "P4estMesh3D: elixir_navierstokes_convergence.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_3d_dgsem", "elixir_navierstokes_convergence.jl"), + initial_refinement_level = 2, tspan=(0.0, 0.1), + l2 = [0.00026599105554982194, 0.000461877794472316, 0.0005424899076052261, 0.0004618777944723191, 0.0015846392581126832], + linf = [0.0025241668929956163, 0.006308461681816373, 0.004334939663169113, 0.006308461681804009, 0.03176343480493493] + ) + end + @trixi_testset "P4estMesh3D: elixir_navierstokes_taylor_green_vortex.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_3d_dgsem", "elixir_navierstokes_taylor_green_vortex.jl"), + initial_refinement_level = 2, tspan=(0.0, 0.25), + l2 = [0.0001547509861140407, 0.015637861347119624, 0.015637861347119687, 0.022024699158522523, 0.009711013505930812], + linf = [0.0006696415247340326, 0.03442565722527785, 0.03442565722577423, 0.06295407168705314, 0.032857472756916195] + ) + end + +end # Clean up afterwards: delete Trixi.jl output directory @test_nowarn isdir(outdir) && rm(outdir, recursive=true) -end # module +end # module \ No newline at end of file From d7ea40b19b98cc18d18e5f047131f141d3c08acc Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 25 Jul 2023 18:42:12 +0200 Subject: [PATCH 052/263] reset threads also when initializing the summary callback (#1587) * reset threads also when initializing the summary callback I added the option to reset the threads from Polyester.jl in also in the summary callback. The idea is that this supports another development workflow where we just modify the RHS implementation and call solve again without re-ccreating the ODE. The same comment as in 036eaed82b92be9376c5b610d8d40eddf45ca1fa applies: However, I did not document it in the docstring since we have not documented that we use Polyester.jl threads in general - and the resetting is specific to Polyester.jl. I was not sure whether we still would like to keep the option to change the threading backend any time - although I do not see a good reason why we should do so. --- src/callbacks_step/summary.jl | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/callbacks_step/summary.jl b/src/callbacks_step/summary.jl index 08e13d0b98d..26981a58b73 100644 --- a/src/callbacks_step/summary.jl +++ b/src/callbacks_step/summary.jl @@ -15,10 +15,14 @@ Create and return a callback that prints a human-readable summary of the simulat beginning of a simulation and then resets the timer. When the returned callback is executed directly, the current timer values are shown. """ -function SummaryCallback() +function SummaryCallback(reset_threads = true) + function initialize(cb, u, t, integrator) + initialize_summary_callback(cb, u, t, integrator; + reset_threads) + end DiscreteCallback(summary_callback, summary_callback, save_positions = (false, false), - initialize = initialize_summary_callback) + initialize = initialize) end function Base.show(io::IO, cb::DiscreteCallback{<:Any, <:typeof(summary_callback)}) @@ -139,7 +143,15 @@ end # Print information about the current simulation setup # Note: This is called *after* all initialization is done, but *before* the first time step -function initialize_summary_callback(cb::DiscreteCallback, u, t, integrator) +function initialize_summary_callback(cb::DiscreteCallback, u, t, integrator; + reset_threads = true) + # Optionally reset Polyester.jl threads. See + # https://github.com/trixi-framework/Trixi.jl/issues/1583 + # https://github.com/JuliaSIMD/Polyester.jl/issues/30 + if reset_threads + Polyester.reset_threads!() + end + mpi_isroot() || return nothing print_startup_message() From 53a826b62241fc0f58c0a3cd0a0acc1789a79509 Mon Sep 17 00:00:00 2001 From: Arpit Babbar Date: Wed, 26 Jul 2023 10:47:07 +0530 Subject: [PATCH 053/263] Timestep stamp in mesh file (#1580) * Timestep stamp in mesh file * Update src/callbacks_step/save_solution.jl Fixes other mesh type issue Co-authored-by: Hendrik Ranocha * Add test for multiple mesh files * Keep within pre-existing tests --------- Co-authored-by: Hendrik Ranocha --- src/callbacks_step/save_solution.jl | 9 ++++++++- test/test_mpi_tree.jl | 6 ++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/callbacks_step/save_solution.jl b/src/callbacks_step/save_solution.jl index 1fe0d6b1e15..14ea33368f8 100644 --- a/src/callbacks_step/save_solution.jl +++ b/src/callbacks_step/save_solution.jl @@ -155,7 +155,14 @@ function save_mesh(semi::AbstractSemidiscretization, output_directory, timestep mesh, _, _, _ = mesh_equations_solver_cache(semi) if mesh.unsaved_changes - mesh.current_filename = save_mesh_file(mesh, output_directory) + # We only append the time step number to the mesh file name if it has + # changed during the simulation due to AMR. We do not append it for + # the first time step. + if timestep == 0 + mesh.current_filename = save_mesh_file(mesh, output_directory) + else + mesh.current_filename = save_mesh_file(mesh, output_directory, timestep) + end mesh.unsaved_changes = false end end diff --git a/test/test_mpi_tree.jl b/test/test_mpi_tree.jl index 84d2609cbb1..8403fcf1b04 100644 --- a/test/test_mpi_tree.jl +++ b/test/test_mpi_tree.jl @@ -55,10 +55,16 @@ CI_ON_WINDOWS = (get(ENV, "GITHUB_ACTIONS", false) == "true") && Sys.iswindows() # Linear scalar advection with AMR # These example files are only for testing purposes and have no practical use @trixi_testset "elixir_advection_amr_refine_twice.jl" begin + # Here, we also test that SaveSolutionCallback prints multiple mesh files with AMR + # Start with a clean environment: remove Trixi.jl output directory if it exists + outdir = "out" + isdir(outdir) && rm(outdir, recursive=true) @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_refine_twice.jl"), l2 = [0.00020547512522578292], linf = [0.007831753383083506], coverage_override = (maxiters=6,)) + meshfiles = filter(file -> endswith(file,".h5") && startswith(file,"mesh"), readdir(outdir)) + @test length(meshfiles) > 1 end @trixi_testset "elixir_advection_amr_coarsen_twice.jl" begin From fe0e78c658283db21e581bbbc6d48d0adcf39510 Mon Sep 17 00:00:00 2001 From: Johannes Markert <10619309+jmark@users.noreply.github.com> Date: Wed, 26 Jul 2023 10:47:54 +0200 Subject: [PATCH 054/263] Feature: t8code as meshing backend (#1426) * Initial commit for the new feature using t8code as meshing backend. * Delete t8code_2d_dgsem * Added new examples and tests. Testing updates for T8code.jl. * Worked in the comments. * Fixed spelling. * Update src/auxiliary/auxiliary.jl Co-authored-by: Hendrik Ranocha * Added whitespace in Unions. * Adapted commented out code block reporting the no. of elements per level. * Added dummy save mesh support for . * Added test . * Added to method signature. * Deleted unnecessary comments. * Removed commented out tests. * Fixed Morton ordering bug in 2D at mortar interfaces. * Disabled `save_solution` callbacks and added more tests. * Added more tests. * Updated code according to the review. * Update src/auxiliary/t8code.jl Co-authored-by: Hendrik Ranocha * Update src/auxiliary/t8code.jl Co-authored-by: Hendrik Ranocha * Update src/auxiliary/t8code.jl Co-authored-by: Hendrik Ranocha * Update src/auxiliary/t8code.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/solvers/dgsem_t8code/containers_2d.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Code cleanup. * Updated to T8code@0.3.0 * Fixing minor issues. * Fixed typo. * Code cleanup. * Enabled `set_ghost` in examples. * Generalized type info in function signature. * Added namespace qualifier. * Updated comments. * Refactored code and deleted lots of it. * Removed a copy operation. * Fixed some merging issues and formatting. * Fixed spelling. * Fixed spelling and changed assert macro. * Applied automatic formatting. * Backup. * Removed superfluous outer constructor for T8codeMesh. * Added return statement for consistency. * Fixed wrong indentation by autoformatter. * Added comments. * Made sure an exception is thrown. * Changed flags for sc_init for t8code initialization. * Updated formatting. * Workaround for error about calling MPI routines after MPI has been finalized. * Upped to T8code v0.4.1. * Added mpi_finailize_hook for proper memory cleanup. * Added t8code to test_threaded.jl * Added a `save_mesh_file` call in order to satisfy code coverage. * Improved finalizer logic for T8coeMesh. * Refined code. * Restructured to do blocks. * Moved save_mesh_file call to test file. * Fixed spelling error. --------- Co-authored-by: Johannes Markert Co-authored-by: Hendrik Ranocha --- .github/workflows/ci.yml | 1 + Project.toml | 2 + ...ixir_advection_amr_solution_independent.jl | 143 ++++++ .../elixir_advection_amr_unstructured_flag.jl | 87 ++++ .../t8code_2d_dgsem/elixir_advection_basic.jl | 59 +++ .../elixir_advection_nonconforming_flag.jl | 109 ++++ .../elixir_advection_unstructured_flag.jl | 81 +++ .../elixir_euler_free_stream.jl | 122 +++++ .../t8code_2d_dgsem/elixir_euler_sedov.jl | 97 ++++ .../elixir_euler_shockcapturing_ec.jl | 68 +++ ...e_terms_nonconforming_unstructured_flag.jl | 122 +++++ .../elixir_eulergravity_convergence.jl | 77 +++ .../t8code_2d_dgsem/elixir_mhd_alfven_wave.jl | 60 +++ examples/t8code_2d_dgsem/elixir_mhd_rotor.jl | 134 +++++ .../elixir_shallowwater_source_terms.jl | 60 +++ src/Trixi.jl | 5 +- src/auxiliary/t8code.jl | 486 ++++++++++++++++++ src/callbacks_step/amr.jl | 63 +++ src/callbacks_step/amr_dg2d.jl | 72 ++- src/callbacks_step/analysis.jl | 30 ++ src/callbacks_step/analysis_dg2d.jl | 16 +- src/callbacks_step/save_restart_dg.jl | 3 +- src/callbacks_step/save_solution_dg.jl | 3 +- src/callbacks_step/stepsize_dg2d.jl | 8 +- src/meshes/mesh_io.jl | 9 +- src/meshes/meshes.jl | 1 + src/meshes/t8code_mesh.jl | 345 +++++++++++++ src/solvers/dg.jl | 4 +- src/solvers/dgsem_p4est/containers.jl | 9 +- src/solvers/dgsem_p4est/containers_2d.jl | 5 +- src/solvers/dgsem_p4est/dg_2d.jl | 33 +- src/solvers/dgsem_structured/dg_2d.jl | 19 +- src/solvers/dgsem_t8code/containers.jl | 60 +++ src/solvers/dgsem_t8code/containers_2d.jl | 58 +++ src/solvers/dgsem_t8code/dg.jl | 31 ++ src/solvers/dgsem_tree/dg_2d.jl | 22 +- src/solvers/dgsem_tree/indicators_2d.jl | 3 +- src/solvers/dgsem_unstructured/dg_2d.jl | 10 +- test/runtests.jl | 220 ++++---- test/test_t8code_2d.jl | 182 +++++++ test/test_threaded.jl | 16 + 41 files changed, 2767 insertions(+), 168 deletions(-) create mode 100644 examples/t8code_2d_dgsem/elixir_advection_amr_solution_independent.jl create mode 100644 examples/t8code_2d_dgsem/elixir_advection_amr_unstructured_flag.jl create mode 100644 examples/t8code_2d_dgsem/elixir_advection_basic.jl create mode 100644 examples/t8code_2d_dgsem/elixir_advection_nonconforming_flag.jl create mode 100644 examples/t8code_2d_dgsem/elixir_advection_unstructured_flag.jl create mode 100644 examples/t8code_2d_dgsem/elixir_euler_free_stream.jl create mode 100644 examples/t8code_2d_dgsem/elixir_euler_sedov.jl create mode 100644 examples/t8code_2d_dgsem/elixir_euler_shockcapturing_ec.jl create mode 100644 examples/t8code_2d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_flag.jl create mode 100644 examples/t8code_2d_dgsem/elixir_eulergravity_convergence.jl create mode 100644 examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl create mode 100644 examples/t8code_2d_dgsem/elixir_mhd_rotor.jl create mode 100644 examples/t8code_2d_dgsem/elixir_shallowwater_source_terms.jl create mode 100644 src/auxiliary/t8code.jl create mode 100644 src/meshes/t8code_mesh.jl create mode 100644 src/solvers/dgsem_t8code/containers.jl create mode 100644 src/solvers/dgsem_t8code/containers_2d.jl create mode 100644 src/solvers/dgsem_t8code/dg.jl create mode 100644 test/test_t8code_2d.jl diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0a2c93db3c..4790f93d913 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,6 +69,7 @@ jobs: - structured - p4est_part1 - p4est_part2 + - t8code_part1 - unstructured_dgmulti - parabolic - paper_self_gravitating_gas_dynamics diff --git a/Project.toml b/Project.toml index 94c47a35ac1..db410317851 100644 --- a/Project.toml +++ b/Project.toml @@ -37,6 +37,7 @@ StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" StrideArrays = "d1fa6d79-ef01-42a6-86c9-f7c551f8593b" StructArrays = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" SummationByPartsOperators = "9f78cca6-572e-554e-b819-917d2f1cf240" +T8code = "d0cc0030-9a40-4274-8435-baadcfd54fa1" TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" Triangulate = "f7e6ffb2-c36d-4f8f-a77e-16e897189344" TriplotBase = "981d1d27-644d-49a2-9326-4793e63143c3" @@ -80,6 +81,7 @@ StaticArrays = "1" StrideArrays = "0.1.18" StructArrays = "0.6" SummationByPartsOperators = "0.5.41" +T8code = "0.4.1" TimerOutputs = "0.5" Triangulate = "2.0" TriplotBase = "0.1" diff --git a/examples/t8code_2d_dgsem/elixir_advection_amr_solution_independent.jl b/examples/t8code_2d_dgsem/elixir_advection_amr_solution_independent.jl new file mode 100644 index 00000000000..653bab41e2d --- /dev/null +++ b/examples/t8code_2d_dgsem/elixir_advection_amr_solution_independent.jl @@ -0,0 +1,143 @@ +using OrdinaryDiffEq +using Trixi + +# Define new structs inside a module to allow re-evaluating the file. +module TrixiExtension + +using Trixi + +struct IndicatorSolutionIndependent{Cache <: NamedTuple} <: Trixi.AbstractIndicator + cache::Cache +end + +function IndicatorSolutionIndependent(semi) + basis = semi.solver.basis + alpha = Vector{real(basis)}() + cache = (; semi.mesh, alpha) + return IndicatorSolutionIndependent{typeof(cache)}(cache) +end + +function (indicator::IndicatorSolutionIndependent)(u::AbstractArray{<:Any, 4}, + mesh, equations, dg, cache; + t, kwargs...) + mesh = indicator.cache.mesh + alpha = indicator.cache.alpha + resize!(alpha, nelements(dg, cache)) + + # Predict the theoretical center. + advection_velocity = (0.2, -0.7) + center = t .* advection_velocity + + inner_distance = 1 + outer_distance = 1.85 + + # Iterate over all elements. + for element in 1:length(alpha) + # Calculate periodic distance between cell and center. + # This requires an uncurved mesh! + coordinates = SVector(0.5 * (cache.elements.node_coordinates[1, 1, 1, element] + + cache.elements.node_coordinates[1, end, 1, element]), + 0.5 * (cache.elements.node_coordinates[2, 1, 1, element] + + cache.elements.node_coordinates[2, 1, end, element])) + + # The geometric shape of the amr should be preserved when the base_level is increased. + # This is done by looking at the original coordinates of each cell. + cell_coordinates = original_coordinates(coordinates, 5 / 8) + cell_distance = periodic_distance_2d(cell_coordinates, center, 10) + if cell_distance < (inner_distance + outer_distance) / 2 + cell_coordinates = original_coordinates(coordinates, 5 / 16) + cell_distance = periodic_distance_2d(cell_coordinates, center, 10) + end + + # Set alpha according to cells position inside the circles. + target_level = (cell_distance < inner_distance) + (cell_distance < outer_distance) + alpha[element] = target_level / 2 + end + return alpha +end + +# For periodic domains, distance between two points must take into account +# periodic extensions of the domain. +function periodic_distance_2d(coordinates, center, domain_length) + dx = coordinates .- center + dx_shifted = abs.(dx .% domain_length) + dx_periodic = min.(dx_shifted, domain_length .- dx_shifted) + return sqrt(sum(dx_periodic .^ 2)) +end + +# This takes a cells coordinates and transforms them into the coordinates of a +# parent-cell it originally refined from. It does it so that the parent-cell +# has given cell_length. +function original_coordinates(coordinates, cell_length) + offset = coordinates .% cell_length + offset_sign = sign.(offset) + border = coordinates - offset + center = border + (offset_sign .* cell_length / 2) + return center +end + +end # module TrixiExtension + +import .TrixiExtension + +############################################################################### +# Semidiscretization of the linear advection equation. + +advection_velocity = (0.2, -0.7) +equations = LinearScalarAdvectionEquation2D(advection_velocity) + +initial_condition = initial_condition_gauss + +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) + +coordinates_min = (-5.0, -5.0) +coordinates_max = (5.0, 5.0) + +mapping = Trixi.coordinates2mapping(coordinates_min, coordinates_max) + +trees_per_dimension = (1, 1) + +mesh = T8codeMesh(trees_per_dimension, polydeg = 3, + mapping = mapping, + initial_refinement_level = 1) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 10.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +amr_controller = ControllerThreeLevel(semi, + TrixiExtension.IndicatorSolutionIndependent(semi), + base_level = 4, + med_level = 5, med_threshold = 0.1, + max_level = 6, max_threshold = 0.6) + +amr_callback = AMRCallback(semi, amr_controller, + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) + +stepsize_callback = StepsizeCallback(cfl = 1.6) + +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 new file mode 100644 index 00000000000..adf1d009a59 --- /dev/null +++ b/examples/t8code_2d_dgsem/elixir_advection_amr_unstructured_flag.jl @@ -0,0 +1,87 @@ +using Downloads: download +using OrdinaryDiffEq +using Trixi + +############################################################################### +# Semidiscretization of the linear advection equation. + +advection_velocity = (0.2, -0.7) +equations = LinearScalarAdvectionEquation2D(advection_velocity) + +initial_condition = initial_condition_gauss + +boundary_condition = BoundaryConditionDirichlet(initial_condition) +boundary_conditions = Dict(:all => boundary_condition) + +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) + +# Deformed rectangle that looks like a waving flag, lower and upper faces are +# sinus curves, left and right are vertical lines. +f1(s) = SVector(-5.0, 5 * s - 5.0) +f2(s) = SVector(5.0, 5 * s + 5.0) +f3(s) = SVector(5 * s, -5.0 + 5 * sin(0.5 * pi * s)) +f4(s) = SVector(5 * s, 5.0 + 5 * sin(0.5 * pi * s)) +faces = (f1, f2, f3, f4) + +# This creates a mapping that transforms [-1, 1]^2 to the domain with the faces +# defined above. It generally doesn't work for meshes loaded from mesh files +# because these can be meshes of arbitrary domains, but the mesh below is +# specifically built on the domain [-1, 1]^2. +Trixi.validate_faces(faces) +mapping_flag = Trixi.transfinite_mapping(faces) + +# Unstructured mesh with 24 cells of the square domain [-1, 1]^n +mesh_file = joinpath(@__DIR__, "square_unstructured_2.inp") +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", + mesh_file) + +# INP mesh files are only support by p4est. Hence, we +# create a p4est connecvity object first from which +# we can create a t8code mesh. +conn = Trixi.read_inp_p4est(mesh_file, Val(2)) + +mesh = T8codeMesh{2}(conn, polydeg = 3, + mapping = mapping_flag, + initial_refinement_level = 1) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 10.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first), + base_level = 1, + med_level = 2, med_threshold = 0.1, + max_level = 3, max_threshold = 0.6) +amr_callback = AMRCallback(semi, amr_controller, + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) + +stepsize_callback = StepsizeCallback(cfl = 0.7) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + amr_callback, stepsize_callback) + +############################################################################### +# Run the simulation. + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1, # 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_basic.jl b/examples/t8code_2d_dgsem/elixir_advection_basic.jl new file mode 100644 index 00000000000..efc51226586 --- /dev/null +++ b/examples/t8code_2d_dgsem/elixir_advection_basic.jl @@ -0,0 +1,59 @@ +# The same setup as tree_2d_dgsem/elixir_advection_basic.jl +# to verify the StructuredMesh implementation against TreeMesh + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear advection equation + +advection_velocity = (0.2, -0.7) +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) + +coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) +coordinates_max = (1.0, 1.0) # maximum coordinates (max(x), max(y)) + +mapping = Trixi.coordinates2mapping(coordinates_min, coordinates_max) + +trees_per_dimension = (8, 8) + +mesh = T8codeMesh(trees_per_dimension, polydeg = 3, + mapping = mapping, + initial_refinement_level = 1) + +# 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.0, 1.0)); + +# 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 StepsizeCallback handles the re-calculation of the maximum Δt after each time step +stepsize_callback = StepsizeCallback(cfl = 1.6) + +# Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver +callbacks = CallbackSet(summary_callback, analysis_callback, 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.0, # 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/t8code_2d_dgsem/elixir_advection_nonconforming_flag.jl b/examples/t8code_2d_dgsem/elixir_advection_nonconforming_flag.jl new file mode 100644 index 00000000000..31a8bc93697 --- /dev/null +++ b/examples/t8code_2d_dgsem/elixir_advection_nonconforming_flag.jl @@ -0,0 +1,109 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear advection equation + +advection_velocity = (0.2, -0.7) +equations = LinearScalarAdvectionEquation2D(advection_velocity) + +# Create DG solver with polynomial degree = 4 and (local) Lax-Friedrichs/Rusanov flux as surface flux +solver = DGSEM(polydeg = 4, surface_flux = flux_lax_friedrichs) + +# Deformed rectangle that looks like a waving flag, +# lower and upper faces are sinus curves, left and right are vertical lines. +f1(s) = SVector(-1.0, s - 1.0) +f2(s) = SVector(1.0, s + 1.0) +f3(s) = SVector(s, -1.0 + sin(0.5 * pi * s)) +f4(s) = SVector(s, 1.0 + sin(0.5 * pi * s)) + +faces = (f1, f2, f3, f4) +mapping = Trixi.transfinite_mapping(faces) + +# Create P4estMesh with 3 x 2 trees and 6 x 4 elements, +# approximate the geometry with a smaller polydeg for testing. +trees_per_dimension = (3, 2) +mesh = T8codeMesh(trees_per_dimension, polydeg = 3, + mapping = mapping, + initial_refinement_level = 1) + +function adapt_callback(forest, + forest_from, + which_tree, + lelement_id, + ts, + is_family, + num_elements, + elements_ptr)::Cint + vertex = Vector{Cdouble}(undef, 3) + + elements = unsafe_wrap(Array, elements_ptr, num_elements) + + Trixi.t8_element_vertex_reference_coords(ts, elements[1], 0, pointer(vertex)) + + level = Trixi.t8_element_level(ts, elements[1]) + + # TODO: Make this condition more general. + if vertex[1] < 1e-8 && vertex[2] < 1e-8 && level < 4 + # return true (refine) + return 1 + else + # return false (don't refine) + return 0 + end +end + +Trixi.@T8_ASSERT(Trixi.t8_forest_is_committed(mesh.forest)!=0); + +# Init new forest. +new_forest_ref = Ref{Trixi.t8_forest_t}() +Trixi.t8_forest_init(new_forest_ref); +new_forest = new_forest_ref[] + +# Check out `examples/t8_step4_partition_balance_ghost.jl` in +# https://github.com/DLR-AMR/T8code.jl for detailed explanations. +let set_from = C_NULL, recursive = 1, set_for_coarsening = 0, no_repartition = 0 + Trixi.t8_forest_set_user_data(new_forest, C_NULL) + Trixi.t8_forest_set_adapt(new_forest, mesh.forest, + Trixi.@t8_adapt_callback(adapt_callback), recursive) + Trixi.t8_forest_set_balance(new_forest, set_from, no_repartition) + Trixi.t8_forest_set_partition(new_forest, set_from, set_for_coarsening) + Trixi.t8_forest_set_ghost(new_forest, 1, Trixi.T8_GHOST_FACES) + Trixi.t8_forest_commit(new_forest) +end + +mesh.forest = new_forest + +# 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 0.2 +ode = semidiscretize(semi, (0.0, 0.2)); + +# 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 StepsizeCallback handles the re-calculation of the maximum Δt after each time step +stepsize_callback = StepsizeCallback(cfl = 1.6) + +# Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver +callbacks = CallbackSet(summary_callback, analysis_callback, 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.0, # 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/t8code_2d_dgsem/elixir_advection_unstructured_flag.jl b/examples/t8code_2d_dgsem/elixir_advection_unstructured_flag.jl new file mode 100644 index 00000000000..df9cbc26f6e --- /dev/null +++ b/examples/t8code_2d_dgsem/elixir_advection_unstructured_flag.jl @@ -0,0 +1,81 @@ +using Downloads: download +using OrdinaryDiffEq +using Trixi + +############################################################################### +# Semidiscretization of the linear advection equation. + +advection_velocity = (0.2, -0.7) +equations = LinearScalarAdvectionEquation2D(advection_velocity) + +initial_condition = initial_condition_convergence_test + +boundary_condition = BoundaryConditionDirichlet(initial_condition) +boundary_conditions = Dict(:all => boundary_condition) + +# 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) + +# Deformed rectangle that looks like a waving flag, +# lower and upper faces are sinus curves, left and right are vertical lines. +f1(s) = SVector(-1.0, s - 1.0) +f2(s) = SVector(1.0, s + 1.0) +f3(s) = SVector(s, -1.0 + sin(0.5 * pi * s)) +f4(s) = SVector(s, 1.0 + sin(0.5 * pi * s)) +faces = (f1, f2, f3, f4) + +Trixi.validate_faces(faces) +mapping_flag = Trixi.transfinite_mapping(faces) + +# Unstructured mesh with 24 cells of the square domain [-1, 1]^n. +mesh_file = joinpath(@__DIR__, "square_unstructured_2.inp") +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", + mesh_file) + +# INP mesh files are only support by p4est. Hence, we +# create a p4est connecvity object first from which +# we can create a t8code mesh. +conn = Trixi.read_inp_p4est(mesh_file, Val(2)) + +mesh = T8codeMesh{2}(conn, polydeg = 3, + mapping = mapping_flag, + initial_refinement_level = 2) + +# A semidiscretization collects data structures and functions for the spatial discretization. +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span from 0.0 to 0.2. +tspan = (0.0, 0.2) +ode = semidiscretize(semi, tspan) + +# 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 StepsizeCallback handles the re-calculation of the maximum Δt after each +# time step. +stepsize_callback = StepsizeCallback(cfl = 1.4) + +# Create a CallbackSet to collect all callbacks such that they can be passed to +# the ODE solver. +callbacks = CallbackSet(summary_callback, analysis_callback, 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.0, # 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/t8code_2d_dgsem/elixir_euler_free_stream.jl b/examples/t8code_2d_dgsem/elixir_euler_free_stream.jl new file mode 100644 index 00000000000..01e0449c67e --- /dev/null +++ b/examples/t8code_2d_dgsem/elixir_euler_free_stream.jl @@ -0,0 +1,122 @@ +using Downloads: download +using OrdinaryDiffEq +using Trixi + +############################################################################### +# Semidiscretization of the compressible Euler equations. + +equations = CompressibleEulerEquations2D(1.4) + +initial_condition = initial_condition_constant + +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) + +# Mapping as described in https://arxiv.org/abs/2012.12040 but reduced to 2D +function mapping(xi_, eta_) + # Transform input variables between -1 and 1 onto [0,3] + xi = 1.5 * xi_ + 1.5 + eta = 1.5 * eta_ + 1.5 + + y = eta + 3 / 8 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3)) + + x = xi + 3 / 8 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3)) + + return SVector(x, y) +end + +############################################################################### +# Get the uncurved mesh from a file (downloads the file if not available locally) + +# Unstructured mesh with 48 cells of the square domain [-1, 1]^n +mesh_file = joinpath(@__DIR__, "square_unstructured_1.inp") +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/a075f8ec39a67fa9fad8f6f84342cbca/raw/a7206a02ed3a5d3cadacd8d9694ac154f9151db7/square_unstructured_1.inp", + mesh_file) + +# INP mesh files are only support by p4est. Hence, we +# create a p4est connecvity object first from which +# we can create a t8code mesh. +conn = Trixi.read_inp_p4est(mesh_file, Val(2)) + +mesh = T8codeMesh{2}(conn, polydeg = 3, + mapping = mapping, + initial_refinement_level = 1) + +function adapt_callback(forest, + forest_from, + which_tree, + lelement_id, + ts, + is_family, + num_elements, + elements_ptr)::Cint + vertex = Vector{Cdouble}(undef, 3) + + elements = unsafe_wrap(Array, elements_ptr, num_elements) + + Trixi.t8_element_vertex_reference_coords(ts, elements[1], 0, pointer(vertex)) + + level = Trixi.t8_element_level(ts, elements[1]) + + # TODO: Make this condition more general. + if vertex[1] < 1e-8 && vertex[2] < 1e-8 && level < 3 + # return true (refine) + return 1 + else + # return false (don't refine) + return 0 + end +end + +Trixi.@T8_ASSERT(Trixi.t8_forest_is_committed(mesh.forest)!=0); + +# Init new forest. +new_forest_ref = Ref{Trixi.t8_forest_t}() +Trixi.t8_forest_init(new_forest_ref); +new_forest = new_forest_ref[] + +# Check out `examples/t8_step4_partition_balance_ghost.jl` in +# https://github.com/DLR-AMR/T8code.jl for detailed explanations. +let set_from = C_NULL, recursive = 1, set_for_coarsening = 0, no_repartition = 0 + Trixi.t8_forest_set_user_data(new_forest, C_NULL) + Trixi.t8_forest_set_adapt(new_forest, mesh.forest, + Trixi.@t8_adapt_callback(adapt_callback), recursive) + Trixi.t8_forest_set_balance(new_forest, set_from, no_repartition) + Trixi.t8_forest_set_partition(new_forest, set_from, set_for_coarsening) + Trixi.t8_forest_set_ghost(new_forest, 1, Trixi.T8_GHOST_FACES) + Trixi.t8_forest_commit(new_forest) +end + +mesh.forest = new_forest + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = Dict(:all => BoundaryConditionDirichlet(initial_condition))) + +############################################################################### +# 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) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +stepsize_callback = StepsizeCallback(cfl = 2.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_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_euler_sedov.jl b/examples/t8code_2d_dgsem/elixir_euler_sedov.jl new file mode 100644 index 00000000000..965d794f8dc --- /dev/null +++ b/examples/t8code_2d_dgsem/elixir_euler_sedov.jl @@ -0,0 +1,97 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# Semidiscretization of the compressible Euler equations. + +equations = CompressibleEulerEquations2D(1.4) + +""" + initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations2D) + +The Sedov blast wave setup based on Flash +- http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 +""" +function initial_condition_sedov_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) + + # Setup based on http://flash.uchicago.edu/site/flashcode/user_support/flash_ug_devel/node184.html#SECTION010114000000000000000 + r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) + E = 1.0 + p0_inner = 3 * (equations.gamma - 1) * E / (3 * pi * r0^2) + p0_outer = 1.0e-5 # = true Sedov setup + + # Calculate primitive variables + rho = 1.0 + 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_sedov_blast_wave + +# Get the DG approximation space +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) + +############################################################################### + +coordinates_min = (-1.0, -1.0) +coordinates_max = (1.0, 1.0) + +mapping = Trixi.coordinates2mapping(coordinates_min, coordinates_max) + +trees_per_dimension = (4, 4) + +mesh = T8codeMesh(trees_per_dimension, polydeg = 4, + mapping = mapping, + initial_refinement_level = 2, periodicity = true) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 12.5) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 300 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +stepsize_callback = StepsizeCallback(cfl = 0.5) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_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_euler_shockcapturing_ec.jl b/examples/t8code_2d_dgsem/elixir_euler_shockcapturing_ec.jl new file mode 100644 index 00000000000..55a9063a001 --- /dev/null +++ b/examples/t8code_2d_dgsem/elixir_euler_shockcapturing_ec.jl @@ -0,0 +1,68 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# Semidiscretization of the compressible Euler equations. + +equations = CompressibleEulerEquations2D(1.4) + +initial_condition = initial_condition_weak_blast_wave + +surface_flux = flux_ranocha +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) + +############################################################################### + +coordinates_min = (-1.0, -1.0) +coordinates_max = (1.0, 1.0) + +mapping = Trixi.coordinates2mapping(coordinates_min, coordinates_max) + +trees_per_dimension = (4, 4) + +mesh = T8codeMesh(trees_per_dimension, polydeg = 4, + mapping = mapping, + initial_refinement_level = 2, periodicity = true) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 2.0) +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.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_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_euler_source_terms_nonconforming_unstructured_flag.jl b/examples/t8code_2d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_flag.jl new file mode 100644 index 00000000000..21f26d79ba8 --- /dev/null +++ b/examples/t8code_2d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_flag.jl @@ -0,0 +1,122 @@ +using Downloads: download +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations2D(1.4) + +initial_condition = initial_condition_convergence_test + +source_terms = source_terms_convergence_test + +# BCs must be passed as Dict +boundary_condition = BoundaryConditionDirichlet(initial_condition) +boundary_conditions = Dict(:all => boundary_condition) + +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) + +# Deformed rectangle that looks like a waving flag, +# lower and upper faces are sinus curves, left and right are vertical lines. +f1(s) = SVector(-1.0, s - 1.0) +f2(s) = SVector(1.0, s + 1.0) +f3(s) = SVector(s, -1.0 + sin(0.5 * pi * s)) +f4(s) = SVector(s, 1.0 + sin(0.5 * pi * s)) +faces = (f1, f2, f3, f4) + +Trixi.validate_faces(faces) +mapping_flag = Trixi.transfinite_mapping(faces) + +# Get the uncurved mesh from a file (downloads the file if not available locally) +# Unstructured mesh with 24 cells of the square domain [-1, 1]^n +mesh_file = joinpath(@__DIR__, "square_unstructured_2.inp") +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", + mesh_file) + +# INP mesh files are only support by p4est. Hence, we +# create a p4est connecvity object first from which +# we can create a t8code mesh. +conn = Trixi.read_inp_p4est(mesh_file, Val(2)) + +mesh = T8codeMesh{2}(conn, polydeg = 3, + mapping = mapping_flag, + initial_refinement_level = 1) + +function adapt_callback(forest, + forest_from, + which_tree, + lelement_id, + ts, + is_family, + num_elements, + elements_ptr)::Cint + vertex = Vector{Cdouble}(undef, 3) + + elements = unsafe_wrap(Array, elements_ptr, num_elements) + + Trixi.t8_element_vertex_reference_coords(ts, elements[1], 0, pointer(vertex)) + + level = Trixi.t8_element_level(ts, elements[1]) + + # TODO: Make this condition more general. + if vertex[1] < 1e-8 && vertex[2] < 1e-8 && level < 2 + # return true (refine) + return 1 + else + # return false (don't refine) + return 0 + end +end + +@assert(Trixi.t8_forest_is_committed(mesh.forest)!=0); + +# Init new forest. +new_forest_ref = Ref{Trixi.t8_forest_t}() +Trixi.t8_forest_init(new_forest_ref); +new_forest = new_forest_ref[] + +# Check out `examples/t8_step4_partition_balance_ghost.jl` in +# https://github.com/DLR-AMR/T8code.jl for detailed explanations. +let set_from = C_NULL, recursive = 1, set_for_coarsening = 0, no_repartition = 0 + Trixi.t8_forest_set_user_data(new_forest, C_NULL) + Trixi.t8_forest_set_adapt(new_forest, mesh.forest, + Trixi.@t8_adapt_callback(adapt_callback), recursive) + Trixi.t8_forest_set_balance(new_forest, set_from, no_repartition) + Trixi.t8_forest_set_partition(new_forest, set_from, set_for_coarsening) + Trixi.t8_forest_set_ghost(new_forest, 1, Trixi.T8_GHOST_FACES) + Trixi.t8_forest_commit(new_forest) +end + +mesh.forest = new_forest + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms, + boundary_conditions = boundary_conditions) + +############################################################################### +# 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) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +stepsize_callback = StepsizeCallback(cfl = 0.8) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_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_eulergravity_convergence.jl b/examples/t8code_2d_dgsem/elixir_eulergravity_convergence.jl new file mode 100644 index 00000000000..32649eacff4 --- /dev/null +++ b/examples/t8code_2d_dgsem/elixir_eulergravity_convergence.jl @@ -0,0 +1,77 @@ +using OrdinaryDiffEq +using Trixi + +initial_condition = initial_condition_eoc_test_coupled_euler_gravity + +############################################################################### +# semidiscretization of the compressible Euler equations +gamma = 2.0 +equations_euler = CompressibleEulerEquations2D(gamma) + +polydeg = 3 +solver_euler = DGSEM(polydeg, flux_hll) + +coordinates_min = (0.0, 0.0) +coordinates_max = (2.0, 2.0) + +trees_per_dimension = (1, 1) + +mapping = Trixi.coordinates2mapping(coordinates_min, coordinates_max) + +mesh = T8codeMesh(trees_per_dimension, polydeg = 1, + mapping = mapping, + initial_refinement_level = 2) + +semi_euler = SemidiscretizationHyperbolic(mesh, equations_euler, initial_condition, solver_euler, + source_terms=source_terms_eoc_test_coupled_euler_gravity) + + +############################################################################### +# semidiscretization of the hyperbolic diffusion equations +equations_gravity = HyperbolicDiffusionEquations2D() + +solver_gravity = DGSEM(polydeg, flux_lax_friedrichs) + +semi_gravity = SemidiscretizationHyperbolic(mesh, equations_gravity, initial_condition, solver_gravity, + source_terms=source_terms_harmonic) + + +############################################################################### +# combining both semidiscretizations for Euler + self-gravity +parameters = ParametersEulerGravity(background_density=2.0, # aka rho0 + # rho0 is (ab)used to add a "+8π" term to the source terms + # for the manufactured solution + gravitational_constant=1.0, # aka G + cfl=1.1, + resid_tol=1.0e-10, + n_iterations_max=1000, + timestep_gravity=timestep_gravity_erk52_3Sstar!) + +semi = SemidiscretizationEulerGravity(semi_euler, semi_gravity, parameters) + + +############################################################################### +# ODE solvers, callbacks etc. +tspan = (0.0, 0.5) +ode = semidiscretize(semi, tspan); + +summary_callback = SummaryCallback() + +stepsize_callback = StepsizeCallback(cfl=0.8) + +analysis_interval = 100 +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +analysis_callback = AnalysisCallback(semi_euler, interval=analysis_interval, + save_analysis=true) + +callbacks = CallbackSet(summary_callback, stepsize_callback, + analysis_callback, alive_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 +println("Number of gravity subcycles: ", semi.gravity_counter.ncalls_since_readout) diff --git a/examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl b/examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl new file mode 100644 index 00000000000..463f916fa2e --- /dev/null +++ b/examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl @@ -0,0 +1,60 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# Semidiscretization of the compressible ideal GLM-MHD equations. + +gamma = 5/3 +equations = IdealGlmMhdEquations2D(gamma) + +initial_condition = initial_condition_convergence_test + +# Get the DG approximation space +volume_flux = (flux_central, flux_nonconservative_powell) +solver = DGSEM(polydeg=4, surface_flux=(flux_hll, flux_nonconservative_powell), + volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = (0.0 , 0.0 ) +coordinates_max = (sqrt(2.0), sqrt(2.0)) + +mapping = Trixi.coordinates2mapping(coordinates_min, coordinates_max) + +trees_per_dimension = (8, 8) + +mesh = T8codeMesh(trees_per_dimension, polydeg=3, + mapping=mapping, + initial_refinement_level=0, periodicity=true) + +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) + +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +cfl = 0.9 +stepsize_callback = StepsizeCallback(cfl=cfl) + +glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + stepsize_callback, + glm_speed_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_mhd_rotor.jl b/examples/t8code_2d_dgsem/elixir_mhd_rotor.jl new file mode 100644 index 00000000000..9a4bd99e444 --- /dev/null +++ b/examples/t8code_2d_dgsem/elixir_mhd_rotor.jl @@ -0,0 +1,134 @@ +using Downloads: download +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible ideal GLM-MHD equations +equations = IdealGlmMhdEquations2D(1.4) + +""" + initial_condition_rotor(x, t, equations::IdealGlmMhdEquations2D) + +The classical MHD rotor test case. Here, the setup is taken from +- Dominik Derigs, Gregor J. Gassner, Stefanie Walch & Andrew R. Winters (2018) + Entropy Stable Finite Volume Approximations for Ideal Magnetohydrodynamics + [doi: 10.1365/s13291-018-0178-9](https://doi.org/10.1365/s13291-018-0178-9) +""" +function initial_condition_rotor(x, t, equations::IdealGlmMhdEquations2D) + # setup taken from Derigs et al. DMV article (2018) + # domain must be [0, 1] x [0, 1], γ = 1.4 + dx = x[1] - 0.5 + dy = x[2] - 0.5 + r = sqrt(dx^2 + dy^2) + f = (0.115 - r) / 0.015 + if r <= 0.1 + rho = 10.0 + v1 = -20.0 * dy + v2 = 20.0 * dx + elseif r >= 0.115 + rho = 1.0 + v1 = 0.0 + v2 = 0.0 + else + rho = 1.0 + 9.0 * f + v1 = -20.0 * f * dy + v2 = 20.0 * f * dx + end + v3 = 0.0 + p = 1.0 + B1 = 5.0 / sqrt(4.0 * pi) + B2 = 0.0 + B3 = 0.0 + psi = 0.0 + return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3, psi), equations) +end +initial_condition = initial_condition_rotor + +surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell) +volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) +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(basis, surface_flux, volume_integral) + +# Affine type mapping to take the [-1,1]^2 domain from the mesh file +# and put it onto the rotor domain [0,1]^2 and then warp it with a mapping +# as described in https://arxiv.org/abs/2012.12040 +function mapping_twist(xi, eta) + y = 0.5 * (eta + 1.0) + + 0.05 * cos(1.5 * pi * (2.0 * xi - 1.0)) * cos(0.5 * pi * (2.0 * eta - 1.0)) + x = 0.5 * (xi + 1.0) + 0.05 * cos(0.5 * pi * (2.0 * xi - 1.0)) * cos(2.0 * pi * y) + return SVector(x, y) +end + +mesh_file = joinpath(@__DIR__, "square_unstructured_2.inp") +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", + mesh_file) + +# INP mesh files are only support by p4est. Hence, we +# create a p4est connecvity object first from which +# we can create a t8code mesh. +conn = Trixi.read_inp_p4est(mesh_file, Val(2)) + +mesh = T8codeMesh{2}(conn, polydeg = 4, + mapping = mapping_twist, + initial_refinement_level = 1) + +boundary_condition = BoundaryConditionDirichlet(initial_condition) +boundary_conditions = Dict(:all => boundary_condition) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.15) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +amr_indicator = IndicatorLöhner(semi, + variable = density_pressure) + +amr_controller = ControllerThreeLevel(semi, amr_indicator, + base_level = 1, + med_level = 3, med_threshold = 0.05, + max_level = 5, max_threshold = 0.1) +amr_callback = AMRCallback(semi, amr_controller, + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) + +cfl = 0.5 +stepsize_callback = StepsizeCallback(cfl = cfl) + +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + amr_callback, + stepsize_callback, + glm_speed_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_shallowwater_source_terms.jl b/examples/t8code_2d_dgsem/elixir_shallowwater_source_terms.jl new file mode 100644 index 00000000000..c19f440ebc7 --- /dev/null +++ b/examples/t8code_2d_dgsem/elixir_shallowwater_source_terms.jl @@ -0,0 +1,60 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# Semidiscretization of the shallow water equations. + +equations = ShallowWaterEquations2D(gravity_constant=9.81) + +initial_condition = initial_condition_convergence_test # MMS EOC test + + +############################################################################### +# Get the DG approximation space + +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) +solver = DGSEM(polydeg=3, surface_flux=(flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), + volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) + +############################################################################### +# Get the P4estMesh and setup a periodic mesh + +coordinates_min = (0.0, 0.0) # minimum coordinates (min(x), min(y)) +coordinates_max = (sqrt(2.0), sqrt(2.0)) # maximum coordinates (max(x), max(y)) + +mapping = Trixi.coordinates2mapping(coordinates_min, coordinates_max) + +trees_per_dimension = (8, 8) + +mesh = T8codeMesh(trees_per_dimension, polydeg=3, + mapping=mapping, + initial_refinement_level=1) + +# A semidiscretization collects data structures and functions for the spatial discretization +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms=source_terms_convergence_test) + + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span from 0.0 to 1.0 +tspan = (0.0, 1.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 500 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) + +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) + +############################################################################### +# run the simulation + +# use a Runge-Kutta method with automatic (error based) time step size control +sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-8, reltol=1.0e-8, + ode_default_options()..., callback=callbacks); +summary_callback() # print the timer summary diff --git a/src/Trixi.jl b/src/Trixi.jl index b0c872b1904..990c33f3c94 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -54,6 +54,7 @@ using Octavian: Octavian, matmul! using Polyester: Polyester, @batch # You know, the cheapest threads you can find... using OffsetArrays: OffsetArray, OffsetVector using P4est +using T8code using Setfield: @set using RecipesBase: RecipesBase using Requires: @require @@ -110,6 +111,7 @@ include("basic_types.jl") include("auxiliary/auxiliary.jl") include("auxiliary/mpi.jl") include("auxiliary/p4est.jl") +include("auxiliary/t8code.jl") include("equations/equations.jl") include("meshes/meshes.jl") include("solvers/solvers.jl") @@ -210,7 +212,7 @@ export entropy, energy_total, energy_kinetic, energy_internal, energy_magnetic, export lake_at_rest_error export ncomponents, eachcomponent -export TreeMesh, StructuredMesh, UnstructuredMesh2D, P4estMesh +export TreeMesh, StructuredMesh, UnstructuredMesh2D, P4estMesh, T8codeMesh export DG, DGSEM, LobattoLegendreBasis, @@ -277,6 +279,7 @@ function __init__() init_mpi() init_p4est() + init_t8code() register_error_hints() diff --git a/src/auxiliary/t8code.jl b/src/auxiliary/t8code.jl new file mode 100644 index 00000000000..37cb782bb93 --- /dev/null +++ b/src/auxiliary/t8code.jl @@ -0,0 +1,486 @@ +""" + init_t8code() + +Initialize `t8code` by calling `sc_init`, `p4est_init`, and `t8_init` while +setting the log level to `SC_LP_ERROR`. This function will check if `t8code` +is already initialized and if yes, do nothing, thus it is safe to call it +multiple times. +""" +function init_t8code() + t8code_package_id = t8_get_package_id() + if t8code_package_id >= 0 + return nothing + end + + # Initialize the sc library, has to happen before we initialize t8code. + let catch_signals = 0, print_backtrace = 0, log_handler = C_NULL + T8code.Libt8.sc_init(mpi_comm(), catch_signals, print_backtrace, log_handler, + T8code.Libt8.SC_LP_ERROR) + end + + if T8code.Libt8.p4est_is_initialized() == 0 + # Initialize `p4est` with log level ERROR to prevent a lot of output in AMR simulations + T8code.Libt8.p4est_init(C_NULL, T8code.Libt8.SC_LP_ERROR) + end + + # Initialize t8code with log level ERROR to prevent a lot of output in AMR simulations. + t8_init(T8code.Libt8.SC_LP_ERROR) + + if haskey(ENV, "TRIXI_T8CODE_SC_FINALIZE") + # Normally, `sc_finalize` should always be called during shutdown of an + # application. It checks whether there is still un-freed memory by t8code + # and/or T8code.jl and throws an exception if this is the case. For + # production runs this is not mandatory, but is helpful during + # development. Hence, this option is only activated when environment + # variable TRIXI_T8CODE_SC_FINALIZE exists. + @warn "T8code.jl: sc_finalize will be called during shutdown of Trixi.jl." + MPI.add_finalize_hook!(T8code.Libt8.sc_finalize) + end + + return nothing +end + +function trixi_t8_unref_forest(forest) + t8_forest_unref(Ref(forest)) +end + +function t8_free(ptr) + T8code.Libt8.sc_free(t8_get_package_id(), ptr) +end + +function trixi_t8_count_interfaces(forest) + # Check that forest is a committed, that is valid and usable, forest. + @assert t8_forest_is_committed(forest) != 0 + + # Get the number of local elements of forest. + num_local_elements = t8_forest_get_local_num_elements(forest) + # Get the number of ghost elements of forest. + num_ghost_elements = t8_forest_get_num_ghosts(forest) + # Get the number of trees that have elements of this process. + num_local_trees = t8_forest_get_num_local_trees(forest) + + current_index = t8_locidx_t(0) + + local_num_conform = 0 + local_num_mortars = 0 + local_num_boundary = 0 + + for itree in 0:(num_local_trees - 1) + tree_class = t8_forest_get_tree_class(forest, itree) + eclass_scheme = t8_forest_get_eclass_scheme(forest, tree_class) + + # Get the number of elements of this tree. + num_elements_in_tree = t8_forest_get_tree_num_elements(forest, itree) + + for ielement in 0:(num_elements_in_tree - 1) + element = t8_forest_get_element_in_tree(forest, itree, ielement) + + level = t8_element_level(eclass_scheme, element) + + num_faces = t8_element_num_faces(eclass_scheme, element) + + for iface in 0:(num_faces - 1) + pelement_indices_ref = Ref{Ptr{t8_locidx_t}}() + pneighbor_leafs_ref = Ref{Ptr{Ptr{t8_element}}}() + pneigh_scheme_ref = Ref{Ptr{t8_eclass_scheme}}() + + dual_faces_ref = Ref{Ptr{Cint}}() + num_neighbors_ref = Ref{Cint}() + + forest_is_balanced = Cint(1) + + t8_forest_leaf_face_neighbors(forest, itree, element, + pneighbor_leafs_ref, iface, dual_faces_ref, + num_neighbors_ref, + pelement_indices_ref, pneigh_scheme_ref, + forest_is_balanced) + + num_neighbors = num_neighbors_ref[] + neighbor_ielements = unsafe_wrap(Array, pelement_indices_ref[], + num_neighbors) + neighbor_leafs = unsafe_wrap(Array, pneighbor_leafs_ref[], num_neighbors) + neighbor_scheme = pneigh_scheme_ref[] + + if num_neighbors > 0 + neighbor_level = t8_element_level(neighbor_scheme, neighbor_leafs[1]) + + # Conforming interface: The second condition ensures we only visit the interface once. + if level == neighbor_level && current_index <= neighbor_ielements[1] + local_num_conform += 1 + elseif level < neighbor_level + local_num_mortars += 1 + end + + else + local_num_boundary += 1 + end + + t8_free(dual_faces_ref[]) + t8_free(pneighbor_leafs_ref[]) + t8_free(pelement_indices_ref[]) + end # for + + current_index += 1 + end # for + end # for + + return (interfaces = local_num_conform, + mortars = local_num_mortars, + boundaries = local_num_boundary) +end + +function trixi_t8_fill_mesh_info(forest, elements, interfaces, mortars, boundaries, + boundary_names) + # Check that forest is a committed, that is valid and usable, forest. + @assert t8_forest_is_committed(forest) != 0 + + # Get the number of local elements of forest. + num_local_elements = t8_forest_get_local_num_elements(forest) + # Get the number of ghost elements of forest. + num_ghost_elements = t8_forest_get_num_ghosts(forest) + # Get the number of trees that have elements of this process. + num_local_trees = t8_forest_get_num_local_trees(forest) + + current_index = t8_locidx_t(0) + + local_num_conform = 0 + local_num_mortars = 0 + local_num_boundary = 0 + + for itree in 0:(num_local_trees - 1) + tree_class = t8_forest_get_tree_class(forest, itree) + eclass_scheme = t8_forest_get_eclass_scheme(forest, tree_class) + + # Get the number of elements of this tree. + num_elements_in_tree = t8_forest_get_tree_num_elements(forest, itree) + + for ielement in 0:(num_elements_in_tree - 1) + element = t8_forest_get_element_in_tree(forest, itree, ielement) + + level = t8_element_level(eclass_scheme, element) + + num_faces = t8_element_num_faces(eclass_scheme, element) + + for iface in 0:(num_faces - 1) + + # Compute the `orientation` of the touching faces. + if t8_element_is_root_boundary(eclass_scheme, element, iface) == 1 + cmesh = t8_forest_get_cmesh(forest) + itree_in_cmesh = t8_forest_ltreeid_to_cmesh_ltreeid(forest, itree) + iface_in_tree = t8_element_tree_face(eclass_scheme, element, iface) + orientation_ref = Ref{Cint}() + + t8_cmesh_get_face_neighbor(cmesh, itree_in_cmesh, iface_in_tree, C_NULL, + orientation_ref) + orientation = orientation_ref[] + else + orientation = zero(Cint) + end + + pelement_indices_ref = Ref{Ptr{t8_locidx_t}}() + pneighbor_leafs_ref = Ref{Ptr{Ptr{t8_element}}}() + pneigh_scheme_ref = Ref{Ptr{t8_eclass_scheme}}() + + dual_faces_ref = Ref{Ptr{Cint}}() + num_neighbors_ref = Ref{Cint}() + + forest_is_balanced = Cint(1) + + t8_forest_leaf_face_neighbors(forest, itree, element, + pneighbor_leafs_ref, iface, dual_faces_ref, + num_neighbors_ref, + pelement_indices_ref, pneigh_scheme_ref, + forest_is_balanced) + + num_neighbors = num_neighbors_ref[] + dual_faces = unsafe_wrap(Array, dual_faces_ref[], num_neighbors) + neighbor_ielements = unsafe_wrap(Array, pelement_indices_ref[], + num_neighbors) + neighbor_leafs = unsafe_wrap(Array, pneighbor_leafs_ref[], num_neighbors) + neighbor_scheme = pneigh_scheme_ref[] + + if num_neighbors > 0 + neighbor_level = t8_element_level(neighbor_scheme, neighbor_leafs[1]) + + # Conforming interface: The second condition ensures we only visit the interface once. + if level == neighbor_level && current_index <= neighbor_ielements[1] + local_num_conform += 1 + + faces = (iface, dual_faces[1]) + interface_id = local_num_conform + + # Write data to interfaces container. + interfaces.neighbor_ids[1, interface_id] = current_index + 1 + interfaces.neighbor_ids[2, interface_id] = neighbor_ielements[1] + 1 + + # Iterate over primary and secondary element. + for side in 1:2 + # Align interface in positive coordinate direction of primary element. + # For orientation == 1, the secondary element needs to be indexed backwards + # relative to the interface. + if side == 1 || orientation == 0 + # Forward indexing + indexing = :i_forward + else + # Backward indexing + indexing = :i_backward + end + + if faces[side] == 0 + # Index face in negative x-direction + interfaces.node_indices[side, interface_id] = (:begin, + indexing) + elseif faces[side] == 1 + # Index face in positive x-direction + interfaces.node_indices[side, interface_id] = (:end, + indexing) + elseif faces[side] == 2 + # Index face in negative y-direction + interfaces.node_indices[side, interface_id] = (indexing, + :begin) + else # faces[side] == 3 + # Index face in positive y-direction + interfaces.node_indices[side, interface_id] = (indexing, + :end) + end + end + + # Non-conforming interface. + elseif level < neighbor_level + local_num_mortars += 1 + + faces = (dual_faces[1], iface) + + mortar_id = local_num_mortars + + # Last entry is the large element. + mortars.neighbor_ids[end, mortar_id] = current_index + 1 + + # First `1:end-1` entries are the smaller elements. + mortars.neighbor_ids[1:(end - 1), mortar_id] .= neighbor_ielements .+ + 1 + + for side in 1:2 + # Align mortar in positive coordinate direction of small side. + # For orientation == 1, the large side needs to be indexed backwards + # relative to the mortar. + if side == 1 || orientation == 0 + # Forward indexing for small side or orientation == 0. + indexing = :i_forward + else + # Backward indexing for large side with reversed orientation. + indexing = :i_backward + # Since the orientation is reversed we have to account for this + # when filling the `neighbor_ids` array. + mortars.neighbor_ids[1, mortar_id] = neighbor_ielements[2] + + 1 + mortars.neighbor_ids[2, mortar_id] = neighbor_ielements[1] + + 1 + end + + if faces[side] == 0 + # Index face in negative x-direction + mortars.node_indices[side, mortar_id] = (:begin, indexing) + elseif faces[side] == 1 + # Index face in positive x-direction + mortars.node_indices[side, mortar_id] = (:end, indexing) + elseif faces[side] == 2 + # Index face in negative y-direction + mortars.node_indices[side, mortar_id] = (indexing, :begin) + else # faces[side] == 3 + # Index face in positive y-direction + mortars.node_indices[side, mortar_id] = (indexing, :end) + end + end + + # else: "level > neighbor_level" is skipped since we visit the mortar interface only once. + end + + # Domain boundary. + else + local_num_boundary += 1 + boundary_id = local_num_boundary + + boundaries.neighbor_ids[boundary_id] = current_index + 1 + + if iface == 0 + # Index face in negative x-direction. + boundaries.node_indices[boundary_id] = (:begin, :i_forward) + elseif iface == 1 + # Index face in positive x-direction. + boundaries.node_indices[boundary_id] = (:end, :i_forward) + elseif iface == 2 + # Index face in negative y-direction. + boundaries.node_indices[boundary_id] = (:i_forward, :begin) + else # iface == 3 + # Index face in positive y-direction. + boundaries.node_indices[boundary_id] = (:i_forward, :end) + end + + # One-based indexing. + boundaries.name[boundary_id] = boundary_names[iface + 1, itree + 1] + end + + t8_free(dual_faces_ref[]) + t8_free(pneighbor_leafs_ref[]) + t8_free(pelement_indices_ref[]) + end # for iface = ... + + current_index += 1 + end # for + end # for + + return (interfaces = local_num_conform, + mortars = local_num_mortars, + boundaries = local_num_boundary) +end + +function trixi_t8_get_local_element_levels(forest) + # Check that forest is a committed, that is valid and usable, forest. + @assert t8_forest_is_committed(forest) != 0 + + levels = Vector{Int}(undef, t8_forest_get_local_num_elements(forest)) + + # Get the number of trees that have elements of this process. + num_local_trees = t8_forest_get_num_local_trees(forest) + + current_index = 0 + + for itree in 0:(num_local_trees - 1) + tree_class = t8_forest_get_tree_class(forest, itree) + eclass_scheme = t8_forest_get_eclass_scheme(forest, tree_class) + + # Get the number of elements of this tree. + num_elements_in_tree = t8_forest_get_tree_num_elements(forest, itree) + + for ielement in 0:(num_elements_in_tree - 1) + element = t8_forest_get_element_in_tree(forest, itree, ielement) + current_index += 1 + levels[current_index] = t8_element_level(eclass_scheme, element) + end # for + end # for + + return levels +end + +# Callback function prototype to decide for refining and coarsening. +# If `is_family` equals 1, the first `num_elements` in elements +# form a family and we decide whether this family should be coarsened +# or only the first element should be refined. +# Otherwise `is_family` must equal zero and we consider the first entry +# of the element array for refinement. +# Entries of the element array beyond the first `num_elements` are undefined. +# \param [in] forest the forest to which the new elements belong +# \param [in] forest_from the forest that is adapted. +# \param [in] which_tree the local tree containing `elements` +# \param [in] lelement_id the local element id in `forest_old` in the tree of the current element +# \param [in] ts the eclass scheme of the tree +# \param [in] is_family if 1, the first `num_elements` entries in `elements` form a family. If 0, they do not. +# \param [in] num_elements the number of entries in `elements` that are defined +# \param [in] elements Pointers to a family or, if `is_family` is zero, +# pointer to one element. +# \return greater zero if the first entry in `elements` should be refined, +# smaller zero if the family `elements` shall be coarsened, +# zero else. +function adapt_callback(forest, + forest_from, + which_tree, + lelement_id, + ts, + is_family, + num_elements, + elements)::Cint + num_levels = t8_forest_get_local_num_elements(forest_from) + + indicator_ptr = Ptr{Int}(t8_forest_get_user_data(forest)) + indicators = unsafe_wrap(Array, indicator_ptr, num_levels) + + offset = t8_forest_get_tree_element_offset(forest_from, which_tree) + + # Only allow coarsening for complete families. + if indicators[offset + lelement_id + 1] < 0 && is_family == 0 + return Cint(0) + end + + return Cint(indicators[offset + lelement_id + 1]) +end + +function trixi_t8_adapt_new(old_forest, indicators) + # Check that forest is a committed, that is valid and usable, forest. + @assert t8_forest_is_committed(old_forest) != 0 + + # Init new forest. + new_forest_ref = Ref{t8_forest_t}() + t8_forest_init(new_forest_ref) + new_forest = new_forest_ref[] + + let set_from = C_NULL, recursive = 0, set_for_coarsening = 0, no_repartition = 0 + t8_forest_set_user_data(new_forest, pointer(indicators)) + t8_forest_set_adapt(new_forest, old_forest, @t8_adapt_callback(adapt_callback), + recursive) + t8_forest_set_balance(new_forest, set_from, no_repartition) + t8_forest_set_partition(new_forest, set_from, set_for_coarsening) + t8_forest_set_ghost(new_forest, 1, T8_GHOST_FACES) # Note: MPI support not available yet so it is a dummy call. + t8_forest_commit(new_forest) + end + + return new_forest +end + +function trixi_t8_get_difference(old_levels, new_levels, num_children) + old_nelems = length(old_levels) + new_nelems = length(new_levels) + + changes = Vector{Int}(undef, old_nelems) + + # Local element indices. + old_index = 1 + new_index = 1 + + while old_index <= old_nelems && new_index <= new_nelems + if old_levels[old_index] < new_levels[new_index] + # Refined. + + changes[old_index] = 1 + + old_index += 1 + new_index += num_children + + elseif old_levels[old_index] > new_levels[new_index] + # Coarsend. + + for child_index in old_index:(old_index + num_children - 1) + changes[child_index] = -1 + end + + old_index += num_children + new_index += 1 + + else + # No changes. + + changes[old_index] = 0 + + old_index += 1 + new_index += 1 + end + end + + return changes +end + +# Coarsen or refine marked cells and rebalance forest. Return a difference between +# old and new mesh. +function trixi_t8_adapt!(mesh, indicators) + old_levels = trixi_t8_get_local_element_levels(mesh.forest) + + forest_cached = trixi_t8_adapt_new(mesh.forest, indicators) + + new_levels = trixi_t8_get_local_element_levels(forest_cached) + + differences = trixi_t8_get_difference(old_levels, new_levels, 2^ndims(mesh)) + + mesh.forest = forest_cached + + return differences +end diff --git a/src/callbacks_step/amr.jl b/src/callbacks_step/amr.jl index bef49b4c482..4d80e6e1139 100644 --- a/src/callbacks_step/amr.jl +++ b/src/callbacks_step/amr.jl @@ -471,6 +471,65 @@ function (amr_callback::AMRCallback)(u_ode::AbstractVector, mesh::P4estMesh, return has_changed end +function (amr_callback::AMRCallback)(u_ode::AbstractVector, mesh::SerialT8codeMesh, + equations, dg::DG, cache, semi, + t, iter; + only_refine = false, only_coarsen = false, + passive_args = ()) + has_changed = false + + @unpack controller, adaptor = amr_callback + + u = wrap_array(u_ode, mesh, equations, dg, cache) + indicators = @trixi_timeit timer() "indicator" controller(u, mesh, equations, dg, + cache, t = t, iter = iter) + + if only_coarsen + indicators[indicators .> 0] .= 0 + end + + if only_refine + indicators[indicators .< 0] .= 0 + end + + @boundscheck begin + @assert axes(indicators)==(Base.OneTo(ncells(mesh)),) ("Indicator array (axes = $(axes(indicators))) and mesh cells (axes = $(Base.OneTo(ncells(mesh)))) have different axes") + end + + @trixi_timeit timer() "adapt" begin + difference = @trixi_timeit timer() "mesh" trixi_t8_adapt!(mesh, indicators) + + @trixi_timeit timer() "solver" adapt!(u_ode, adaptor, mesh, equations, dg, + cache, difference) + end + + # Store whether there were any cells coarsened or refined and perform load balancing. + has_changed = any(difference .!= 0) + + # TODO: T8codeMesh for MPI not implemented yet. + # Check if mesh changed on other processes + # if mpi_isparallel() + # has_changed = MPI.Allreduce!(Ref(has_changed), |, mpi_comm())[] + # end + + if has_changed + # TODO: T8codeMesh for MPI not implemented yet. + # if mpi_isparallel() && amr_callback.dynamic_load_balancing + # @trixi_timeit timer() "dynamic load balancing" begin + # global_first_quadrant = unsafe_wrap(Array, mesh.p4est.global_first_quadrant, mpi_nranks() + 1) + # old_global_first_quadrant = copy(global_first_quadrant) + # partition!(mesh) + # rebalance_solver!(u_ode, mesh, equations, dg, cache, old_global_first_quadrant) + # end + # end + + reinitialize_boundaries!(semi.boundary_conditions, cache) + end + + # Return true if there were any cells coarsened or refined, otherwise false. + return has_changed +end + function reinitialize_boundaries!(boundary_conditions::UnstructuredSortedBoundaryTypes, cache) # Reinitialize boundary types container because boundaries may have changed. @@ -639,6 +698,10 @@ function current_element_levels(mesh::P4estMesh, solver, cache) return current_levels end +function current_element_levels(mesh::T8codeMesh, solver, cache) + return trixi_t8_get_local_element_levels(mesh.forest) +end + # TODO: Taal refactor, merge the two loops of ControllerThreeLevel and IndicatorLöhner etc.? # But that would remove the simplest possibility to write that stuff to a file... # We could of course implement some additional logic and workarounds, but is it worth the effort? diff --git a/src/callbacks_step/amr_dg2d.jl b/src/callbacks_step/amr_dg2d.jl index 400d16347d5..1d37dfce034 100644 --- a/src/callbacks_step/amr_dg2d.jl +++ b/src/callbacks_step/amr_dg2d.jl @@ -333,9 +333,79 @@ function coarsen_elements!(u::AbstractArray{<:Any, 4}, element_id, end end +# Coarsen and refine elements in the DG solver based on a difference list. +function adapt!(u_ode::AbstractVector, adaptor, mesh::T8codeMesh{2}, equations, + dg::DGSEM, cache, difference) + + # Return early if there is nothing to do. + if !any(difference .!= 0) + return nothing + end + + # Number of (local) cells/elements. + old_nelems = nelements(dg, cache) + new_nelems = ncells(mesh) + + # Local element indices. + old_index = 1 + new_index = 1 + + # Note: This is true for `quads` only. + T8_CHILDREN = 4 + + # Retain current solution data. + old_u_ode = copy(u_ode) + + GC.@preserve old_u_ode begin + old_u = wrap_array(old_u_ode, mesh, equations, dg, cache) + + reinitialize_containers!(mesh, equations, dg, cache) + + resize!(u_ode, + nvariables(equations) * nnodes(dg)^ndims(mesh) * nelements(dg, cache)) + u = wrap_array(u_ode, mesh, equations, dg, cache) + + while old_index <= old_nelems && new_index <= new_nelems + if difference[old_index] > 0 # Refine. + + # Refine element and store solution directly in new data structure. + refine_element!(u, new_index, old_u, old_index, adaptor, equations, dg) + + old_index += 1 + new_index += T8_CHILDREN + + elseif difference[old_index] < 0 # Coarsen. + + # If an element is to be removed, sanity check if the following elements + # are also marked - otherwise there would be an error in the way the + # cells/elements are sorted. + @assert all(difference[old_index:(old_index + T8_CHILDREN - 1)] .< 0) "bad cell/element order" + + # Coarsen elements and store solution directly in new data structure. + coarsen_elements!(u, new_index, old_u, old_index, adaptor, equations, + dg) + + 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] + + old_index += 1 + new_index += 1 + end + end # while + end # GC.@preserve old_u_ode + + return nothing +end + # this method is called when an `ControllerThreeLevel` is constructed function create_cache(::Type{ControllerThreeLevel}, - mesh::Union{TreeMesh{2}, P4estMesh{2}}, equations, dg::DG, cache) + mesh::Union{TreeMesh{2}, P4estMesh{2}, T8codeMesh{2}}, equations, + dg::DG, cache) controller_value = Vector{Int}(undef, nelements(dg, cache)) return (; controller_value) end diff --git a/src/callbacks_step/analysis.jl b/src/callbacks_step/analysis.jl index 7c453aab633..fad42b11098 100644 --- a/src/callbacks_step/analysis.jl +++ b/src/callbacks_step/analysis.jl @@ -534,6 +534,36 @@ function print_amr_information(callbacks, mesh::P4estMesh, solver, cache) return nothing end +# Print level information only if AMR is enabled +function print_amr_information(callbacks, mesh::T8codeMesh, solver, cache) + + # Return early if there is nothing to print + uses_amr(callbacks) || return nothing + + # TODO: Switch to global element levels array when MPI supported or find + # another solution. + levels = trixi_t8_get_local_element_levels(mesh.forest) + + min_level = minimum(levels) + max_level = maximum(levels) + + mpi_println(" minlevel = $min_level") + mpi_println(" maxlevel = $max_level") + + if min_level > 0 + elements_per_level = [count(==(l), levels) for l in 1:max_level] + + for level in max_level:-1:(min_level + 1) + mpi_println(" ├── level $level: " * + @sprintf("% 14d", elements_per_level[level])) + end + mpi_println(" └── level $min_level: " * + @sprintf("% 14d", elements_per_level[min_level])) + end + + return nothing +end + # Iterate over tuples of analysis integrals in a type-stable way using "lispy tuple programming". function analyze_integrals(analysis_integrals::NTuple{N, Any}, io, du, u, t, semi) where {N} diff --git a/src/callbacks_step/analysis_dg2d.jl b/src/callbacks_step/analysis_dg2d.jl index 6c74e172e46..4e456f79872 100644 --- a/src/callbacks_step/analysis_dg2d.jl +++ b/src/callbacks_step/analysis_dg2d.jl @@ -31,7 +31,7 @@ end function create_cache_analysis(analyzer, mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, - P4estMesh{2}}, + P4estMesh{2}, T8codeMesh{2}}, equations, dg::DG, cache, RealT, uEltype) @@ -108,7 +108,7 @@ end function calc_error_norms(func, u, t, analyzer, mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, - P4estMesh{2}}, equations, + P4estMesh{2}, T8codeMesh{2}}, equations, initial_condition, dg::DGSEM, cache, cache_analysis) @unpack vandermonde, weights = analyzer @unpack node_coordinates, inverse_jacobian = cache.elements @@ -176,7 +176,7 @@ end function integrate_via_indices(func::Func, u, mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, - P4estMesh{2}}, equations, + P4estMesh{2}, T8codeMesh{2}}, equations, dg::DGSEM, cache, args...; normalize = true) where {Func} @unpack weights = dg.basis @@ -204,7 +204,7 @@ end function integrate(func::Func, u, mesh::Union{TreeMesh{2}, StructuredMesh{2}, UnstructuredMesh2D, - P4estMesh{2}}, + P4estMesh{2}, T8codeMesh{2}}, equations, dg::DG, cache; normalize = true) where {Func} integrate_via_indices(u, mesh, equations, dg, cache; normalize = normalize) do u, i, j, element, equations, dg @@ -215,7 +215,7 @@ end function analyze(::typeof(entropy_timederivative), du, u, t, mesh::Union{TreeMesh{2}, StructuredMesh{2}, UnstructuredMesh2D, - P4estMesh{2}}, + P4estMesh{2}, T8codeMesh{2}}, equations, dg::DG, cache) # Calculate ∫(∂S/∂u ⋅ ∂u/∂t)dΩ integrate_via_indices(u, mesh, equations, dg, cache, @@ -259,7 +259,8 @@ function analyze(::Val{:l2_divb}, du, u, t, end function analyze(::Val{:l2_divb}, du, u, t, - mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, P4estMesh{2}}, + mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, P4estMesh{2}, + T8codeMesh{2}}, equations::IdealGlmMhdEquations2D, dg::DGSEM, cache) @unpack contravariant_vectors = cache.elements integrate_via_indices(u, mesh, equations, dg, cache, cache, @@ -326,7 +327,8 @@ function analyze(::Val{:linf_divb}, du, u, t, end function analyze(::Val{:linf_divb}, du, u, t, - mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, P4estMesh{2}}, + mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, P4estMesh{2}, + T8codeMesh{2}}, equations::IdealGlmMhdEquations2D, dg::DGSEM, cache) @unpack derivative_matrix, weights = dg.basis @unpack contravariant_vectors = cache.elements diff --git a/src/callbacks_step/save_restart_dg.jl b/src/callbacks_step/save_restart_dg.jl index 5695eb8bede..8db6db2d2b8 100644 --- a/src/callbacks_step/save_restart_dg.jl +++ b/src/callbacks_step/save_restart_dg.jl @@ -7,7 +7,8 @@ function save_restart_file(u, time, dt, timestep, mesh::Union{SerialTreeMesh, StructuredMesh, - UnstructuredMesh2D, SerialP4estMesh}, + UnstructuredMesh2D, SerialP4estMesh, + SerialT8codeMesh}, equations, dg::DG, cache, restart_callback) @unpack output_directory = restart_callback diff --git a/src/callbacks_step/save_solution_dg.jl b/src/callbacks_step/save_solution_dg.jl index 6cd4a0ec9c1..6d5004ff65f 100644 --- a/src/callbacks_step/save_solution_dg.jl +++ b/src/callbacks_step/save_solution_dg.jl @@ -7,7 +7,8 @@ function save_solution_file(u, time, dt, timestep, mesh::Union{SerialTreeMesh, StructuredMesh, - UnstructuredMesh2D, SerialP4estMesh}, + UnstructuredMesh2D, SerialP4estMesh, + SerialT8codeMesh}, equations, dg::DG, cache, solution_callback, element_variables = Dict{Symbol, Any}(); system = "") diff --git a/src/callbacks_step/stepsize_dg2d.jl b/src/callbacks_step/stepsize_dg2d.jl index 89a2b2b8350..673c3ba6aa6 100644 --- a/src/callbacks_step/stepsize_dg2d.jl +++ b/src/callbacks_step/stepsize_dg2d.jl @@ -75,7 +75,9 @@ function max_dt(u, t, mesh::ParallelTreeMesh{2}, return dt end -function max_dt(u, t, mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, P4estMesh{2}}, +function max_dt(u, t, + mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, P4estMesh{2}, + T8codeMesh{2}}, constant_speed::False, equations, dg::DG, cache) # to avoid a division by zero if the speed vanishes everywhere, # e.g. for steady-state linear advection @@ -109,7 +111,9 @@ function max_dt(u, t, mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, P4estMe return 2 / (nnodes(dg) * max_scaled_speed) end -function max_dt(u, t, mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, P4estMesh{2}}, +function max_dt(u, t, + mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, P4estMesh{2}, + T8codeMesh{2}}, constant_speed::True, equations, dg::DG, cache) @unpack contravariant_vectors, inverse_jacobian = cache.elements diff --git a/src/meshes/mesh_io.jl b/src/meshes/mesh_io.jl index da67fe23e0e..b9895e7d454 100644 --- a/src/meshes/mesh_io.jl +++ b/src/meshes/mesh_io.jl @@ -6,7 +6,7 @@ #! format: noindent # Save current mesh with some context information as an HDF5 file. -function save_mesh_file(mesh::Union{TreeMesh, P4estMesh}, output_directory, +function save_mesh_file(mesh::Union{TreeMesh, P4estMesh, T8codeMesh}, output_directory, timestep = 0) save_mesh_file(mesh, output_directory, timestep, mpi_parallel(mesh)) end @@ -220,6 +220,13 @@ function save_mesh_file(mesh::P4estMesh, output_directory, timestep, mpi_paralle return filename end +# TODO: Implement this function as soon as there is support for this in `t8code`. +function save_mesh_file(mesh::T8codeMesh, output_directory, timestep, mpi_parallel) + error("Mesh file output not supported yet for `T8codeMesh`.") + + return joinpath(output_directory, "dummy_mesh.h5") +end + """ load_mesh(restart_file::AbstractString; n_cells_max) diff --git a/src/meshes/meshes.jl b/src/meshes/meshes.jl index 2716aa2007b..ed2158b169a 100644 --- a/src/meshes/meshes.jl +++ b/src/meshes/meshes.jl @@ -12,6 +12,7 @@ include("unstructured_mesh.jl") include("face_interpolant.jl") include("transfinite_mappings_3d.jl") include("p4est_mesh.jl") +include("t8code_mesh.jl") include("mesh_io.jl") include("dgmulti_meshes.jl") end # @muladd diff --git a/src/meshes/t8code_mesh.jl b/src/meshes/t8code_mesh.jl new file mode 100644 index 00000000000..13edcc29711 --- /dev/null +++ b/src/meshes/t8code_mesh.jl @@ -0,0 +1,345 @@ +""" + T8codeMesh{NDIMS} <: AbstractMesh{NDIMS} + +An unstructured curved mesh based on trees that uses the C library +['t8code'](https://github.com/DLR-AMR/t8code) +to manage trees and mesh refinement. +""" +mutable struct T8codeMesh{NDIMS, RealT <: Real, IsParallel, NDIMSP2, NNODES} <: + AbstractMesh{NDIMS} + cmesh :: Ptr{t8_cmesh} # cpointer to coarse mesh + scheme :: Ptr{t8_eclass_scheme} # cpointer to element scheme + forest :: Ptr{t8_forest} # cpointer to forest + is_parallel :: IsParallel + + # This specifies the geometry interpolation for each tree. + tree_node_coordinates::Array{RealT, NDIMSP2} # [dimension, i, j, k, tree] + + # Stores the quadrature nodes. + nodes::SVector{NNODES, RealT} + + boundary_names :: Array{Symbol, 2} # [face direction, tree] + current_filename :: String + + ninterfaces :: Int + nmortars :: Int + nboundaries :: Int + + function T8codeMesh{NDIMS}(cmesh, scheme, forest, tree_node_coordinates, nodes, + boundary_names, + current_filename) where {NDIMS} + is_parallel = False() + + mesh = new{NDIMS, Float64, typeof(is_parallel), NDIMS + 2, length(nodes)}(cmesh, + scheme, + forest, + is_parallel) + + mesh.nodes = nodes + mesh.boundary_names = boundary_names + mesh.current_filename = current_filename + mesh.tree_node_coordinates = tree_node_coordinates + + finalizer(mesh) do mesh + # When finalizing `mesh.forest`, `mesh.scheme` and `mesh.cmesh` are + # also cleaned up from within `t8code`. The cleanup code for + # `cmesh` does some MPI calls for deallocating shared memory + # arrays. Due to garbage collection in Julia the order of shutdown + # is not deterministic. The following code might happen after MPI + # is already in finalized state. + # If the environment variable `TRIXI_T8CODE_SC_FINALIZE` is set the + # `finalize_hook` of the MPI module takes care of the cleanup. See + # further down. However, this might cause a pile-up of `mesh` + # objects during long-running sessions. + if !MPI.Finalized() + trixi_t8_unref_forest(mesh.forest) + end + end + + # This finalizer call is only recommended during development and not for + # production runs, especially long-running sessions since a reference to + # the `mesh` object will be kept throughout the lifetime of the session. + # See comments in `init_t8code()` in file `src/auxiliary/t8code.jl` for + # more information. + if haskey(ENV, "TRIXI_T8CODE_SC_FINALIZE") + MPI.add_finalize_hook!() do + trixi_t8_unref_forest(mesh.forest) + end + end + + return mesh + end +end + +const SerialT8codeMesh{NDIMS} = T8codeMesh{NDIMS, <:Real, <:False} +@inline mpi_parallel(mesh::SerialT8codeMesh) = False() + +@inline Base.ndims(::T8codeMesh{NDIMS}) where {NDIMS} = NDIMS +@inline Base.real(::T8codeMesh{NDIMS, RealT}) where {NDIMS, RealT} = RealT + +@inline ntrees(mesh::T8codeMesh) = Int(t8_forest_get_num_local_trees(mesh.forest)) +@inline ncells(mesh::T8codeMesh) = Int(t8_forest_get_local_num_elements(mesh.forest)) +@inline ninterfaces(mesh::T8codeMesh) = mesh.ninterfaces +@inline nmortars(mesh::T8codeMesh) = mesh.nmortars +@inline nboundaries(mesh::T8codeMesh) = mesh.nboundaries + +function Base.show(io::IO, mesh::T8codeMesh) + print(io, "T8codeMesh{", ndims(mesh), ", ", real(mesh), "}") +end + +function Base.show(io::IO, ::MIME"text/plain", mesh::T8codeMesh) + if get(io, :compact, false) + show(io, mesh) + else + setup = [ + "#trees" => ntrees(mesh), + "current #cells" => ncells(mesh), + "polydeg" => length(mesh.nodes) - 1, + ] + summary_box(io, + "T8codeMesh{" * string(ndims(mesh)) * ", " * string(real(mesh)) * "}", + setup) + end +end + +""" + T8codeMesh(trees_per_dimension; polydeg, mapping=identity, + RealT=Float64, initial_refinement_level=0, periodicity=true) + +Create a structured potentially curved 'T8codeMesh' of the specified size. + +Non-periodic boundaries will be called ':x_neg', ':x_pos', ':y_neg', ':y_pos', ':z_neg', ':z_pos'. + +# Arguments +- 'trees_per_dimension::NTupleE{NDIMS, Int}': the number of trees in each dimension. +- 'polydeg::Integer': polynomial degree used to store the geometry of the mesh. + The mapping will be approximated by an interpolation polynomial + of the specified degree for each tree. +- 'mapping': a function of 'NDIMS' variables to describe the mapping that transforms + the reference mesh ('[-1, 1]^n') to the physical domain. +- '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. +- 'periodicity': either a 'Bool' deciding if all of the boundaries are periodic or an 'NTuple{NDIMS, Bool}' + deciding for each dimension if the boundaries in this dimension are periodic. +""" +function T8codeMesh(trees_per_dimension; polydeg, + mapping = coordinates2mapping((-1.0, -1.0), (1.0, 1.0)), + RealT = Float64, initial_refinement_level = 0, periodicity = true) + NDIMS = length(trees_per_dimension) + + @assert NDIMS == 2 # Only support for NDIMS = 2 yet. + + # Convert periodicity to a Tuple of a Bool for every dimension + if all(periodicity) + # Also catches case where periodicity = true + periodicity = ntuple(_ -> true, NDIMS) + elseif !any(periodicity) + # Also catches case where periodicity = false + periodicity = ntuple(_ -> false, NDIMS) + else + # Default case if periodicity is an iterable + periodicity = Tuple(periodicity) + end + + conn = T8code.Libt8.p4est_connectivity_new_brick(trees_per_dimension..., periodicity...) + do_partition = 0 + cmesh = t8_cmesh_new_from_p4est(conn, mpi_comm(), do_partition) + T8code.Libt8.p4est_connectivity_destroy(conn) + + scheme = t8_scheme_new_default_cxx() + forest = t8_forest_new_uniform(cmesh, scheme, initial_refinement_level, 0, mpi_comm()) + + basis = LobattoLegendreBasis(RealT, polydeg) + nodes = basis.nodes + + tree_node_coordinates = Array{RealT, NDIMS + 2}(undef, NDIMS, + ntuple(_ -> length(nodes), NDIMS)..., + prod(trees_per_dimension)) + + # Get cell length in reference mesh: Omega_ref = [-1,1]^2. + dx = 2 / trees_per_dimension[1] + dy = 2 / trees_per_dimension[2] + + num_local_trees = t8_cmesh_get_num_local_trees(cmesh) + + # Non-periodic boundaries. + boundary_names = fill(Symbol("---"), 2 * NDIMS, prod(trees_per_dimension)) + + for itree in 1:num_local_trees + veptr = t8_cmesh_get_tree_vertices(cmesh, itree - 1) + verts = unsafe_wrap(Array, veptr, (3, 1 << NDIMS)) + + # Calculate node coordinates of reference mesh. + cell_x_offset = (verts[1, 1] - 1 / 2 * (trees_per_dimension[1] - 1)) * dx + cell_y_offset = (verts[2, 1] - 1 / 2 * (trees_per_dimension[2] - 1)) * dy + + for j in eachindex(nodes), i in eachindex(nodes) + tree_node_coordinates[:, i, j, itree] .= mapping(cell_x_offset + + dx * nodes[i] / 2, + cell_y_offset + + dy * nodes[j] / 2) + end + + if !periodicity[1] + boundary_names[1, itree] = :x_neg + boundary_names[2, itree] = :x_pos + end + + if !periodicity[2] + boundary_names[3, itree] = :y_neg + boundary_names[4, itree] = :y_pos + end + end + + return T8codeMesh{NDIMS}(cmesh, scheme, forest, tree_node_coordinates, nodes, + boundary_names, "") +end + +""" + T8codeMesh{NDIMS}(cmesh::Ptr{t8_cmesh}, + mapping=nothing, polydeg=1, RealT=Float64, + initial_refinement_level=0) + +Main mesh constructor for the `T8codeMesh` that imports an unstructured, +conforming mesh from a `t8_cmesh` data structure. + +# Arguments +- `cmesh::Ptr{t8_cmesh}`: Pointer to a cmesh object. +- `mapping`: a function of `NDIMS` variables to describe the mapping that transforms + the imported mesh to the physical domain. Use `nothing` for the identity map. +- `polydeg::Integer`: polynomial degree used to store the geometry of the mesh. + The mapping will be approximated by an interpolation polynomial + of the specified degree for each tree. + The default of `1` creates an uncurved geometry. Use a higher value if the mapping + will curve the imported uncurved mesh. +- `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. +""" +function T8codeMesh{NDIMS}(cmesh::Ptr{t8_cmesh}; + mapping = nothing, polydeg = 1, RealT = Float64, + initial_refinement_level = 0) where {NDIMS} + @assert NDIMS == 2 # Only support for NDIMS = 2 yet. + + scheme = t8_scheme_new_default_cxx() + forest = t8_forest_new_uniform(cmesh, scheme, initial_refinement_level, 0, mpi_comm()) + + basis = LobattoLegendreBasis(RealT, polydeg) + nodes = basis.nodes + + num_local_trees = t8_cmesh_get_num_local_trees(cmesh) + + tree_node_coordinates = Array{RealT, NDIMS + 2}(undef, NDIMS, + ntuple(_ -> length(nodes), NDIMS)..., + num_local_trees) + + nodes_in = [-1.0, 1.0] + matrix = polynomial_interpolation_matrix(nodes_in, nodes) + data_in = Array{RealT, 3}(undef, 2, 2, 2) + tmp1 = zeros(RealT, 2, length(nodes), length(nodes_in)) + + for itree in 0:(num_local_trees - 1) + veptr = t8_cmesh_get_tree_vertices(cmesh, itree) + verts = unsafe_wrap(Array, veptr, (3, 1 << NDIMS)) + + u = verts[:, 2] - verts[:, 1] + v = verts[:, 3] - verts[:, 1] + w = [0.0, 0.0, 1.0] + + vol = dot(cross(u, v), w) + + if vol < 0.0 + @warn "Discovered negative volumes in `cmesh`: vol = $vol" + end + + # Tree vertices are stored in z-order. + @views data_in[:, 1, 1] .= verts[1:2, 1] + @views data_in[:, 2, 1] .= verts[1:2, 2] + @views data_in[:, 1, 2] .= verts[1:2, 3] + @views data_in[:, 2, 2] .= verts[1:2, 4] + + # Interpolate corner coordinates to specified nodes. + multiply_dimensionwise!(view(tree_node_coordinates, :, :, :, itree + 1), + matrix, matrix, + data_in, + tmp1) + end + + map_node_coordinates!(tree_node_coordinates, mapping) + + # There's no simple and generic way to distinguish boundaries. Name all of them :all. + boundary_names = fill(:all, 2 * NDIMS, num_local_trees) + + return T8codeMesh{NDIMS}(cmesh, scheme, forest, tree_node_coordinates, nodes, + boundary_names, "") +end + +""" + T8codeMesh{NDIMS}(conn::Ptr{p4est_connectivity}, + mapping=nothing, polydeg=1, RealT=Float64, + initial_refinement_level=0) + +Main mesh constructor for the `T8codeMesh` that imports an unstructured, +conforming mesh from a `p4est_connectivity` data structure. + +# Arguments +- `conn::Ptr{p4est_connectivity}`: Pointer to a P4est connectivity object. +- `mapping`: a function of `NDIMS` variables to describe the mapping that transforms + the imported mesh to the physical domain. Use `nothing` for the identity map. +- `polydeg::Integer`: polynomial degree used to store the geometry of the mesh. + The mapping will be approximated by an interpolation polynomial + of the specified degree for each tree. + The default of `1` creates an uncurved geometry. Use a higher value if the mapping + will curve the imported uncurved mesh. +- `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. +""" +function T8codeMesh{NDIMS}(conn::Ptr{p4est_connectivity}; kwargs...) where {NDIMS} + @assert NDIMS == 2 # Only support for NDIMS = 2 yet. + + cmesh = t8_cmesh_new_from_p4est(conn, mpi_comm(), 0) + + return T8codeMesh{NDIMS}(cmesh; kwargs...) +end + +""" + T8codeMesh{NDIMS}(meshfile::String; + mapping=nothing, polydeg=1, RealT=Float64, + initial_refinement_level=0) + +Main mesh constructor for the `T8codeMesh` that imports an unstructured, conforming +mesh from a Gmsh mesh file (`.msh`). + +# Arguments +- `meshfile::String`: path to a Gmsh mesh file. +- `mapping`: a function of `NDIMS` variables to describe the mapping that transforms + the imported mesh to the physical domain. Use `nothing` for the identity map. +- `polydeg::Integer`: polynomial degree used to store the geometry of the mesh. + The mapping will be approximated by an interpolation polynomial + of the specified degree for each tree. + The default of `1` creates an uncurved geometry. Use a higher value if the mapping + will curve the imported uncurved mesh. +- `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. +""" +function T8codeMesh{NDIMS}(meshfile::String; kwargs...) where {NDIMS} + @assert NDIMS == 2 # Only support for NDIMS = 2 yet. + + # Prevent `t8code` from crashing Julia if the file doesn't exist. + @assert isfile(meshfile) + + meshfile_prefix, meshfile_suffix = splitext(meshfile) + + cmesh = t8_cmesh_from_msh_file(meshfile_prefix, 0, mpi_comm(), NDIMS, 0, 0) + + return T8codeMesh{NDIMS}(cmesh; kwargs...) +end + +# TODO: Just a placeholder. Will be implemented later when MPI is supported. +function balance!(mesh::T8codeMesh, init_fn = C_NULL) + return nothing +end + +# TODO: Just a placeholder. Will be implemented later when MPI is supported. +function partition!(mesh::T8codeMesh; allow_coarsening = true, weight_fn = C_NULL) + return nothing +end diff --git a/src/solvers/dg.jl b/src/solvers/dg.jl index 2536cfe0bf2..495e0ffc4a4 100644 --- a/src/solvers/dg.jl +++ b/src/solvers/dg.jl @@ -363,7 +363,8 @@ function get_element_variables!(element_variables, u, mesh, equations, dg::DG, c dg, cache) end -const MeshesDGSEM = Union{TreeMesh, StructuredMesh, UnstructuredMesh2D, P4estMesh} +const MeshesDGSEM = Union{TreeMesh, StructuredMesh, UnstructuredMesh2D, P4estMesh, + T8codeMesh} @inline function ndofs(mesh::MeshesDGSEM, dg::DG, cache) nelements(cache.elements) * nnodes(dg)^ndims(mesh) @@ -679,4 +680,5 @@ include("dgsem_tree/dg.jl") include("dgsem_structured/dg.jl") include("dgsem_unstructured/dg.jl") include("dgsem_p4est/dg.jl") +include("dgsem_t8code/dg.jl") end # @muladd diff --git a/src/solvers/dgsem_p4est/containers.jl b/src/solvers/dgsem_p4est/containers.jl index 2b9c6987d24..0176f5c6346 100644 --- a/src/solvers/dgsem_p4est/containers.jl +++ b/src/solvers/dgsem_p4est/containers.jl @@ -81,7 +81,8 @@ function Base.resize!(elements::P4estElementContainer, capacity) end # Create element container and initialize element data -function init_elements(mesh::P4estMesh{NDIMS, RealT}, equations, +function init_elements(mesh::Union{P4estMesh{NDIMS, RealT}, T8codeMesh{NDIMS, RealT}}, + equations, basis, ::Type{uEltype}) where {NDIMS, RealT <: Real, uEltype <: Real} nelements = ncells(mesh) @@ -165,7 +166,7 @@ function Base.resize!(interfaces::P4estInterfaceContainer, capacity) end # Create interface container and initialize interface data. -function init_interfaces(mesh::P4estMesh, equations, basis, elements) +function init_interfaces(mesh::Union{P4estMesh, T8codeMesh}, equations, basis, elements) NDIMS = ndims(elements) uEltype = eltype(elements) @@ -240,7 +241,7 @@ function Base.resize!(boundaries::P4estBoundaryContainer, capacity) end # Create interface container and initialize interface data in `elements`. -function init_boundaries(mesh::P4estMesh, equations, basis, elements) +function init_boundaries(mesh::Union{P4estMesh, T8codeMesh}, equations, basis, elements) NDIMS = ndims(elements) uEltype = eltype(elements) @@ -371,7 +372,7 @@ function Base.resize!(mortars::P4estMortarContainer, capacity) end # Create mortar container and initialize mortar data. -function init_mortars(mesh::P4estMesh, equations, basis, elements) +function init_mortars(mesh::Union{P4estMesh, T8codeMesh}, equations, basis, elements) NDIMS = ndims(elements) uEltype = eltype(elements) diff --git a/src/solvers/dgsem_p4est/containers_2d.jl b/src/solvers/dgsem_p4est/containers_2d.jl index 11747f1f175..236d7d24c06 100644 --- a/src/solvers/dgsem_p4est/containers_2d.jl +++ b/src/solvers/dgsem_p4est/containers_2d.jl @@ -6,7 +6,8 @@ #! format: noindent # Initialize data structures in element container -function init_elements!(elements, mesh::P4estMesh{2}, basis::LobattoLegendreBasis) +function init_elements!(elements, mesh::Union{P4estMesh{2}, T8codeMesh{2}}, + basis::LobattoLegendreBasis) @unpack node_coordinates, jacobian_matrix, contravariant_vectors, inverse_jacobian = elements @@ -25,7 +26,7 @@ end # Interpolate tree_node_coordinates to each quadrant at the nodes of the specified basis function calc_node_coordinates!(node_coordinates, - mesh::P4estMesh{2}, + mesh::Union{P4estMesh{2}, T8codeMesh{2}}, basis::LobattoLegendreBasis) # Hanging nodes will cause holes in the mesh if its polydeg is higher # than the polydeg of the solver. diff --git a/src/solvers/dgsem_p4est/dg_2d.jl b/src/solvers/dgsem_p4est/dg_2d.jl index bc7d9edb6ef..97b931fa325 100644 --- a/src/solvers/dgsem_p4est/dg_2d.jl +++ b/src/solvers/dgsem_p4est/dg_2d.jl @@ -7,8 +7,8 @@ # The methods below are specialized on the mortar type # and called from the basic `create_cache` method at the top. -function create_cache(mesh::P4estMesh{2}, equations, mortar_l2::LobattoLegendreMortarL2, - uEltype) +function create_cache(mesh::Union{P4estMesh{2}, T8codeMesh{2}}, equations, + mortar_l2::LobattoLegendreMortarL2, uEltype) # TODO: Taal performance using different types MA2d = MArray{Tuple{nvariables(equations), nnodes(mortar_l2)}, uEltype, 2, @@ -58,7 +58,7 @@ end # We pass the `surface_integral` argument solely for dispatch function prolong2interfaces!(cache, u, - mesh::P4estMesh{2}, + mesh::Union{P4estMesh{2}, T8codeMesh{2}}, equations, surface_integral, dg::DG) @unpack interfaces = cache index_range = eachnode(dg) @@ -114,7 +114,7 @@ function prolong2interfaces!(cache, u, end function calc_interface_flux!(surface_flux_values, - mesh::P4estMesh{2}, + mesh::Union{P4estMesh{2}, T8codeMesh{2}}, nonconservative_terms, equations, surface_integral, dg::DG, cache) @unpack neighbor_ids, node_indices = cache.interfaces @@ -182,7 +182,7 @@ end # Inlined version of the interface flux computation for conservation laws @inline function calc_interface_flux!(surface_flux_values, - mesh::P4estMesh{2}, + mesh::Union{P4estMesh{2}, T8codeMesh{2}}, nonconservative_terms::False, equations, surface_integral, dg::DG, cache, interface_index, normal_direction, @@ -206,7 +206,7 @@ end # Inlined version of the interface flux computation for equations with conservative and nonconservative terms @inline function calc_interface_flux!(surface_flux_values, - mesh::P4estMesh{2}, + mesh::Union{P4estMesh{2}, T8codeMesh{2}}, nonconservative_terms::True, equations, surface_integral, dg::DG, cache, interface_index, normal_direction, @@ -247,7 +247,7 @@ end end function prolong2boundaries!(cache, u, - mesh::P4estMesh{2}, + mesh::Union{P4estMesh{2}, T8codeMesh{2}}, equations, surface_integral, dg::DG) @unpack boundaries = cache index_range = eachnode(dg) @@ -276,7 +276,7 @@ function prolong2boundaries!(cache, u, end function calc_boundary_flux!(cache, t, boundary_condition, boundary_indexing, - mesh::P4estMesh{2}, + mesh::Union{P4estMesh{2}, T8codeMesh{2}}, equations, surface_integral, dg::DG) @unpack boundaries = cache @unpack surface_flux_values = cache.elements @@ -312,7 +312,7 @@ end # inlined version of the boundary flux calculation along a physical interface @inline function calc_boundary_flux!(surface_flux_values, t, boundary_condition, - mesh::P4estMesh{2}, + mesh::Union{P4estMesh{2}, T8codeMesh{2}}, nonconservative_terms::False, equations, surface_integral, dg::DG, cache, i_index, j_index, @@ -343,7 +343,7 @@ end # inlined version of the boundary flux with nonconservative terms calculation along a physical interface @inline function calc_boundary_flux!(surface_flux_values, t, boundary_condition, - mesh::P4estMesh{2}, + mesh::Union{P4estMesh{2}, T8codeMesh{2}}, nonconservative_terms::True, equations, surface_integral, dg::DG, cache, i_index, j_index, @@ -385,7 +385,7 @@ end end function prolong2mortars!(cache, u, - mesh::P4estMesh{2}, equations, + mesh::Union{P4estMesh{2}, T8codeMesh{2}}, equations, mortar_l2::LobattoLegendreMortarL2, surface_integral, dg::DGSEM) @unpack neighbor_ids, node_indices = cache.mortars @@ -452,7 +452,7 @@ function prolong2mortars!(cache, u, end function calc_mortar_flux!(surface_flux_values, - mesh::P4estMesh{2}, + mesh::Union{P4estMesh{2}, T8codeMesh{2}}, nonconservative_terms, equations, mortar_l2::LobattoLegendreMortarL2, surface_integral, dg::DG, cache) @@ -511,7 +511,7 @@ end # Inlined version of the mortar flux computation on small elements for conservation laws @inline function calc_mortar_flux!(fstar, - mesh::P4estMesh{2}, + mesh::Union{P4estMesh{2}, T8codeMesh{2}}, nonconservative_terms::False, equations, surface_integral, dg::DG, cache, mortar_index, position_index, normal_direction, @@ -531,7 +531,7 @@ end # Inlined version of the mortar flux computation on small elements for equations with conservative and # nonconservative terms @inline function calc_mortar_flux!(fstar, - mesh::P4estMesh{2}, + mesh::Union{P4estMesh{2}, T8codeMesh{2}}, nonconservative_terms::True, equations, surface_integral, dg::DG, cache, mortar_index, position_index, normal_direction, @@ -559,7 +559,8 @@ end end @inline function mortar_fluxes_to_elements!(surface_flux_values, - mesh::P4estMesh{2}, equations, + mesh::Union{P4estMesh{2}, T8codeMesh{2}}, + equations, mortar_l2::LobattoLegendreMortarL2, dg::DGSEM, cache, mortar, fstar, u_buffer) @unpack neighbor_ids, node_indices = cache.mortars @@ -620,7 +621,7 @@ end end function calc_surface_integral!(du, u, - mesh::P4estMesh{2}, + mesh::Union{P4estMesh{2}, T8codeMesh{2}}, equations, surface_integral::SurfaceIntegralWeakForm, dg::DGSEM, cache) diff --git a/src/solvers/dgsem_structured/dg_2d.jl b/src/solvers/dgsem_structured/dg_2d.jl index c013bf62d98..3e8ce759b30 100644 --- a/src/solvers/dgsem_structured/dg_2d.jl +++ b/src/solvers/dgsem_structured/dg_2d.jl @@ -52,7 +52,7 @@ end @inline function weak_form_kernel!(du, u, element, mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, - P4estMesh{2}}, + P4estMesh{2}, T8codeMesh{2}}, nonconservative_terms::False, equations, dg::DGSEM, cache, alpha = true) # true * [some floating point value] == [exactly the same floating point value] @@ -93,8 +93,8 @@ end @inline function flux_differencing_kernel!(du, u, element, mesh::Union{StructuredMesh{2}, - UnstructuredMesh2D, P4estMesh{2} - }, + UnstructuredMesh2D, P4estMesh{2}, + T8codeMesh{2}}, nonconservative_terms::False, equations, volume_flux, dg::DGSEM, cache, alpha = true) @unpack derivative_split = dg.basis @@ -150,8 +150,8 @@ end @inline function flux_differencing_kernel!(du, u, element, mesh::Union{StructuredMesh{2}, - UnstructuredMesh2D, P4estMesh{2} - }, + UnstructuredMesh2D, P4estMesh{2}, + T8codeMesh{2}}, nonconservative_terms::True, equations, volume_flux, dg::DGSEM, cache, alpha = true) @unpack derivative_split = dg.basis @@ -219,7 +219,7 @@ end # [arXiv: 2008.12044v2](https://arxiv.org/pdf/2008.12044) @inline function calcflux_fv!(fstar1_L, fstar1_R, fstar2_L, fstar2_R, u, mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, - P4estMesh{2}}, + P4estMesh{2}, T8codeMesh{2}}, nonconservative_terms::False, equations, volume_flux_fv, dg::DGSEM, element, cache) @unpack contravariant_vectors = cache.elements @@ -289,7 +289,7 @@ end @inline function calcflux_fv!(fstar1_L, fstar1_R, fstar2_L, fstar2_R, u::AbstractArray{<:Any, 4}, mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, - P4estMesh{2}}, + P4estMesh{2}, T8codeMesh{2}}, nonconservative_terms::True, equations, volume_flux_fv, dg::DGSEM, element, cache) @unpack contravariant_vectors = cache.elements @@ -609,9 +609,8 @@ function calc_boundary_flux!(cache, u, t, boundary_conditions::NamedTuple, end function apply_jacobian!(du, - mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, P4estMesh{2 - } - }, + mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, + P4estMesh{2}, T8codeMesh{2}}, equations, dg::DG, cache) @unpack inverse_jacobian = cache.elements diff --git a/src/solvers/dgsem_t8code/containers.jl b/src/solvers/dgsem_t8code/containers.jl new file mode 100644 index 00000000000..093feb2985a --- /dev/null +++ b/src/solvers/dgsem_t8code/containers.jl @@ -0,0 +1,60 @@ +function reinitialize_containers!(mesh::T8codeMesh, equations, dg::DGSEM, cache) + # Re-initialize elements container. + @unpack elements = cache + resize!(elements, ncells(mesh)) + init_elements!(elements, mesh, dg.basis) + + count_required_surfaces!(mesh) + + # Resize interfaces container. + @unpack interfaces = cache + resize!(interfaces, mesh.ninterfaces) + + # Resize mortars container. + @unpack mortars = cache + resize!(mortars, mesh.nmortars) + + # Resize boundaries container. + @unpack boundaries = cache + resize!(boundaries, mesh.nboundaries) + + trixi_t8_fill_mesh_info(mesh.forest, elements, interfaces, mortars, boundaries, + mesh.boundary_names) + + return nothing +end + +function count_required_surfaces!(mesh::T8codeMesh) + counts = trixi_t8_count_interfaces(mesh.forest) + + mesh.nmortars = counts.mortars + mesh.ninterfaces = counts.interfaces + mesh.nboundaries = counts.boundaries + + return counts +end + +# Compatibility to `dgsem_p4est/containers.jl`. +function count_required_surfaces(mesh::T8codeMesh) + return (interfaces = mesh.ninterfaces, + mortars = mesh.nmortars, + boundaries = mesh.nboundaries) +end + +# Compatibility to `dgsem_p4est/containers.jl`. +function init_interfaces!(interfaces, mesh::T8codeMesh) + # Already computed. Do nothing. + return nothing +end + +# Compatibility to `dgsem_p4est/containers.jl`. +function init_mortars!(mortars, mesh::T8codeMesh) + # Already computed. Do nothing. + return nothing +end + +# Compatibility to `dgsem_p4est/containers.jl`. +function init_boundaries!(boundaries, mesh::T8codeMesh) + # Already computed. Do nothing. + return nothing +end diff --git a/src/solvers/dgsem_t8code/containers_2d.jl b/src/solvers/dgsem_t8code/containers_2d.jl new file mode 100644 index 00000000000..029e6674afb --- /dev/null +++ b/src/solvers/dgsem_t8code/containers_2d.jl @@ -0,0 +1,58 @@ +@muladd begin +#! format: noindent + +# Interpolate tree_node_coordinates to each quadrant at the specified nodes. +function calc_node_coordinates!(node_coordinates, + mesh::T8codeMesh{2}, + nodes::AbstractVector) + # We use `StrideArray`s here since these buffers are used in performance-critical + # places and the additional information passed to the compiler makes them faster + # than native `Array`s. + tmp1 = StrideArray(undef, real(mesh), + StaticInt(2), static_length(nodes), static_length(mesh.nodes)) + matrix1 = StrideArray(undef, real(mesh), + static_length(nodes), static_length(mesh.nodes)) + matrix2 = similar(matrix1) + baryweights_in = barycentric_weights(mesh.nodes) + + num_local_trees = t8_forest_get_num_local_trees(mesh.forest) + + current_index = 0 + for itree in 0:(num_local_trees - 1) + tree_class = t8_forest_get_tree_class(mesh.forest, itree) + eclass_scheme = t8_forest_get_eclass_scheme(mesh.forest, tree_class) + num_elements_in_tree = t8_forest_get_tree_num_elements(mesh.forest, itree) + + for ielement in 0:(num_elements_in_tree - 1) + element = t8_forest_get_element_in_tree(mesh.forest, itree, ielement) + element_level = t8_element_level(eclass_scheme, element) + + element_length = t8_quad_len(element_level) / t8_quad_root_len + + element_coords = Array{Float64}(undef, 3) + t8_element_vertex_reference_coords(eclass_scheme, element, 0, + pointer(element_coords)) + + nodes_out_x = 2 * + (element_length * 1 / 2 * (nodes .+ 1) .+ element_coords[1]) .- + 1 + nodes_out_y = 2 * + (element_length * 1 / 2 * (nodes .+ 1) .+ element_coords[2]) .- + 1 + + polynomial_interpolation_matrix!(matrix1, mesh.nodes, nodes_out_x, + baryweights_in) + polynomial_interpolation_matrix!(matrix2, mesh.nodes, nodes_out_y, + baryweights_in) + + multiply_dimensionwise!(view(node_coordinates, :, :, :, current_index += 1), + matrix1, matrix2, + view(mesh.tree_node_coordinates, :, :, :, + itree + 1), + tmp1) + end + end + + return node_coordinates +end +end # @muladd diff --git a/src/solvers/dgsem_t8code/dg.jl b/src/solvers/dgsem_t8code/dg.jl new file mode 100644 index 00000000000..16a9d7d35b1 --- /dev/null +++ b/src/solvers/dgsem_t8code/dg.jl @@ -0,0 +1,31 @@ +@muladd begin +#! format: noindent + +# This method is called when a SemidiscretizationHyperbolic is constructed. +# It constructs the basic `cache` used throughout the simulation to compute +# the RHS etc. +function create_cache(mesh::T8codeMesh, equations::AbstractEquations, dg::DG, ::Any, + ::Type{uEltype}) where {uEltype <: Real} + count_required_surfaces!(mesh) + + elements = init_elements(mesh, equations, dg.basis, uEltype) + interfaces = init_interfaces(mesh, equations, dg.basis, elements) + boundaries = init_boundaries(mesh, equations, dg.basis, elements) + mortars = init_mortars(mesh, equations, dg.basis, elements) + + trixi_t8_fill_mesh_info(mesh.forest, elements, interfaces, mortars, boundaries, + mesh.boundary_names) + + cache = (; elements, interfaces, boundaries, mortars) + + # Add specialized parts of the cache required to compute the volume integral etc. + cache = (; cache..., + create_cache(mesh, equations, dg.volume_integral, dg, uEltype)...) + cache = (; cache..., create_cache(mesh, equations, dg.mortar, uEltype)...) + + return cache +end + +include("containers.jl") +include("containers_2d.jl") +end # @muladd diff --git a/src/solvers/dgsem_tree/dg_2d.jl b/src/solvers/dgsem_tree/dg_2d.jl index 6c5e0cee0cf..c30d0a8e01a 100644 --- a/src/solvers/dgsem_tree/dg_2d.jl +++ b/src/solvers/dgsem_tree/dg_2d.jl @@ -37,14 +37,14 @@ end # The methods below are specialized on the volume integral type # and called from the basic `create_cache` method at the top. function create_cache(mesh::Union{TreeMesh{2}, StructuredMesh{2}, UnstructuredMesh2D, - P4estMesh{2}}, + P4estMesh{2}, T8codeMesh{2}}, equations, volume_integral::VolumeIntegralFluxDifferencing, dg::DG, uEltype) NamedTuple() end function create_cache(mesh::Union{TreeMesh{2}, StructuredMesh{2}, UnstructuredMesh2D, - P4estMesh{2}}, equations, + P4estMesh{2}, T8codeMesh{2}}, equations, volume_integral::VolumeIntegralShockCapturingHG, dg::DG, uEltype) element_ids_dg = Int[] element_ids_dgfv = Int[] @@ -70,7 +70,7 @@ function create_cache(mesh::Union{TreeMesh{2}, StructuredMesh{2}, UnstructuredMe end function create_cache(mesh::Union{TreeMesh{2}, StructuredMesh{2}, UnstructuredMesh2D, - P4estMesh{2}}, equations, + P4estMesh{2}, T8codeMesh{2}}, equations, volume_integral::VolumeIntegralPureLGLFiniteVolume, dg::DG, uEltype) A3dp1_x = Array{uEltype, 3} @@ -92,7 +92,7 @@ end # The methods below are specialized on the mortar type # and called from the basic `create_cache` method at the top. function create_cache(mesh::Union{TreeMesh{2}, StructuredMesh{2}, UnstructuredMesh2D, - P4estMesh{2}}, + P4estMesh{2}, T8codeMesh{2}}, equations, mortar_l2::LobattoLegendreMortarL2, uEltype) # TODO: Taal performance using different types MA2d = MArray{Tuple{nvariables(equations), nnodes(mortar_l2)}, uEltype, 2, @@ -110,7 +110,7 @@ end # TODO: Taal discuss/refactor timer, allowing users to pass a custom timer? function rhs!(du, u, t, - mesh::Union{TreeMesh{2}, P4estMesh{2}}, equations, + mesh::Union{TreeMesh{2}, P4estMesh{2}, T8codeMesh{2}}, equations, initial_condition, boundary_conditions, source_terms::Source, dg::DG, cache) where {Source} # Reset du @@ -180,7 +180,8 @@ end function calc_volume_integral!(du, u, mesh::Union{TreeMesh{2}, StructuredMesh{2}, - UnstructuredMesh2D, P4estMesh{2}}, + UnstructuredMesh2D, P4estMesh{2}, + T8codeMesh{2}}, nonconservative_terms, equations, volume_integral::VolumeIntegralWeakForm, dg::DGSEM, cache) @@ -226,7 +227,8 @@ end # from the evaluation of the physical fluxes in each Cartesian direction function calc_volume_integral!(du, u, mesh::Union{TreeMesh{2}, StructuredMesh{2}, - UnstructuredMesh2D, P4estMesh{2}}, + UnstructuredMesh2D, P4estMesh{2}, + T8codeMesh{2}}, nonconservative_terms, equations, volume_integral::VolumeIntegralFluxDifferencing, dg::DGSEM, cache) @@ -322,7 +324,8 @@ end # TODO: Taal dimension agnostic function calc_volume_integral!(du, u, mesh::Union{TreeMesh{2}, StructuredMesh{2}, - UnstructuredMesh2D, P4estMesh{2}}, + UnstructuredMesh2D, P4estMesh{2}, + T8codeMesh{2}}, nonconservative_terms, equations, volume_integral::VolumeIntegralShockCapturingHG, dg::DGSEM, cache) @@ -381,7 +384,8 @@ end @inline function fv_kernel!(du, u, mesh::Union{TreeMesh{2}, StructuredMesh{2}, - UnstructuredMesh2D, P4estMesh{2}}, + UnstructuredMesh2D, P4estMesh{2}, T8codeMesh{2} + }, nonconservative_terms, equations, volume_flux_fv, dg::DGSEM, cache, element, alpha = true) @unpack fstar1_L_threaded, fstar1_R_threaded, fstar2_L_threaded, fstar2_R_threaded = cache diff --git a/src/solvers/dgsem_tree/indicators_2d.jl b/src/solvers/dgsem_tree/indicators_2d.jl index f7c78547174..2f34e0eb661 100644 --- a/src/solvers/dgsem_tree/indicators_2d.jl +++ b/src/solvers/dgsem_tree/indicators_2d.jl @@ -208,7 +208,8 @@ end end # Diffuse alpha values by setting each alpha to at least 50% of neighboring elements' alpha -function apply_smoothing!(mesh::Union{TreeMesh{2}, P4estMesh{2}}, alpha, alpha_tmp, dg, +function apply_smoothing!(mesh::Union{TreeMesh{2}, P4estMesh{2}, T8codeMesh{2}}, alpha, + alpha_tmp, dg, cache) # Copy alpha values such that smoothing is indpedenent of the element access order alpha_tmp .= alpha diff --git a/src/solvers/dgsem_unstructured/dg_2d.jl b/src/solvers/dgsem_unstructured/dg_2d.jl index 95dec027a82..7b8dafdddd2 100644 --- a/src/solvers/dgsem_unstructured/dg_2d.jl +++ b/src/solvers/dgsem_unstructured/dg_2d.jl @@ -307,14 +307,14 @@ end # TODO: Taal dimension agnostic function calc_boundary_flux!(cache, t, boundary_condition::BoundaryConditionPeriodic, - mesh::Union{UnstructuredMesh2D, P4estMesh}, + mesh::Union{UnstructuredMesh2D, P4estMesh, T8codeMesh}, equations, surface_integral, dg::DG) @assert isempty(eachboundary(dg, cache)) end # Function barrier for type stability function calc_boundary_flux!(cache, t, boundary_conditions, - mesh::Union{UnstructuredMesh2D, P4estMesh}, + mesh::Union{UnstructuredMesh2D, P4estMesh, T8codeMesh}, equations, surface_integral, dg::DG) @unpack boundary_condition_types, boundary_indices = boundary_conditions @@ -327,7 +327,8 @@ end # in a type-stable way using "lispy tuple programming". function calc_boundary_flux_by_type!(cache, t, BCs::NTuple{N, Any}, BC_indices::NTuple{N, Vector{Int}}, - mesh::Union{UnstructuredMesh2D, P4estMesh}, + mesh::Union{UnstructuredMesh2D, P4estMesh, + T8codeMesh}, equations, surface_integral, dg::DG) where {N} # Extract the boundary condition type and index vector boundary_condition = first(BCs) @@ -350,7 +351,8 @@ end # terminate the type-stable iteration over tuples function calc_boundary_flux_by_type!(cache, t, BCs::Tuple{}, BC_indices::Tuple{}, - mesh::Union{UnstructuredMesh2D, P4estMesh}, + mesh::Union{UnstructuredMesh2D, P4estMesh, + T8codeMesh}, equations, surface_integral, dg::DG) nothing end diff --git a/test/runtests.jl b/test/runtests.jl index f76811dddbf..1d7eefe1fcb 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -4,113 +4,119 @@ using MPI: mpiexec # run tests on Travis CI in parallel const TRIXI_TEST = get(ENV, "TRIXI_TEST", "all") const TRIXI_MPI_NPROCS = clamp(Sys.CPU_THREADS, 2, 3) -const TRIXI_NTHREADS = clamp(Sys.CPU_THREADS, 2, 3) +const TRIXI_NTHREADS = clamp(Sys.CPU_THREADS, 2, 3) @time @testset "Trixi.jl tests" begin - # This is placed first since tests error out otherwise if `TRIXI_TEST == "all"`, - # at least on some systems. - @time if TRIXI_TEST == "all" || TRIXI_TEST == "mpi" - # Do a dummy `@test true`: - # If the process errors out the testset would error out as well, - # cf. https://github.com/JuliaParallel/MPI.jl/pull/391 - @test true - - # There are spurious test failures of Trixi.jl with MPI on Windows, see - # https://github.com/trixi-framework/Trixi.jl/issues/901 - # To reduce their impact, we do not test MPI with coverage on Windows. - # This reduces the chance to hit a spurious test failure by one half. - # In addition, it looks like the Linux GitHub runners run out of memory during the 3D tests - # with coverage, so we currently do not test MPI with coverage on Linux. For more details, - # see the discussion at https://github.com/trixi-framework/Trixi.jl/pull/1062#issuecomment-1035901020 - cmd = string(Base.julia_cmd()) - coverage = occursin("--code-coverage", cmd) && !occursin("--code-coverage=none", cmd) - if !(coverage && Sys.iswindows()) && !(coverage && Sys.islinux()) - # We provide a `--heap-size-hint` to avoid/reduce out-of-memory errors during CI testing - mpiexec() do cmd - run(`$cmd -n $TRIXI_MPI_NPROCS $(Base.julia_cmd()) --threads=1 --check-bounds=yes --heap-size-hint=1G $(abspath("test_mpi.jl"))`) - end - end - end - - @time if TRIXI_TEST == "all" || TRIXI_TEST == "threaded" || TRIXI_TEST == "threaded_legacy" - # Do a dummy `@test true`: - # If the process errors out the testset would error out as well, - # cf. https://github.com/JuliaParallel/MPI.jl/pull/391 - @test true - - run(`$(Base.julia_cmd()) --threads=$TRIXI_NTHREADS --check-bounds=yes --code-coverage=none $(abspath("test_threaded.jl"))`) - end - - @time if TRIXI_TEST == "all" || TRIXI_TEST == "tree_part1" - include("test_tree_1d.jl") - include("test_tree_2d_part1.jl") - end - - @time if TRIXI_TEST == "all" || TRIXI_TEST == "tree_part2" - include("test_tree_2d_part2.jl") - end - - @time if TRIXI_TEST == "all" || TRIXI_TEST == "tree_part3" - include("test_tree_2d_part3.jl") - end - - @time if TRIXI_TEST == "all" || TRIXI_TEST == "tree_part4" - include("test_tree_3d_part1.jl") - end - - @time if TRIXI_TEST == "all" || TRIXI_TEST == "tree_part5" - include("test_tree_3d_part2.jl") - end - - @time if TRIXI_TEST == "all" || TRIXI_TEST == "tree_part6" - include("test_tree_3d_part3.jl") - end - - @time if TRIXI_TEST == "all" || TRIXI_TEST == "structured" - include("test_structured_1d.jl") - include("test_structured_2d.jl") - include("test_structured_3d.jl") - end - - @time if TRIXI_TEST == "all" || TRIXI_TEST == "p4est_part1" - include("test_p4est_2d.jl") - end - - @time if TRIXI_TEST == "all" || TRIXI_TEST == "p4est_part2" - include("test_p4est_3d.jl") - end - - @time if TRIXI_TEST == "all" || TRIXI_TEST == "unstructured_dgmulti" - include("test_unstructured_2d.jl") - include("test_dgmulti_1d.jl") - include("test_dgmulti_2d.jl") - include("test_dgmulti_3d.jl") - end - - @time if TRIXI_TEST == "all" || TRIXI_TEST == "parabolic" - include("test_parabolic_1d.jl") - include("test_parabolic_2d.jl") - include("test_parabolic_3d.jl") - end - - @time if TRIXI_TEST == "all" || TRIXI_TEST == "misc_part1" - include("test_unit.jl") - include("test_visualization.jl") - end - - @time if TRIXI_TEST == "all" || TRIXI_TEST == "misc_part2" - include("test_special_elixirs.jl") - end - - @time if TRIXI_TEST == "all" || TRIXI_TEST == "performance_specializations_part1" - include("test_performance_specializations_2d.jl") - end - - @time if TRIXI_TEST == "all" || TRIXI_TEST == "performance_specializations_part2" - include("test_performance_specializations_3d.jl") - end - - @time if TRIXI_TEST == "all" || TRIXI_TEST == "paper_self_gravitating_gas_dynamics" - include("test_paper_self_gravitating_gas_dynamics.jl") - end + # This is placed first since tests error out otherwise if `TRIXI_TEST == "all"`, + # at least on some systems. + @time if TRIXI_TEST == "all" || TRIXI_TEST == "mpi" + # Do a dummy `@test true`: + # If the process errors out the testset would error out as well, + # cf. https://github.com/JuliaParallel/MPI.jl/pull/391 + @test true + + # There are spurious test failures of Trixi.jl with MPI on Windows, see + # https://github.com/trixi-framework/Trixi.jl/issues/901 + # To reduce their impact, we do not test MPI with coverage on Windows. + # This reduces the chance to hit a spurious test failure by one half. + # In addition, it looks like the Linux GitHub runners run out of memory during the 3D tests + # with coverage, so we currently do not test MPI with coverage on Linux. For more details, + # see the discussion at https://github.com/trixi-framework/Trixi.jl/pull/1062#issuecomment-1035901020 + cmd = string(Base.julia_cmd()) + coverage = occursin("--code-coverage", cmd) && + !occursin("--code-coverage=none", cmd) + if !(coverage && Sys.iswindows()) && !(coverage && Sys.islinux()) + # We provide a `--heap-size-hint` to avoid/reduce out-of-memory errors during CI testing + mpiexec() do cmd + run(`$cmd -n $TRIXI_MPI_NPROCS $(Base.julia_cmd()) --threads=1 --check-bounds=yes --heap-size-hint=1G $(abspath("test_mpi.jl"))`) + end + end + end + + @time if TRIXI_TEST == "all" || TRIXI_TEST == "threaded" || + TRIXI_TEST == "threaded_legacy" + # Do a dummy `@test true`: + # If the process errors out the testset would error out as well, + # cf. https://github.com/JuliaParallel/MPI.jl/pull/391 + @test true + + run(`$(Base.julia_cmd()) --threads=$TRIXI_NTHREADS --check-bounds=yes --code-coverage=none $(abspath("test_threaded.jl"))`) + end + + @time if TRIXI_TEST == "all" || TRIXI_TEST == "tree_part1" + include("test_tree_1d.jl") + include("test_tree_2d_part1.jl") + end + + @time if TRIXI_TEST == "all" || TRIXI_TEST == "tree_part2" + include("test_tree_2d_part2.jl") + end + + @time if TRIXI_TEST == "all" || TRIXI_TEST == "tree_part3" + include("test_tree_2d_part3.jl") + end + + @time if TRIXI_TEST == "all" || TRIXI_TEST == "tree_part4" + include("test_tree_3d_part1.jl") + end + + @time if TRIXI_TEST == "all" || TRIXI_TEST == "tree_part5" + include("test_tree_3d_part2.jl") + end + + @time if TRIXI_TEST == "all" || TRIXI_TEST == "tree_part6" + include("test_tree_3d_part3.jl") + end + + @time if TRIXI_TEST == "all" || TRIXI_TEST == "structured" + include("test_structured_1d.jl") + include("test_structured_2d.jl") + include("test_structured_3d.jl") + end + + @time if TRIXI_TEST == "all" || TRIXI_TEST == "p4est_part1" + include("test_p4est_2d.jl") + end + + @time if TRIXI_TEST == "all" || TRIXI_TEST == "p4est_part2" + include("test_p4est_3d.jl") + end + + @time if TRIXI_TEST == "all" || TRIXI_TEST == "t8code_part1" + include("test_t8code_2d.jl") + end + + @time if TRIXI_TEST == "all" || TRIXI_TEST == "unstructured_dgmulti" + include("test_unstructured_2d.jl") + include("test_dgmulti_1d.jl") + include("test_dgmulti_2d.jl") + include("test_dgmulti_3d.jl") + end + + @time if TRIXI_TEST == "all" || TRIXI_TEST == "parabolic" + include("test_parabolic_1d.jl") + include("test_parabolic_2d.jl") + include("test_parabolic_3d.jl") + end + + @time if TRIXI_TEST == "all" || TRIXI_TEST == "misc_part1" + include("test_unit.jl") + include("test_visualization.jl") + end + + @time if TRIXI_TEST == "all" || TRIXI_TEST == "misc_part2" + include("test_special_elixirs.jl") + end + + @time if TRIXI_TEST == "all" || TRIXI_TEST == "performance_specializations_part1" + include("test_performance_specializations_2d.jl") + end + + @time if TRIXI_TEST == "all" || TRIXI_TEST == "performance_specializations_part2" + include("test_performance_specializations_3d.jl") + end + + @time if TRIXI_TEST == "all" || TRIXI_TEST == "paper_self_gravitating_gas_dynamics" + include("test_paper_self_gravitating_gas_dynamics.jl") + end end diff --git a/test/test_t8code_2d.jl b/test/test_t8code_2d.jl new file mode 100644 index 00000000000..a424c9df84b --- /dev/null +++ b/test/test_t8code_2d.jl @@ -0,0 +1,182 @@ +module TestExamplesT8codeMesh2D + +using Test +using Trixi + +include("test_trixi.jl") + +EXAMPLES_DIR = joinpath(examples_dir(), "t8code_2d_dgsem") + +# Start with a clean environment: remove Trixi.jl output directory if it exists +outdir = "out" +isdir(outdir) && rm(outdir, recursive = true) +mkdir(outdir) + +@testset "T8codeMesh2D" begin + + @trixi_testset "test save_mesh_file" begin + @test_throws Exception begin + # Save mesh file support will be added in the future. The following + # lines of code are here for satisfying code coverage. + + # Create dummy mesh. + mesh = T8codeMesh((1, 1), polydeg = 1, + mapping = Trixi.coordinates2mapping((-1.0, -1.0), ( 1.0, 1.0)), + initial_refinement_level = 1) + + # This call throws an error. + Trixi.save_mesh_file(mesh, "dummy") + end + end + + @trixi_testset "elixir_advection_basic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), + # Expected errors are exactly the same as with TreeMesh! + l2=[8.311947673061856e-6], + linf=[6.627000273229378e-5]) + end + + @trixi_testset "elixir_advection_nonconforming_flag.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_nonconforming_flag.jl"), + l2=[3.198940059144588e-5], + linf=[0.00030636069494005547]) + end + + @trixi_testset "elixir_advection_unstructured_flag.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_unstructured_flag.jl"), + l2=[0.0005379687442422346], + linf=[0.007438525029884735]) + 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], + coverage_override=(maxiters = 6,)) + end + + @trixi_testset "elixir_advection_amr_solution_independent.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_amr_solution_independent.jl"), + # Expected errors are exactly the same as with StructuredMesh! + l2=[4.949660644033807e-5], + linf=[0.0004867846262313763], + coverage_override=(maxiters = 6,)) + end + + @trixi_testset "elixir_euler_source_terms_nonconforming_unstructured_flag.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), + l2=[ + 0.0034516244508588046, + 0.0023420334036925493, + 0.0024261923964557187, + 0.004731710454271893, + ], + linf=[ + 0.04155789011775046, + 0.024772109862748914, + 0.03759938693042297, + 0.08039824959535657, + ]) + end + + @trixi_testset "elixir_euler_free_stream.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_free_stream.jl"), + l2=[ + 2.063350241405049e-15, + 1.8571016296925367e-14, + 3.1769447886391905e-14, + 1.4104095258528071e-14, + ], + linf=[1.9539925233402755e-14, 2e-12, 4.8e-12, 4e-12], + atol=2.0e-12,) + end + + @trixi_testset "elixir_euler_shockcapturing_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing_ec.jl"), + l2=[ + 9.53984675e-02, + 1.05633455e-01, + 1.05636158e-01, + 3.50747237e-01, + ], + linf=[ + 2.94357464e-01, + 4.07893014e-01, + 3.97334516e-01, + 1.08142520e+00, + ], + tspan=(0.0, 1.0)) + end + + @trixi_testset "elixir_euler_sedov.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov.jl"), + l2=[ + 3.76149952e-01, + 2.46970327e-01, + 2.46970327e-01, + 1.28889042e+00, + ], + linf=[ + 1.22139001e+00, + 1.17742626e+00, + 1.17742626e+00, + 6.20638482e+00, + ], + tspan=(0.0, 0.3)) + end + + @trixi_testset "elixir_shallowwater_source_terms.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), + l2=[ + 9.168126407325352e-5, + 0.0009795410115453788, + 0.002546408320320785, + 3.941189812642317e-6, + ], + linf=[ + 0.0009903782521019089, + 0.0059752684687262025, + 0.010941106525454103, + 1.2129488214718265e-5, + ], + tspan=(0.0, 0.1)) + end + + @trixi_testset "elixir_mhd_alfven_wave.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), + l2=[1.0513414461545583e-5, 1.0517900957166411e-6, + 1.0517900957304043e-6, 1.511816606372376e-6, + 1.0443997728645063e-6, 7.879639064990798e-7, + 7.879639065049896e-7, 1.0628631669056271e-6, + 4.3382328912336153e-7], + linf=[4.255466285174592e-5, 1.0029706745823264e-5, + 1.0029706747467781e-5, 1.2122265939010224e-5, + 5.4791097160444835e-6, 5.18922042269665e-6, + 5.189220422141538e-6, 9.552667261422676e-6, + 1.4237578427628152e-6]) + end + + @trixi_testset "elixir_mhd_rotor.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_rotor.jl"), + l2=[0.44211360369891683, 0.8805178316216257, 0.8262710688468049, + 0.0, + 0.9616090460973586, 0.10386643568745411, + 0.15403457366543802, 0.0, + 2.8399715649715473e-5], + linf=[10.04369305341599, 17.995640564998403, 9.576041548174265, + 0.0, + 19.429658884314534, 1.3821395681242314, 1.818559351543182, + 0.0, + 0.002261930217575465], + tspan=(0.0, 0.02)) + end +end + +# Clean up afterwards: delete Trixi.jl output directory +@test_nowarn rm(outdir, recursive = true) + +end # module diff --git a/test/test_threaded.jl b/test/test_threaded.jl index 77fa16ad33e..9b30836d0ed 100644 --- a/test/test_threaded.jl +++ b/test/test_threaded.jl @@ -235,6 +235,22 @@ Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) end + @testset "T8codeMesh" begin + @trixi_testset "elixir_euler_source_terms_nonconforming_unstructured_flag.jl" begin + @test_trixi_include(joinpath(examples_dir(), "t8code_2d_dgsem", "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), + l2 = [0.0034516244508588046, 0.0023420334036925493, 0.0024261923964557187, 0.004731710454271893], + linf = [0.04155789011775046, 0.024772109862748914, 0.03759938693042297, 0.08039824959535657]) + end + + @trixi_testset "elixir_eulergravity_convergence.jl" begin + @test_trixi_include(joinpath(examples_dir(), "t8code_2d_dgsem", "elixir_eulergravity_convergence.jl"), + l2 = [0.00024871265138964204, 0.0003370077102132591, 0.0003370077102131964, 0.0007231525513793697], + linf = [0.0015813032944647087, 0.0020494288423820173, 0.0020494288423824614, 0.004793821195083758], + tspan = (0.0, 0.1)) + end + end + + @testset "DGMulti" begin @trixi_testset "elixir_euler_weakform.jl (SBP, EC)" begin @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_euler_weakform.jl"), From e1e680ca8574acd10daa2e5bc5e1f49e1ce008f9 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Fri, 28 Jul 2023 04:35:33 +0200 Subject: [PATCH 055/263] Enstrophy for 2D Navier-Stokes (#1591) * Doubly periodic shear layer * test if prject toml shows up in git diff * remove chnages * Enstrophy for 2D Navier-Stokes --- Project.toml | 2 +- .../elixir_navierstokes_shear_layer.jl | 71 +++++++++++++++++++ src/callbacks_step/analysis_dg2d.jl | 18 +++++ .../compressible_navier_stokes_2d.jl | 15 ++++ test/test_parabolic_2d.jl | 4 ++ 5 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 examples/tree_2d_dgsem/elixir_navierstokes_shear_layer.jl diff --git a/Project.toml b/Project.toml index db410317851..b3ca99be9ec 100644 --- a/Project.toml +++ b/Project.toml @@ -60,8 +60,8 @@ HDF5 = "0.14, 0.15, 0.16" IfElse = "0.1" LinearMaps = "2.7, 3.0" LoopVectorization = "0.12.118" -Makie = "0.19" MPI = "0.20" +Makie = "0.19" MuladdMacro = "0.2.2" Octavian = "0.3.5" OffsetArrays = "1.3" diff --git a/examples/tree_2d_dgsem/elixir_navierstokes_shear_layer.jl b/examples/tree_2d_dgsem/elixir_navierstokes_shear_layer.jl new file mode 100644 index 00000000000..a7cb2fc89f1 --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_navierstokes_shear_layer.jl @@ -0,0 +1,71 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Navier-Stokes equations + +# TODO: parabolic; unify names of these accessor functions +prandtl_number() = 0.72 +mu() = 1.0/3.0 * 10^(-3) # equivalent to Re = 3000 + +equations = CompressibleEulerEquations2D(1.4) +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu=mu(), + Prandtl=prandtl_number()) + +function initial_condition_shear_layer(x, t, equations::CompressibleEulerEquations2D) + k = 80 + delta = 0.05 + u0 = 1.0 + Ms = 0.1 # maximum Mach number + + rho = 1.0 + v1 = x[2] <= 0.5 ? u0*tanh(k*(x[2]*0.5 - 0.25)) : tanh(k*(0.75 -x[2]*0.5)) + v2 = u0*delta * sin(2*pi*(x[1]*0.5 + 0.25)) + p = (u0 / Ms)^2 * rho / equations.gamma # scaling to get Ms + + return prim2cons(SVector(rho, v1, v2, p), equations) +end +initial_condition = initial_condition_shear_layer + +volume_flux = flux_ranocha +solver = DGSEM(polydeg=3, surface_flux=flux_hllc, + volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = (0.0, 0.0) +coordinates_max = (1.0, 1.0) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + n_cells_max=100_000) + + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 2.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 50 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=true, + extra_analysis_integrals=(energy_kinetic, + energy_internal, + enstrophy)) + +alive_callback = AliveCallback(analysis_interval=analysis_interval,) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, + ode_default_options()..., callback=callbacks) +summary_callback() # print the timer summary \ No newline at end of file diff --git a/src/callbacks_step/analysis_dg2d.jl b/src/callbacks_step/analysis_dg2d.jl index 4e456f79872..aecabf0e4b7 100644 --- a/src/callbacks_step/analysis_dg2d.jl +++ b/src/callbacks_step/analysis_dg2d.jl @@ -213,6 +213,24 @@ function integrate(func::Func, u, end end +function integrate(func::Func, u, + mesh::Union{TreeMesh{2}, P4estMesh{2}}, + equations, equations_parabolic, + dg::DGSEM, + cache, cache_parabolic; normalize = true) where {Func} + gradients_x, gradients_y = cache_parabolic.gradients + integrate_via_indices(u, mesh, equations, dg, cache; + normalize = normalize) do u, i, j, element, equations, dg + u_local = get_node_vars(u, equations, dg, i, j, element) + gradients_1_local = get_node_vars(gradients_x, equations_parabolic, dg, i, j, + element) + gradients_2_local = get_node_vars(gradients_y, equations_parabolic, dg, i, j, + element) + return func(u_local, (gradients_1_local, gradients_2_local), + equations_parabolic) + end +end + function analyze(::typeof(entropy_timederivative), du, u, t, mesh::Union{TreeMesh{2}, StructuredMesh{2}, UnstructuredMesh2D, P4estMesh{2}, T8codeMesh{2}}, diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 9b06e0b5abf..a1f11717e69 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -300,6 +300,21 @@ end return T end +@inline function enstrophy(u, gradients, equations::CompressibleNavierStokesDiffusion2D) + # Enstrophy is 0.5 rho ω⋅ω where ω = ∇ × v + + omega = vorticity(u, gradients, equations) + return 0.5 * u[1] * omega^2 +end + +@inline function vorticity(u, gradients, equations::CompressibleNavierStokesDiffusion2D) + # Ensure that we have velocity `gradients` by way of the `convert_gradient_variables` function. + _, dv1dx, dv2dx, _ = convert_derivative_to_primitive(u, gradients[1], equations) + _, dv1dy, dv2dy, _ = convert_derivative_to_primitive(u, gradients[2], equations) + + return dv2dx - dv1dy +end + # TODO: can we generalize this to MHD? """ struct BoundaryConditionNavierStokesWall diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 471b976e990..57f296b55fe 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -136,6 +136,10 @@ isdir(outdir) && rm(outdir, recursive=true) @trixi_testset "TreeMesh2D: elixir_navierstokes_convergence.jl" begin @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navierstokes_convergence.jl"), initial_refinement_level = 2, tspan=(0.0, 0.1), + analysis_callback = AnalysisCallback(semi, interval=analysis_interval, + extra_analysis_integrals=(energy_kinetic, + energy_internal, + enstrophy)), l2 = [0.002111672530658797, 0.0034322351490857846, 0.0038742528195910416, 0.012469246082568561], linf = [0.012006418939223495, 0.035520871209746126, 0.024512747492231427, 0.11191122588756564] ) From 73e58dc59ad0e06616507b9338c8fe0bee5b99b4 Mon Sep 17 00:00:00 2001 From: Jesse Chan <1156048+jlchan@users.noreply.github.com> Date: Fri, 28 Jul 2023 23:28:53 -0500 Subject: [PATCH 056/263] remove CI functions that cause preocmpilation errors (#1593) --- src/solvers/dgsem_p4est/dg_3d_parabolic.jl | 54 ---------------------- 1 file changed, 54 deletions(-) diff --git a/src/solvers/dgsem_p4est/dg_3d_parabolic.jl b/src/solvers/dgsem_p4est/dg_3d_parabolic.jl index 5370c927e05..6439cad69bb 100644 --- a/src/solvers/dgsem_p4est/dg_3d_parabolic.jl +++ b/src/solvers/dgsem_p4est/dg_3d_parabolic.jl @@ -563,60 +563,6 @@ function prolong2boundaries!(cache_parabolic, flux_viscous, return nothing end -# # Function barrier for type stability -# !!! TODO: Figure out why this cannot removed eventhough it exists in the dg_2d_parabolic.jl file -function calc_boundary_flux_gradients!(cache, t, boundary_conditions, mesh::P4estMesh, - equations, surface_integral, dg::DG) - (; boundary_condition_types, boundary_indices) = boundary_conditions - - calc_boundary_flux_by_type!(cache, t, boundary_condition_types, boundary_indices, - Gradient(), mesh, equations, surface_integral, dg) - return nothing -end - -function calc_boundary_flux_divergence!(cache, t, boundary_conditions, mesh::P4estMesh, - equations, surface_integral, dg::DG) - (; boundary_condition_types, boundary_indices) = boundary_conditions - - calc_boundary_flux_by_type!(cache, t, boundary_condition_types, boundary_indices, - Divergence(), mesh, equations, surface_integral, dg) - return nothing -end - -# Iterate over tuples of boundary condition types and associated indices -# in a type-stable way using "lispy tuple programming". -function calc_boundary_flux_by_type!(cache, t, BCs::NTuple{N, Any}, - BC_indices::NTuple{N, Vector{Int}}, - operator_type, - mesh::P4estMesh, - equations, surface_integral, dg::DG) where {N} - # Extract the boundary condition type and index vector - boundary_condition = first(BCs) - boundary_condition_indices = first(BC_indices) - # Extract the remaining types and indices to be processed later - remaining_boundary_conditions = Base.tail(BCs) - remaining_boundary_condition_indices = Base.tail(BC_indices) - - # process the first boundary condition type - calc_boundary_flux!(cache, t, boundary_condition, boundary_condition_indices, - operator_type, mesh, equations, surface_integral, dg) - - # recursively call this method with the unprocessed boundary types - calc_boundary_flux_by_type!(cache, t, remaining_boundary_conditions, - remaining_boundary_condition_indices, - operator_type, - mesh, equations, surface_integral, dg) - - return nothing -end - -# terminate the type-stable iteration over tuples -function calc_boundary_flux_by_type!(cache, t, BCs::Tuple{}, BC_indices::Tuple{}, - operator_type, mesh::P4estMesh, equations, - surface_integral, dg::DG) - nothing -end - function calc_boundary_flux!(cache, t, boundary_condition_parabolic, # works with Dict types boundary_condition_indices, From d05f9c5bfc329db3448a7af18bb1c24cfb75deb2 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Sun, 30 Jul 2023 08:19:37 +0200 Subject: [PATCH 057/263] run only threaded tests by default (#1592) --- test/runtests.jl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 1d7eefe1fcb..1b0c745dbfd 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,8 +1,11 @@ using Test using MPI: mpiexec -# run tests on Travis CI in parallel -const TRIXI_TEST = get(ENV, "TRIXI_TEST", "all") +# We run tests in parallel with CI jobs setting the `TRIXI_TEST` environment +# variable to determine the subset of tests to execute. +# By default, we just run the threaded tests since they are relatively cheap +# and test a good amount of different functionality. +const TRIXI_TEST = get(ENV, "TRIXI_TEST", "threaded") const TRIXI_MPI_NPROCS = clamp(Sys.CPU_THREADS, 2, 3) const TRIXI_NTHREADS = clamp(Sys.CPU_THREADS, 2, 3) From d208cee2690fb5b1d63a0511ad5f73967d340205 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Sun, 30 Jul 2023 09:47:44 +0200 Subject: [PATCH 058/263] set version to v0.5.37 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index b3ca99be9ec..1d06317f53a 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.5.37-pre" +version = "0.5.37" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From e76ea3932d875774220811ff0c14c8e966c312bf Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Sun, 30 Jul 2023 09:47:57 +0200 Subject: [PATCH 059/263] set development version to v0.5.38-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 1d06317f53a..c22d4b90642 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.5.37" +version = "0.5.38-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 6c97c48e53feb9fe372dc020cbd5f3e1e8fef458 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Aug 2023 07:15:15 +0200 Subject: [PATCH 060/263] Bump crate-ci/typos from 1.16.1 to 1.16.2 (#1598) * Bump crate-ci/typos from 1.16.1 to 1.16.2 Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.16.1 to 1.16.2. - [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.16.1...v1.16.2) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * f_sur -> f_surface --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Hendrik Ranocha --- .github/workflows/SpellCheck.yml | 2 +- docs/literate/src/files/DGSEM_FluxDiff.jl | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/SpellCheck.yml b/.github/workflows/SpellCheck.yml index f72c3b0947b..a1a429cad97 100644 --- a/.github/workflows/SpellCheck.yml +++ b/.github/workflows/SpellCheck.yml @@ -10,4 +10,4 @@ jobs: - name: Checkout Actions Repository uses: actions/checkout@v3 - name: Check spelling - uses: crate-ci/typos@v1.16.1 + uses: crate-ci/typos@v1.16.2 diff --git a/docs/literate/src/files/DGSEM_FluxDiff.jl b/docs/literate/src/files/DGSEM_FluxDiff.jl index cf3b0a1dbd4..5ec156ebbe3 100644 --- a/docs/literate/src/files/DGSEM_FluxDiff.jl +++ b/docs/literate/src/files/DGSEM_FluxDiff.jl @@ -96,13 +96,13 @@ # \begin{align*} # J \underline{\dot{u}}(t) &= - M^{-1} B (\underline{f}^* - \underline{f}) - 2D \underline{f}_{vol}(u^-, u^+)\\[5pt] # &= - M^{-1} B (\underline{f}^* - \underline{f}_{vol}(\underline{u}, \underline{u})) - 2D \underline{f}_{vol}(u^-, u^+)\\[5pt] -# &= - M^{-1} B \underline{f}_{sur}^* - (2D - M^{-1} B) \underline{f}_{vol}\\[5pt] -# &= - M^{-1} B \underline{f}_{sur}^* - D_{split} \underline{f}_{vol} +# &= - M^{-1} B \underline{f}_{surface}^* - (2D - M^{-1} B) \underline{f}_{vol}\\[5pt] +# &= - M^{-1} B \underline{f}_{surface}^* - D_{split} \underline{f}_{vol} # \end{align*} # ``` # This formulation is in a weak form type formulation and can be implemented by using the derivative # split matrix $D_{split}=(2D-M^{-1}B)$ and two different fluxes. We divide between the surface -# flux $f=f_{sur}$ used for the numerical flux $f_{sur}^*$ and the already mentioned volume +# flux $f=f_{surface}$ used for the numerical flux $f_{surface}^*$ and the already mentioned volume # flux $f_{vol}$ especially for this formulation. From ddf089271c65d82b466711e59b5f791c0bd21021 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Tue, 8 Aug 2023 10:17:31 +0200 Subject: [PATCH 061/263] Avoid allocations in `boundary flux` for parabolic RHS (#1594) * Remove doubled implementations * kepp main updated with true main * Avoid allocations in parabolic boundary fluxes * Correct shear layer IC * Whitespaces * Update examples/tree_2d_dgsem/elixir_navierstokes_convergence.jl Co-authored-by: Hendrik Ranocha * Update examples/tree_3d_dgsem/elixir_navierstokes_convergence.jl Co-authored-by: Hendrik Ranocha --------- Co-authored-by: Hendrik Ranocha --- examples/tree_2d_dgsem/elixir_navierstokes_convergence.jl | 5 ++++- examples/tree_2d_dgsem/elixir_navierstokes_shear_layer.jl | 6 ++++-- examples/tree_3d_dgsem/elixir_navierstokes_convergence.jl | 5 ++++- src/solvers/dgsem_tree/containers_2d.jl | 6 +++--- src/solvers/dgsem_tree/containers_3d.jl | 8 ++++---- 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_navierstokes_convergence.jl b/examples/tree_2d_dgsem/elixir_navierstokes_convergence.jl index 36a9f52e39d..b68e9e6c97e 100644 --- a/examples/tree_2d_dgsem/elixir_navierstokes_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_navierstokes_convergence.jl @@ -170,7 +170,10 @@ end initial_condition = initial_condition_navier_stokes_convergence_test # BC types -velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:3]) +velocity_bc_top_bottom = NoSlip() do x, t, equations + u = initial_condition_navier_stokes_convergence_test(x, t, equations) + return SVector(u[2], u[3]) +end heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, heat_bc_top_bottom) diff --git a/examples/tree_2d_dgsem/elixir_navierstokes_shear_layer.jl b/examples/tree_2d_dgsem/elixir_navierstokes_shear_layer.jl index a7cb2fc89f1..dd26fd8097b 100644 --- a/examples/tree_2d_dgsem/elixir_navierstokes_shear_layer.jl +++ b/examples/tree_2d_dgsem/elixir_navierstokes_shear_layer.jl @@ -14,14 +14,16 @@ equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu=mu(), Prandtl=prandtl_number()) function initial_condition_shear_layer(x, t, equations::CompressibleEulerEquations2D) + # Shear layer parameters k = 80 delta = 0.05 u0 = 1.0 + Ms = 0.1 # maximum Mach number rho = 1.0 - v1 = x[2] <= 0.5 ? u0*tanh(k*(x[2]*0.5 - 0.25)) : tanh(k*(0.75 -x[2]*0.5)) - v2 = u0*delta * sin(2*pi*(x[1]*0.5 + 0.25)) + v1 = x[2] <= 0.5 ? u0 * tanh(k*(x[2]*0.5 - 0.25)) : u0 * tanh(k*(0.75 -x[2]*0.5)) + v2 = u0 * delta * sin(2*pi*(x[1]*0.5 + 0.25)) p = (u0 / Ms)^2 * rho / equations.gamma # scaling to get Ms return prim2cons(SVector(rho, v1, v2, p), equations) diff --git a/examples/tree_3d_dgsem/elixir_navierstokes_convergence.jl b/examples/tree_3d_dgsem/elixir_navierstokes_convergence.jl index b32355c48df..ebb0137a1bb 100644 --- a/examples/tree_3d_dgsem/elixir_navierstokes_convergence.jl +++ b/examples/tree_3d_dgsem/elixir_navierstokes_convergence.jl @@ -220,7 +220,10 @@ end initial_condition = initial_condition_navier_stokes_convergence_test # BC types -velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:4]) +velocity_bc_top_bottom = NoSlip() do x, t, equations + u = initial_condition_navier_stokes_convergence_test(x, t, equations) + return SVector(u[2], u[3], u[4]) +end heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, heat_bc_top_bottom) diff --git a/src/solvers/dgsem_tree/containers_2d.jl b/src/solvers/dgsem_tree/containers_2d.jl index 5cf256d3499..d80522d42fd 100644 --- a/src/solvers/dgsem_tree/containers_2d.jl +++ b/src/solvers/dgsem_tree/containers_2d.jl @@ -764,10 +764,10 @@ end # Container data structure (structure-of-arrays style) for DG MPI interfaces mutable struct MPIInterfaceContainer2D{uEltype <: Real} <: AbstractContainer - u::Array{uEltype, 4} # [leftright, variables, i, interfaces] + u::Array{uEltype, 4} # [leftright, variables, i, interfaces] local_neighbor_ids::Vector{Int} # [interfaces] - orientations::Vector{Int} # [interfaces] - remote_sides::Vector{Int} # [interfaces] + orientations::Vector{Int} # [interfaces] + remote_sides::Vector{Int} # [interfaces] # internal `resize!`able storage _u::Vector{uEltype} end diff --git a/src/solvers/dgsem_tree/containers_3d.jl b/src/solvers/dgsem_tree/containers_3d.jl index 0318946e34d..5fc027ad001 100644 --- a/src/solvers/dgsem_tree/containers_3d.jl +++ b/src/solvers/dgsem_tree/containers_3d.jl @@ -520,14 +520,14 @@ end # Left and right are used *both* for the numbering of the mortar faces *and* for the position of the # elements with respect to the axis orthogonal to the mortar. mutable struct L2MortarContainer3D{uEltype <: Real} <: AbstractContainer - u_upper_left::Array{uEltype, 5} # [leftright, variables, i, j, mortars] + u_upper_left::Array{uEltype, 5} # [leftright, variables, i, j, mortars] u_upper_right::Array{uEltype, 5} # [leftright, variables, i, j, mortars] - u_lower_left::Array{uEltype, 5} # [leftright, variables, i, j, mortars] + u_lower_left::Array{uEltype, 5} # [leftright, variables, i, j, mortars] u_lower_right::Array{uEltype, 5} # [leftright, variables, i, j, mortars] - neighbor_ids::Array{Int, 2} # [position, mortars] + neighbor_ids::Array{Int, 2} # [position, mortars] # Large sides: left -> 1, right -> 2 large_sides::Vector{Int} # [mortars] - orientations::Vector{Int} # [mortars] + orientations::Vector{Int} # [mortars] # internal `resize!`able storage _u_upper_left::Vector{uEltype} _u_upper_right::Vector{uEltype} From 7936e61b46b6a61ac0854b42a6082204700c7eca Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Wed, 9 Aug 2023 13:33:59 +0200 Subject: [PATCH 062/263] Adapt `jacobian_ad_forward` for hyperbolic-parabolic semidiscretizations (#1589) * JacobianAD calls correct RHS for Hyperbolic-Parabolic * Nonlinear test * Format * Bring default _jacobian_ad_forward back * CI for 2D Taylor-Green * covered by standard version * implement rhs directly in jacobina_ad_forward * Update src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl Co-authored-by: Hendrik Ranocha * Add reference for 3D Taylor-Green Vortex * Update doc * Update tests 2D Taylor-Green Vortex * Fix copy-paste error * Viscous TGV comment --------- Co-authored-by: Hendrik Ranocha --- ...elixir_navierstokes_taylor_green_vortex.jl | 78 +++++++++++++++++++ ...elixir_navierstokes_taylor_green_vortex.jl | 6 +- ...semidiscretization_hyperbolic_parabolic.jl | 15 ++++ test/test_parabolic_2d.jl | 7 ++ test/test_special_elixirs.jl | 18 +++++ 5 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 examples/tree_2d_dgsem/elixir_navierstokes_taylor_green_vortex.jl diff --git a/examples/tree_2d_dgsem/elixir_navierstokes_taylor_green_vortex.jl b/examples/tree_2d_dgsem/elixir_navierstokes_taylor_green_vortex.jl new file mode 100644 index 00000000000..c3cbc858f7b --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_navierstokes_taylor_green_vortex.jl @@ -0,0 +1,78 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Navier-Stokes equations + +# TODO: parabolic; unify names of these accessor functions +prandtl_number() = 0.72 +mu() = 6.25e-4 # equivalent to Re = 1600 + +equations = CompressibleEulerEquations2D(1.4) +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu=mu(), + Prandtl=prandtl_number()) + +""" + initial_condition_taylor_green_vortex(x, t, equations::CompressibleEulerEquations2D) + +The classical viscous Taylor-Green vortex in 2D. +This forms the basis behind the 3D case found for instance in + - Jonathan R. Bull and Antony Jameson + Simulation of the Compressible Taylor Green Vortex using High-Order Flux Reconstruction Schemes + [DOI: 10.2514/6.2014-3210](https://doi.org/10.2514/6.2014-3210) +""" +function initial_condition_taylor_green_vortex(x, t, equations::CompressibleEulerEquations2D) + A = 1.0 # magnitude of speed + Ms = 0.1 # maximum Mach number + + rho = 1.0 + v1 = A * sin(x[1]) * cos(x[2]) + v2 = -A * cos(x[1]) * sin(x[2]) + p = (A / Ms)^2 * rho / equations.gamma # scaling to get Ms + p = p + 1.0/4.0 * A^2 * rho * (cos(2*x[1]) + cos(2*x[2])) + + return prim2cons(SVector(rho, v1, v2, p), equations) +end +initial_condition = initial_condition_taylor_green_vortex + +volume_flux = flux_ranocha +solver = DGSEM(polydeg=3, surface_flux=flux_hllc, + volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = (-1.0, -1.0) .* pi +coordinates_max = ( 1.0, 1.0) .* pi +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + n_cells_max=100_000) + + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 20.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=true, + extra_analysis_integrals=(energy_kinetic, + energy_internal)) + +alive_callback = AliveCallback(analysis_interval=analysis_interval,) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-9 +sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, + ode_default_options()..., callback=callbacks) +summary_callback() # print the timer summary \ No newline at end of file diff --git a/examples/tree_3d_dgsem/elixir_navierstokes_taylor_green_vortex.jl b/examples/tree_3d_dgsem/elixir_navierstokes_taylor_green_vortex.jl index 9cb73a462b7..5556831a59d 100644 --- a/examples/tree_3d_dgsem/elixir_navierstokes_taylor_green_vortex.jl +++ b/examples/tree_3d_dgsem/elixir_navierstokes_taylor_green_vortex.jl @@ -16,7 +16,11 @@ equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu=mu(), """ initial_condition_taylor_green_vortex(x, t, equations::CompressibleEulerEquations3D) -The classical inviscid Taylor-Green vortex. +The classical viscous Taylor-Green vortex, as found for instance in + +- Jonathan R. Bull and Antony Jameson + Simulation of the Compressible Taylor Green Vortex using High-Order Flux Reconstruction Schemes + [DOI: 10.2514/6.2014-3210](https://doi.org/10.2514/6.2014-3210) """ function initial_condition_taylor_green_vortex(x, t, equations::CompressibleEulerEquations3D) A = 1.0 # magnitude of speed diff --git a/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl b/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl index 8f1e38c891b..b12ecadb58b 100644 --- a/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl +++ b/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl @@ -330,4 +330,19 @@ function rhs_parabolic!(du_ode, u_ode, semi::SemidiscretizationHyperbolicParabol return nothing end + +function _jacobian_ad_forward(semi::SemidiscretizationHyperbolicParabolic, t0, u0_ode, + du_ode, config) + new_semi = remake(semi, uEltype = eltype(config)) + + du_ode_hyp = Vector{eltype(config)}(undef, length(du_ode)) + J = ForwardDiff.jacobian(du_ode, u0_ode, config) do du_ode, u_ode + # Implementation of split ODE problem in OrdinaryDiffEq + rhs!(du_ode_hyp, u_ode, new_semi, t0) + rhs_parabolic!(du_ode, u_ode, new_semi, t0) + du_ode .+= du_ode_hyp + end + + return J +end end # @muladd diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 57f296b55fe..e3bb1ed9fb1 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -188,6 +188,13 @@ isdir(outdir) && rm(outdir, recursive=true) ) end + @trixi_testset "TreeMesh2D: elixir_navierstokes_taylor_green_vortex.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navierstokes_taylor_green_vortex.jl"), + l2 = [0.0009279657228109691, 0.012454661988687185, 0.012454661988689886, 0.030487112728612178], + linf = [0.002435582543096171, 0.024824039368199546, 0.024824039368212758, 0.06731583711777489] + ) + end + @trixi_testset "P4estMesh2D: elixir_advection_diffusion_periodic.jl" begin @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_advection_diffusion_periodic.jl"), trees_per_dimension = (1, 1), initial_refinement_level = 2, tspan=(0.0, 0.5), diff --git a/test/test_special_elixirs.jl b/test/test_special_elixirs.jl index 23017059eaa..c05dfbdfca1 100644 --- a/test/test_special_elixirs.jl +++ b/test/test_special_elixirs.jl @@ -107,6 +107,15 @@ coverage = occursin("--code-coverage", cmd) && !occursin("--code-coverage=none", @test maximum(real, λ) < 10 * sqrt(eps(real(semi))) end + @timed_testset "Linear advection-diffusion" begin + trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_2d_dgsem", "elixir_advection_diffusion.jl"), + tspan=(0.0, 0.0), initial_refinement_level=2) + + J = jacobian_ad_forward(semi) + λ = eigvals(J) + @test maximum(real, λ) < 10 * sqrt(eps(real(semi))) + end + @timed_testset "Compressible Euler equations" begin trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_2d_dgsem", "elixir_euler_density_wave.jl"), tspan=(0.0, 0.0), initial_refinement_level=1) @@ -165,6 +174,15 @@ coverage = occursin("--code-coverage", cmd) && !occursin("--code-coverage=none", end end + @timed_testset "Navier-Stokes" begin + trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_2d_dgsem", "elixir_navierstokes_taylor_green_vortex.jl"), + tspan=(0.0, 0.0), initial_refinement_level=2) + + J = jacobian_ad_forward(semi) + λ = eigvals(J) + @test maximum(real, λ) < 0.2 + end + @timed_testset "MHD" begin trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_2d_dgsem", "elixir_mhd_alfven_wave.jl"), tspan=(0.0, 0.0), initial_refinement_level=0) From ce81702ef7c092e6b8c783a405312e7c461dfc04 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Wed, 9 Aug 2023 14:39:32 +0200 Subject: [PATCH 063/263] Fix typo (#1600) * Fix typo --------- Co-authored-by: Hendrik Ranocha --- src/semidiscretization/semidiscretization.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/semidiscretization/semidiscretization.jl b/src/semidiscretization/semidiscretization.jl index fbdcd73e2a8..c784f716426 100644 --- a/src/semidiscretization/semidiscretization.jl +++ b/src/semidiscretization/semidiscretization.jl @@ -363,7 +363,7 @@ end # # In some sense, having plain multidimensional `Array`s not support `resize!` # isn't necessarily a bug (although it would be nice to add this possibility to -# base Julia) but can turn out to be a feature for us, because it will aloow us +# base Julia) but can turn out to be a feature for us, because it will allow us # more specializations. # Since we can use multiple dispatch, these kinds of specializations can be # tailored specifically to each combinations of mesh/solver etc. From 3ca93afed4ab4efbd6022f65aa88b9a3a7608906 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Thu, 10 Aug 2023 22:25:36 +0200 Subject: [PATCH 064/263] L2 Mortars for Parabolic Terms on TreeMeshes (#1571) * First try mortars for parabolic terms * Use correct interface values in calc_fstar! * Format parabolic 2d dgsem * Remove unused function parameters * L2 Mortars for 3D DGSEM TreeMesh * Format * Back to original example * Dispatch 2D DGSEm rhs_parabolic for p4est and classic tree * Re-use standard prolong2mortars in gradient comp * Back to original version * Add tests for L2 mortars for hyp-para * remove whitespaces * Use original analysis callback * Test Taylor-Green with different integrator * Remove whitespace * check coverage status * Stick to CK2N54 for 3D test * Add more explicit dispatch * Less invasive treatment for mortars and p4est * Revert "Add more explicit dispatch" This reverts commit 491c923d09ba335c03524894d9f59acf1d6ee699. * More explicit dispatch * Remove additional end * Remove doubled implementations * kepp main updated with true main * Add comment * comment parabolic 3d * whitespace * Avoid allocations in parabolic boundary fluxes * Update src/solvers/dgsem_tree/dg_2d_parabolic.jl Co-authored-by: Andrew Winters * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl Co-authored-by: Andrew Winters * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl Co-authored-by: Andrew Winters * revert alloc BC (other PR) * Revert alloc BC (other PR) * Name & News * Update NEWS.md Co-authored-by: Andrew Winters * Update src/solvers/dgsem_p4est/dg_2d_parabolic.jl Co-authored-by: Hendrik Ranocha * Update src/solvers/dgsem_p4est/dg_3d_parabolic.jl Co-authored-by: Hendrik Ranocha * Check allocations --------- Co-authored-by: Hendrik Ranocha Co-authored-by: Andrew Winters --- AUTHORS.md | 1 + NEWS.md | 1 + src/solvers/dgsem_p4est/dg_2d_parabolic.jl | 91 ++++++ src/solvers/dgsem_p4est/dg_3d_parabolic.jl | 99 +++++++ src/solvers/dgsem_tree/dg_2d_parabolic.jl | 252 +++++++++++++++- src/solvers/dgsem_tree/dg_3d_parabolic.jl | 323 ++++++++++++++++++++- test/test_parabolic_2d.jl | 54 ++++ test/test_parabolic_3d.jl | 58 +++- 8 files changed, 870 insertions(+), 9 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index abaa3e7e037..74bfaa9c852 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -28,6 +28,7 @@ are listed in alphabetical order: * Jesse Chan * Lars Christmann * Christof Czernik +* Daniel Doehring * Patrick Ersing * Erik Faulhaber * Gregor Gassner diff --git a/NEWS.md b/NEWS.md index 8e374d9ce99..10125c40d17 100644 --- a/NEWS.md +++ b/NEWS.md @@ -9,6 +9,7 @@ for human readability. #### Added - Experimental support for 3D parabolic diffusion terms has been added. +- Non-uniform `TreeMesh` available for hyperbolic-parabolic equations. - Capability to set truly discontinuous initial conditions in 1D. - Wetting and drying feature and examples for 1D and 2D shallow water equations diff --git a/src/solvers/dgsem_p4est/dg_2d_parabolic.jl b/src/solvers/dgsem_p4est/dg_2d_parabolic.jl index 7e90a83a9ca..a04523d2fb4 100644 --- a/src/solvers/dgsem_p4est/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_p4est/dg_2d_parabolic.jl @@ -22,6 +22,97 @@ function create_cache_parabolic(mesh::P4estMesh{2}, equations_hyperbolic::Abstra return cache end +# TODO: Remove in favor of the implementation for the TreeMesh +# once the P4estMesh can handle mortars as well +function rhs_parabolic!(du, u, t, mesh::P4estMesh{2}, + equations_parabolic::AbstractEquationsParabolic, + initial_condition, boundary_conditions_parabolic, source_terms, + dg::DG, parabolic_scheme, cache, cache_parabolic) + (; u_transformed, gradients, flux_viscous) = cache_parabolic + + # Convert conservative variables to a form more suitable for viscous flux calculations + @trixi_timeit timer() "transform variables" begin + transform_variables!(u_transformed, u, mesh, equations_parabolic, + dg, parabolic_scheme, cache, cache_parabolic) + end + + # Compute the gradients of the transformed variables + @trixi_timeit timer() "calculate gradient" begin + calc_gradient!(gradients, u_transformed, t, mesh, equations_parabolic, + boundary_conditions_parabolic, dg, cache, cache_parabolic) + end + + # Compute and store the viscous fluxes + @trixi_timeit timer() "calculate viscous fluxes" begin + calc_viscous_fluxes!(flux_viscous, gradients, u_transformed, mesh, + equations_parabolic, dg, cache, cache_parabolic) + end + + # The remainder of this function is essentially a regular rhs! for parabolic + # equations (i.e., it computes the divergence of the viscous fluxes) + # + # OBS! In `calc_viscous_fluxes!`, the viscous flux values at the volume nodes of each element have + # been computed and stored in `fluxes_viscous`. In the following, we *reuse* (abuse) the + # `interfaces` and `boundaries` containers in `cache_parabolic` to interpolate and store the + # *fluxes* at the element surfaces, as opposed to interpolating and storing the *solution* (as it + # is done in the hyperbolic operator). That is, `interfaces.u`/`boundaries.u` store *viscous flux values* + # and *not the solution*. The advantage is that a) we do not need to allocate more storage, b) we + # do not need to recreate the existing data structure only with a different name, and c) we do not + # need to interpolate solutions *and* gradients to the surfaces. + + # TODO: parabolic; reconsider current data structure reuse strategy + + # Reset du + @trixi_timeit timer() "reset ∂u/∂t" reset_du!(du, dg, cache) + + # Calculate volume integral + @trixi_timeit timer() "volume integral" begin + calc_volume_integral!(du, flux_viscous, mesh, equations_parabolic, dg, cache) + end + + # Prolong solution to interfaces + @trixi_timeit timer() "prolong2interfaces" begin + prolong2interfaces!(cache_parabolic, flux_viscous, mesh, equations_parabolic, + dg.surface_integral, dg, cache) + end + + # Calculate interface fluxes + @trixi_timeit timer() "interface flux" begin + calc_interface_flux!(cache_parabolic.elements.surface_flux_values, mesh, + equations_parabolic, dg, cache_parabolic) + end + + # Prolong solution to boundaries + @trixi_timeit timer() "prolong2boundaries" begin + prolong2boundaries!(cache_parabolic, flux_viscous, mesh, equations_parabolic, + dg.surface_integral, dg, cache) + end + + # Calculate boundary fluxes + @trixi_timeit timer() "boundary flux" begin + calc_boundary_flux_divergence!(cache_parabolic, t, + boundary_conditions_parabolic, mesh, + equations_parabolic, + dg.surface_integral, dg) + end + + # TODO: parabolic; extend to mortars + @assert nmortars(dg, cache) == 0 + + # Calculate surface integrals + @trixi_timeit timer() "surface integral" begin + calc_surface_integral!(du, u, mesh, equations_parabolic, + dg.surface_integral, dg, cache_parabolic) + end + + # Apply Jacobian from mapping to reference element + @trixi_timeit timer() "Jacobian" begin + apply_jacobian_parabolic!(du, mesh, equations_parabolic, dg, cache_parabolic) + end + + return nothing +end + function calc_gradient!(gradients, u_transformed, t, mesh::P4estMesh{2}, equations_parabolic, boundary_conditions_parabolic, dg::DG, diff --git a/src/solvers/dgsem_p4est/dg_3d_parabolic.jl b/src/solvers/dgsem_p4est/dg_3d_parabolic.jl index 6439cad69bb..2d26c1aff50 100644 --- a/src/solvers/dgsem_p4est/dg_3d_parabolic.jl +++ b/src/solvers/dgsem_p4est/dg_3d_parabolic.jl @@ -22,6 +22,105 @@ function create_cache_parabolic(mesh::P4estMesh{3}, equations_hyperbolic::Abstra return cache end +# This file collects all methods that have been updated to work with parabolic systems of equations +# +# assumptions: parabolic terms are of the form div(f(u, grad(u))) and +# will be discretized first order form as follows: +# 1. compute grad(u) +# 2. compute f(u, grad(u)) +# 3. compute div(f(u, grad(u))) (i.e., the "regular" rhs! call) +# boundary conditions will be applied to both grad(u) and div(f(u, grad(u))). +# TODO: Remove in favor of the implementation for the TreeMesh +# once the P4estMesh can handle mortars as well +function rhs_parabolic!(du, u, t, mesh::P4estMesh{3}, + equations_parabolic::AbstractEquationsParabolic, + initial_condition, boundary_conditions_parabolic, source_terms, + dg::DG, parabolic_scheme, cache, cache_parabolic) + @unpack u_transformed, gradients, flux_viscous = cache_parabolic + + # Convert conservative variables to a form more suitable for viscous flux calculations + @trixi_timeit timer() "transform variables" begin + transform_variables!(u_transformed, u, mesh, equations_parabolic, + dg, parabolic_scheme, cache, cache_parabolic) + end + + # Compute the gradients of the transformed variables + @trixi_timeit timer() "calculate gradient" begin + calc_gradient!(gradients, u_transformed, t, mesh, equations_parabolic, + boundary_conditions_parabolic, dg, cache, cache_parabolic) + end + + # Compute and store the viscous fluxes + @trixi_timeit timer() "calculate viscous fluxes" begin + calc_viscous_fluxes!(flux_viscous, gradients, u_transformed, mesh, + equations_parabolic, dg, cache, cache_parabolic) + end + + # The remainder of this function is essentially a regular rhs! for parabolic + # equations (i.e., it computes the divergence of the viscous fluxes) + # + # OBS! In `calc_viscous_fluxes!`, the viscous flux values at the volume nodes of each element have + # been computed and stored in `fluxes_viscous`. In the following, we *reuse* (abuse) the + # `interfaces` and `boundaries` containers in `cache_parabolic` to interpolate and store the + # *fluxes* at the element surfaces, as opposed to interpolating and storing the *solution* (as it + # is done in the hyperbolic operator). That is, `interfaces.u`/`boundaries.u` store *viscous flux values* + # and *not the solution*. The advantage is that a) we do not need to allocate more storage, b) we + # do not need to recreate the existing data structure only with a different name, and c) we do not + # need to interpolate solutions *and* gradients to the surfaces. + + # TODO: parabolic; reconsider current data structure reuse strategy + + # Reset du + @trixi_timeit timer() "reset ∂u/∂t" reset_du!(du, dg, cache) + + # Calculate volume integral + @trixi_timeit timer() "volume integral" begin + calc_volume_integral!(du, flux_viscous, mesh, equations_parabolic, dg, cache) + end + + # Prolong solution to interfaces + @trixi_timeit timer() "prolong2interfaces" begin + prolong2interfaces!(cache_parabolic, flux_viscous, mesh, equations_parabolic, + dg.surface_integral, dg, cache) + end + + # Calculate interface fluxes + @trixi_timeit timer() "interface flux" begin + calc_interface_flux!(cache_parabolic.elements.surface_flux_values, mesh, + equations_parabolic, dg, cache_parabolic) + end + + # Prolong solution to boundaries + @trixi_timeit timer() "prolong2boundaries" begin + prolong2boundaries!(cache_parabolic, flux_viscous, mesh, equations_parabolic, + dg.surface_integral, dg, cache) + end + + # Calculate boundary fluxes + @trixi_timeit timer() "boundary flux" begin + calc_boundary_flux_divergence!(cache_parabolic, t, + boundary_conditions_parabolic, + mesh, equations_parabolic, + dg.surface_integral, dg) + end + + # TODO: parabolic; extend to mortars + @assert nmortars(dg, cache) == 0 + + # Calculate surface integrals + @trixi_timeit timer() "surface integral" begin + calc_surface_integral!(du, u, mesh, equations_parabolic, + dg.surface_integral, dg, cache_parabolic) + end + + # Apply Jacobian from mapping to reference element + @trixi_timeit timer() "Jacobian" begin + apply_jacobian_parabolic!(du, mesh, equations_parabolic, dg, cache_parabolic) + end + + return nothing +end + function calc_gradient!(gradients, u_transformed, t, mesh::P4estMesh{3}, equations_parabolic, boundary_conditions_parabolic, dg::DG, diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index c5862579992..0da25230380 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -13,7 +13,7 @@ # 2. compute f(u, grad(u)) # 3. compute div(f(u, grad(u))) (i.e., the "regular" rhs! call) # boundary conditions will be applied to both grad(u) and div(f(u, grad(u))). -function rhs_parabolic!(du, u, t, mesh::Union{TreeMesh{2}, P4estMesh{2}}, +function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, initial_condition, boundary_conditions_parabolic, source_terms, dg::DG, parabolic_scheme, cache, cache_parabolic) @@ -85,8 +85,18 @@ function rhs_parabolic!(du, u, t, mesh::Union{TreeMesh{2}, P4estMesh{2}}, dg.surface_integral, dg) end - # TODO: parabolic; extend to mortars - @assert nmortars(dg, cache) == 0 + # Prolong solution to mortars + @trixi_timeit timer() "prolong2mortars" begin + prolong2mortars!(cache, flux_viscous, mesh, equations_parabolic, + dg.mortar, dg.surface_integral, dg) + end + + # Calculate mortar fluxes + @trixi_timeit timer() "mortar flux" begin + calc_mortar_flux!(cache_parabolic.elements.surface_flux_values, mesh, + equations_parabolic, + dg.mortar, dg.surface_integral, dg, cache) + end # Calculate surface integrals @trixi_timeit timer() "surface integral" begin @@ -500,6 +510,227 @@ function calc_boundary_flux_by_direction_divergence!(surface_flux_values::Abstra return nothing end +function prolong2mortars!(cache, flux_viscous::Tuple{AbstractArray, AbstractArray}, + mesh::TreeMesh{2}, + equations_parabolic::AbstractEquationsParabolic, + mortar_l2::LobattoLegendreMortarL2, surface_integral, + dg::DGSEM) + flux_viscous_x, flux_viscous_y = flux_viscous + @threaded for mortar in eachmortar(dg, cache) + large_element = cache.mortars.neighbor_ids[3, mortar] + upper_element = cache.mortars.neighbor_ids[2, mortar] + lower_element = cache.mortars.neighbor_ids[1, mortar] + + # Copy solution small to small + if cache.mortars.large_sides[mortar] == 1 # -> small elements on right side + if cache.mortars.orientations[mortar] == 1 + # L2 mortars in x-direction + for l in eachnode(dg) + for v in eachvariable(equations_parabolic) + cache.mortars.u_upper[2, v, l, mortar] = flux_viscous_x[v, 1, l, + upper_element] + cache.mortars.u_lower[2, v, l, mortar] = flux_viscous_x[v, 1, l, + lower_element] + end + end + else + # L2 mortars in y-direction + for l in eachnode(dg) + for v in eachvariable(equations_parabolic) + cache.mortars.u_upper[2, v, l, mortar] = flux_viscous_y[v, l, 1, + upper_element] + cache.mortars.u_lower[2, v, l, mortar] = flux_viscous_y[v, l, 1, + lower_element] + end + end + end + else # large_sides[mortar] == 2 -> small elements on left side + if cache.mortars.orientations[mortar] == 1 + # L2 mortars in x-direction + for l in eachnode(dg) + for v in eachvariable(equations_parabolic) + cache.mortars.u_upper[1, v, l, mortar] = flux_viscous_x[v, + nnodes(dg), + l, + upper_element] + cache.mortars.u_lower[1, v, l, mortar] = flux_viscous_x[v, + nnodes(dg), + l, + lower_element] + end + end + else + # L2 mortars in y-direction + for l in eachnode(dg) + for v in eachvariable(equations_parabolic) + cache.mortars.u_upper[1, v, l, mortar] = flux_viscous_y[v, l, + nnodes(dg), + upper_element] + cache.mortars.u_lower[1, v, l, mortar] = flux_viscous_y[v, l, + nnodes(dg), + lower_element] + end + end + end + end + + # Interpolate large element face data to small interface locations + if cache.mortars.large_sides[mortar] == 1 # -> large element on left side + leftright = 1 + if cache.mortars.orientations[mortar] == 1 + # L2 mortars in x-direction + u_large = view(flux_viscous_x, :, nnodes(dg), :, large_element) + element_solutions_to_mortars!(cache.mortars, mortar_l2, leftright, + mortar, u_large) + else + # L2 mortars in y-direction + u_large = view(flux_viscous_y, :, :, nnodes(dg), large_element) + element_solutions_to_mortars!(cache.mortars, mortar_l2, leftright, + mortar, u_large) + end + else # large_sides[mortar] == 2 -> large element on right side + leftright = 2 + if cache.mortars.orientations[mortar] == 1 + # L2 mortars in x-direction + u_large = view(flux_viscous_x, :, 1, :, large_element) + element_solutions_to_mortars!(cache.mortars, mortar_l2, leftright, + mortar, u_large) + else + # L2 mortars in y-direction + u_large = view(flux_viscous_y, :, :, 1, large_element) + element_solutions_to_mortars!(cache.mortars, mortar_l2, leftright, + mortar, u_large) + end + end + end + + return nothing +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 +# hyperbolic terms with conserved terms only, i.e., no nonconservative terms. +function calc_mortar_flux!(surface_flux_values, + mesh::TreeMesh{2}, + equations_parabolic::AbstractEquationsParabolic, + mortar_l2::LobattoLegendreMortarL2, + surface_integral, dg::DG, cache) + @unpack surface_flux = surface_integral + @unpack u_lower, u_upper, orientations = cache.mortars + @unpack fstar_upper_threaded, fstar_lower_threaded = cache + + @threaded for mortar in eachmortar(dg, cache) + # Choose thread-specific pre-allocated container + fstar_upper = fstar_upper_threaded[Threads.threadid()] + fstar_lower = fstar_lower_threaded[Threads.threadid()] + + # Calculate fluxes + orientation = orientations[mortar] + calc_fstar!(fstar_upper, equations_parabolic, surface_flux, dg, u_upper, mortar, + orientation) + calc_fstar!(fstar_lower, equations_parabolic, surface_flux, dg, u_lower, mortar, + orientation) + + mortar_fluxes_to_elements!(surface_flux_values, + mesh, equations_parabolic, mortar_l2, dg, cache, + mortar, fstar_upper, fstar_lower) + end + + return nothing +end + +@inline function calc_fstar!(destination::AbstractArray{<:Any, 2}, + equations_parabolic::AbstractEquationsParabolic, + surface_flux, dg::DGSEM, + u_interfaces, interface, orientation) + for i in eachnode(dg) + # Call pointwise two-point numerical flux function + 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) + + # Copy flux to left and right element storage + set_node_vars!(destination, flux, equations_parabolic, dg, i) + end + + return nothing +end + +@inline function mortar_fluxes_to_elements!(surface_flux_values, + mesh::TreeMesh{2}, + equations_parabolic::AbstractEquationsParabolic, + mortar_l2::LobattoLegendreMortarL2, + dg::DGSEM, cache, + mortar, fstar_upper, fstar_lower) + large_element = cache.mortars.neighbor_ids[3, mortar] + upper_element = cache.mortars.neighbor_ids[2, mortar] + lower_element = cache.mortars.neighbor_ids[1, mortar] + + # Copy flux small to small + if cache.mortars.large_sides[mortar] == 1 # -> small elements on right side + if cache.mortars.orientations[mortar] == 1 + # L2 mortars in x-direction + direction = 1 + else + # L2 mortars in y-direction + direction = 3 + end + else # large_sides[mortar] == 2 -> small elements on left side + if cache.mortars.orientations[mortar] == 1 + # L2 mortars in x-direction + direction = 2 + else + # L2 mortars in y-direction + direction = 4 + end + end + surface_flux_values[:, :, direction, upper_element] .= fstar_upper + surface_flux_values[:, :, direction, lower_element] .= fstar_lower + + # Project small fluxes to large element + if cache.mortars.large_sides[mortar] == 1 # -> large element on left side + if cache.mortars.orientations[mortar] == 1 + # L2 mortars in x-direction + direction = 2 + else + # L2 mortars in y-direction + direction = 4 + end + else # large_sides[mortar] == 2 -> large element on right side + if cache.mortars.orientations[mortar] == 1 + # L2 mortars in x-direction + direction = 1 + else + # L2 mortars in y-direction + direction = 3 + end + end + + # TODO: Taal performance + # for v in eachvariable(equations) + # # The code below is semantically equivalent to + # # surface_flux_values[v, :, direction, large_element] .= + # # (mortar_l2.reverse_upper * fstar_upper[v, :] + mortar_l2.reverse_lower * fstar_lower[v, :]) + # # but faster and does not allocate. + # # Note that `true * some_float == some_float` in Julia, i.e. `true` acts as + # # a universal `one`. Hence, the second `mul!` means "add the matrix-vector + # # product to the current value of the destination". + # @views mul!(surface_flux_values[v, :, direction, large_element], + # mortar_l2.reverse_upper, fstar_upper[v, :]) + # @views mul!(surface_flux_values[v, :, direction, large_element], + # mortar_l2.reverse_lower, fstar_lower[v, :], true, true) + # end + # The code above could be replaced by the following code. However, the relative efficiency + # depends on the types of fstar_upper/fstar_lower and dg.l2mortar_reverse_upper. + # Using StaticArrays for both makes the code above faster for common test cases. + multiply_dimensionwise!(view(surface_flux_values, :, :, direction, large_element), + mortar_l2.reverse_upper, fstar_upper, + mortar_l2.reverse_lower, fstar_lower) + + return nothing +end + # Calculate the gradient of the transformed variables function calc_gradient!(gradients, u_transformed, t, mesh::TreeMesh{2}, equations_parabolic, @@ -589,7 +820,20 @@ function calc_gradient!(gradients, u_transformed, t, dg.surface_integral, dg) end - # TODO: parabolic; mortars + # Prolong solution to mortars + # NOTE: This re-uses the implementation for hyperbolic terms in "dg_2d.jl" + @trixi_timeit timer() "prolong2mortars" begin + prolong2mortars!(cache, u_transformed, mesh, equations_parabolic, + dg.mortar, dg.surface_integral, dg) + end + + # Calculate mortar fluxes + @trixi_timeit timer() "mortar flux" begin + calc_mortar_flux!(surface_flux_values, + mesh, + equations_parabolic, + dg.mortar, dg.surface_integral, dg, cache) + end # Calculate surface integrals @trixi_timeit timer() "surface integral" begin diff --git a/src/solvers/dgsem_tree/dg_3d_parabolic.jl b/src/solvers/dgsem_tree/dg_3d_parabolic.jl index 5b63b971cd8..2745d312b37 100644 --- a/src/solvers/dgsem_tree/dg_3d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_3d_parabolic.jl @@ -13,7 +13,7 @@ # 2. compute f(u, grad(u)) # 3. compute div(f(u, grad(u))) (i.e., the "regular" rhs! call) # boundary conditions will be applied to both grad(u) and div(f(u, grad(u))). -function rhs_parabolic!(du, u, t, mesh::Union{TreeMesh{3}, P4estMesh{3}}, +function rhs_parabolic!(du, u, t, mesh::TreeMesh{3}, equations_parabolic::AbstractEquationsParabolic, initial_condition, boundary_conditions_parabolic, source_terms, dg::DG, parabolic_scheme, cache, cache_parabolic) @@ -85,8 +85,18 @@ function rhs_parabolic!(du, u, t, mesh::Union{TreeMesh{3}, P4estMesh{3}}, dg.surface_integral, dg) end - # TODO: parabolic; extend to mortars - @assert nmortars(dg, cache) == 0 + # Prolong solution to mortars + @trixi_timeit timer() "prolong2mortars" begin + prolong2mortars!(cache, flux_viscous, mesh, equations_parabolic, + dg.mortar, dg.surface_integral, dg) + end + + # Calculate mortar fluxes + @trixi_timeit timer() "mortar flux" begin + calc_mortar_flux!(cache_parabolic.elements.surface_flux_values, mesh, + equations_parabolic, + dg.mortar, dg.surface_integral, dg, cache) + end # Calculate surface integrals @trixi_timeit timer() "surface integral" begin @@ -583,6 +593,298 @@ function calc_boundary_flux_by_direction_divergence!(surface_flux_values::Abstra return nothing end +function prolong2mortars!(cache, + flux_viscous::Tuple{AbstractArray, AbstractArray, + AbstractArray}, + mesh::TreeMesh{3}, + equations_parabolic::AbstractEquationsParabolic, + mortar_l2::LobattoLegendreMortarL2, + surface_integral, dg::DGSEM) + # temporary buffer for projections + @unpack fstar_tmp1_threaded = cache + + flux_viscous_x, flux_viscous_y, flux_viscous_z = flux_viscous + @threaded for mortar in eachmortar(dg, cache) + fstar_tmp1 = fstar_tmp1_threaded[Threads.threadid()] + + lower_left_element = cache.mortars.neighbor_ids[1, mortar] + lower_right_element = cache.mortars.neighbor_ids[2, mortar] + upper_left_element = cache.mortars.neighbor_ids[3, mortar] + upper_right_element = cache.mortars.neighbor_ids[4, mortar] + large_element = cache.mortars.neighbor_ids[5, mortar] + + # Copy solution small to small + if cache.mortars.large_sides[mortar] == 1 # -> small elements on right side + if cache.mortars.orientations[mortar] == 1 + # L2 mortars in x-direction + for k in eachnode(dg), j in eachnode(dg) + for v in eachvariable(equations_parabolic) + cache.mortars.u_upper_left[2, v, j, k, mortar] = flux_viscous_x[v, + 1, + j, + k, + upper_left_element] + cache.mortars.u_upper_right[2, v, j, k, mortar] = flux_viscous_x[v, + 1, + j, + k, + upper_right_element] + cache.mortars.u_lower_left[2, v, j, k, mortar] = flux_viscous_x[v, + 1, + j, + k, + lower_left_element] + cache.mortars.u_lower_right[2, v, j, k, mortar] = flux_viscous_x[v, + 1, + j, + k, + lower_right_element] + end + end + elseif cache.mortars.orientations[mortar] == 2 + # L2 mortars in y-direction + for k in eachnode(dg), i in eachnode(dg) + for v in eachvariable(equations_parabolic) + cache.mortars.u_upper_left[2, v, i, k, mortar] = flux_viscous_y[v, + i, + 1, + k, + upper_left_element] + cache.mortars.u_upper_right[2, v, i, k, mortar] = flux_viscous_y[v, + i, + 1, + k, + upper_right_element] + cache.mortars.u_lower_left[2, v, i, k, mortar] = flux_viscous_y[v, + i, + 1, + k, + lower_left_element] + cache.mortars.u_lower_right[2, v, i, k, mortar] = flux_viscous_y[v, + i, + 1, + k, + lower_right_element] + end + end + else # orientations[mortar] == 3 + # L2 mortars in z-direction + for j in eachnode(dg), i in eachnode(dg) + for v in eachvariable(equations_parabolic) + cache.mortars.u_upper_left[2, v, i, j, mortar] = flux_viscous_z[v, + i, + j, + 1, + upper_left_element] + cache.mortars.u_upper_right[2, v, i, j, mortar] = flux_viscous_z[v, + i, + j, + 1, + upper_right_element] + cache.mortars.u_lower_left[2, v, i, j, mortar] = flux_viscous_z[v, + i, + j, + 1, + lower_left_element] + cache.mortars.u_lower_right[2, v, i, j, mortar] = flux_viscous_z[v, + i, + j, + 1, + lower_right_element] + end + end + end + else # large_sides[mortar] == 2 -> small elements on left side + if cache.mortars.orientations[mortar] == 1 + # L2 mortars in x-direction + for k in eachnode(dg), j in eachnode(dg) + for v in eachvariable(equations_parabolic) + cache.mortars.u_upper_left[1, v, j, k, mortar] = flux_viscous_x[v, + nnodes(dg), + j, + k, + upper_left_element] + cache.mortars.u_upper_right[1, v, j, k, mortar] = flux_viscous_x[v, + nnodes(dg), + j, + k, + upper_right_element] + cache.mortars.u_lower_left[1, v, j, k, mortar] = flux_viscous_x[v, + nnodes(dg), + j, + k, + lower_left_element] + cache.mortars.u_lower_right[1, v, j, k, mortar] = flux_viscous_x[v, + nnodes(dg), + j, + k, + lower_right_element] + end + end + elseif cache.mortars.orientations[mortar] == 2 + # L2 mortars in y-direction + for k in eachnode(dg), i in eachnode(dg) + for v in eachvariable(equations_parabolic) + cache.mortars.u_upper_left[1, v, i, k, mortar] = flux_viscous_y[v, + i, + nnodes(dg), + k, + upper_left_element] + cache.mortars.u_upper_right[1, v, i, k, mortar] = flux_viscous_y[v, + i, + nnodes(dg), + k, + upper_right_element] + cache.mortars.u_lower_left[1, v, i, k, mortar] = flux_viscous_y[v, + i, + nnodes(dg), + k, + lower_left_element] + cache.mortars.u_lower_right[1, v, i, k, mortar] = flux_viscous_y[v, + i, + nnodes(dg), + k, + lower_right_element] + end + end + else # if cache.mortars.orientations[mortar] == 3 + # L2 mortars in z-direction + for j in eachnode(dg), i in eachnode(dg) + for v in eachvariable(equations_parabolic) + cache.mortars.u_upper_left[1, v, i, j, mortar] = flux_viscous_z[v, + i, + j, + nnodes(dg), + upper_left_element] + cache.mortars.u_upper_right[1, v, i, j, mortar] = flux_viscous_z[v, + i, + j, + nnodes(dg), + upper_right_element] + cache.mortars.u_lower_left[1, v, i, j, mortar] = flux_viscous_z[v, + i, + j, + nnodes(dg), + lower_left_element] + cache.mortars.u_lower_right[1, v, i, j, mortar] = flux_viscous_z[v, + i, + j, + nnodes(dg), + lower_right_element] + end + end + end + end + + # Interpolate large element face data to small interface locations + if cache.mortars.large_sides[mortar] == 1 # -> large element on left side + leftright = 1 + if cache.mortars.orientations[mortar] == 1 + # L2 mortars in x-direction + u_large = view(flux_viscous_x, :, nnodes(dg), :, :, large_element) + element_solutions_to_mortars!(cache.mortars, mortar_l2, leftright, + mortar, u_large, fstar_tmp1) + elseif cache.mortars.orientations[mortar] == 2 + # L2 mortars in y-direction + u_large = view(flux_viscous_y, :, :, nnodes(dg), :, large_element) + element_solutions_to_mortars!(cache.mortars, mortar_l2, leftright, + mortar, u_large, fstar_tmp1) + else # cache.mortars.orientations[mortar] == 3 + # L2 mortars in z-direction + u_large = view(flux_viscous_z, :, :, :, nnodes(dg), large_element) + element_solutions_to_mortars!(cache.mortars, mortar_l2, leftright, + mortar, u_large, fstar_tmp1) + end + else # large_sides[mortar] == 2 -> large element on right side + leftright = 2 + if cache.mortars.orientations[mortar] == 1 + # L2 mortars in x-direction + u_large = view(flux_viscous_x, :, 1, :, :, large_element) + element_solutions_to_mortars!(cache.mortars, mortar_l2, leftright, + mortar, u_large, fstar_tmp1) + elseif cache.mortars.orientations[mortar] == 2 + # L2 mortars in y-direction + u_large = view(flux_viscous_y, :, :, 1, :, large_element) + element_solutions_to_mortars!(cache.mortars, mortar_l2, leftright, + mortar, u_large, fstar_tmp1) + else # cache.mortars.orientations[mortar] == 3 + # L2 mortars in z-direction + u_large = view(flux_viscous_z, :, :, :, 1, large_element) + element_solutions_to_mortars!(cache.mortars, mortar_l2, leftright, + mortar, u_large, fstar_tmp1) + end + end + end + + return nothing +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 +# hyperbolic terms with conserved terms only, i.e., no nonconservative terms. +function calc_mortar_flux!(surface_flux_values, + mesh::TreeMesh{3}, + equations_parabolic::AbstractEquationsParabolic, + mortar_l2::LobattoLegendreMortarL2, + surface_integral, dg::DG, cache) + @unpack surface_flux = surface_integral + @unpack u_lower_left, u_lower_right, u_upper_left, u_upper_right, orientations = cache.mortars + @unpack (fstar_upper_left_threaded, fstar_upper_right_threaded, + fstar_lower_left_threaded, fstar_lower_right_threaded, + fstar_tmp1_threaded) = cache + + @threaded for mortar in eachmortar(dg, cache) + # Choose thread-specific pre-allocated container + fstar_upper_left = fstar_upper_left_threaded[Threads.threadid()] + fstar_upper_right = fstar_upper_right_threaded[Threads.threadid()] + fstar_lower_left = fstar_lower_left_threaded[Threads.threadid()] + fstar_lower_right = fstar_lower_right_threaded[Threads.threadid()] + fstar_tmp1 = fstar_tmp1_threaded[Threads.threadid()] + + # Calculate fluxes + orientation = orientations[mortar] + calc_fstar!(fstar_upper_left, equations_parabolic, surface_flux, dg, + u_upper_left, mortar, + orientation) + calc_fstar!(fstar_upper_right, equations_parabolic, surface_flux, dg, + u_upper_right, + mortar, orientation) + calc_fstar!(fstar_lower_left, equations_parabolic, surface_flux, dg, + u_lower_left, mortar, + orientation) + calc_fstar!(fstar_lower_right, equations_parabolic, surface_flux, dg, + u_lower_right, + mortar, orientation) + + mortar_fluxes_to_elements!(surface_flux_values, + mesh, equations_parabolic, mortar_l2, dg, cache, + mortar, + fstar_upper_left, fstar_upper_right, + fstar_lower_left, fstar_lower_right, + fstar_tmp1) + end + + return nothing +end + +@inline function calc_fstar!(destination::AbstractArray{<:Any, 3}, + equations_parabolic::AbstractEquationsParabolic, + surface_flux, dg::DGSEM, + u_interfaces, interface, orientation) + for j in eachnode(dg), i in eachnode(dg) + # Call pointwise two-point numerical flux function + 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) + + # Copy flux to left and right element storage + set_node_vars!(destination, flux, equations_parabolic, dg, i, j) + end + + return nothing +end + # Calculate the gradient of the transformed variables function calc_gradient!(gradients, u_transformed, t, mesh::TreeMesh{3}, equations_parabolic, @@ -679,7 +981,20 @@ function calc_gradient!(gradients, u_transformed, t, dg.surface_integral, dg) end - # TODO: parabolic; mortars + # Prolong solution to mortars + # NOTE: This re-uses the implementation for hyperbolic terms in "dg_3d.jl" + @trixi_timeit timer() "prolong2mortars" begin + prolong2mortars!(cache, u_transformed, mesh, equations_parabolic, + dg.mortar, dg.surface_integral, dg) + end + + # Calculate mortar fluxes + @trixi_timeit timer() "mortar flux" begin + calc_mortar_flux!(surface_flux_values, + mesh, + equations_parabolic, + dg.mortar, dg.surface_integral, dg, cache) + end # Calculate surface integrals @trixi_timeit timer() "surface integral" begin diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index e3bb1ed9fb1..1564a33dc41 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -125,6 +125,39 @@ isdir(outdir) && rm(outdir, recursive=true) ) end + @trixi_testset "TreeMesh2D: elixir_advection_diffusion.jl (Refined mesh)" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_diffusion.jl"), + tspan=(0.0, 0.0)) + LLID = Trixi.local_leaf_cells(mesh.tree) + num_leafs = length(LLID) + @assert num_leafs % 8 == 0 + Trixi.refine!(mesh.tree, LLID[1:Int(num_leafs/8)]) + tspan=(0.0, 1.5) + semi = SemidiscretizationHyperbolicParabolic(mesh, + (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions=(boundary_conditions, + boundary_conditions_parabolic)) + ode = semidiscretize(semi, tspan) + analysis_callback = AnalysisCallback(semi, interval=analysis_interval) + callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) + sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, + ode_default_options()..., callback=callbacks) + ac_sol = analysis_callback(sol) + @test ac_sol.l2[1] ≈ 1.67452550744728e-6 + @test ac_sol.linf[1] ≈ 7.905059166368744e-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)) < 100 + @test (@allocated Trixi.rhs_parabolic!(du_ode, u_ode, semi, t)) < 100 + end + end + @trixi_testset "TreeMesh2D: elixir_advection_diffusion_nonperiodic.jl" begin @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_diffusion_nonperiodic.jl"), initial_refinement_level = 2, tspan=(0.0, 0.1), @@ -180,6 +213,27 @@ isdir(outdir) && rm(outdir, recursive=true) ) end + @trixi_testset "TreeMesh2D: elixir_navierstokes_convergence.jl (Refined mesh)" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navierstokes_convergence.jl"), + tspan=(0.0, 0.0), initial_refinement_level=3) + LLID = Trixi.local_leaf_cells(mesh.tree) + num_leafs = length(LLID) + @assert num_leafs % 4 == 0 + Trixi.refine!(mesh.tree, LLID[1:Int(num_leafs/4)]) + tspan=(0.0, 0.5) + semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; + boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), + source_terms=source_terms_navier_stokes_convergence_test) + ode = semidiscretize(semi, tspan) + analysis_callback = AnalysisCallback(semi, interval=analysis_interval) + callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) + sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, + ode_default_options()..., callback=callbacks) + ac_sol = analysis_callback(sol) + @test ac_sol.l2 ≈ [0.00024296959173852447; 0.0002093263158670915; 0.0005390572390977262; 0.00026753561392341537] + @test ac_sol.linf ≈ [0.0016210102053424436; 0.002593287648655501; 0.002953907343823712; 0.002077119120180271] + end + @trixi_testset "TreeMesh2D: elixir_navierstokes_lid_driven_cavity.jl" begin @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navierstokes_lid_driven_cavity.jl"), initial_refinement_level = 2, tspan=(0.0, 0.5), diff --git a/test/test_parabolic_3d.jl b/test/test_parabolic_3d.jl index 67a27238969..d607962afa0 100644 --- a/test/test_parabolic_3d.jl +++ b/test/test_parabolic_3d.jl @@ -78,6 +78,27 @@ isdir(outdir) && rm(outdir, recursive=true) ) end + @trixi_testset "TreeMesh3D: elixir_navierstokes_convergence.jl (Refined mesh)" begin + @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", "elixir_navierstokes_convergence.jl"), + tspan=(0.0, 0.0)) + LLID = Trixi.local_leaf_cells(mesh.tree) + num_leafs = length(LLID) + @assert num_leafs % 16 == 0 + Trixi.refine!(mesh.tree, LLID[1:Int(num_leafs/16)]) + tspan=(0.0, 1.0) + semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; + boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), + source_terms=source_terms_navier_stokes_convergence_test) + ode = semidiscretize(semi, tspan) + analysis_callback = AnalysisCallback(semi, interval=analysis_interval) + callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) + sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, + ode_default_options()..., callback=callbacks) + ac_sol = analysis_callback(sol) + @test ac_sol.l2 ≈ [0.0003991794175622818; 0.0008853745163670504; 0.0010658655552066817; 0.0008785559918324284; 0.001403163458422815] + @test ac_sol.linf ≈ [0.0035306410538458177; 0.01505692306169911; 0.008862444161110705; 0.015065647972869856; 0.030402714743065218] + end + @trixi_testset "TreeMesh3D: elixir_navierstokes_taylor_green_vortex.jl" begin @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", "elixir_navierstokes_taylor_green_vortex.jl"), initial_refinement_level = 2, tspan=(0.0, 0.25), @@ -86,6 +107,41 @@ isdir(outdir) && rm(outdir, recursive=true) ) end + @trixi_testset "TreeMesh3D: elixir_navierstokes_taylor_green_vortex.jl (Refined mesh)" begin + @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", "elixir_navierstokes_taylor_green_vortex.jl"), + tspan=(0.0, 0.0)) + LLID = Trixi.local_leaf_cells(mesh.tree) + num_leafs = length(LLID) + @assert num_leafs % 32 == 0 + Trixi.refine!(mesh.tree, LLID[1:Int(num_leafs/32)]) + tspan=(0.0, 10.0) + semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver) + ode = semidiscretize(semi, tspan) + analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=true, + extra_analysis_integrals=(energy_kinetic, + energy_internal, + enstrophy)) + callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) + # Use CarpenterKennedy2N54 since `RDPK3SpFSAL49` gives slightly different results on different machines + sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), + dt=5e-3, + save_everystep=false, callback=callbacks); + ac_sol = analysis_callback(sol) + @test ac_sol.l2 ≈ [0.0013666103707729502; 0.2313581629543744; 0.2308164306264533; 0.17460246787819503; 0.28121914446544005] + @test ac_sol.linf ≈ [0.006938093883741336; 1.028235074139312; 1.0345438209717241; 1.0821111605203542; 1.2669636522564645] + + # 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)) < 100 + @test (@allocated Trixi.rhs_parabolic!(du_ode, u_ode, semi, t)) < 100 + end + end + @trixi_testset "P4estMesh3D: elixir_navierstokes_convergence.jl" begin @test_trixi_include(joinpath(examples_dir(), "p4est_3d_dgsem", "elixir_navierstokes_convergence.jl"), initial_refinement_level = 2, tspan=(0.0, 0.1), @@ -101,8 +157,8 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [0.0006696415247340326, 0.03442565722527785, 0.03442565722577423, 0.06295407168705314, 0.032857472756916195] ) end - end + # Clean up afterwards: delete Trixi.jl output directory @test_nowarn isdir(outdir) && rm(outdir, recursive=true) From d52a0419f0fe5dbee8dd58e3b12a23bc9fa67fc1 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Fri, 11 Aug 2023 09:43:31 +0200 Subject: [PATCH 065/263] Navier-Stokes 1D (#1597) * Remove doubled implementations * kepp main updated with true main * Avoid allocations in parabolic boundary fluxes * Correct shear layer IC * Whitespaces * Restore main * restore main * 1D Navier Stokes * Conventional notation for heat flux * remove multi-dim artefacts * Move general part into own file * Slip Wall BC for 1D Compressible Euler * Correct arguments for 1D BCs * format * Add convergence test with walls * Test gradient with entropy variables * Test isothermal BC, test gradient in entropy vars * Correct test data --------- Co-authored-by: Hendrik Ranocha --- ...lixir_navierstokes_convergence_periodic.jl | 136 ++++++ .../elixir_navierstokes_convergence_walls.jl | 160 +++++++ src/Trixi.jl | 3 +- src/equations/compressible_euler_1d.jl | 51 +++ src/equations/compressible_navier_stokes.jl | 70 +++ .../compressible_navier_stokes_1d.jl | 403 ++++++++++++++++++ .../compressible_navier_stokes_2d.jl | 77 +--- .../compressible_navier_stokes_3d.jl | 6 +- src/equations/equations_parabolic.jl | 2 + test/test_parabolic_1d.jl | 35 +- 10 files changed, 864 insertions(+), 79 deletions(-) create mode 100644 examples/tree_1d_dgsem/elixir_navierstokes_convergence_periodic.jl create mode 100644 examples/tree_1d_dgsem/elixir_navierstokes_convergence_walls.jl create mode 100644 src/equations/compressible_navier_stokes.jl create mode 100644 src/equations/compressible_navier_stokes_1d.jl diff --git a/examples/tree_1d_dgsem/elixir_navierstokes_convergence_periodic.jl b/examples/tree_1d_dgsem/elixir_navierstokes_convergence_periodic.jl new file mode 100644 index 00000000000..3f72d319b0b --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_navierstokes_convergence_periodic.jl @@ -0,0 +1,136 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Navier-Stokes equations + +# TODO: parabolic; unify names of these accessor functions +prandtl_number() = 0.72 +mu() = 6.25e-4 # equivalent to Re = 1600 + +equations = CompressibleEulerEquations1D(1.4) +equations_parabolic = CompressibleNavierStokesDiffusion1D(equations, mu=mu(), + Prandtl=prandtl_number()) + +# This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) +# (Simplified version of the 2D) +function initial_condition_navier_stokes_convergence_test(x, t, equations) + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_t = pi * t + + rho = c + A * sin(pi_x) * cos(pi_t) + v1 = sin(pi_x) * cos(pi_t) + p = rho^2 + + return prim2cons(SVector(rho, v1, p), equations) +end +initial_condition = initial_condition_navier_stokes_convergence_test + +@inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + mu_ = mu() + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * sin(pi_x) * cos(pi_t) + rho_t = -pi * A * sin(pi_x) * sin(pi_t) + rho_x = pi * A * cos(pi_x) * cos(pi_t) + rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_t) + + v1 = sin(pi_x) * cos(pi_t) + v1_t = -pi * sin(pi_x) * sin(pi_t) + v1_x = pi * cos(pi_x) * cos(pi_t) + v1_xx = -pi * pi * sin(pi_x) * cos(pi_t) + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + + E = p * inv_gamma_minus_one + 0.5 * rho * v1^2 + E_t = p_t * inv_gamma_minus_one + 0.5 * rho_t * v1^2 + rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + 0.5 * rho_x * v1^2 + rho * v1 * v1_x + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one / Pr + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + + # x-momentum equation + du2 = ( rho_t * v1 + rho * v1_t + + p_x + rho_x * v1^2 + 2.0 * rho * v1 * v1_x + # stress tensor from x-direction + - v1_xx * mu_) + + # total energy equation + du3 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) + # stress tensor and temperature gradient terms from x-direction + - v1_xx * v1 * mu_ + - v1_x * v1_x * mu_ + - T_const * inv_rho_cubed * ( p_xx * rho * rho + - 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x + - p * rho * rho_xx ) * mu_) + + return SVector(du1, du2, du3) +end + +volume_flux = flux_ranocha +solver = DGSEM(polydeg=3, surface_flux=flux_hllc, + volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = -1.0 +coordinates_max = 1.0 +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + n_cells_max=100_000) + + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver, + source_terms = source_terms_navier_stokes_convergence_test) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 10.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) + +alive_callback = AliveCallback(analysis_interval=analysis_interval,) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-9 +sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, + ode_default_options()..., callback=callbacks) +summary_callback() # print the timer summary \ No newline at end of file diff --git a/examples/tree_1d_dgsem/elixir_navierstokes_convergence_walls.jl b/examples/tree_1d_dgsem/elixir_navierstokes_convergence_walls.jl new file mode 100644 index 00000000000..181a2cb209f --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_navierstokes_convergence_walls.jl @@ -0,0 +1,160 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal compressible Navier-Stokes equations + +prandtl_number() = 0.72 +mu() = 0.01 + +equations = CompressibleEulerEquations1D(1.4) +equations_parabolic = CompressibleNavierStokesDiffusion1D(equations, mu=mu(), Prandtl=prandtl_number(), + gradient_variables=GradientVariablesPrimitive()) + +# 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, + volume_integral=VolumeIntegralWeakForm()) + +coordinates_min = -1.0 +coordinates_max = 1.0 + +# Create a uniformly refined mesh with periodic boundaries +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=3, + periodicity=false, + n_cells_max=30_000) # set maximum capacity of tree data structure + +# Note: the initial condition cannot be specialized to `CompressibleNavierStokesDiffusion1D` +# since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesDiffusion1D`) +# and by the initial condition (which passes in `CompressibleEulerEquations1D`). +# This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) +function initial_condition_navier_stokes_convergence_test(x, t, equations) + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_t = pi * t + + rho = c + A * cos(pi_x) * cos(pi_t) + v1 = log(x[1] + 2.0) * (1.0 - exp(-A * (x[1] - 1.0)) ) * cos(pi_t) + p = rho^2 + + return prim2cons(SVector(rho, v1, p), equations) +end + +@inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) + x = x[1] + + # TODO: parabolic + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + mu_ = mu() + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * cos(pi_x) * cos(pi_t) + rho_t = -pi * A * cos(pi_x) * sin(pi_t) + rho_x = -pi * A * sin(pi_x) * cos(pi_t) + rho_xx = -pi * pi * A * cos(pi_x) * cos(pi_t) + + v1 = log(x + 2.0) * (1.0 - exp(-A * (x - 1.0))) * cos(pi_t) + v1_t = -pi * log(x + 2.0) * (1.0 - exp(-A * (x - 1.0))) * sin(pi_t) + v1_x = (A * log(x + 2.0) * exp(-A * (x - 1.0)) + (1.0 - exp(-A * (x - 1.0))) / (x + 2.0)) * cos(pi_t) + v1_xx = (( 2.0 * A * exp(-A * (x - 1.0)) / (x + 2.0) + - A * A * log(x + 2.0) * exp(-A * (x - 1.0)) + - (1.0 - exp(-A * (x - 1.0))) / ((x + 2.0) * (x + 2.0))) * cos(pi_t)) + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + + # Note this simplifies slightly because the ansatz assumes that v1 = v2 + E = p * inv_gamma_minus_one + 0.5 * rho * v1^2 + E_t = p_t * inv_gamma_minus_one + 0.5 * rho_t * v1^2 + rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + 0.5 * rho_x * v1^2 + rho * v1 * v1_x + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one / Pr + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + + # y-momentum equation + du2 = ( rho_t * v1 + rho * v1_t + + p_x + rho_x * v1^2 + 2.0 * rho * v1 * v1_x + # stress tensor from y-direction + - v1_xx * mu_) + + # total energy equation + du3 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) + # stress tensor and temperature gradient terms from x-direction + - v1_xx * v1 * mu_ + - v1_x * v1_x * mu_ + - T_const * inv_rho_cubed * ( p_xx * rho * rho + - 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x + - p * rho * rho_xx ) * mu_ ) + + return SVector(du1, du2, du3) +end + +initial_condition = initial_condition_navier_stokes_convergence_test + +# BC types +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) -> 0.0) + +boundary_condition_left = BoundaryConditionNavierStokesWall(velocity_bc_left_right, heat_bc_left) +boundary_condition_right = BoundaryConditionNavierStokesWall(velocity_bc_left_right, heat_bc_right) + +# define inviscid boundary conditions +boundary_conditions = (; x_neg = boundary_condition_slip_wall, + x_pos = boundary_condition_slip_wall) + +# define viscous boundary conditions +boundary_conditions_parabolic = (; x_neg = boundary_condition_left, + x_pos = boundary_condition_right) + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; + boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), + source_terms=source_terms_navier_stokes_convergence_test) + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span `tspan` +tspan = (0.0, 1.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() +alive_callback = AliveCallback(alive_interval=10) +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, + ode_default_options()..., callback=callbacks) +summary_callback() # print the timer summary \ No newline at end of file diff --git a/src/Trixi.jl b/src/Trixi.jl index 990c33f3c94..78ddaa3ca7f 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -152,7 +152,8 @@ export AcousticPerturbationEquations2D, LinearizedEulerEquations2D export LaplaceDiffusion1D, LaplaceDiffusion2D, - CompressibleNavierStokesDiffusion2D, CompressibleNavierStokesDiffusion3D + CompressibleNavierStokesDiffusion1D, CompressibleNavierStokesDiffusion2D, + CompressibleNavierStokesDiffusion3D export GradientVariablesPrimitive, GradientVariablesEntropy diff --git a/src/equations/compressible_euler_1d.jl b/src/equations/compressible_euler_1d.jl index e4fd0997eae..9204989e8be 100644 --- a/src/equations/compressible_euler_1d.jl +++ b/src/equations/compressible_euler_1d.jl @@ -198,6 +198,57 @@ function initial_condition_eoc_test_coupled_euler_gravity(x, t, return prim2cons(SVector(rho, v1, p), equations) end +""" + boundary_condition_slip_wall(u_inner, orientation, direction, x, t, + surface_flux_function, equations::CompressibleEulerEquations1D) +Determine the boundary numerical surface flux for a slip wall condition. +Imposes a zero normal velocity at the wall. +Density is taken from the internal solution state and pressure is computed as an +exact solution of a 1D Riemann problem. Further details about this boundary state +are available in the paper: +- J. J. W. van der Vegt and H. van der Ven (2002) + Slip flow boundary conditions in discontinuous Galerkin discretizations of + the Euler equations of gas dynamics + [PDF](https://reports.nlr.nl/bitstream/handle/10921/692/TP-2002-300.pdf?sequence=1) + + Should be used together with [`TreeMesh`](@ref). +""" +@inline function boundary_condition_slip_wall(u_inner, orientation, + direction, x, t, + surface_flux_function, + equations::CompressibleEulerEquations1D) + # compute the primitive variables + rho_local, v_normal, p_local = cons2prim(u_inner, equations) + + if isodd(direction) # flip sign of normal to make it outward pointing + v_normal *= -1 + end + + # Get the solution of the pressure Riemann problem + # See Section 6.3.3 of + # Eleuterio F. Toro (2009) + # Riemann Solvers and Numerical Methods for Fluid Dynamics: A Practical Introduction + # [DOI: 10.1007/b79761](https://doi.org/10.1007/b79761) + if v_normal <= 0.0 + sound_speed = sqrt(equations.gamma * p_local / rho_local) # local sound speed + p_star = p_local * + (1 + 0.5 * (equations.gamma - 1) * v_normal / sound_speed)^(2 * + equations.gamma * + equations.inv_gamma_minus_one) + else # v_normal > 0.0 + A = 2 / ((equations.gamma + 1) * rho_local) + B = p_local * (equations.gamma - 1) / (equations.gamma + 1) + p_star = p_local + + 0.5 * v_normal / A * + (v_normal + sqrt(v_normal^2 + 4 * A * (p_local + B))) + end + + # For the slip wall we directly set the flux as the normal velocity is zero + return SVector(zero(eltype(u_inner)), + p_star, + zero(eltype(u_inner))) +end + # Calculate 1D flux for a single point @inline function flux(u, orientation::Integer, equations::CompressibleEulerEquations1D) rho, rho_v1, rho_e = u diff --git a/src/equations/compressible_navier_stokes.jl b/src/equations/compressible_navier_stokes.jl new file mode 100644 index 00000000000..af7897d4586 --- /dev/null +++ b/src/equations/compressible_navier_stokes.jl @@ -0,0 +1,70 @@ +# TODO: can we generalize this to MHD? +""" + struct BoundaryConditionNavierStokesWall + +Creates a wall-type boundary conditions for the compressible Navier-Stokes equations. +The fields `boundary_condition_velocity` and `boundary_condition_heat_flux` are intended +to be boundary condition types such as the `NoSlip` velocity boundary condition and the +`Adiabatic` or `Isothermal` heat boundary condition. + +!!! warning "Experimental feature" + This is an experimental feature and may change in future releases. +""" +struct BoundaryConditionNavierStokesWall{V, H} + boundary_condition_velocity::V + boundary_condition_heat_flux::H +end + +""" + struct NoSlip + +Use to create a no-slip boundary condition with `BoundaryConditionNavierStokesWall`. The field `boundary_value_function` +should be a function with signature `boundary_value_function(x, t, equations)` +and should return a `SVector{NDIMS}` whose entries are the velocity vector at a +point `x` and time `t`. +""" +struct NoSlip{F} + boundary_value_function::F # value of the velocity vector on the boundary +end + +""" + struct Isothermal + +Used to create a no-slip boundary condition with [`BoundaryConditionNavierStokesWall`](@ref). +The field `boundary_value_function` should be a function with signature +`boundary_value_function(x, t, equations)` and return a scalar value for the +temperature at point `x` and time `t`. +""" +struct Isothermal{F} + boundary_value_function::F # value of the temperature on the boundary +end + +""" + struct Adiabatic + +Used to create a no-slip boundary condition with [`BoundaryConditionNavierStokesWall`](@ref). +The field `boundary_value_normal_flux_function` should be a function with signature +`boundary_value_normal_flux_function(x, t, equations)` and return a scalar value for the +normal heat flux at point `x` and time `t`. +""" +struct Adiabatic{F} + boundary_value_normal_flux_function::F # scaled heat flux 1/T * kappa * dT/dn +end + +""" +!!! warning "Experimental code" + This code is experimental and may be changed or removed in any future release. + +`GradientVariablesPrimitive` and `GradientVariablesEntropy` are gradient variable type parameters +for `CompressibleNavierStokesDiffusion1D`. By default, the gradient variables are set to be +`GradientVariablesPrimitive`. Specifying `GradientVariablesEntropy` instead uses the entropy variable +formulation from +- Hughes, Mallet, Franca (1986) + A new finite element formulation for computational fluid dynamics: I. Symmetric forms of the + compressible Euler and Navier-Stokes equations and the second law of thermodynamics. + [https://doi.org/10.1016/0045-7825(86)90127-1](https://doi.org/10.1016/0045-7825(86)90127-1) + +Under `GradientVariablesEntropy`, the Navier-Stokes discretization is provably entropy stable. +""" +struct GradientVariablesPrimitive end +struct GradientVariablesEntropy end diff --git a/src/equations/compressible_navier_stokes_1d.jl b/src/equations/compressible_navier_stokes_1d.jl new file mode 100644 index 00000000000..dca846cac1e --- /dev/null +++ b/src/equations/compressible_navier_stokes_1d.jl @@ -0,0 +1,403 @@ +@doc raw""" + CompressibleNavierStokesDiffusion1D(equations; mu, Pr, + gradient_variables=GradientVariablesPrimitive()) + +Contains the diffusion (i.e. parabolic) terms applied +to mass, momenta, and total energy together with the advective terms from +the [`CompressibleEulerEquations1D`](@ref). + +- `equations`: instance of the [`CompressibleEulerEquations1D`](@ref) +- `mu`: dynamic viscosity, +- `Pr`: Prandtl number, +- `gradient_variables`: which variables the gradients are taken with respect to. + Defaults to `GradientVariablesPrimitive()`. + +Fluid properties such as the dynamic viscosity ``\mu`` can be provided in any consistent unit system, e.g., +[``\mu``] = kg m⁻¹ s⁻¹. + +The particular form of the compressible Navier-Stokes implemented is +```math +\frac{\partial}{\partial t} +\begin{pmatrix} +\rho \\ \rho v \\ \rho e +\end{pmatrix} ++ +\frac{\partial}{\partial x} +\begin{pmatrix} + \rho v \\ \rho v^2 + p \\ (\rho e + p) v +\end{pmatrix} += +\frac{\partial}{\partial x} +\begin{pmatrix} +0 \\ \tau \\ \tau v - q +\end{pmatrix} +``` +where the system is closed with the ideal gas assumption giving +```math +p = (\gamma - 1) \left( \rho e - \frac{1}{2} \rho v^2 \right) +``` +as the pressure. The value of the adiabatic constant `gamma` is taken from the [`CompressibleEulerEquations1D`](@ref). +The terms on the right hand side of the system above +are built from the viscous stress +```math +\tau = \mu \frac{\partial}{\partial x} v +``` +where the heat flux is +```math +q = -\kappa \frac{\partial}{\partial x} \left(T\right),\quad T = \frac{p}{R\rho} +``` +where ``T`` is the temperature and ``\kappa`` is the thermal conductivity for Fick's law. +Under the assumption that the gas has a constant Prandtl number, +the thermal conductivity is +```math +\kappa = \frac{\gamma \mu R}{(\gamma - 1)\textrm{Pr}}. +``` +From this combination of temperature ``T`` and thermal conductivity ``\kappa`` we see +that the gas constant `R` cancels and the heat flux becomes +```math +q = -\kappa \frac{\partial}{\partial x} \left(T\right) = -\frac{\gamma \mu}{(\gamma - 1)\textrm{Pr}} \frac{\partial}{\partial x} \left(\frac{p}{\rho}\right) +``` +which is the form implemented below in the [`flux`](@ref) function. + +In one spatial dimensions we require gradients for two quantities, e.g., +primitive quantities +```math +\frac{\partial}{\partial x} v,\, \frac{\partial}{\partial x} T +``` +or the entropy variables +```math +\frac{\partial}{\partial x} w_2,\, \frac{\partial}{\partial x} w_3 +``` +where +```math +w_2 = \frac{\rho v1}{p},\, w_3 = -\frac{\rho}{p} +``` + +!!! warning "Experimental code" + This code is experimental and may be changed or removed in any future release. +""" +struct CompressibleNavierStokesDiffusion1D{GradientVariables, RealT <: Real, + E <: AbstractCompressibleEulerEquations{1}} <: + AbstractCompressibleNavierStokesDiffusion{1, 3} + # TODO: parabolic + # 1) For now save gamma and inv(gamma-1) again, but could potentially reuse them from the Euler equations + # 2) Add NGRADS as a type parameter here and in AbstractEquationsParabolic, add `ngradients(...)` accessor function + gamma::RealT # ratio of specific heats + inv_gamma_minus_one::RealT # = inv(gamma - 1); can be used to write slow divisions as fast multiplications + + mu::RealT # viscosity + Pr::RealT # Prandtl number + kappa::RealT # thermal diffusivity for Fick's law + + equations_hyperbolic::E # CompressibleEulerEquations1D + gradient_variables::GradientVariables # GradientVariablesPrimitive or GradientVariablesEntropy +end + +# default to primitive gradient variables +function CompressibleNavierStokesDiffusion1D(equations::CompressibleEulerEquations1D; + mu, Prandtl, + gradient_variables = GradientVariablesPrimitive()) + gamma = equations.gamma + inv_gamma_minus_one = equations.inv_gamma_minus_one + μ, Pr = promote(mu, Prandtl) + + # Under the assumption of constant Prandtl number the thermal conductivity + # constant is kappa = gamma μ / ((gamma-1) Pr). + # Important note! Factor of μ is accounted for later in `flux`. + kappa = gamma * inv_gamma_minus_one / Pr + + CompressibleNavierStokesDiffusion1D{typeof(gradient_variables), typeof(gamma), + typeof(equations)}(gamma, inv_gamma_minus_one, + μ, Pr, kappa, + equations, gradient_variables) +end + +# TODO: parabolic +# This is the flexibility a user should have to select the different gradient variable types +# varnames(::typeof(cons2prim) , ::CompressibleNavierStokesDiffusion1D) = ("v1", "v2", "T") +# varnames(::typeof(cons2entropy), ::CompressibleNavierStokesDiffusion1D) = ("w2", "w3", "w4") + +function varnames(variable_mapping, + equations_parabolic::CompressibleNavierStokesDiffusion1D) + varnames(variable_mapping, equations_parabolic.equations_hyperbolic) +end + +# we specialize this function to compute gradients of primitive variables instead of +# conservative variables. +function gradient_variable_transformation(::CompressibleNavierStokesDiffusion1D{ + GradientVariablesPrimitive + }) + cons2prim +end +function gradient_variable_transformation(::CompressibleNavierStokesDiffusion1D{ + GradientVariablesEntropy + }) + cons2entropy +end + +# Explicit formulas for the diffusive Navier-Stokes fluxes are available, e.g., in Section 2 +# of the paper by Rueda-Ramírez, Hennemann, Hindenlang, Winters, and Gassner +# "An Entropy Stable Nodal Discontinuous Galerkin Method for the resistive +# MHD Equations. Part II: Subcell Finite Volume Shock Capturing" +# where one sets the magnetic field components equal to 0. +function flux(u, gradients, orientation::Integer, + equations::CompressibleNavierStokesDiffusion1D) + # Here, `u` is assumed to be the "transformed" variables specified by `gradient_variable_transformation`. + rho, v1, _ = convert_transformed_to_primitive(u, equations) + # Here `gradients` is assumed to contain the gradients of the primitive variables (rho, v1, v2, T) + # either computed directly or reverse engineered from the gradient of the entropy variables + # by way of the `convert_gradient_variables` function. + _, dv1dx, dTdx = convert_derivative_to_primitive(u, gradients, equations) + + # Viscous stress (tensor) + tau_11 = dv1dx + + # Fick's law q = -kappa * grad(T) = -kappa * grad(p / (R rho)) + # with thermal diffusivity constant kappa = gamma μ R / ((gamma-1) Pr) + # Note, the gas constant cancels under this formulation, so it is not present + # in the implementation + q1 = equations.kappa * dTdx + + # Constant dynamic viscosity is copied to a variable for readability. + # Offers flexibility for dynamic viscosity via Sutherland's law where it depends + # on temperature and reference values, Ts and Tref such that mu(T) + mu = equations.mu + + # viscous flux components in the x-direction + f1 = zero(rho) + f2 = tau_11 * mu + f3 = (v1 * tau_11 + q1) * mu + + return SVector(f1, f2, f3) +end + +# Convert conservative variables to primitive +@inline function cons2prim(u, equations::CompressibleNavierStokesDiffusion1D) + rho, rho_v1, _ = u + + v1 = rho_v1 / rho + T = temperature(u, equations) + + return SVector(rho, v1, T) +end + +# Convert conservative variables to entropy +# TODO: parabolic. We can improve efficiency by not computing w_1, which involves logarithms +# This can be done by specializing `cons2entropy` and `entropy2cons` to `CompressibleNavierStokesDiffusion1D`, +# but this may be confusing to new users. +function cons2entropy(u, equations::CompressibleNavierStokesDiffusion1D) + cons2entropy(u, equations.equations_hyperbolic) +end +function entropy2cons(w, equations::CompressibleNavierStokesDiffusion1D) + entropy2cons(w, equations.equations_hyperbolic) +end + +# the `flux` function takes in transformed variables `u` which depend on the type of the gradient variables. +# For CNS, it is simplest to formulate the viscous terms in primitive variables, so we transform the transformed +# variables into primitive variables. +@inline function convert_transformed_to_primitive(u_transformed, + equations::CompressibleNavierStokesDiffusion1D{ + GradientVariablesPrimitive + }) + return u_transformed +end + +# TODO: parabolic. Make this more efficient! +@inline function convert_transformed_to_primitive(u_transformed, + equations::CompressibleNavierStokesDiffusion1D{ + GradientVariablesEntropy + }) + # note: this uses CompressibleNavierStokesDiffusion1D versions of cons2prim and entropy2cons + return cons2prim(entropy2cons(u_transformed, equations), equations) +end + +# Takes the solution values `u` and gradient of the entropy variables (w_2, w_3, w_4) and +# reverse engineers the gradients to be terms of the primitive variables (v1, v2, T). +# Helpful because then the diffusive fluxes have the same form as on paper. +# Note, the first component of `gradient_entropy_vars` contains gradient(rho) which is unused. +# TODO: parabolic; entropy stable viscous terms +@inline function convert_derivative_to_primitive(u, gradient, + ::CompressibleNavierStokesDiffusion1D{ + GradientVariablesPrimitive + }) + return gradient +end + +# the first argument is always the "transformed" variables. +@inline function convert_derivative_to_primitive(w, gradient_entropy_vars, + equations::CompressibleNavierStokesDiffusion1D{ + GradientVariablesEntropy + }) + + # TODO: parabolic. This is inefficient to pass in transformed variables but then transform them back. + # We can fix this if we directly compute v1, v2, T from the entropy variables + u = entropy2cons(w, equations) # calls a "modified" entropy2cons defined for CompressibleNavierStokesDiffusion1D + rho, rho_v1, _ = u + + v1 = rho_v1 / rho + T = temperature(u, equations) + + return SVector(gradient_entropy_vars[1], + T * (gradient_entropy_vars[2] + v1 * gradient_entropy_vars[3]), # grad(u) = T*(grad(w_2)+v1*grad(w_3)) + T * T * gradient_entropy_vars[3]) +end + +# This routine is required because `prim2cons` is called in `initial_condition`, which +# is called with `equations::CompressibleEulerEquations1D`. This means it is inconsistent +# with `cons2prim(..., ::CompressibleNavierStokesDiffusion1D)` as defined above. +# TODO: parabolic. Is there a way to clean this up? +@inline function prim2cons(u, equations::CompressibleNavierStokesDiffusion1D) + prim2cons(u, equations.equations_hyperbolic) +end + +@inline function temperature(u, equations::CompressibleNavierStokesDiffusion1D) + rho, rho_v1, rho_e = u + + p = (equations.gamma - 1) * (rho_e - 0.5 * rho_v1^2 / rho) + T = p / rho + return T +end + +@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip, + <:Adiabatic})(flux_inner, + u_inner, + orientation::Integer, + direction, + x, t, + operator_type::Gradient, + equations::CompressibleNavierStokesDiffusion1D{ + GradientVariablesPrimitive + }) + v1 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, + equations) + return SVector(u_inner[1], v1, u_inner[3]) +end + +@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip, + <:Adiabatic})(flux_inner, + u_inner, + orientation::Integer, + direction, + x, t, + operator_type::Divergence, + equations::CompressibleNavierStokesDiffusion1D{ + GradientVariablesPrimitive + }) + # rho, v1, v2, _ = u_inner + normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x, + t, + equations) + v1 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, + equations) + _, tau_1n, _ = flux_inner # extract fluxes for 2nd equation + normal_energy_flux = v1 * tau_1n + normal_heat_flux + return SVector(flux_inner[1], flux_inner[2], normal_energy_flux) +end + +@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip, + <:Isothermal})(flux_inner, + u_inner, + orientation::Integer, + direction, + x, t, + operator_type::Gradient, + equations::CompressibleNavierStokesDiffusion1D{ + GradientVariablesPrimitive + }) + v1 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, + equations) + T = boundary_condition.boundary_condition_heat_flux.boundary_value_function(x, t, + equations) + return SVector(u_inner[1], v1, T) +end + +@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip, + <:Isothermal})(flux_inner, + u_inner, + orientation::Integer, + direction, + x, t, + operator_type::Divergence, + equations::CompressibleNavierStokesDiffusion1D{ + GradientVariablesPrimitive + }) + return flux_inner +end + +# specialized BC impositions for GradientVariablesEntropy. + +# This should return a SVector containing the boundary values of entropy variables. +# Here, `w_inner` are the transformed variables (e.g., entropy variables). +# +# Taken from "Entropy stable modal discontinuous Galerkin schemes and wall boundary conditions +# for the compressible Navier-Stokes equations" by Chan, Lin, Warburton 2022. +# DOI: 10.1016/j.jcp.2021.110723 +@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip, + <:Adiabatic})(flux_inner, + w_inner, + orientation::Integer, + direction, + x, t, + operator_type::Gradient, + equations::CompressibleNavierStokesDiffusion1D{ + GradientVariablesEntropy + }) + v1 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, + equations) + negative_rho_inv_p = w_inner[3] # w_3 = -rho / p + return SVector(w_inner[1], -v1 * negative_rho_inv_p, negative_rho_inv_p) +end + +# this is actually identical to the specialization for GradientVariablesPrimitive, but included for completeness. +@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip, + <:Adiabatic})(flux_inner, + w_inner, + orientation::Integer, + direction, + x, t, + operator_type::Divergence, + equations::CompressibleNavierStokesDiffusion1D{ + GradientVariablesEntropy + }) + normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x, + t, + equations) + v1 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, + equations) + _, tau_1n, _ = flux_inner # extract fluxes for 2nd equation + normal_energy_flux = v1 * tau_1n + normal_heat_flux + return SVector(flux_inner[1], flux_inner[2], normal_energy_flux) +end + +@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip, + <:Isothermal})(flux_inner, + w_inner, + orientation::Integer, + direction, + x, t, + operator_type::Gradient, + equations::CompressibleNavierStokesDiffusion1D{ + GradientVariablesEntropy + }) + v1 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, + equations) + T = boundary_condition.boundary_condition_heat_flux.boundary_value_function(x, t, + equations) + + # the entropy variables w2 = rho * v1 / p = v1 / T = -v1 * w3. + w3 = -1 / T + return SVector(w_inner[1], -v1 * w3, w3) +end + +@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip, + <:Isothermal})(flux_inner, + w_inner, + orientation::Integer, + direction, + x, t, + operator_type::Divergence, + equations::CompressibleNavierStokesDiffusion1D{ + GradientVariablesEntropy + }) + return SVector(flux_inner[1], flux_inner[2], flux_inner[3]) +end diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index a1f11717e69..f762fe5d5ee 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -29,7 +29,7 @@ The particular form of the compressible Navier-Stokes implemented is = \nabla \cdot \begin{pmatrix} -0 \\ \underline{\tau} \\ \underline{\tau}\mathbf{v} - \nabla q +0 \\ \underline{\tau} \\ \underline{\tau}\mathbf{v} - \mathbf{q} \end{pmatrix} ``` where the system is closed with the ideal gas assumption giving @@ -44,7 +44,7 @@ are built from the viscous stress tensor ``` where ``\underline{I}`` is the ``2\times 2`` identity matrix and the heat flux is ```math -\nabla q = -\kappa\nabla\left(T\right),\quad T = \frac{p}{R\rho} +\mathbf{q} = -\kappa\nabla\left(T\right),\quad T = \frac{p}{R\rho} ``` where ``T`` is the temperature and ``\kappa`` is the thermal conductivity for Fick's law. Under the assumption that the gas has a constant Prandtl number, @@ -55,7 +55,7 @@ the thermal conductivity is From this combination of temperature ``T`` and thermal conductivity ``\kappa`` we see that the gas constant `R` cancels and the heat flux becomes ```math -\nabla q = -\kappa\nabla\left(T\right) = -\frac{\gamma \mu}{(\gamma - 1)\textrm{Pr}}\nabla\left(\frac{p}{\rho}\right) +\mathbf{q} = -\kappa\nabla\left(T\right) = -\frac{\gamma \mu}{(\gamma - 1)\textrm{Pr}}\nabla\left(\frac{p}{\rho}\right) ``` which is the form implemented below in the [`flux`](@ref) function. @@ -93,24 +93,6 @@ struct CompressibleNavierStokesDiffusion2D{GradientVariables, RealT <: Real, gradient_variables::GradientVariables # GradientVariablesPrimitive or GradientVariablesEntropy end -""" -!!! warning "Experimental code" - This code is experimental and may be changed or removed in any future release. - -`GradientVariablesPrimitive` and `GradientVariablesEntropy` are gradient variable type parameters -for `CompressibleNavierStokesDiffusion2D`. By default, the gradient variables are set to be -`GradientVariablesPrimitive`. Specifying `GradientVariablesEntropy` instead uses the entropy variable -formulation from -- Hughes, Mallet, Franca (1986) - A new finite element formulation for computational fluid dynamics: I. Symmetric forms of the - compressible Euler and Navier-Stokes equations and the second law of thermodynamics. - [https://doi.org/10.1016/0045-7825(86)90127-1](https://doi.org/10.1016/0045-7825(86)90127-1) - -Under `GradientVariablesEntropy`, the Navier-Stokes discretization is provably entropy stable. -""" -struct GradientVariablesPrimitive end -struct GradientVariablesEntropy end - # default to primitive gradient variables function CompressibleNavierStokesDiffusion2D(equations::CompressibleEulerEquations2D; mu, Prandtl, @@ -315,59 +297,6 @@ end return dv2dx - dv1dy end -# TODO: can we generalize this to MHD? -""" - struct BoundaryConditionNavierStokesWall - -Creates a wall-type boundary conditions for the compressible Navier-Stokes equations. -The fields `boundary_condition_velocity` and `boundary_condition_heat_flux` are intended -to be boundary condition types such as the `NoSlip` velocity boundary condition and the -`Adiabatic` or `Isothermal` heat boundary condition. - -!!! warning "Experimental feature" - This is an experimental feature and may change in future releases. -""" -struct BoundaryConditionNavierStokesWall{V, H} - boundary_condition_velocity::V - boundary_condition_heat_flux::H -end - -""" - struct NoSlip - -Use to create a no-slip boundary condition with `BoundaryConditionNavierStokesWall`. The field `boundary_value_function` -should be a function with signature `boundary_value_function(x, t, equations)` -and should return a `SVector{NDIMS}` whose entries are the velocity vector at a -point `x` and time `t`. -""" -struct NoSlip{F} - boundary_value_function::F # value of the velocity vector on the boundary -end - -""" - struct Isothermal - -Used to create a no-slip boundary condition with [`BoundaryConditionNavierStokesWall`](@ref). -The field `boundary_value_function` should be a function with signature -`boundary_value_function(x, t, equations)` and return a scalar value for the -temperature at point `x` and time `t`. -""" -struct Isothermal{F} - boundary_value_function::F # value of the temperature on the boundary -end - -""" - struct Adiabatic - -Used to create a no-slip boundary condition with [`BoundaryConditionNavierStokesWall`](@ref). -The field `boundary_value_normal_flux_function` should be a function with signature -`boundary_value_normal_flux_function(x, t, equations)` and return a scalar value for the -normal heat flux at point `x` and time `t`. -""" -struct Adiabatic{F} - boundary_value_normal_flux_function::F # scaled heat flux 1/T * kappa * dT/dn -end - @inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip, <:Adiabatic})(flux_inner, u_inner, diff --git a/src/equations/compressible_navier_stokes_3d.jl b/src/equations/compressible_navier_stokes_3d.jl index 0b770dff1ca..166b53bf615 100644 --- a/src/equations/compressible_navier_stokes_3d.jl +++ b/src/equations/compressible_navier_stokes_3d.jl @@ -29,7 +29,7 @@ The particular form of the compressible Navier-Stokes implemented is = \nabla \cdot \begin{pmatrix} -0 \\ \underline{\tau} \\ \underline{\tau}\mathbf{v} - \nabla q +0 \\ \underline{\tau} \\ \underline{\tau}\mathbf{v} - \mathbf{q} \end{pmatrix} ``` where the system is closed with the ideal gas assumption giving @@ -44,7 +44,7 @@ are built from the viscous stress tensor ``` where ``\underline{I}`` is the ``3\times 3`` identity matrix and the heat flux is ```math -\nabla q = -\kappa\nabla\left(T\right),\quad T = \frac{p}{R\rho} +\mathbf{q} = -\kappa\nabla\left(T\right),\quad T = \frac{p}{R\rho} ``` where ``T`` is the temperature and ``\kappa`` is the thermal conductivity for Fick's law. Under the assumption that the gas has a constant Prandtl number, @@ -55,7 +55,7 @@ the thermal conductivity is From this combination of temperature ``T`` and thermal conductivity ``\kappa`` we see that the gas constant `R` cancels and the heat flux becomes ```math -\nabla q = -\kappa\nabla\left(T\right) = -\frac{\gamma \mu}{(\gamma - 1)\textrm{Pr}}\nabla\left(\frac{p}{\rho}\right) +\mathbf{q} = -\kappa\nabla\left(T\right) = -\frac{\gamma \mu}{(\gamma - 1)\textrm{Pr}}\nabla\left(\frac{p}{\rho}\right) ``` which is the form implemented below in the [`flux`](@ref) function. diff --git a/src/equations/equations_parabolic.jl b/src/equations/equations_parabolic.jl index 6c0be43798a..66214025044 100644 --- a/src/equations/equations_parabolic.jl +++ b/src/equations/equations_parabolic.jl @@ -11,5 +11,7 @@ include("laplace_diffusion_2d.jl") # Compressible Navier-Stokes equations abstract type AbstractCompressibleNavierStokesDiffusion{NDIMS, NVARS} <: AbstractEquationsParabolic{NDIMS, NVARS} end +include("compressible_navier_stokes.jl") +include("compressible_navier_stokes_1d.jl") include("compressible_navier_stokes_2d.jl") include("compressible_navier_stokes_3d.jl") diff --git a/test/test_parabolic_1d.jl b/test/test_parabolic_1d.jl index 1aaf23d576a..06a55100d62 100644 --- a/test/test_parabolic_1d.jl +++ b/test/test_parabolic_1d.jl @@ -19,7 +19,40 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [2.847421658558336e-05] ) end - + + @trixi_testset "TreeMesh1D: elixir_navierstokes_convergence_periodic.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", "elixir_navierstokes_convergence_periodic.jl"), + l2 = [0.0001133835907077494, 6.226282245610444e-5, 0.0002820171699999139], + linf = [0.0006255102377159538, 0.00036195501456059986, 0.0016147729485886941] + ) + end + + @trixi_testset "TreeMesh1D: elixir_navierstokes_convergence_periodic.jl: GradientVariablesEntropy" begin + @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", "elixir_navierstokes_convergence_periodic.jl"), + equations_parabolic = CompressibleNavierStokesDiffusion1D(equations, mu=mu(), + Prandtl=prandtl_number(), + gradient_variables = GradientVariablesEntropy()), + l2 = [0.00011310615871043463, 6.216495207074201e-5, 0.00028195843110817814], + linf = [0.0006240837363233886, 0.0003616694320713876, 0.0016147339542413874] + ) + end + + @trixi_testset "TreeMesh1D: elixir_navierstokes_convergence_walls.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", "elixir_navierstokes_convergence_walls.jl"), + l2 = [0.00047023310868269237, 0.00032181736027057234, 0.0014966266486095025], + linf = [0.002996375101363302, 0.002863904256059634, 0.012691132946258676] + ) + end + + @trixi_testset "TreeMesh1D: elixir_navierstokes_convergence_walls.jl: GradientVariablesEntropy" begin + @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", "elixir_navierstokes_convergence_walls.jl"), + equations_parabolic = CompressibleNavierStokesDiffusion1D(equations, mu=mu(), + Prandtl=prandtl_number(), + gradient_variables = GradientVariablesEntropy()), + l2 = [0.0004608500483647771, 0.00032431091222851285, 0.0015159733360626845], + linf = [0.002754803146635787, 0.0028567714697580906, 0.012941794048176192] + ) + end end # Clean up afterwards: delete Trixi output directory From 68df09d5a21bd8f7393df90dab915247f9498505 Mon Sep 17 00:00:00 2001 From: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Date: Fri, 11 Aug 2023 09:44:19 +0200 Subject: [PATCH 066/263] fix typo in Davis wave speed estimate for 1d swe (#1601) Co-authored-by: Andrew Winters Co-authored-by: Hendrik Ranocha --- src/equations/shallow_water_1d.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/equations/shallow_water_1d.jl b/src/equations/shallow_water_1d.jl index 57bcb1212e1..32782d5478c 100644 --- a/src/equations/shallow_water_1d.jl +++ b/src/equations/shallow_water_1d.jl @@ -653,7 +653,7 @@ end c_rr = sqrt(equations.gravity * h_rr) λ_min = min(v_ll - c_ll, v_rr - c_rr) - λ_max = max(v_rr + c_rr, v_rr + c_rr) + λ_max = max(v_ll + c_ll, v_rr + c_rr) return λ_min, λ_max end From 34c123c285d44af6725b68ae176029736c357542 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Sun, 13 Aug 2023 05:50:12 +0200 Subject: [PATCH 067/263] set version to v0.5.38 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index c22d4b90642..6419be4d8fc 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.5.38-pre" +version = "0.5.38" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 0b8405a0950944b0883818eb5756ad9b7cd4094e Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Sun, 13 Aug 2023 05:50:27 +0200 Subject: [PATCH 068/263] set development version to v0.5.39-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 6419be4d8fc..dd937ed213b 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.5.38" +version = "0.5.39-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From add2542c0076dc6526d969f78cec2f732430bc15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 19:05:34 +0200 Subject: [PATCH 069/263] Bump crate-ci/typos from 1.16.2 to 1.16.5 (#1606) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.16.2 to 1.16.5. - [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.16.2...v1.16.5) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-type: direct:production update-type: version-update:semver-patch ... 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 a1a429cad97..6ebb288ea30 100644 --- a/.github/workflows/SpellCheck.yml +++ b/.github/workflows/SpellCheck.yml @@ -10,4 +10,4 @@ jobs: - name: Checkout Actions Repository uses: actions/checkout@v3 - name: Check spelling - uses: crate-ci/typos@v1.16.2 + uses: crate-ci/typos@v1.16.5 From 7f83a1a938eecd9b841efe215a6e482e67cfdcc1 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 15 Aug 2023 11:58:32 +0200 Subject: [PATCH 070/263] Enable MPI coverage with Linux and reduce heap size hint (#1603) * Enable MPI coverage with Linux and reduce heap size hint * Update runtests.jl * no MPI coverage CI on macOS * Update runtests.jl * Update runtests.jl --- test/runtests.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 1b0c745dbfd..f1adbaaf1df 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -28,10 +28,10 @@ const TRIXI_NTHREADS = clamp(Sys.CPU_THREADS, 2, 3) cmd = string(Base.julia_cmd()) coverage = occursin("--code-coverage", cmd) && !occursin("--code-coverage=none", cmd) - if !(coverage && Sys.iswindows()) && !(coverage && Sys.islinux()) + if !(coverage && Sys.iswindows()) && !(coverage && Sys.isapple()) # We provide a `--heap-size-hint` to avoid/reduce out-of-memory errors during CI testing mpiexec() do cmd - run(`$cmd -n $TRIXI_MPI_NPROCS $(Base.julia_cmd()) --threads=1 --check-bounds=yes --heap-size-hint=1G $(abspath("test_mpi.jl"))`) + run(`$cmd -n $TRIXI_MPI_NPROCS $(Base.julia_cmd()) --threads=1 --check-bounds=yes --heap-size-hint=0.5G $(abspath("test_mpi.jl"))`) end end end From a4283e1e8253f7ddf2cabf22e2c7b39ce29a644f Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 15 Aug 2023 17:20:52 +0200 Subject: [PATCH 071/263] Update dependabot.yml (#1608) --- .github/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 700707ced32..d60f0707fc2 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,4 +4,4 @@ updates: - package-ecosystem: "github-actions" directory: "/" # Location of package manifests schedule: - interval: "weekly" + interval: "monthly" From 4da5c53776c1d617a2b9bb656da02640f1d6a211 Mon Sep 17 00:00:00 2001 From: Benjamin Bolm <74359358+bennibolm@users.noreply.github.com> Date: Fri, 18 Aug 2023 12:37:06 +0200 Subject: [PATCH 072/263] Subcell positivity IDP limiting for conservative variables (#1476) * Add IDP positivity limiting for conservative variables * Add elixir with modified blast wave * Add documentation * Fix parameter type * Adjust output of summary callback * Merge changes from `subcell-limiting` and `main` * Fix test with right time stepping * Implement first suggestions * Implement suggestions * Fix elixir * Relocate `perform_idp_correction!` * Rename variable in `snake_case` * Implement other suggestions * Rename container variables using `snake_case` * Delete timer * Merge `subcell-limiting` (Adapt docstrings) * Merge `subcell-limiting` * Merge `subcell-limiting` (Renaming and dispatch) * Fix documentation * Implement positivty limiter with numbers of cons vars * Merge suggestions already implemented in `subcell-limiting` * Fix elixir * Update docstring and output * Restructure parameter for positivity limiting * Add test for "show" routine * Rename Limiters and Containers * Rename antidiffusive stage callback * Relocate subcell limiter code * Move create_cache routine to specific file * Implement suggestions * Implement suggestions --------- Co-authored-by: Hendrik Ranocha Co-authored-by: Michael Schlottke-Lakemper --- NEWS.md | 1 + .../elixir_euler_shockcapturing_subcell.jl | 92 +++++++ ...ubble_shockcapturing_subcell_positivity.jl | 140 ++++++++++ src/Trixi.jl | 5 +- src/callbacks_stage/callbacks_stage.jl | 1 + .../subcell_limiter_idp_correction.jl | 69 +++++ .../subcell_limiter_idp_correction_2d.jl | 44 ++++ src/solvers/dg.jl | 40 +++ src/solvers/dgsem_tree/containers_2d.jl | 136 +++++++++- src/solvers/dgsem_tree/dg.jl | 5 + .../dgsem_tree/dg_2d_subcell_limiters.jl | 193 ++++++++++++++ src/solvers/dgsem_tree/subcell_limiters.jl | 103 ++++++++ src/solvers/dgsem_tree/subcell_limiters_2d.jl | 114 +++++++++ src/time_integration/methods_SSP.jl | 241 ++++++++++++++++++ src/time_integration/time_integration.jl | 1 + test/test_tree_2d_euler.jl | 6 + test/test_tree_2d_eulermulti.jl | 8 + test/test_unit.jl | 39 +-- 18 files changed, 1218 insertions(+), 20 deletions(-) create mode 100644 examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl create mode 100644 examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl create mode 100644 src/callbacks_stage/subcell_limiter_idp_correction.jl create mode 100644 src/callbacks_stage/subcell_limiter_idp_correction_2d.jl create mode 100644 src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl create mode 100644 src/solvers/dgsem_tree/subcell_limiters.jl create mode 100644 src/solvers/dgsem_tree/subcell_limiters_2d.jl create mode 100644 src/time_integration/methods_SSP.jl diff --git a/NEWS.md b/NEWS.md index 10125c40d17..4b96e1e2834 100644 --- a/NEWS.md +++ b/NEWS.md @@ -12,6 +12,7 @@ for human readability. - Non-uniform `TreeMesh` available for hyperbolic-parabolic equations. - Capability to set truly discontinuous initial conditions in 1D. - Wetting and drying feature and examples for 1D and 2D shallow water equations +- Subcell positivity limiting support for conservative variables in 2D for `TreeMesh` #### Changed diff --git a/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl b/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl new file mode 100644 index 00000000000..6b69e4db563 --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl @@ -0,0 +1,92 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations2D(1.4) + +""" + initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations2D) + +A medium blast wave (modified to lower density and higher pressure) taken from +- Sebastian Hennemann, Gregor J. Gassner (2020) + A provably entropy stable subcell shock capturing approach for high order split form DG + [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) +""" +function initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations2D) + # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> modified to lower density, higher pressure + # 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) + phi = atan(y_norm, x_norm) + sin_phi, cos_phi = sincos(phi) + + # Calculate primitive variables "normal" medium blast wave + rho = r > 0.5 ? 0.1 : 0.2691 # rho = r > 0.5 ? 1 : 1.1691 + v1 = r > 0.5 ? 0.0 : 0.1882 * cos_phi + v2 = r > 0.5 ? 0.0 : 0.1882 * sin_phi + p = r > 0.5 ? 1.0E-1 : 1.245 # p = r > 0.5 ? 1.0E-3 : 1.245 + + return prim2cons(SVector(rho, v1, v2, p), equations) +end +initial_condition = initial_condition_blast_wave + +surface_flux = flux_lax_friedrichs +volume_flux = flux_ranocha +basis = LobattoLegendreBasis(3) +limiter_idp = SubcellLimiterIDP(equations, basis; + positivity_variables_cons=[1], + positivity_correction_factor=0.5) +volume_integral = VolumeIntegralSubcellLimiting(limiter_idp; + volume_flux_dg=volume_flux, + volume_flux_fv=surface_flux) +solver = DGSEM(basis, surface_flux, volume_integral) + +coordinates_min = (-2.0, -2.0) +coordinates_max = ( 2.0, 2.0) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=5, + n_cells_max=100_000) + +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) + +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +save_solution = SaveSolutionCallback(interval=100, + save_initial_solution=true, + save_final_solution=true, + solution_variables=cons2prim) + +stepsize_callback = StepsizeCallback(cfl=0.6) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback) + + +############################################################################### +# run the simulation + +stage_callbacks = (SubcellLimiterIDPCorrection(),) + +sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks=stage_callbacks); + 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/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl new file mode 100644 index 00000000000..a67eaeb5b2b --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl @@ -0,0 +1,140 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler multicomponent equations + +# 1) Dry Air 2) Helium + 28% Air +equations = CompressibleEulerMulticomponentEquations2D(gammas = (1.4, 1.648), + gas_constants = (0.287, 1.578)) + +""" + initial_condition_shock_bubble(x, t, equations::CompressibleEulerMulticomponentEquations2D{5, 2}) + +A shock-bubble testcase for multicomponent Euler equations +- Ayoub Gouasmi, Karthik Duraisamy, Scott Murman + Formulation of Entropy-Stable schemes for the multicomponent compressible Euler equations + [arXiv: 1904.00972](https://arxiv.org/abs/1904.00972) +""" +function initial_condition_shock_bubble(x, t, equations::CompressibleEulerMulticomponentEquations2D{5, 2}) + # bubble test case, see Gouasmi et al. https://arxiv.org/pdf/1904.00972 + # other reference: https://www.researchgate.net/profile/Pep_Mulet/publication/222675930_A_flux-split_algorithm_applied_to_conservative_models_for_multicomponent_compressible_flows/links/568da54508aeaa1481ae7af0.pdf + # typical domain is rectangular, we change it to a square, as Trixi can only do squares + @unpack gas_constants = equations + + # Positivity Preserving Parameter, can be set to zero if scheme is positivity preserving + delta = 0.03 + + # Region I + rho1_1 = delta + rho2_1 = 1.225 * gas_constants[1]/gas_constants[2] - delta + v1_1 = zero(delta) + v2_1 = zero(delta) + p_1 = 101325 + + # Region II + rho1_2 = 1.225-delta + rho2_2 = delta + v1_2 = zero(delta) + v2_2 = zero(delta) + p_2 = 101325 + + # Region III + rho1_3 = 1.6861 - delta + rho2_3 = delta + v1_3 = -113.5243 + v2_3 = zero(delta) + p_3 = 159060 + + # Set up Region I & II: + inicenter = SVector(zero(delta), zero(delta)) + x_norm = x[1] - inicenter[1] + y_norm = x[2] - inicenter[2] + r = sqrt(x_norm^2 + y_norm^2) + + if (x[1] > 0.50) + # Set up Region III + rho1 = rho1_3 + rho2 = rho2_3 + v1 = v1_3 + v2 = v2_3 + p = p_3 + elseif (r < 0.25) + # Set up Region I + rho1 = rho1_1 + rho2 = rho2_1 + v1 = v1_1 + v2 = v2_1 + p = p_1 + else + # Set up Region II + rho1 = rho1_2 + rho2 = rho2_2 + v1 = v1_2 + v2 = v2_2 + p = p_2 + end + + return prim2cons(SVector(v1, v2, p, rho1, rho2), equations) +end +initial_condition = initial_condition_shock_bubble + +surface_flux = flux_lax_friedrichs +volume_flux = flux_ranocha +basis = LobattoLegendreBasis(3) + +limiter_idp = SubcellLimiterIDP(equations, basis; + positivity_variables_cons=[(i+3 for i in eachcomponent(equations))...]) + +volume_integral = VolumeIntegralSubcellLimiting(limiter_idp; + volume_flux_dg=volume_flux, + volume_flux_fv=surface_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + +coordinates_min = (-2.25, -2.225) +coordinates_max = ( 2.20, 2.225) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=3, + n_cells_max=1_000_000) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.01) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 300 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval, + extra_analysis_integrals=(Trixi.density,)) + +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +save_solution = SaveSolutionCallback(interval=300, + save_initial_solution=true, + save_final_solution=true, + solution_variables=cons2prim) + +stepsize_callback = StepsizeCallback(cfl=0.9) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) + + +############################################################################### +# run the simulation + +stage_callbacks = (SubcellLimiterIDPCorrection(),) + +sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks=stage_callbacks); + 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 \ No newline at end of file diff --git a/src/Trixi.jl b/src/Trixi.jl index 78ddaa3ca7f..ec4d20558e5 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -121,10 +121,10 @@ include("semidiscretization/semidiscretization_hyperbolic.jl") include("semidiscretization/semidiscretization_hyperbolic_parabolic.jl") include("semidiscretization/semidiscretization_euler_acoustics.jl") include("semidiscretization/semidiscretization_coupled.jl") +include("time_integration/time_integration.jl") include("callbacks_step/callbacks_step.jl") include("callbacks_stage/callbacks_stage.jl") include("semidiscretization/semidiscretization_euler_gravity.jl") -include("time_integration/time_integration.jl") # `trixi_include` and special elixirs such as `convergence_test` include("auxiliary/special_elixirs.jl") @@ -229,6 +229,9 @@ export DG, SurfaceIntegralUpwind, MortarL2 +export VolumeIntegralSubcellLimiting, + SubcellLimiterIDP, SubcellLimiterIDPCorrection + export nelements, nnodes, nvariables, eachelement, eachnode, eachvariable diff --git a/src/callbacks_stage/callbacks_stage.jl b/src/callbacks_stage/callbacks_stage.jl index ab0f34efb78..976af327e6f 100644 --- a/src/callbacks_stage/callbacks_stage.jl +++ b/src/callbacks_stage/callbacks_stage.jl @@ -6,6 +6,7 @@ #! format: noindent include("positivity_zhang_shu.jl") +include("subcell_limiter_idp_correction.jl") # TODO: TrixiShallowWater: move specific limiter file include("positivity_shallow_water.jl") end # @muladd diff --git a/src/callbacks_stage/subcell_limiter_idp_correction.jl b/src/callbacks_stage/subcell_limiter_idp_correction.jl new file mode 100644 index 00000000000..69125ebecd9 --- /dev/null +++ b/src/callbacks_stage/subcell_limiter_idp_correction.jl @@ -0,0 +1,69 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +""" + SubcellLimiterIDPCorrection() + +Perform antidiffusive correction stage for the a posteriori IDP limiter [`SubcellLimiterIDP`](@ref) +called with [`VolumeIntegralSubcellLimiting`](@ref). + +!!! note + This callback and the actual limiter [`SubcellLimiterIDP`](@ref) only work together. + This is not a replacement but a necessary addition. + +## References + +- Rueda-Ramírez, Pazner, Gassner (2022) + Subcell Limiting Strategies for Discontinuous Galerkin Spectral Element Methods + [DOI: 10.1016/j.compfluid.2022.105627](https://doi.org/10.1016/j.compfluid.2022.105627) +- Pazner (2020) + Sparse invariant domain preserving discontinuous Galerkin methods with subcell convex limiting + [DOI: 10.1016/j.cma.2021.113876](https://doi.org/10.1016/j.cma.2021.113876) + +!!! warning "Experimental implementation" + This is an experimental feature and may change in future releases. +""" +struct SubcellLimiterIDPCorrection end + +function (limiter!::SubcellLimiterIDPCorrection)(u_ode, + integrator::Trixi.SimpleIntegratorSSP, + stage) + semi = integrator.p + limiter!(u_ode, semi, integrator.t, integrator.dt, + semi.solver.volume_integral) +end + +function (limiter!::SubcellLimiterIDPCorrection)(u_ode, semi, t, dt, + volume_integral::VolumeIntegralSubcellLimiting) + @trixi_timeit timer() "a posteriori limiter" limiter!(u_ode, semi, t, dt, + volume_integral.limiter) +end + +function (limiter!::SubcellLimiterIDPCorrection)(u_ode, semi, t, dt, + limiter::SubcellLimiterIDP) + mesh, equations, solver, cache = mesh_equations_solver_cache(semi) + + u = wrap_array(u_ode, mesh, equations, solver, cache) + + # Calculate blending factor alpha in [0,1] + # f_ij = alpha_ij * f^(FV)_ij + (1 - alpha_ij) * f^(DG)_ij + # = f^(FV)_ij + (1 - alpha_ij) * f^(antidiffusive)_ij + @trixi_timeit timer() "blending factors" solver.volume_integral.limiter(u, semi, + solver, t, + dt) + + perform_idp_correction!(u, dt, mesh, equations, solver, cache) + + return nothing +end + +init_callback(limiter!::SubcellLimiterIDPCorrection, semi) = nothing + +finalize_callback(limiter!::SubcellLimiterIDPCorrection, semi) = nothing + +include("subcell_limiter_idp_correction_2d.jl") +end # @muladd diff --git a/src/callbacks_stage/subcell_limiter_idp_correction_2d.jl b/src/callbacks_stage/subcell_limiter_idp_correction_2d.jl new file mode 100644 index 00000000000..f6b91444578 --- /dev/null +++ b/src/callbacks_stage/subcell_limiter_idp_correction_2d.jl @@ -0,0 +1,44 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +function perform_idp_correction!(u, dt, mesh::TreeMesh2D, equations, dg, cache) + @unpack inverse_weights = dg.basis + @unpack antidiffusive_flux1, antidiffusive_flux2 = cache.antidiffusive_fluxes + @unpack alpha1, alpha2 = dg.volume_integral.limiter.cache.subcell_limiter_coefficients + + @threaded for element in eachelement(dg, cache) + # Sign switch as in apply_jacobian! + inverse_jacobian = -cache.elements.inverse_jacobian[element] + + for j in eachnode(dg), i in eachnode(dg) + # Note: antidiffusive_flux1[v, i, xi, element] = antidiffusive_flux2[v, xi, i, element] = 0 for all i in 1:nnodes and xi in {1, nnodes+1} + alpha_flux1 = (1 - alpha1[i, j, element]) * + get_node_vars(antidiffusive_flux1, equations, dg, i, j, + element) + alpha_flux1_ip1 = (1 - alpha1[i + 1, j, element]) * + get_node_vars(antidiffusive_flux1, equations, dg, i + 1, + j, element) + alpha_flux2 = (1 - alpha2[i, j, element]) * + get_node_vars(antidiffusive_flux2, equations, dg, i, j, + element) + alpha_flux2_jp1 = (1 - alpha2[i, j + 1, element]) * + get_node_vars(antidiffusive_flux2, equations, dg, i, + j + 1, element) + + for v in eachvariable(equations) + u[v, i, j, element] += dt * inverse_jacobian * + (inverse_weights[i] * + (alpha_flux1_ip1[v] - alpha_flux1[v]) + + inverse_weights[j] * + (alpha_flux2_jp1[v] - alpha_flux2[v])) + end + end + end + + return nothing +end +end # @muladd diff --git a/src/solvers/dg.jl b/src/solvers/dg.jl index 495e0ffc4a4..36bbc6de361 100644 --- a/src/solvers/dg.jl +++ b/src/solvers/dg.jl @@ -174,6 +174,46 @@ function Base.show(io::IO, ::MIME"text/plain", end end +""" + VolumeIntegralSubcellLimiting(limiter; + volume_flux_dg, volume_flux_fv) + +A subcell limiting volume integral type for DG methods based on subcell blending approaches +with a low-order FV method. Used with limiter [`SubcellLimiterIDP`](@ref). + +!!! warning "Experimental implementation" + This is an experimental feature and may change in future releases. +""" +struct VolumeIntegralSubcellLimiting{VolumeFluxDG, VolumeFluxFV, Limiter} <: + AbstractVolumeIntegral + volume_flux_dg::VolumeFluxDG + volume_flux_fv::VolumeFluxFV + limiter::Limiter +end + +function VolumeIntegralSubcellLimiting(limiter; volume_flux_dg, + volume_flux_fv) + VolumeIntegralSubcellLimiting{typeof(volume_flux_dg), typeof(volume_flux_fv), + typeof(limiter)}(volume_flux_dg, volume_flux_fv, + limiter) +end + +function Base.show(io::IO, mime::MIME"text/plain", + integral::VolumeIntegralSubcellLimiting) + @nospecialize integral # reduce precompilation time + + if get(io, :compact, false) + show(io, integral) + else + summary_header(io, "VolumeIntegralSubcellLimiting") + summary_line(io, "volume flux DG", integral.volume_flux_dg) + summary_line(io, "volume flux FV", integral.volume_flux_fv) + summary_line(io, "limiter", integral.limiter |> typeof |> nameof) + show(increment_indent(io), mime, integral.limiter) + summary_footer(io) + end +end + # TODO: FD. Should this definition live in a different file because it is # not strictly a DG method? """ diff --git a/src/solvers/dgsem_tree/containers_2d.jl b/src/solvers/dgsem_tree/containers_2d.jl index d80522d42fd..9148b936312 100644 --- a/src/solvers/dgsem_tree/containers_2d.jl +++ b/src/solvers/dgsem_tree/containers_2d.jl @@ -77,7 +77,7 @@ end eachelement(elements::ElementContainer2D) Return an iterator over the indices that specify the location in relevant data structures -for the elements in `elements`. +for the elements in `elements`. In particular, not the elements themselves are returned. """ @inline eachelement(elements::ElementContainer2D) = Base.OneTo(nelements(elements)) @@ -1254,4 +1254,138 @@ function init_mpi_mortars!(mpi_mortars, elements, mesh::TreeMesh2D) return nothing end + +# Container data structure (structure-of-arrays style) for FCT-type antidiffusive fluxes +# (i, j+1) +# | +# flux2(i, j+1) +# | +# (i-1, j) ---flux1(i, j)--- (i, j) ---flux1(i+1, j)--- (i+1, j) +# | +# flux2(i, j) +# | +# (i, j-1) +mutable struct ContainerAntidiffusiveFlux2D{uEltype <: Real} + antidiffusive_flux1::Array{uEltype, 4} # [variables, i, j, elements] + antidiffusive_flux2::Array{uEltype, 4} # [variables, i, j, elements] + # internal `resize!`able storage + _antidiffusive_flux1::Vector{uEltype} + _antidiffusive_flux2::Vector{uEltype} +end + +function ContainerAntidiffusiveFlux2D{uEltype}(capacity::Integer, n_variables, + n_nodes) where {uEltype <: Real} + nan_uEltype = convert(uEltype, NaN) + + # Initialize fields with defaults + _antidiffusive_flux1 = fill(nan_uEltype, + n_variables * (n_nodes + 1) * n_nodes * capacity) + antidiffusive_flux1 = unsafe_wrap(Array, pointer(_antidiffusive_flux1), + (n_variables, n_nodes + 1, n_nodes, capacity)) + + _antidiffusive_flux2 = fill(nan_uEltype, + n_variables * n_nodes * (n_nodes + 1) * capacity) + antidiffusive_flux2 = unsafe_wrap(Array, pointer(_antidiffusive_flux2), + (n_variables, n_nodes, n_nodes + 1, capacity)) + + return ContainerAntidiffusiveFlux2D{uEltype}(antidiffusive_flux1, + antidiffusive_flux2, + _antidiffusive_flux1, + _antidiffusive_flux2) +end + +nvariables(fluxes::ContainerAntidiffusiveFlux2D) = size(fluxes.antidiffusive_flux1, 1) +nnodes(fluxes::ContainerAntidiffusiveFlux2D) = size(fluxes.antidiffusive_flux1, 3) + +# Only one-dimensional `Array`s are `resize!`able in Julia. +# Hence, we use `Vector`s as internal storage and `resize!` +# them whenever needed. Then, we reuse the same memory by +# `unsafe_wrap`ping multi-dimensional `Array`s around the +# internal storage. +function Base.resize!(fluxes::ContainerAntidiffusiveFlux2D, capacity) + n_nodes = nnodes(fluxes) + n_variables = nvariables(fluxes) + + @unpack _antidiffusive_flux1, _antidiffusive_flux2 = fluxes + + resize!(_antidiffusive_flux1, n_variables * (n_nodes + 1) * n_nodes * capacity) + fluxes.antidiffusive_flux1 = unsafe_wrap(Array, pointer(_antidiffusive_flux1), + (n_variables, n_nodes + 1, n_nodes, + capacity)) + resize!(_antidiffusive_flux2, n_variables * n_nodes * (n_nodes + 1) * capacity) + fluxes.antidiffusive_flux2 = unsafe_wrap(Array, pointer(_antidiffusive_flux2), + (n_variables, n_nodes, n_nodes + 1, + capacity)) + + return nothing +end + +# Container data structure (structure-of-arrays style) for variables used for IDP limiting +mutable struct ContainerSubcellLimiterIDP2D{uEltype <: Real} + alpha::Array{uEltype, 3} # [i, j, element] + alpha1::Array{uEltype, 3} + alpha2::Array{uEltype, 3} + variable_bounds::Vector{Array{uEltype, 3}} + # internal `resize!`able storage + _alpha::Vector{uEltype} + _alpha1::Vector{uEltype} + _alpha2::Vector{uEltype} + _variable_bounds::Vector{Vector{uEltype}} +end + +function ContainerSubcellLimiterIDP2D{uEltype}(capacity::Integer, n_nodes, + length) where {uEltype <: Real} + nan_uEltype = convert(uEltype, NaN) + + # Initialize fields with defaults + _alpha = fill(nan_uEltype, n_nodes * n_nodes * capacity) + alpha = unsafe_wrap(Array, pointer(_alpha), (n_nodes, n_nodes, capacity)) + _alpha1 = fill(nan_uEltype, (n_nodes + 1) * n_nodes * capacity) + alpha1 = unsafe_wrap(Array, pointer(_alpha1), (n_nodes + 1, n_nodes, capacity)) + _alpha2 = fill(nan_uEltype, n_nodes * (n_nodes + 1) * capacity) + alpha2 = unsafe_wrap(Array, pointer(_alpha2), (n_nodes, n_nodes + 1, capacity)) + + _variable_bounds = Vector{Vector{uEltype}}(undef, length) + variable_bounds = Vector{Array{uEltype, 3}}(undef, length) + for i in 1:length + _variable_bounds[i] = fill(nan_uEltype, n_nodes * n_nodes * capacity) + variable_bounds[i] = unsafe_wrap(Array, pointer(_variable_bounds[i]), + (n_nodes, n_nodes, capacity)) + end + + return ContainerSubcellLimiterIDP2D{uEltype}(alpha, alpha1, alpha2, + variable_bounds, + _alpha, _alpha1, _alpha2, + _variable_bounds) +end + +nnodes(container::ContainerSubcellLimiterIDP2D) = size(container.alpha, 1) + +# Only one-dimensional `Array`s are `resize!`able in Julia. +# Hence, we use `Vector`s as internal storage and `resize!` +# them whenever needed. Then, we reuse the same memory by +# `unsafe_wrap`ping multi-dimensional `Array`s around the +# internal storage. +function Base.resize!(container::ContainerSubcellLimiterIDP2D, capacity) + n_nodes = nnodes(container) + + @unpack _alpha, _alpha1, _alpha2 = container + resize!(_alpha, n_nodes * n_nodes * capacity) + container.alpha = unsafe_wrap(Array, pointer(_alpha), (n_nodes, n_nodes, capacity)) + resize!(_alpha1, (n_nodes + 1) * n_nodes * capacity) + container.alpha1 = unsafe_wrap(Array, pointer(_alpha1), + (n_nodes + 1, n_nodes, capacity)) + resize!(_alpha2, n_nodes * (n_nodes + 1) * capacity) + container.alpha2 = unsafe_wrap(Array, pointer(_alpha2), + (n_nodes, n_nodes + 1, capacity)) + + @unpack _variable_bounds = container + for i in 1:length(_variable_bounds) + resize!(_variable_bounds[i], n_nodes * n_nodes * capacity) + container.variable_bounds[i] = unsafe_wrap(Array, pointer(_variable_bounds[i]), + (n_nodes, n_nodes, capacity)) + end + + return nothing +end end # @muladd diff --git a/src/solvers/dgsem_tree/dg.jl b/src/solvers/dgsem_tree/dg.jl index cb28dad968c..6e02bc1d94a 100644 --- a/src/solvers/dgsem_tree/dg.jl +++ b/src/solvers/dgsem_tree/dg.jl @@ -71,4 +71,9 @@ include("dg_3d_parabolic.jl") # as well as specialized implementations used to improve performance include("dg_2d_compressible_euler.jl") include("dg_3d_compressible_euler.jl") + +# Subcell limiters +include("subcell_limiters.jl") +include("subcell_limiters_2d.jl") +include("dg_2d_subcell_limiters.jl") end # @muladd diff --git a/src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl b/src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl new file mode 100644 index 00000000000..70ff346740d --- /dev/null +++ b/src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl @@ -0,0 +1,193 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +function create_cache(mesh::TreeMesh{2}, equations, + volume_integral::VolumeIntegralSubcellLimiting, dg::DG, uEltype) + cache = create_cache(mesh, equations, + VolumeIntegralPureLGLFiniteVolume(volume_integral.volume_flux_fv), + dg, uEltype) + + A3dp1_x = Array{uEltype, 3} + A3dp1_y = Array{uEltype, 3} + A3d = Array{uEltype, 3} + + fhat1_threaded = A3dp1_x[A3dp1_x(undef, nvariables(equations), nnodes(dg) + 1, + nnodes(dg)) for _ in 1:Threads.nthreads()] + fhat2_threaded = A3dp1_y[A3dp1_y(undef, nvariables(equations), nnodes(dg), + nnodes(dg) + 1) for _ in 1:Threads.nthreads()] + flux_temp_threaded = A3d[A3d(undef, nvariables(equations), nnodes(dg), nnodes(dg)) + for _ in 1:Threads.nthreads()] + + antidiffusive_fluxes = Trixi.ContainerAntidiffusiveFlux2D{uEltype}(0, + nvariables(equations), + nnodes(dg)) + + return (; cache..., antidiffusive_fluxes, fhat1_threaded, fhat2_threaded, + flux_temp_threaded) +end + +function calc_volume_integral!(du, u, + mesh::TreeMesh{2}, + nonconservative_terms, equations, + volume_integral::VolumeIntegralSubcellLimiting, + dg::DGSEM, cache) + @unpack limiter = volume_integral + + @threaded for element in eachelement(dg, cache) + subcell_limiting_kernel!(du, u, element, mesh, + nonconservative_terms, equations, + volume_integral, limiter, + dg, cache) + end +end + +@inline function subcell_limiting_kernel!(du, u, + element, mesh::TreeMesh{2}, + nonconservative_terms::False, equations, + volume_integral, limiter::SubcellLimiterIDP, + dg::DGSEM, cache) + @unpack inverse_weights = dg.basis + @unpack volume_flux_dg, volume_flux_fv = volume_integral + + # high-order DG fluxes + @unpack fhat1_threaded, fhat2_threaded = cache + + fhat1 = fhat1_threaded[Threads.threadid()] + fhat2 = fhat2_threaded[Threads.threadid()] + calcflux_fhat!(fhat1, fhat2, u, mesh, + nonconservative_terms, equations, volume_flux_dg, dg, element, cache) + + # low-order FV fluxes + @unpack fstar1_L_threaded, fstar1_R_threaded, fstar2_L_threaded, fstar2_R_threaded = cache + + fstar1_L = fstar1_L_threaded[Threads.threadid()] + fstar2_L = fstar2_L_threaded[Threads.threadid()] + fstar1_R = fstar1_R_threaded[Threads.threadid()] + fstar2_R = fstar2_R_threaded[Threads.threadid()] + calcflux_fv!(fstar1_L, fstar1_R, fstar2_L, fstar2_R, u, mesh, + nonconservative_terms, equations, volume_flux_fv, dg, element, cache) + + # antidiffusive flux + calcflux_antidiffusive!(fhat1, fhat2, fstar1_L, fstar2_L, u, mesh, + nonconservative_terms, equations, limiter, dg, element, + cache) + + # Calculate volume integral contribution of low-order FV flux + for j in eachnode(dg), i in eachnode(dg) + for v in eachvariable(equations) + du[v, i, j, element] += inverse_weights[i] * + (fstar1_L[v, i + 1, j] - fstar1_R[v, i, j]) + + inverse_weights[j] * + (fstar2_L[v, i, j + 1] - fstar2_R[v, i, j]) + end + end + + return nothing +end + +# Calculate the DG staggered volume fluxes `fhat` in subcell FV-form inside the element +# (**without non-conservative terms**). +# +# See also `flux_differencing_kernel!`. +@inline function calcflux_fhat!(fhat1, fhat2, u, + mesh::TreeMesh{2}, nonconservative_terms::False, + equations, + volume_flux, dg::DGSEM, element, cache) + @unpack weights, derivative_split = dg.basis + @unpack flux_temp_threaded = cache + + flux_temp = flux_temp_threaded[Threads.threadid()] + + # The FV-form fluxes are calculated in a recursive manner, i.e.: + # fhat_(0,1) = w_0 * FVol_0, + # fhat_(j,j+1) = fhat_(j-1,j) + w_j * FVol_j, for j=1,...,N-1, + # with the split form volume fluxes FVol_j = -2 * sum_i=0^N D_ji f*_(j,i). + + # To use the symmetry of the `volume_flux`, the split form volume flux is precalculated + # like in `calc_volume_integral!` for the `VolumeIntegralFluxDifferencing` + # and saved in in `flux_temp`. + + # Split form volume flux in orientation 1: x direction + flux_temp .= zero(eltype(flux_temp)) + + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, j, element) + + # All diagonal entries of `derivative_split` are zero. Thus, we can skip + # the computation of the diagonal terms. In addition, we use the symmetry + # of the `volume_flux` to save half of the possible two-point flux + # computations. + for ii in (i + 1):nnodes(dg) + u_node_ii = get_node_vars(u, equations, dg, ii, j, element) + flux1 = volume_flux(u_node, u_node_ii, 1, equations) + multiply_add_to_node_vars!(flux_temp, derivative_split[i, ii], flux1, + equations, dg, i, j) + multiply_add_to_node_vars!(flux_temp, derivative_split[ii, i], flux1, + equations, dg, ii, j) + end + end + + # FV-form flux `fhat` in x direction + fhat1[:, 1, :] .= zero(eltype(fhat1)) + fhat1[:, nnodes(dg) + 1, :] .= zero(eltype(fhat1)) + + for j in eachnode(dg), i in 1:(nnodes(dg) - 1), v in eachvariable(equations) + fhat1[v, i + 1, j] = fhat1[v, i, j] + weights[i] * flux_temp[v, i, j] + end + + # Split form volume flux in orientation 2: y direction + flux_temp .= zero(eltype(flux_temp)) + + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, j, element) + for jj in (j + 1):nnodes(dg) + u_node_jj = get_node_vars(u, equations, dg, i, jj, element) + flux2 = volume_flux(u_node, u_node_jj, 2, equations) + multiply_add_to_node_vars!(flux_temp, derivative_split[j, jj], flux2, + equations, dg, i, j) + multiply_add_to_node_vars!(flux_temp, derivative_split[jj, j], flux2, + equations, dg, i, jj) + end + end + + # FV-form flux `fhat` in y direction + fhat2[:, :, 1] .= zero(eltype(fhat2)) + fhat2[:, :, nnodes(dg) + 1] .= zero(eltype(fhat2)) + + for j in 1:(nnodes(dg) - 1), i in eachnode(dg), v in eachvariable(equations) + fhat2[v, i, j + 1] = fhat2[v, i, j] + weights[j] * flux_temp[v, i, j] + end + + return nothing +end + +# Calculate the antidiffusive flux `antidiffusive_flux` as the subtraction between `fhat` and `fstar`. +@inline function calcflux_antidiffusive!(fhat1, fhat2, fstar1, fstar2, u, mesh, + nonconservative_terms, equations, + limiter::SubcellLimiterIDP, dg, element, cache) + @unpack antidiffusive_flux1, antidiffusive_flux2 = cache.antidiffusive_fluxes + + for j in eachnode(dg), i in 2:nnodes(dg) + for v in eachvariable(equations) + antidiffusive_flux1[v, i, j, element] = fhat1[v, i, j] - fstar1[v, i, j] + end + end + for j in 2:nnodes(dg), i in eachnode(dg) + for v in eachvariable(equations) + antidiffusive_flux2[v, i, j, element] = fhat2[v, i, j] - fstar2[v, i, j] + end + end + + antidiffusive_flux1[:, 1, :, element] .= zero(eltype(antidiffusive_flux1)) + antidiffusive_flux1[:, nnodes(dg) + 1, :, element] .= zero(eltype(antidiffusive_flux1)) + + antidiffusive_flux2[:, :, 1, element] .= zero(eltype(antidiffusive_flux2)) + antidiffusive_flux2[:, :, nnodes(dg) + 1, element] .= zero(eltype(antidiffusive_flux2)) + + return nothing +end +end # @muladd diff --git a/src/solvers/dgsem_tree/subcell_limiters.jl b/src/solvers/dgsem_tree/subcell_limiters.jl new file mode 100644 index 00000000000..3a707de3bc7 --- /dev/null +++ b/src/solvers/dgsem_tree/subcell_limiters.jl @@ -0,0 +1,103 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +abstract type AbstractSubcellLimiter end + +function create_cache(typ::Type{LimiterType}, + semi) where {LimiterType <: AbstractSubcellLimiter} + create_cache(typ, mesh_equations_solver_cache(semi)...) +end + +""" + SubcellLimiterIDP(equations::AbstractEquations, basis; + positivity_variables_cons = [], + positivity_correction_factor = 0.1) + +Subcell invariant domain preserving (IDP) limiting used with [`VolumeIntegralSubcellLimiting`](@ref) +including: +- positivity limiting for conservative variables (`positivity_variables_cons`) + +The bounds are calculated using the low-order FV solution. The positivity limiter uses +`positivity_correction_factor` such that `u^new >= positivity_correction_factor * u^FV`. + +!!! note + This limiter and the correction callback [`SubcellLimiterIDPCorrection`](@ref) only work together. + Without the callback, no limiting takes place, leading to a standard flux-differencing DGSEM scheme. + +## References + +- Rueda-Ramírez, Pazner, Gassner (2022) + Subcell Limiting Strategies for Discontinuous Galerkin Spectral Element Methods + [DOI: 10.1016/j.compfluid.2022.105627](https://doi.org/10.1016/j.compfluid.2022.105627) +- Pazner (2020) + Sparse invariant domain preserving discontinuous Galerkin methods with subcell convex limiting + [DOI: 10.1016/j.cma.2021.113876](https://doi.org/10.1016/j.cma.2021.113876) + +!!! warning "Experimental implementation" + This is an experimental feature and may change in future releases. +""" +struct SubcellLimiterIDP{RealT <: Real, Cache} <: AbstractSubcellLimiter + positivity::Bool + positivity_variables_cons::Vector{Int} # Positivity for conservative variables + positivity_correction_factor::RealT + cache::Cache +end + +# this method is used when the indicator is constructed as for shock-capturing volume integrals +function SubcellLimiterIDP(equations::AbstractEquations, basis; + positivity_variables_cons = [], + positivity_correction_factor = 0.1) + positivity = (length(positivity_variables_cons) > 0) + number_bounds = length(positivity_variables_cons) + + cache = create_cache(SubcellLimiterIDP, equations, basis, number_bounds) + + SubcellLimiterIDP{typeof(positivity_correction_factor), typeof(cache)}(positivity, + positivity_variables_cons, + positivity_correction_factor, + cache) +end + +function Base.show(io::IO, limiter::SubcellLimiterIDP) + @nospecialize limiter # reduce precompilation time + @unpack positivity = limiter + + print(io, "SubcellLimiterIDP(") + if !(positivity) + print(io, "No limiter selected => pure DG method") + else + print(io, "limiter=(") + positivity && print(io, "positivity") + print(io, "), ") + end + print(io, ")") +end + +function Base.show(io::IO, ::MIME"text/plain", limiter::SubcellLimiterIDP) + @nospecialize limiter # reduce precompilation time + @unpack positivity = limiter + + if get(io, :compact, false) + show(io, limiter) + else + if !(positivity) + setup = ["limiter" => "No limiter selected => pure DG method"] + else + setup = ["limiter" => ""] + if positivity + string = "positivity with conservative variables $(limiter.positivity_variables_cons)" + setup = [setup..., "" => string] + setup = [ + setup..., + "" => " positivity correction factor = $(limiter.positivity_correction_factor)", + ] + end + end + summary_box(io, "SubcellLimiterIDP", setup) + end +end +end # @muladd diff --git a/src/solvers/dgsem_tree/subcell_limiters_2d.jl b/src/solvers/dgsem_tree/subcell_limiters_2d.jl new file mode 100644 index 00000000000..09ab84ed11a --- /dev/null +++ b/src/solvers/dgsem_tree/subcell_limiters_2d.jl @@ -0,0 +1,114 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +# this method is used when the limiter is constructed as for shock-capturing volume integrals +function create_cache(indicator::Type{SubcellLimiterIDP}, + equations::AbstractEquations{2}, + basis::LobattoLegendreBasis, number_bounds) + subcell_limiter_coefficients = Trixi.ContainerSubcellLimiterIDP2D{real(basis) + }(0, + nnodes(basis), + number_bounds) + + cache = (; subcell_limiter_coefficients) + + return cache +end + +function (limiter::SubcellLimiterIDP)(u::AbstractArray{<:Any, 4}, semi, dg::DGSEM, t, + dt; + kwargs...) + @unpack alpha = limiter.cache.subcell_limiter_coefficients + alpha .= zero(eltype(alpha)) + + if limiter.positivity + @trixi_timeit timer() "positivity" idp_positivity!(alpha, limiter, u, dt, + semi) + end + + # Calculate alpha1 and alpha2 + @unpack alpha1, alpha2 = limiter.cache.subcell_limiter_coefficients + @threaded for element in eachelement(dg, semi.cache) + for j in eachnode(dg), i in 2:nnodes(dg) + alpha1[i, j, element] = max(alpha[i - 1, j, element], alpha[i, j, element]) + end + for j in 2:nnodes(dg), i in eachnode(dg) + alpha2[i, j, element] = max(alpha[i, j - 1, element], alpha[i, j, element]) + end + alpha1[1, :, element] .= zero(eltype(alpha1)) + alpha1[nnodes(dg) + 1, :, element] .= zero(eltype(alpha1)) + alpha2[:, 1, element] .= zero(eltype(alpha2)) + alpha2[:, nnodes(dg) + 1, element] .= zero(eltype(alpha2)) + end + + return nothing +end + +@inline function idp_positivity!(alpha, limiter, u, dt, semi) + # Conservative variables + for (index, variable) in enumerate(limiter.positivity_variables_cons) + idp_positivity!(alpha, limiter, u, dt, semi, variable, index) + end + + return nothing +end + +@inline function idp_positivity!(alpha, limiter, u, dt, semi, variable, index) + mesh, equations, dg, cache = mesh_equations_solver_cache(semi) + @unpack antidiffusive_flux1, antidiffusive_flux2 = cache.antidiffusive_fluxes + @unpack inverse_weights = dg.basis + @unpack positivity_correction_factor = limiter + + @unpack variable_bounds = limiter.cache.subcell_limiter_coefficients + + var_min = variable_bounds[index] + + @threaded for element in eachelement(dg, semi.cache) + inverse_jacobian = cache.elements.inverse_jacobian[element] + for j in eachnode(dg), i in eachnode(dg) + var = u[variable, i, j, element] + if var < 0 + error("Safe $variable is not safe. element=$element, node: $i $j, value=$var") + end + + # Compute bound + var_min[i, j, element] = positivity_correction_factor * var + + # Real one-sided Zalesak-type limiter + # * Zalesak (1979). "Fully multidimensional flux-corrected transport algorithms for fluids" + # * Kuzmin et al. (2010). "Failsafe flux limiting and constrained data projections for equations of gas dynamics" + # Note: The Zalesak limiter has to be computed, even if the state is valid, because the correction is + # for each interface, not each node + Qm = min(0, (var_min[i, j, element] - var) / dt) + + # Calculate Pm + # Note: Boundaries of antidiffusive_flux1/2 are constant 0, so they make no difference here. + val_flux1_local = inverse_weights[i] * + antidiffusive_flux1[variable, i, j, element] + val_flux1_local_ip1 = -inverse_weights[i] * + antidiffusive_flux1[variable, i + 1, j, element] + val_flux2_local = inverse_weights[j] * + antidiffusive_flux2[variable, i, j, element] + val_flux2_local_jp1 = -inverse_weights[j] * + antidiffusive_flux2[variable, i, j + 1, element] + + Pm = min(0, val_flux1_local) + min(0, val_flux1_local_ip1) + + min(0, val_flux2_local) + min(0, val_flux2_local_jp1) + Pm = inverse_jacobian * Pm + + # Compute blending coefficient avoiding division by zero + # (as in paper of [Guermond, Nazarov, Popov, Thomas] (4.8)) + Qm = abs(Qm) / (abs(Pm) + eps(typeof(Qm)) * 100) + + # Calculate alpha + alpha[i, j, element] = max(alpha[i, j, element], 1 - Qm) + end + end + + return nothing +end +end # @muladd diff --git a/src/time_integration/methods_SSP.jl b/src/time_integration/methods_SSP.jl new file mode 100644 index 00000000000..8ecad69748b --- /dev/null +++ b/src/time_integration/methods_SSP.jl @@ -0,0 +1,241 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +# Abstract base type for time integration schemes of explicit strong stability-preserving (SSP) +# Runge-Kutta (RK) methods. They are high-order time discretizations that guarantee the TVD property. +abstract type SimpleAlgorithmSSP end + +""" + SimpleSSPRK33(; stage_callbacks=()) + +The third-order SSP Runge-Kutta method of Shu and Osher. + +## References + +- Shu, Osher (1988) + "Efficient Implementation of Essentially Non-oscillatory Shock-Capturing Schemes" (Eq. 2.18) + [DOI: 10.1016/0021-9991(88)90177-5](https://doi.org/10.1016/0021-9991(88)90177-5) + +!!! warning "Experimental implementation" + This is an experimental feature and may change in future releases. +""" +struct SimpleSSPRK33{StageCallbacks} <: SimpleAlgorithmSSP + a::SVector{3, Float64} + b::SVector{3, Float64} + c::SVector{3, Float64} + stage_callbacks::StageCallbacks + + function SimpleSSPRK33(; stage_callbacks = ()) + a = SVector(0.0, 3 / 4, 1 / 3) + b = SVector(1.0, 1 / 4, 2 / 3) + c = SVector(0.0, 1.0, 1 / 2) + + # Butcher tableau + # c | a + # 0 | + # 1 | 1 + # 1/2 | 1/4 1/4 + # -------------------- + # b | 1/6 1/6 2/3 + + new{typeof(stage_callbacks)}(a, b, c, stage_callbacks) + end +end + +# This struct is needed to fake https://github.com/SciML/OrdinaryDiffEq.jl/blob/0c2048a502101647ac35faabd80da8a5645beac7/src/integrators/type.jl#L1 +mutable struct SimpleIntegratorSSPOptions{Callback} + callback::Callback # callbacks; used in Trixi + adaptive::Bool # whether the algorithm is adaptive; ignored + dtmax::Float64 # ignored + maxiters::Int # maximal number of time steps + tstops::Vector{Float64} # tstops from https://diffeq.sciml.ai/v6.8/basics/common_solver_opts/#Output-Control-1; ignored +end + +function SimpleIntegratorSSPOptions(callback, tspan; maxiters = typemax(Int), kwargs...) + SimpleIntegratorSSPOptions{typeof(callback)}(callback, false, Inf, maxiters, + [last(tspan)]) +end + +# This struct is needed to fake https://github.com/SciML/OrdinaryDiffEq.jl/blob/0c2048a502101647ac35faabd80da8a5645beac7/src/integrators/type.jl#L77 +# This implements the interface components described at +# https://diffeq.sciml.ai/v6.8/basics/integrator/#Handing-Integrators-1 +# which are used in Trixi. +mutable struct SimpleIntegratorSSP{RealT <: Real, uType, Params, Sol, F, Alg, + SimpleIntegratorSSPOptions} + u::uType + du::uType + r0::uType + t::RealT + dt::RealT # current time step + dtcache::RealT # ignored + iter::Int # current number of time steps (iteration) + p::Params # will be the semidiscretization from Trixi + sol::Sol # faked + f::F + alg::Alg + opts::SimpleIntegratorSSPOptions + finalstep::Bool # added for convenience +end + +# Forward integrator.stats.naccept to integrator.iter (see GitHub PR#771) +function Base.getproperty(integrator::SimpleIntegratorSSP, field::Symbol) + if field === :stats + return (naccept = getfield(integrator, :iter),) + end + # general fallback + return getfield(integrator, field) +end + +""" + solve(ode, alg; dt, callbacks, kwargs...) + +The following structures and methods provide the infrastructure for SSP Runge-Kutta methods +of type `SimpleAlgorithmSSP`. + +!!! warning "Experimental implementation" + This is an experimental feature and may change in future releases. +""" +function solve(ode::ODEProblem, alg = SimpleSSPRK33()::SimpleAlgorithmSSP; + dt, callback = nothing, kwargs...) + u = copy(ode.u0) + du = similar(u) + r0 = similar(u) + t = first(ode.tspan) + iter = 0 + integrator = SimpleIntegratorSSP(u, du, r0, t, dt, zero(dt), iter, ode.p, + (prob = ode,), ode.f, alg, + SimpleIntegratorSSPOptions(callback, ode.tspan; + kwargs...), false) + + # resize container + resize!(integrator.p, nelements(integrator.p.solver, integrator.p.cache)) + + # initialize callbacks + if callback isa CallbackSet + for cb in callback.continuous_callbacks + error("unsupported") + end + for cb in callback.discrete_callbacks + cb.initialize(cb, integrator.u, integrator.t, integrator) + end + elseif !isnothing(callback) + error("unsupported") + end + + for stage_callback in alg.stage_callbacks + init_callback(stage_callback, integrator.p) + end + + solve!(integrator) +end + +function solve!(integrator::SimpleIntegratorSSP) + @unpack prob = integrator.sol + @unpack alg = integrator + t_end = last(prob.tspan) + callbacks = integrator.opts.callback + + integrator.finalstep = false + while !integrator.finalstep + if isnan(integrator.dt) + error("time step size `dt` is NaN") + end + + # if the next iteration would push the simulation beyond the end time, set dt accordingly + if integrator.t + integrator.dt > t_end || + isapprox(integrator.t + integrator.dt, t_end) + integrator.dt = t_end - integrator.t + terminate!(integrator) + end + + @. integrator.r0 = integrator.u + for stage in eachindex(alg.c) + t_stage = integrator.t + integrator.dt * alg.c[stage] + # compute du + integrator.f(integrator.du, integrator.u, integrator.p, t_stage) + + # perform forward Euler step + @. integrator.u = integrator.u + integrator.dt * integrator.du + + for stage_callback in alg.stage_callbacks + stage_callback(integrator.u, integrator, stage) + end + + # perform convex combination + @. integrator.u = alg.a[stage] * integrator.r0 + alg.b[stage] * integrator.u + end + + integrator.iter += 1 + integrator.t += integrator.dt + + # handle callbacks + if callbacks isa CallbackSet + for cb in callbacks.discrete_callbacks + if cb.condition(integrator.u, integrator.t, integrator) + cb.affect!(integrator) + end + end + end + + # respect maximum number of iterations + if integrator.iter >= integrator.opts.maxiters && !integrator.finalstep + @warn "Interrupted. Larger maxiters is needed." + terminate!(integrator) + end + end + + for stage_callback in alg.stage_callbacks + finalize_callback(stage_callback, integrator.p) + end + + return TimeIntegratorSolution((first(prob.tspan), integrator.t), + (prob.u0, integrator.u), prob) +end + +# get a cache where the RHS can be stored +get_du(integrator::SimpleIntegratorSSP) = integrator.du +get_tmp_cache(integrator::SimpleIntegratorSSP) = (integrator.r0,) + +# some algorithms from DiffEq like FSAL-ones need to be informed when a callback has modified u +u_modified!(integrator::SimpleIntegratorSSP, ::Bool) = false + +# used by adaptive timestepping algorithms in DiffEq +function set_proposed_dt!(integrator::SimpleIntegratorSSP, dt) + integrator.dt = dt +end + +# stop the time integration +function terminate!(integrator::SimpleIntegratorSSP) + integrator.finalstep = true + empty!(integrator.opts.tstops) +end + +# used for AMR +function Base.resize!(integrator::SimpleIntegratorSSP, new_size) + resize!(integrator.u, new_size) + resize!(integrator.du, new_size) + resize!(integrator.r0, new_size) + + # Resize container + resize!(integrator.p, new_size) +end + +function Base.resize!(semi::AbstractSemidiscretization, new_size) + resize!(semi, semi.solver.volume_integral, new_size) +end + +Base.resize!(semi, volume_integral::AbstractVolumeIntegral, new_size) = nothing + +function Base.resize!(semi, volume_integral::VolumeIntegralSubcellLimiting, new_size) + # Resize container antidiffusive_fluxes + resize!(semi.cache.antidiffusive_fluxes, new_size) + + # Resize container subcell_limiter_coefficients + @unpack limiter = volume_integral + resize!(limiter.cache.subcell_limiter_coefficients, new_size) +end +end # @muladd diff --git a/src/time_integration/time_integration.jl b/src/time_integration/time_integration.jl index 539e00ff700..c1e53527121 100644 --- a/src/time_integration/time_integration.jl +++ b/src/time_integration/time_integration.jl @@ -15,4 +15,5 @@ end include("methods_2N.jl") include("methods_3Sstar.jl") +include("methods_SSP.jl") end # @muladd diff --git a/test/test_tree_2d_euler.jl b/test/test_tree_2d_euler.jl index 6de380288db..e1e3ad32e7d 100644 --- a/test/test_tree_2d_euler.jl +++ b/test/test_tree_2d_euler.jl @@ -63,6 +63,12 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") linf = [0.18527440131928286, 0.2404798030563736, 0.23269573860381076, 0.6874012187446894]) end + @trixi_testset "elixir_euler_shockcapturing_subcell.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing_subcell.jl"), + l2 = [0.08508147906199143, 0.04510299017724501, 0.045103019801950375, 0.6930704343869766], + linf = [0.31123546471463326, 0.5616274869594462, 0.5619692712224448, 2.88670199345138]) + end + @trixi_testset "elixir_euler_blast_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blast_wave.jl"), l2 = [0.14170569763947993, 0.11647068900798814, 0.11647072556898294, 0.3391989213659599], diff --git a/test/test_tree_2d_eulermulti.jl b/test/test_tree_2d_eulermulti.jl index 800dc31f84f..606afca1034 100644 --- a/test/test_tree_2d_eulermulti.jl +++ b/test/test_tree_2d_eulermulti.jl @@ -19,6 +19,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") tspan = (0.0, 0.001)) end + @trixi_testset "elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl"), + l2 = [81.52845664909304, 2.5455678559421346, 63229.190712645846, 0.19929478404550321, 0.011068604228443425], + linf = [249.21708417382013, 40.33299887640794, 174205.0118831558, 0.6881458768113586, 0.11274401158173972], + initial_refinement_level = 3, + tspan = (0.0, 0.001)) + end + @trixi_testset "elixir_eulermulti_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_ec.jl"), l2 = [0.050182236154087095, 0.050189894464434635, 0.2258715597305131, 0.06175171559771687], diff --git a/test/test_unit.jl b/test/test_unit.jl index e70a9be6a4a..5c5291c2430 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -402,6 +402,9 @@ isdir(outdir) && rm(outdir, recursive=true) indicator_hg = IndicatorHennemannGassner(1.0, 0.0, true, "variable", "cache") @test_nowarn show(stdout, indicator_hg) + limiter_idp = SubcellLimiterIDP(true, [1], 0.1, "cache") + @test_nowarn show(stdout, limiter_idp) + # TODO: TrixiShallowWater: move unit test indicator_hg_swe = IndicatorHennemannGassnerShallowWater(1.0, 0.0, true, "variable", "cache") @test_nowarn show(stdout, indicator_hg_swe) @@ -637,7 +640,7 @@ isdir(outdir) && rm(outdir, recursive=true) for normal_direction in normal_directions @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) - end + end end @timed_testset "Consistency check for HLL flux (naive): SWE" begin @@ -674,7 +677,7 @@ isdir(outdir) && rm(outdir, recursive=true) SVector(0.0, 1.0), SVector(0.5, -0.5), SVector(-1.2, 0.3)] - orientations = [1, 2] + orientations = [1, 2] u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] @@ -704,7 +707,7 @@ isdir(outdir) && rm(outdir, recursive=true) for u in u_values, normal_direction in normal_directions @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) - end + end end @timed_testset "Consistency check for HLL flux with Davis wave speed estimates: CEE" begin @@ -718,7 +721,7 @@ isdir(outdir) && rm(outdir, recursive=true) for orientation in orientations @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) end - + equations = CompressibleEulerEquations2D(1.4) u = SVector(1.1, -0.5, 2.34, 5.5) @@ -734,7 +737,7 @@ isdir(outdir) && rm(outdir, recursive=true) for normal_direction in normal_directions @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) - end + end equations = CompressibleEulerEquations3D(1.4) u = SVector(1.1, -0.5, 2.34, 2.4, 5.5) @@ -752,7 +755,7 @@ isdir(outdir) && rm(outdir, recursive=true) for normal_direction in normal_directions @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) - end + end end @timed_testset "Consistency check for HLL flux with Davis wave speed estimates: LEE" begin @@ -815,7 +818,7 @@ isdir(outdir) && rm(outdir, recursive=true) SVector(0.0, 1.0), SVector(0.5, -0.5), SVector(-1.2, 0.3)] - orientations = [1, 2] + orientations = [1, 2] u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] @@ -845,7 +848,7 @@ isdir(outdir) && rm(outdir, recursive=true) for u in u_values, normal_direction in normal_directions @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) - end + end end @timed_testset "Consistency check for HLLE flux: CEE" begin @@ -873,7 +876,7 @@ isdir(outdir) && rm(outdir, recursive=true) for normal_direction in normal_directions @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) - end + end equations = CompressibleEulerEquations3D(1.4) u = SVector(1.1, -0.5, 2.34, 2.4, 5.5) @@ -891,7 +894,7 @@ isdir(outdir) && rm(outdir, recursive=true) for normal_direction in normal_directions @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) - end + end end @timed_testset "Consistency check for HLLE flux: SWE" begin @@ -907,7 +910,7 @@ isdir(outdir) && rm(outdir, recursive=true) SVector(0.0, 1.0), SVector(0.5, -0.5), SVector(-1.2, 0.3)] - orientations = [1, 2] + orientations = [1, 2] u = SVector(1, 0.5, 0.5, 0.0) @@ -937,7 +940,7 @@ isdir(outdir) && rm(outdir, recursive=true) SVector(0.0, 1.0), SVector(0.5, -0.5), SVector(-1.2, 0.3)] - orientations = [1, 2] + orientations = [1, 2] u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] @@ -956,7 +959,7 @@ isdir(outdir) && rm(outdir, recursive=true) SVector(0.0, 0.0, 1.0), SVector(0.5, -0.5, 0.2), SVector(-1.2, 0.3, 1.4)] - orientations = [1, 2, 3] + orientations = [1, 2, 3] u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] @@ -967,7 +970,7 @@ isdir(outdir) && rm(outdir, recursive=true) for u in u_values, normal_direction in normal_directions @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) - end + end end @timed_testset "Consistency check for Godunov flux" begin @@ -1137,7 +1140,7 @@ isdir(outdir) && rm(outdir, recursive=true) SVector(-1.2, 0.3)] u_values = [SVector(1.0, 0.5, -0.7, 1.0), SVector(1.5, -0.2, 0.1, 5.0),] - fluxes = [flux_central, flux_ranocha, flux_shima_etal, flux_kennedy_gruber, + fluxes = [flux_central, flux_ranocha, flux_shima_etal, flux_kennedy_gruber, flux_hll, FluxHLL(min_max_speed_davis)] for f_std in fluxes @@ -1157,7 +1160,7 @@ isdir(outdir) && rm(outdir, recursive=true) SVector(-1.2, 0.3, 1.4)] u_values = [SVector(1.0, 0.5, -0.7, 0.1, 1.0), SVector(1.5, -0.2, 0.1, 0.2, 5.0),] - fluxes = [flux_central, flux_ranocha, flux_shima_etal, flux_kennedy_gruber, FluxLMARS(340), + fluxes = [flux_central, flux_ranocha, flux_shima_etal, flux_kennedy_gruber, FluxLMARS(340), flux_hll, FluxHLL(min_max_speed_davis)] for f_std in fluxes @@ -1173,11 +1176,11 @@ isdir(outdir) && rm(outdir, recursive=true) normal_directions = [SVector(1.0, 0.0), SVector(0.0, 1.0), SVector(0.5, -0.5), - SVector(-1.2, 0.3)] + SVector(-1.2, 0.3)] u = SVector(1, 0.5, 0.5, 0.0) - fluxes = [flux_central, flux_fjordholm_etal, flux_wintermeyer_etal, + fluxes = [flux_central, flux_fjordholm_etal, flux_wintermeyer_etal, flux_hll, FluxHLL(min_max_speed_davis), FluxHLL(min_max_speed_einfeldt)] end From 925c0474938a2b6e095a795a4c155b40965625e0 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 22 Aug 2023 15:58:08 +0200 Subject: [PATCH 073/263] set version to v0.5.39 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index dd937ed213b..6a11655d345 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.5.39-pre" +version = "0.5.39" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From add3a7f9e9c4b7445ee669e43afd8b84350e04d4 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 22 Aug 2023 15:58:20 +0200 Subject: [PATCH 074/263] set development version to v0.5.40-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 6a11655d345..4374eaa3b0a 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.5.39" +version = "0.5.40-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From bfefef15d3ccd71f43a5518560d0cd96b599881b Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Tue, 22 Aug 2023 17:21:45 +0200 Subject: [PATCH 075/263] Update visualization.md (#1612) Compare [examples/tree\_2d\_dgsem/elixir\_advection\_amr\_visualization.jl](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_advection_amr_visualization.jl): to (existing) [examples/tree_2d_dgsem/elixir\_advection\_amr\_visualization.jl](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_advection_amr_visualization.jl): --- docs/src/visualization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/visualization.md b/docs/src/visualization.md index 8f72bb4b1c6..4e4b780004d 100644 --- a/docs/src/visualization.md +++ b/docs/src/visualization.md @@ -375,7 +375,7 @@ During the simulation, the visualization callback creates and displays visualizations of the current solution in regular intervals. This can be useful to, e.g., monitor the validity of a long-running simulation or for illustrative purposes. An example for how to create a `VisualizationCallback` can be found in -[examples/tree_2d_dgsem/elixir\_advection\_amr\_visualization.jl](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_advection_amr_visualization.jl): +[examples/tree\_2d\_dgsem/elixir\_advection\_amr\_visualization.jl](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_advection_amr_visualization.jl): ```julia [...] From e22b11e5859b5168e24dabb4cb34a6a35fce3e66 Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Tue, 22 Aug 2023 19:30:35 +0200 Subject: [PATCH 076/263] Add review checklist to new PRs (#1609) Co-authored-by: Hendrik Ranocha --- .github/review-checklist.md | 38 +++++++++++++++++++++++++++ .github/workflows/ReviewChecklist.yml | 20 ++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 .github/review-checklist.md create mode 100644 .github/workflows/ReviewChecklist.yml diff --git a/.github/review-checklist.md b/.github/review-checklist.md new file mode 100644 index 00000000000..2d8a24f1971 --- /dev/null +++ b/.github/review-checklist.md @@ -0,0 +1,38 @@ +### Review checklist + +This checklist is meant to assist creators of PRs (to let them know what reviewers will typically look for) and reviewers (to guide them in a structured review process). Items do not need to be checked explicitly for a PR to be eligible for merging. + +#### Purpose and scope +- [ ] The PR has a single goal that is clear from the PR title and/or description. +- [ ] All code changes represent a single set of modifications that logically belong together. +- [ ] No more than 500 lines of code are changed or there is no obvious way to split the PR into multiple PRs. + +#### Code quality +- [ ] The code can be understood easily. +- [ ] Newly introduced names for variables etc. are self-descriptive and consistent with existing naming conventions. +- [ ] There are no redundancies that can be removed by simple modularization/refactoring. +- [ ] There are no leftover debug statements or commented code sections. +- [ ] The code adheres to our [conventions](https://trixi-framework.github.io/Trixi.jl/stable/conventions/) and [style guide](https://trixi-framework.github.io/Trixi.jl/stable/styleguide/), and to the [Julia guidelines](https://docs.julialang.org/en/v1/manual/style-guide/). + +#### Documentation +- [ ] New functions and types are documented with a docstring or top-level comment. +- [ ] Relevant publications are referenced in docstrings (see [example](https://github.com/trixi-framework/Trixi.jl/blob/7f83a1a938eecd9b841efe215a6e482e67cfdcc1/src/equations/compressible_euler_2d.jl#L601-L615) for formatting). +- [ ] Inline comments are used to document longer or unusual code sections. +- [ ] Comments describe intent ("why?") and not just functionality ("what?"). +- [ ] If the PR introduces a significant change or new feature, it is documented in `NEWS.md`. + +#### Testing +- [ ] The PR passes all tests. +- [ ] New or modified lines of code are covered by tests. +- [ ] New or modified tests run in less then 10 seconds. + +#### Performance +- [ ] There are no type instabilities or memory allocations in performance-critical parts. +- [ ] If the PR intent is to improve performance, before/after [time measurements](https://trixi-framework.github.io/Trixi.jl/stable/performance/#Manual-benchmarking) are posted in the PR. + +#### Verification +- [ ] The correctness of the code was verified using appropriate tests. +- [ ] If new equations/methods are added, a convergence test has been run and the results + are posted in the PR. + +*Created with :heart: by the Trixi.jl community.* \ No newline at end of file diff --git a/.github/workflows/ReviewChecklist.yml b/.github/workflows/ReviewChecklist.yml new file mode 100644 index 00000000000..959a04752d7 --- /dev/null +++ b/.github/workflows/ReviewChecklist.yml @@ -0,0 +1,20 @@ +name: Add review checklist + +on: + pull_request_target: + types: [opened] + +permissions: + pull-requests: write + +jobs: + add-review-checklist: + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v3 + - name: Add review checklist + uses: trixi-framework/add-pr-review-checklist@v1 + with: + file: '.github/review-checklist.md' + no-checklist-keyword: '[no checklist]' \ No newline at end of file From e82ebb557a280abb87e7b6f3db9d90bcac715321 Mon Sep 17 00:00:00 2001 From: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Date: Wed, 30 Aug 2023 20:16:45 +0200 Subject: [PATCH 077/263] unify how we refer to links to elixirs in docs (#1620) --- .../src/files/differentiable_programming.jl | 2 +- docs/literate/src/files/index.jl | 2 +- docs/src/callbacks.md | 22 +++++++++---------- docs/src/meshes/dgmulti_mesh.md | 14 +++++++----- docs/src/overview.md | 4 ++-- docs/src/restart.md | 10 ++++----- docs/src/visualization.md | 2 +- 7 files changed, 30 insertions(+), 26 deletions(-) diff --git a/docs/literate/src/files/differentiable_programming.jl b/docs/literate/src/files/differentiable_programming.jl index ecc09d05dcf..5c5a7cd7440 100644 --- a/docs/literate/src/files/differentiable_programming.jl +++ b/docs/literate/src/files/differentiable_programming.jl @@ -128,7 +128,7 @@ condition_number = cond(V) # you can compute the gradient of an entropy-dissipative semidiscretization with respect to the # ideal gas constant of the compressible Euler equations as described in the following. This example # is also available as the elixir -# [examples/special\_elixirs/elixir\_euler\_ad.jl](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/special_elixirs/elixir_euler_ad.jl) +# [`examples/special_elixirs/elixir_euler_ad.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/special_elixirs/elixir_euler_ad.jl) # First, we create a semidiscretization of the compressible Euler equations. diff --git a/docs/literate/src/files/index.jl b/docs/literate/src/files/index.jl index 5b669881502..0c8de66bf42 100644 --- a/docs/literate/src/files/index.jl +++ b/docs/literate/src/files/index.jl @@ -116,7 +116,7 @@ # ## Examples in Trixi.jl # Trixi.jl already contains several more coding examples, the so-called `elixirs`. You can find them -# in the folder [`examples`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/). +# in the folder [`examples/`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/). # They are structured by the underlying mesh type and the respective number of spatial dimensions. # The name of an elixir is composed of the underlying system of conservation equations (for instance # `advection` or `euler`) and other special characteristics like the initial condition diff --git a/docs/src/callbacks.md b/docs/src/callbacks.md index a85f8e8191b..1d3e5e34b51 100644 --- a/docs/src/callbacks.md +++ b/docs/src/callbacks.md @@ -15,7 +15,7 @@ control, adaptive mesh refinement, I/O, and more. ### CFL-based time step control Time step control can be performed with a [`StepsizeCallback`](@ref). An example making use -of this can be found at [examples/tree_2d_dgsem/elixir\_advection\_basic.jl](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_advection_basic.jl) +of this can be found at [`examples/tree_2d_dgsem/elixir_advection_basic.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_advection_basic.jl) ### Adaptive mesh refinement Trixi.jl uses a hierarchical Cartesian mesh which can be locally refined in a solution-adaptive way. @@ -24,12 +24,12 @@ passing an [`AMRCallback`](@ref) to the ODE solver. The `AMRCallback` requires a [`ControllerThreeLevel`](@ref) or [`ControllerThreeLevelCombined`](@ref) to tell the AMR algorithm which cells to refine/coarsen. -An example elixir using AMR can be found at [examples/tree_2d_dgsem/elixir\_advection\_amr.jl](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_advection_amr.jl). +An example elixir using AMR can be found at [`examples/tree_2d_dgsem/elixir_advection_amr.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_advection_amr.jl). ### Analyzing the numerical solution The [`AnalysisCallback`](@ref) can be used to analyze the numerical solution, e.g. calculate errors or user-specified integrals, and print the results to the screen. The results can also be -saved in a file. An example can be found at [examples/tree_2d_dgsem/elixir\_euler\_vortex.jl](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_euler_vortex.jl). +saved in a file. An example can be found at [`examples/tree_2d_dgsem/elixir_euler_vortex.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_euler_vortex.jl). In [Performance metrics of the `AnalysisCallback`](@ref) you can find a detailed description of the different performance metrics the `AnalysisCallback` computes. @@ -38,15 +38,15 @@ description of the different performance metrics the `AnalysisCallback` computes #### Solution and restart files To save the solution in regular intervals you can use a [`SaveSolutionCallback`](@ref). It is also possible to create restart files using the [`SaveRestartCallback`](@ref). An example making use -of these can be found at [examples/tree_2d_dgsem/elixir\_advection\_extended.jl](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_advection_extended.jl). +of these can be found at [`examples/tree_2d_dgsem/elixir_advection_extended.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_advection_extended.jl). An example showing how to restart a simulation from a restart file can be found at -[examples/tree_2d_dgsem/elixir\_advection\_restart.jl](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_advection_restart.jl). +[`examples/tree_2d_dgsem/elixir_advection_restart.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_advection_restart.jl). #### Time series Sometimes it is useful to record the evaluations of state variables over time at a given set of points. This can be achieved by the [`TimeSeriesCallback`](@ref), which is used, e.g., in -[examples/tree_2d_dgsem/elixir\_acoustics\_gaussian\_source.jl](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_acoustics_gaussian_source.jl). +[`examples/tree_2d_dgsem/elixir_acoustics_gaussian_source.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_acoustics_gaussian_source.jl). The `TimeSeriesCallback` constructor expects a semidiscretization and a list of points at which the solution should be recorded in regular time step intervals. After the last time step, the entire record is stored in an HDF5 file. @@ -113,12 +113,12 @@ will yield the following plot: Some callbacks provided by Trixi.jl implement specific features for certain equations: * The [`LBMCollisionCallback`](@ref) implements the Lattice-Boltzmann method (LBM) collision operator and should only be used when solving the Lattice-Boltzmann equations. See e.g. - [examples/tree_2d_dgsem/elixir\_lbm\_constant.jl](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_lbm_constant.jl) + [`examples/tree_2d_dgsem/elixir_lbm_constant.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_lbm_constant.jl) * The [`SteadyStateCallback`](@ref) terminates the time integration when the residual steady state falls below a certain threshold. This checks the convergence of the potential ``\phi`` for - hyperbolic diffusion. See e.g. [examples/tree_2d_dgsem/elixir\_hypdiff\_nonperiodic.jl](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_hypdiff_nonperiodic.jl). + hyperbolic diffusion. See e.g. [`examples/tree_2d_dgsem/elixir_hypdiff_nonperiodic.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_hypdiff_nonperiodic.jl). * The [`GlmSpeedCallback`](@ref) updates the divergence cleaning wave speed `c_h` for the ideal - GLM-MHD equations. See e.g. [examples/tree_2d_dgsem/elixir\_mhd\_alfven\_wave.jl](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_mhd_alfven_wave.jl). + GLM-MHD equations. See e.g. [`examples/tree_2d_dgsem/elixir_mhd_alfven_wave.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_mhd_alfven_wave.jl). ## Usage of step callbacks Step callbacks are passed to the `solve` method from the ODE solver via the keyword argument @@ -152,7 +152,7 @@ more callbacks, you need to turn them into a `CallbackSet` first by calling ## Stage callbacks [`PositivityPreservingLimiterZhangShu`](@ref) is a positivity-preserving limiter, used to enforce physical constraints. An example elixir using this feature can be found at -[examples/tree_2d_dgsem/elixir\_euler\_positivity.jl](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_euler_positivity.jl). +[`examples/tree_2d_dgsem/elixir_euler_positivity.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_euler_positivity.jl). ## Implementing new callbacks Since Trixi.jl is compatible with [OrdinaryDiffEq.jl](https://github.com/SciML/OrdinaryDiffEq.jl), @@ -162,4 +162,4 @@ Step callbacks are just called [callbacks](https://diffeq.sciml.ai/latest/featur Stage callbacks are called [`stage_limiter!`](https://diffeq.sciml.ai/latest/solvers/ode_solve/#Explicit-Strong-Stability-Preserving-Runge-Kutta-Methods-for-Hyperbolic-PDEs-(Conservation-Laws)). An example elixir showing how to implement a new simple stage callback and a new simple step -callback can be found at [examples/tree_2d_dgsem/elixir\_advection\_callbacks.jl](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_advection_callbacks.jl). +callback can be found at [`examples/tree_2d_dgsem/elixir_advection_callbacks.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_advection_callbacks.jl). diff --git a/docs/src/meshes/dgmulti_mesh.md b/docs/src/meshes/dgmulti_mesh.md index e07ba70a80a..fc086bba146 100644 --- a/docs/src/meshes/dgmulti_mesh.md +++ b/docs/src/meshes/dgmulti_mesh.md @@ -81,16 +81,20 @@ type, but will be more efficient at high orders of approximation. ## Trixi.jl elixirs on simplicial and tensor product element meshes Example elixirs with triangular, quadrilateral, and tetrahedral meshes can be found in -the `examples/dgmulti_2d` and `examples/dgmulti_3d` folders. Some key elixirs to look at: +the [`examples/dgmulti_2d/`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/dgmulti_2d/) +and [`examples/dgmulti_3d/`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/dgmulti_3d/) +folders. Some key elixirs to look at: -* `examples/dgmulti_2d/elixir_euler_weakform.jl`: basic weak form DG discretization on a uniform triangular mesh. +* [`examples/dgmulti_2d/elixir_euler_weakform.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/dgmulti_2d/elixir_euler_weakform.jl): + basic weak form DG discretization on a uniform triangular mesh. Changing `element_type = Quad()` or `approximation_type = SBP()` will switch to a quadrilateral mesh or an SBP-type discretization. Changing `surface_integral = SurfaceIntegralWeakForm(flux_ec)` and `volume_integral = VolumeIntegralFluxDifferencing(flux_ec)` for some entropy conservative flux (e.g., [`flux_chandrashekar`](@ref) or [`flux_ranocha`](@ref)) will switch to an entropy conservative formulation. -* `examples/dgmulti_2d/elixir_euler_triangulate_pkg_mesh.jl`: uses an unstructured mesh generated by - [Triangulate.jl](https://github.com/JuliaGeometry/Triangulate.jl). -* `examples/dgmulti_3d/elixir_euler_weakform.jl`: basic weak form DG discretization on a uniform tetrahedral mesh. +* [`examples/dgmulti_2d/elixir_euler_triangulate_pkg_mesh.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/dgmulti_2d/elixir_euler_triangulate_pkg_mesh.jl): + uses an unstructured mesh generated by [Triangulate.jl](https://github.com/JuliaGeometry/Triangulate.jl). +* [`examples/dgmulti_3d/elixir_euler_weakform.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/dgmulti_3d/elixir_euler_weakform.jl): + ´basic weak form DG discretization on a uniform tetrahedral mesh. Changing `element_type = Hex()` will switch to a hexahedral mesh. Changing `surface_integral = SurfaceIntegralWeakForm(flux_ec)` and `volume_integral = VolumeIntegralFluxDifferencing(flux_ec)` for some entropy conservative flux diff --git a/docs/src/overview.md b/docs/src/overview.md index 519ec2ca424..46bc28b6025 100644 --- a/docs/src/overview.md +++ b/docs/src/overview.md @@ -5,7 +5,7 @@ conservation laws. Thus, it is not a monolithic PDE solver that is configured at via parameter files, as it is often found in classical numerical simulation codes. Instead, each simulation is configured by pure Julia code. Many examples of such simulation setups, called *elixirs* in Trixi.jl, are provided in the -[examples](https://github.com/trixi-framework/Trixi.jl/blob/main/examples) +[`examples/`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples) folder. Trixi.jl uses the method of lines, i.e., the full space-time discretization is separated into two steps; @@ -77,7 +77,7 @@ Further information can be found in the ## Next steps We explicitly encourage people interested in Trixi.jl to have a look at the -[examples](https://github.com/trixi-framework/Trixi.jl/blob/main/examples) +[`examples/`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples) bundled with Trixi.jl to get an impression of what is possible and the general look and feel of Trixi.jl. Before doing that, it is usually good to get an idea of diff --git a/docs/src/restart.md b/docs/src/restart.md index d24d93cb297..767269ff27d 100644 --- a/docs/src/restart.md +++ b/docs/src/restart.md @@ -18,7 +18,7 @@ save_restart = SaveRestartCallback(interval=100, Make this part of your `CallbackSet`. An example is -[```examples/examples/structured_2d_dgsem/elixir_advection_extended.jl```](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/structured_2d_dgsem/elixir_advection_extended.jl). +[`examples/examples/structured_2d_dgsem/elixir_advection_extended.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/structured_2d_dgsem/elixir_advection_extended.jl). ## [Perform the simulation restart](@id restart_perform) @@ -26,7 +26,7 @@ Since all of the information about the simulation can be obtained from the last snapshot, the restart can be done with relatively few lines in an extra elixir file. However, some might prefer to keep everything in one elixir and -conditionals like ```if restart``` with a boolean variable ```restart``` that is user defined. +conditionals like `if restart` with a boolean variable `restart` that is user defined. First we need to define from which file we want to restart, e.g. ```julia @@ -50,7 +50,7 @@ time the one form the snapshot: tspan = (load_time(restart_filename), 2.0) ``` -We now also take the last ```dt```, so that our solver does not need to first find +We now also take the last `dt`, so that our solver does not need to first find one to fulfill the CFL condition: ```julia dt = load_dt(restart_filename) @@ -63,7 +63,7 @@ ode = semidiscretize(semi, tspan, restart_filename) You should now define a [`SaveSolutionCallback`](@ref) similar to the [original simulation](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/structured_2d_dgsem/elixir_advection_extended.jl), -but with ```save_initial_solution=false```, otherwise our initial snapshot will be overwritten. +but with `save_initial_solution=false`, otherwise our initial snapshot will be overwritten. If you are using one file for the original simulation and the restart you can reuse your [`SaveSolutionCallback`](@ref), but need to set ```julia @@ -86,4 +86,4 @@ Now we can compute the solution: sol = solve!(integrator) ``` -An example is in `[``examples/structured_2d_dgsem/elixir_advection_restart.jl```](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/structured_2d_dgsem/elixir_advection_restart.jl). +An example is in [`examples/structured_2d_dgsem/elixir_advection_restart.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/structured_2d_dgsem/elixir_advection_restart.jl). diff --git a/docs/src/visualization.md b/docs/src/visualization.md index 4e4b780004d..36a7e8f5ac8 100644 --- a/docs/src/visualization.md +++ b/docs/src/visualization.md @@ -375,7 +375,7 @@ During the simulation, the visualization callback creates and displays visualizations of the current solution in regular intervals. This can be useful to, e.g., monitor the validity of a long-running simulation or for illustrative purposes. An example for how to create a `VisualizationCallback` can be found in -[examples/tree\_2d\_dgsem/elixir\_advection\_amr\_visualization.jl](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_advection_amr_visualization.jl): +[`examples/tree_2d_dgsem/elixir_advection_amr_visualization.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_advection_amr_visualization.jl): ```julia [...] From af70d89eb35b30561833a20a6d6d3bb6e9567264 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 1 Sep 2023 15:35:30 +0200 Subject: [PATCH 078/263] update affiliation of HR (#1621) --- .zenodo.json | 2 +- AUTHORS.md | 2 +- README.md | 2 +- docs/src/index.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.zenodo.json b/.zenodo.json index 95879af1e90..905c0170ab9 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -15,7 +15,7 @@ "orcid": "0000-0002-1752-1158" }, { - "affiliation": "Applied Mathematics, University of Hamburg, Germany", + "affiliation": "Numerical Mathematics, Johannes Gutenberg University Mainz, Germany", "name": "Ranocha, Hendrik", "orcid": "0000-0002-3456-2277" }, diff --git a/AUTHORS.md b/AUTHORS.md index 74bfaa9c852..f1debf8ba76 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -12,7 +12,7 @@ provided substantial additions or modifications. Together, these two groups form * [Gregor Gassner](https://www.mi.uni-koeln.de/NumSim/gregor-gassner), University of Cologne, Germany * [Hendrik Ranocha](https://ranocha.de), - University of Hamburg, Germany + Johannes Gutenberg University Mainz, Germany * [Andrew Winters](https://liu.se/en/employee/andwi94), Linköping University, Sweden * [Jesse Chan](https://jlchan.github.io), diff --git a/README.md b/README.md index 7eaee8750dd..63540b1f640 100644 --- a/README.md +++ b/README.md @@ -247,7 +247,7 @@ Schlottke-Lakemper](https://lakemper.eu) (RWTH Aachen University/High-Performance Computing Center Stuttgart (HLRS), Germany) and [Gregor Gassner](https://www.mi.uni-koeln.de/NumSim/gregor-gassner) (University of Cologne, Germany). Together with [Hendrik Ranocha](https://ranocha.de) -(University of Hamburg, Germany), [Andrew Winters](https://liu.se/en/employee/andwi94) +(Johannes Gutenberg University Mainz, Germany), [Andrew Winters](https://liu.se/en/employee/andwi94) (Linköping University, Sweden), and [Jesse Chan](https://jlchan.github.io) (Rice University, US), they are the principal developers of Trixi.jl. The full list of contributors can be found in [AUTHORS.md](AUTHORS.md). diff --git a/docs/src/index.md b/docs/src/index.md index 3af785bc681..bb2afd1019f 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -324,7 +324,7 @@ Schlottke-Lakemper](https://lakemper.eu) (RWTH Aachen University/High-Performance Computing Center Stuttgart (HLRS), Germany) and [Gregor Gassner](https://www.mi.uni-koeln.de/NumSim/gregor-gassner) (University of Cologne, Germany). Together with [Hendrik Ranocha](https://ranocha.de) -(University of Hamburg, Germany) and [Andrew Winters](https://liu.se/en/employee/andwi94) +(Johannes Gutenberg University Mainz, Germany) and [Andrew Winters](https://liu.se/en/employee/andwi94) (Linköping University, Sweden), and [Jesse Chan](https://jlchan.github.io) (Rice University, US), they are the principal developers of Trixi.jl. The full list of contributors can be found under [Authors](@ref). From 6403a480825dcebdd10cb90584c5cc877b4b2c5d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:13:47 +0200 Subject: [PATCH 079/263] Bump crate-ci/typos from 1.16.5 to 1.16.9 (#1622) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.16.5 to 1.16.9. - [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.16.5...v1.16.9) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-type: direct:production update-type: version-update:semver-patch ... 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 6ebb288ea30..a06121e7ca1 100644 --- a/.github/workflows/SpellCheck.yml +++ b/.github/workflows/SpellCheck.yml @@ -10,4 +10,4 @@ jobs: - name: Checkout Actions Repository uses: actions/checkout@v3 - name: Check spelling - uses: crate-ci/typos@v1.16.5 + uses: crate-ci/typos@v1.16.9 From bd5ba865478a889c48a7675072d921906c27c0c4 Mon Sep 17 00:00:00 2001 From: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Date: Wed, 6 Sep 2023 09:15:38 +0200 Subject: [PATCH 080/263] Update docs on how to use a system-provided MPI installation with T8code.jl (#1613) * update docs on how to use a system-provided MPI installation with T8code.jl * reduce number of characters per line * adjust path of shared object files * fix typo --- docs/src/parallelization.md | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/docs/src/parallelization.md b/docs/src/parallelization.md index 08470fd064a..245fdc11852 100644 --- a/docs/src/parallelization.md +++ b/docs/src/parallelization.md @@ -53,16 +53,24 @@ a system-provided MPI installation with Trixi.jl can be found in the following s ### [Using a system-provided MPI installation](@id parallel_system_MPI) -When using Trixi.jl with a system-provided MPI backend the underlying [`p4est`](https://github.com/cburstedde/p4est) -library needs to be compiled with the same MPI installation. Therefore, you also need to use -a system-provided `p4est` installation (for notes on how to install `p4est` see e.g. -[here](https://github.com/cburstedde/p4est/blob/master/README), use the configure option -`--enable-mpi`). In addition, [P4est.jl](https://github.com/trixi-framework/P4est.jl) needs to -be configured to use the custom `p4est` installation. Follow the steps described -[here](https://github.com/trixi-framework/P4est.jl/blob/main/README.md) for the configuration. +When using Trixi.jl with a system-provided MPI backend the underlying +[`p4est`](https://github.com/cburstedde/p4est) and [`t8code`](https://github.com/DLR-AMR/t8code) +libraries need to be compiled with the same MPI installation. Therefore, you also need to +use system-provided `p4est` and `t8code` installations (for notes on how to install `p4est` +and `t8code` see e.g. [here](https://github.com/cburstedde/p4est/blob/master/README) and +[here](https://github.com/DLR-AMR/t8code/wiki/Installation), use the configure option +`--enable-mpi`). Note that `t8code` already comes with a `p4est` installation, so it suffices +to install `t8code`. In addition, [P4est.jl](https://github.com/trixi-framework/P4est.jl) and +[T8code.jl](https://github.com/DLR-AMR/T8code.jl) need to be configured to use the custom +installations. Follow the steps described +[here](https://github.com/DLR-AMR/T8code.jl/blob/main/README.md#installation) and +[here](https://github.com/trixi-framework/P4est.jl/blob/main/README.md#installation) for the +configuration. The paths that point to `libp4est.so` (and potentially to `libsc.so`) need to be +the same for P4est.jl and T8code.jl. This could e.g. be `libp4est.so` that usually can be found +in `lib/` or `local/lib/` in the installation directory of `t8code`. In total, in your active Julia project you should have a LocalPreferences.toml file with sections -`[MPIPreferences]` and `[P4est]` as well as an entry `MPIPreferences` in your Project.toml to -use a custom MPI installation. +`[MPIPreferences]`, `[T8code]` and `[P4est]` as well as an entry `MPIPreferences` in your +Project.toml to use a custom MPI installation. ### [Usage](@id parallel_usage) From 76b4c5fc842e47c4bd9f33c044ae99bd2dfbf789 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 6 Sep 2023 09:16:48 +0200 Subject: [PATCH 081/263] set version to v0.5.40 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 4374eaa3b0a..0d27c0fd6e8 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.5.40-pre" +version = "0.5.40" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From f098ea20f545007d741745c160c7d1e1919733c4 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 6 Sep 2023 09:17:13 +0200 Subject: [PATCH 082/263] set development version to v0.5.41-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 0d27c0fd6e8..e14dbcd0c03 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.5.40" +version = "0.5.41-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 81d2b70965f361b0bfd9b113ebe4fb360b1437cb Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 6 Sep 2023 15:33:48 +0200 Subject: [PATCH 083/263] workaround for allocations when broadcasting equations (#1626) --- src/equations/equations.jl | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 90b2cd62191..570a25cece9 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -75,8 +75,14 @@ end @inline Base.ndims(::AbstractEquations{NDIMS}) where {NDIMS} = NDIMS -# equations act like scalars in broadcasting -Base.broadcastable(equations::AbstractEquations) = Ref(equations) +# Equations act like scalars in broadcasting. +# Using `Ref(equations)` would be more convenient in some circumstances. +# However, this does not work with Julia v1.9.3 correctly due to a (performance) +# bug in Julia, see +# - https://github.com/trixi-framework/Trixi.jl/pull/1618 +# - https://github.com/JuliaLang/julia/issues/51118 +# Thus, we use the workaround below. +Base.broadcastable(equations::AbstractEquations) = (equations,) """ flux(u, orientation_or_normal, equations) From 4e6d1638a279130e0f5008ff75acadb8307b0a6d Mon Sep 17 00:00:00 2001 From: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Date: Wed, 6 Sep 2023 17:00:08 +0200 Subject: [PATCH 084/263] increase absolute tolerance (#1625) Co-authored-by: Hendrik Ranocha --- test/test_tree_1d_shallowwater.jl | 3 ++- test/test_trixi.jl | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test/test_tree_1d_shallowwater.jl b/test/test_tree_1d_shallowwater.jl index cafa17edd4c..1e5aeac1786 100644 --- a/test/test_tree_1d_shallowwater.jl +++ b/test/test_tree_1d_shallowwater.jl @@ -102,7 +102,8 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_beach.jl"), l2 = [0.17979210479598923, 1.2377495706611434, 6.289818963361573e-8], linf = [0.845938394800688, 3.3740800777086575, 4.4541473087633676e-7], - tspan = (0.0, 0.05)) + tspan = (0.0, 0.05), + atol = 3e-10) # see https://github.com/trixi-framework/Trixi.jl/issues/1617 end @trixi_testset "elixir_shallowwater_parabolic_bowl.jl" begin diff --git a/test/test_trixi.jl b/test/test_trixi.jl index ddace6b4fbe..f2cd0cab94d 100644 --- a/test/test_trixi.jl +++ b/test/test_trixi.jl @@ -5,7 +5,7 @@ import Trixi # inside an elixir. """ @test_trixi_include(elixir; l2=nothing, linf=nothing, - atol=10*eps(), rtol=0.001, + atol=500*eps(), rtol=sqrt(eps()), parameters...) Test Trixi by calling `trixi_include(elixir; parameters...)`. From a7867e7376541d1326f2796661f5ca35bc9fe499 Mon Sep 17 00:00:00 2001 From: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Date: Wed, 6 Sep 2023 18:38:45 +0200 Subject: [PATCH 085/263] Update docs for parallel HDF5 (#1504) * update docs for parallel HDF5 * Update docs/src/parallelization.md Co-authored-by: Hendrik Ranocha * update docs on parallel HDF5 * bump compat for HDF5 * mention T8code * reduce number of characters per line * add information for older HDF5.jl versions --------- Co-authored-by: Hendrik Ranocha --- Project.toml | 2 +- docs/src/parallelization.md | 41 +++++++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/Project.toml b/Project.toml index e14dbcd0c03..41dde8662ab 100644 --- a/Project.toml +++ b/Project.toml @@ -56,7 +56,7 @@ DiffEqCallbacks = "2.25" EllipsisNotation = "1.0" FillArrays = "0.13.2, 1" ForwardDiff = "0.10.18" -HDF5 = "0.14, 0.15, 0.16" +HDF5 = "0.14, 0.15, 0.16, 0.17" IfElse = "0.1" LinearMaps = "2.7, 3.0" LoopVectorization = "0.12.118" diff --git a/docs/src/parallelization.md b/docs/src/parallelization.md index 245fdc11852..d56777c9af4 100644 --- a/docs/src/parallelization.md +++ b/docs/src/parallelization.md @@ -166,17 +166,36 @@ section, specifically at the descriptions of the performance index (PID). ### Using error-based step size control with MPI -If you use error-based step size control (see also the section on [error-based adaptive step sizes](@ref adaptive_step_sizes)) -together with MPI you need to pass `internalnorm=ode_norm` and you should pass -`unstable_check=ode_unstable_check` to OrdinaryDiffEq's [`solve`](https://docs.sciml.ai/DiffEqDocs/latest/basics/common_solver_opts/), +If you use error-based step size control (see also the section on +[error-based adaptive step sizes](@ref adaptive_step_sizes)) together with MPI you need to pass +`internalnorm=ode_norm` and you should pass `unstable_check=ode_unstable_check` to +OrdinaryDiffEq's [`solve`](https://docs.sciml.ai/DiffEqDocs/latest/basics/common_solver_opts/), which are both included in [`ode_default_options`](@ref). ### Using parallel input and output -Trixi.jl allows parallel I/O using MPI by leveraging parallel HDF5.jl. To enable this, you first need -to use a system-provided MPI library, see also [here](@ref parallel_system_MPI) and you need to tell -[HDF5.jl](https://github.com/JuliaIO/HDF5.jl) to use this library. -To do so, set the environment variable `JULIA_HDF5_PATH` to the local path -that contains the `libhdf5.so` shared object file and build HDF5.jl by executing `using Pkg; Pkg.build("HDF5")`. -For more information see also the [documentation of HDF5.jl](https://juliaio.github.io/HDF5.jl/stable/mpi/). - -If you do not perform these steps to use parallel HDF5 or if the HDF5 is not MPI-enabled, Trixi.jl will fall back on a less efficient I/O mechanism. In that case, all disk I/O is performed only on rank zero and data is distributed to/gathered from the other ranks using regular MPI communication. +Trixi.jl allows parallel I/O using MPI by leveraging parallel HDF5.jl. On most systems, this is +enabled by default. Additionally, you can also use a local installation of the HDF5 library +(with MPI support). For this, you first need to use a system-provided MPI library, see also +[here](@ref parallel_system_MPI) and you need to tell [HDF5.jl](https://github.com/JuliaIO/HDF5.jl) +to use this library. To do so with HDF5.jl v0.17 and newer, set the preferences `libhdf5` and +`libhdf5_hl` to the local paths of the libraries `libhdf5` and `libhdf5_hl`, which can be done by +```julia +julia> using Preferences, UUIDs +julia> set_preferences!( + UUID("f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f"), # UUID of HDF5.jl + "libhdf5" => "/path/to/your/libhdf5.so", + "libhdf5_hl" => "/path/to/your/libhdf5_hl.so", force = true) +``` +For more information see also the +[documentation of HDF5.jl](https://juliaio.github.io/HDF5.jl/stable/mpi/). In total, you should +have a file called LocalPreferences.toml in the project directory that contains a section +`[MPIPreferences]`, a section `[HDF5]` with entries `libhdf5` and `libhdf5_hl`, a section `[P4est]` +with the entry `libp4est` as well as a section `[T8code]` with the entries `libt8`, `libp4est` +and `libsc`. +If you use HDF5.jl v0.16 or older, instead of setting the preferences for HDF5.jl, you need to set +the environment variable `JULIA_HDF5_PATH` to the path, where the HDF5 binaries are located and +then call `]build HDF5` from Julia. + +If HDF5 is not MPI-enabled, Trixi.jl will fall back on a less efficient I/O mechanism. In that +case, all disk I/O is performed only on rank zero and data is distributed to/gathered from the +other ranks using regular MPI communication. From 13260284dcbed67e9c430623cef049e171d19bfd Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Thu, 7 Sep 2023 08:10:57 +0200 Subject: [PATCH 086/263] set version to v0.5.41 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 41dde8662ab..37553fb70f4 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.5.41-pre" +version = "0.5.41" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 953f88a78688969b893f34b3cf99693674217381 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Thu, 7 Sep 2023 08:11:09 +0200 Subject: [PATCH 087/263] set development version to v0.5.42-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 37553fb70f4..d37c0548a6a 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.5.41" +version = "0.5.42-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 7791faa0ca116c047b41b8c556ec5175c4507a24 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 12 Sep 2023 10:53:52 +0200 Subject: [PATCH 088/263] Some multi-threading improvements (#1630) * fix multi-threaded parabolic terms on ARM On ARM, the previous versions resulted in cfunction: closures are not supported on this platform With this change, everything seems to work fine locally. At least test/test_threaded.jl runs fine with two threads. * reduce alloactions of multi-threaded parabolic terms a bit Polyester.jl passes arrays as pointer arrays to the closures without requiring allocations. More complicated structs may still require allocations, so unpacking some arrays before entering a threaded loop can reduce allocations. * format --- src/solvers/dgmulti/dg_parabolic.jl | 5 +- src/solvers/dgsem_tree/dg_1d_parabolic.jl | 34 +++++++----- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 51 ++++++++++-------- src/solvers/dgsem_tree/dg_3d_parabolic.jl | 65 ++++++++++++----------- 4 files changed, 86 insertions(+), 69 deletions(-) diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index 72dbe2c4256..7dfe4430244 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -62,9 +62,10 @@ end function transform_variables!(u_transformed, u, mesh, equations_parabolic::AbstractEquationsParabolic, dg::DGMulti, parabolic_scheme, cache, cache_parabolic) + transformation = gradient_variable_transformation(equations_parabolic) + @threaded for i in eachindex(u) - u_transformed[i] = gradient_variable_transformation(equations_parabolic)(u[i], - equations_parabolic) + u_transformed[i] = transformation(u[i], equations_parabolic) end end diff --git a/src/solvers/dgsem_tree/dg_1d_parabolic.jl b/src/solvers/dgsem_tree/dg_1d_parabolic.jl index c2aa75388c8..7602331d7c8 100644 --- a/src/solvers/dgsem_tree/dg_1d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_1d_parabolic.jl @@ -105,12 +105,13 @@ end function transform_variables!(u_transformed, u, mesh::TreeMesh{1}, equations_parabolic::AbstractEquationsParabolic, dg::DG, parabolic_scheme, cache, cache_parabolic) + transformation = gradient_variable_transformation(equations_parabolic) + @threaded for element in eachelement(dg, cache) # Calculate volume terms in one element for i in eachnode(dg) u_node = get_node_vars(u, equations_parabolic, dg, i, element) - u_transformed_node = gradient_variable_transformation(equations_parabolic)(u_node, - equations_parabolic) + u_transformed_node = transformation(u_node, equations_parabolic) set_node_vars!(u_transformed, u_transformed_node, equations_parabolic, dg, i, element) end @@ -147,16 +148,18 @@ function prolong2interfaces!(cache_parabolic, flux_viscous, equations_parabolic::AbstractEquationsParabolic, surface_integral, dg::DG, cache) @unpack interfaces = cache_parabolic + @unpack neighbor_ids = interfaces + interfaces_u = interfaces.u @threaded for interface in eachinterface(dg, cache) - left_element = interfaces.neighbor_ids[1, interface] - right_element = interfaces.neighbor_ids[2, interface] + left_element = neighbor_ids[1, interface] + right_element = neighbor_ids[2, interface] # interface in x-direction for v in eachvariable(equations_parabolic) - # OBS! `interfaces.u` stores the interpolated *fluxes* and *not the solution*! - interfaces.u[1, v, interface] = flux_viscous[v, nnodes(dg), left_element] - interfaces.u[2, v, interface] = flux_viscous[v, 1, right_element] + # OBS! `interfaces_u` stores the interpolated *fluxes* and *not the solution*! + interfaces_u[1, v, interface] = flux_viscous[v, nnodes(dg), left_element] + interfaces_u[2, v, interface] = flux_viscous[v, 1, right_element] end end @@ -204,21 +207,22 @@ function prolong2boundaries!(cache_parabolic, flux_viscous, equations_parabolic::AbstractEquationsParabolic, surface_integral, dg::DG, cache) @unpack boundaries = cache_parabolic - @unpack neighbor_sides = boundaries + @unpack neighbor_sides, neighbor_ids = boundaries + boundaries_u = boundaries.u @threaded for boundary in eachboundary(dg, cache_parabolic) - element = boundaries.neighbor_ids[boundary] + element = neighbor_ids[boundary] if neighbor_sides[boundary] == 1 # element in -x direction of boundary for v in eachvariable(equations_parabolic) - # OBS! `boundaries.u` stores the interpolated *fluxes* and *not the solution*! - boundaries.u[1, v, boundary] = flux_viscous[v, nnodes(dg), element] + # OBS! `boundaries_u` stores the interpolated *fluxes* and *not the solution*! + boundaries_u[1, v, boundary] = flux_viscous[v, nnodes(dg), element] end else # Element in +x direction of boundary for v in eachvariable(equations_parabolic) - # OBS! `boundaries.u` stores the interpolated *fluxes* and *not the solution*! - boundaries.u[2, v, boundary] = flux_viscous[v, 1, element] + # OBS! `boundaries_u` stores the interpolated *fluxes* and *not the solution*! + boundaries_u[2, v, boundary] = flux_viscous[v, 1, element] end end end @@ -552,8 +556,10 @@ end # where f(u) is the inviscid flux and g(u) is the viscous flux. function apply_jacobian_parabolic!(du, mesh::TreeMesh{1}, equations::AbstractEquationsParabolic, dg::DG, cache) + @unpack inverse_jacobian = cache.elements + @threaded for element in eachelement(dg, cache) - factor = cache.elements.inverse_jacobian[element] + factor = inverse_jacobian[element] for i in eachnode(dg) for v in eachvariable(equations) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 0da25230380..3dbc55412ad 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -118,12 +118,13 @@ end function transform_variables!(u_transformed, u, mesh::Union{TreeMesh{2}, P4estMesh{2}}, equations_parabolic::AbstractEquationsParabolic, dg::DG, parabolic_scheme, cache, cache_parabolic) + transformation = gradient_variable_transformation(equations_parabolic) + @threaded for element in eachelement(dg, cache) # Calculate volume terms in one element for j in eachnode(dg), i in eachnode(dg) u_node = get_node_vars(u, equations_parabolic, dg, i, j, element) - u_transformed_node = gradient_variable_transformation(equations_parabolic)(u_node, - equations_parabolic) + u_transformed_node = transformation(u_node, equations_parabolic) set_node_vars!(u_transformed, u_transformed_node, equations_parabolic, dg, i, j, element) end @@ -168,30 +169,31 @@ function prolong2interfaces!(cache_parabolic, flux_viscous, equations_parabolic::AbstractEquationsParabolic, surface_integral, dg::DG, cache) @unpack interfaces = cache_parabolic - @unpack orientations = interfaces + @unpack orientations, neighbor_ids = interfaces + interfaces_u = interfaces.u flux_viscous_x, flux_viscous_y = flux_viscous @threaded for interface in eachinterface(dg, cache) - left_element = interfaces.neighbor_ids[1, interface] - right_element = interfaces.neighbor_ids[2, interface] + left_element = neighbor_ids[1, interface] + right_element = neighbor_ids[2, interface] if orientations[interface] == 1 # interface in x-direction for j in eachnode(dg), v in eachvariable(equations_parabolic) - # OBS! `interfaces.u` stores the interpolated *fluxes* and *not the solution*! - interfaces.u[1, v, j, interface] = flux_viscous_x[v, nnodes(dg), j, + # OBS! `interfaces_u` stores the interpolated *fluxes* and *not the solution*! + interfaces_u[1, v, j, interface] = flux_viscous_x[v, nnodes(dg), j, left_element] - interfaces.u[2, v, j, interface] = flux_viscous_x[v, 1, j, + interfaces_u[2, v, j, interface] = flux_viscous_x[v, 1, j, right_element] end else # if orientations[interface] == 2 # interface in y-direction for i in eachnode(dg), v in eachvariable(equations_parabolic) - # OBS! `interfaces.u` stores the interpolated *fluxes* and *not the solution*! - interfaces.u[1, v, i, interface] = flux_viscous_y[v, i, nnodes(dg), + # OBS! `interfaces_u` stores the interpolated *fluxes* and *not the solution*! + interfaces_u[1, v, i, interface] = flux_viscous_y[v, i, nnodes(dg), left_element] - interfaces.u[2, v, i, interface] = flux_viscous_y[v, i, 1, + interfaces_u[2, v, i, interface] = flux_viscous_y[v, i, 1, right_element] end end @@ -244,25 +246,26 @@ function prolong2boundaries!(cache_parabolic, flux_viscous, equations_parabolic::AbstractEquationsParabolic, surface_integral, dg::DG, cache) @unpack boundaries = cache_parabolic - @unpack orientations, neighbor_sides = boundaries + @unpack orientations, neighbor_sides, neighbor_ids = boundaries + boundaries_u = boundaries.u flux_viscous_x, flux_viscous_y = flux_viscous @threaded for boundary in eachboundary(dg, cache_parabolic) - element = boundaries.neighbor_ids[boundary] + element = neighbor_ids[boundary] if orientations[boundary] == 1 # boundary in x-direction if neighbor_sides[boundary] == 1 # element in -x direction of boundary for l in eachnode(dg), v in eachvariable(equations_parabolic) - # OBS! `boundaries.u` stores the interpolated *fluxes* and *not the solution*! - boundaries.u[1, v, l, boundary] = flux_viscous_x[v, nnodes(dg), l, + # OBS! `boundaries_u` stores the interpolated *fluxes* and *not the solution*! + boundaries_u[1, v, l, boundary] = flux_viscous_x[v, nnodes(dg), l, element] end else # Element in +x direction of boundary for l in eachnode(dg), v in eachvariable(equations_parabolic) - # OBS! `boundaries.u` stores the interpolated *fluxes* and *not the solution*! - boundaries.u[2, v, l, boundary] = flux_viscous_x[v, 1, l, element] + # OBS! `boundaries_u` stores the interpolated *fluxes* and *not the solution*! + boundaries_u[2, v, l, boundary] = flux_viscous_x[v, 1, l, element] end end else # if orientations[boundary] == 2 @@ -270,15 +273,15 @@ function prolong2boundaries!(cache_parabolic, flux_viscous, if neighbor_sides[boundary] == 1 # element in -y direction of boundary for l in eachnode(dg), v in eachvariable(equations_parabolic) - # OBS! `boundaries.u` stores the interpolated *fluxes* and *not the solution*! - boundaries.u[1, v, l, boundary] = flux_viscous_y[v, l, nnodes(dg), + # OBS! `boundaries_u` stores the interpolated *fluxes* and *not the solution*! + boundaries_u[1, v, l, boundary] = flux_viscous_y[v, l, nnodes(dg), element] end else # element in +y direction of boundary for l in eachnode(dg), v in eachvariable(equations_parabolic) - # OBS! `boundaries.u` stores the interpolated *fluxes* and *not the solution*! - boundaries.u[2, v, l, boundary] = flux_viscous_y[v, l, 1, element] + # OBS! `boundaries_u` stores the interpolated *fluxes* and *not the solution*! + boundaries_u[2, v, l, boundary] = flux_viscous_y[v, l, 1, element] end end end @@ -608,7 +611,7 @@ function prolong2mortars!(cache, flux_viscous::Tuple{AbstractArray, AbstractArra 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. function calc_mortar_flux!(surface_flux_values, mesh::TreeMesh{2}, @@ -934,8 +937,10 @@ end # where f(u) is the inviscid flux and g(u) is the viscous flux. function apply_jacobian_parabolic!(du, mesh::Union{TreeMesh{2}, P4estMesh{2}}, equations::AbstractEquationsParabolic, dg::DG, cache) + @unpack inverse_jacobian = cache.elements + @threaded for element in eachelement(dg, cache) - factor = cache.elements.inverse_jacobian[element] + factor = inverse_jacobian[element] for j in eachnode(dg), i in eachnode(dg) for v in eachvariable(equations) diff --git a/src/solvers/dgsem_tree/dg_3d_parabolic.jl b/src/solvers/dgsem_tree/dg_3d_parabolic.jl index 2745d312b37..9817e0e5f0e 100644 --- a/src/solvers/dgsem_tree/dg_3d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_3d_parabolic.jl @@ -118,12 +118,13 @@ end function transform_variables!(u_transformed, u, mesh::Union{TreeMesh{3}, P4estMesh{3}}, equations_parabolic::AbstractEquationsParabolic, dg::DG, parabolic_scheme, cache, cache_parabolic) + transformation = gradient_variable_transformation(equations_parabolic) + @threaded for element in eachelement(dg, cache) # Calculate volume terms in one element for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg) u_node = get_node_vars(u, equations_parabolic, dg, i, j, k, element) - u_transformed_node = gradient_variable_transformation(equations_parabolic)(u_node, - equations_parabolic) + u_transformed_node = transformation(u_node, equations_parabolic) set_node_vars!(u_transformed, u_transformed_node, equations_parabolic, dg, i, j, k, element) end @@ -175,43 +176,44 @@ function prolong2interfaces!(cache_parabolic, flux_viscous, equations_parabolic::AbstractEquationsParabolic, surface_integral, dg::DG, cache) @unpack interfaces = cache_parabolic - @unpack orientations = interfaces + @unpack orientations, neighbor_ids = interfaces + interfaces_u = interfaces.u flux_viscous_x, flux_viscous_y, flux_viscous_z = flux_viscous @threaded for interface in eachinterface(dg, cache) - left_element = interfaces.neighbor_ids[1, interface] - right_element = interfaces.neighbor_ids[2, interface] + left_element = neighbor_ids[1, interface] + right_element = neighbor_ids[2, interface] if orientations[interface] == 1 # interface in x-direction for k in eachnode(dg), j in eachnode(dg), v in eachvariable(equations_parabolic) - # OBS! `interfaces.u` stores the interpolated *fluxes* and *not the solution*! - interfaces.u[1, v, j, k, interface] = flux_viscous_x[v, nnodes(dg), j, + # OBS! `interfaces_u` stores the interpolated *fluxes* and *not the solution*! + interfaces_u[1, v, j, k, interface] = flux_viscous_x[v, nnodes(dg), j, k, left_element] - interfaces.u[2, v, j, k, interface] = flux_viscous_x[v, 1, j, k, + interfaces_u[2, v, j, k, interface] = flux_viscous_x[v, 1, j, k, right_element] end elseif orientations[interface] == 2 # interface in y-direction for k in eachnode(dg), i in eachnode(dg), v in eachvariable(equations_parabolic) - # OBS! `interfaces.u` stores the interpolated *fluxes* and *not the solution*! - interfaces.u[1, v, i, k, interface] = flux_viscous_y[v, i, nnodes(dg), + # OBS! `interfaces_u` stores the interpolated *fluxes* and *not the solution*! + interfaces_u[1, v, i, k, interface] = flux_viscous_y[v, i, nnodes(dg), k, left_element] - interfaces.u[2, v, i, k, interface] = flux_viscous_y[v, i, 1, k, + interfaces_u[2, v, i, k, interface] = flux_viscous_y[v, i, 1, k, right_element] end else # if orientations[interface] == 3 # interface in z-direction for j in eachnode(dg), i in eachnode(dg), v in eachvariable(equations_parabolic) - # OBS! `interfaces.u` stores the interpolated *fluxes* and *not the solution*! - interfaces.u[1, v, i, j, interface] = flux_viscous_z[v, i, j, + # OBS! `interfaces_u` stores the interpolated *fluxes* and *not the solution*! + interfaces_u[1, v, i, j, interface] = flux_viscous_z[v, i, j, nnodes(dg), left_element] - interfaces.u[2, v, i, j, interface] = flux_viscous_z[v, i, j, 1, + interfaces_u[2, v, i, j, interface] = flux_viscous_z[v, i, j, 1, right_element] end end @@ -265,11 +267,12 @@ function prolong2boundaries!(cache_parabolic, flux_viscous, equations_parabolic::AbstractEquationsParabolic, surface_integral, dg::DG, cache) @unpack boundaries = cache_parabolic - @unpack orientations, neighbor_sides = boundaries + @unpack orientations, neighbor_sides, neighbor_ids = boundaries + boundaries_u = boundaries.u flux_viscous_x, flux_viscous_y, flux_viscous_z = flux_viscous @threaded for boundary in eachboundary(dg, cache_parabolic) - element = boundaries.neighbor_ids[boundary] + element = neighbor_ids[boundary] if orientations[boundary] == 1 # boundary in x-direction @@ -277,15 +280,15 @@ function prolong2boundaries!(cache_parabolic, flux_viscous, # element in -x direction of boundary for k in eachnode(dg), j in eachnode(dg), v in eachvariable(equations_parabolic) - # OBS! `boundaries.u` stores the interpolated *fluxes* and *not the solution*! - boundaries.u[1, v, j, k, boundary] = flux_viscous_x[v, nnodes(dg), + # OBS! `boundaries_u` stores the interpolated *fluxes* and *not the solution*! + boundaries_u[1, v, j, k, boundary] = flux_viscous_x[v, nnodes(dg), j, k, element] end else # Element in +x direction of boundary for k in eachnode(dg), j in eachnode(dg), v in eachvariable(equations_parabolic) - # OBS! `boundaries.u` stores the interpolated *fluxes* and *not the solution*! - boundaries.u[2, v, j, k, boundary] = flux_viscous_x[v, 1, j, k, + # OBS! `boundaries_u` stores the interpolated *fluxes* and *not the solution*! + boundaries_u[2, v, j, k, boundary] = flux_viscous_x[v, 1, j, k, element] end end @@ -295,8 +298,8 @@ function prolong2boundaries!(cache_parabolic, flux_viscous, # element in -y direction of boundary for k in eachnode(dg), i in eachnode(dg), v in eachvariable(equations_parabolic) - # OBS! `boundaries.u` stores the interpolated *fluxes* and *not the solution*! - boundaries.u[1, v, i, k, boundary] = flux_viscous_y[v, i, + # OBS! `boundaries_u` stores the interpolated *fluxes* and *not the solution*! + boundaries_u[1, v, i, k, boundary] = flux_viscous_y[v, i, nnodes(dg), k, element] end @@ -304,8 +307,8 @@ function prolong2boundaries!(cache_parabolic, flux_viscous, # element in +y direction of boundary for k in eachnode(dg), i in eachnode(dg), v in eachvariable(equations_parabolic) - # OBS! `boundaries.u` stores the interpolated *fluxes* and *not the solution*! - boundaries.u[2, v, i, k, boundary] = flux_viscous_y[v, i, 1, k, + # OBS! `boundaries_u` stores the interpolated *fluxes* and *not the solution*! + boundaries_u[2, v, i, k, boundary] = flux_viscous_y[v, i, 1, k, element] end end @@ -315,8 +318,8 @@ function prolong2boundaries!(cache_parabolic, flux_viscous, # element in -z direction of boundary for j in eachnode(dg), i in eachnode(dg), v in eachvariable(equations_parabolic) - # OBS! `boundaries.u` stores the interpolated *fluxes* and *not the solution*! - boundaries.u[1, v, i, j, boundary] = flux_viscous_z[v, i, j, + # OBS! `boundaries_u` stores the interpolated *fluxes* and *not the solution*! + boundaries_u[1, v, i, j, boundary] = flux_viscous_z[v, i, j, nnodes(dg), element] end @@ -324,8 +327,8 @@ function prolong2boundaries!(cache_parabolic, flux_viscous, # element in +z direction of boundary for j in eachnode(dg), i in eachnode(dg), v in eachvariable(equations_parabolic) - # OBS! `boundaries.u` stores the interpolated *fluxes* and *not the solution*! - boundaries.u[2, v, i, j, boundary] = flux_viscous_z[v, i, j, 1, + # OBS! `boundaries_u` stores the interpolated *fluxes* and *not the solution*! + boundaries_u[2, v, i, j, boundary] = flux_viscous_z[v, i, j, 1, element] end end @@ -820,7 +823,7 @@ function prolong2mortars!(cache, 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. function calc_mortar_flux!(surface_flux_values, mesh::TreeMesh{3}, @@ -1124,8 +1127,10 @@ end # where f(u) is the inviscid flux and g(u) is the viscous flux. function apply_jacobian_parabolic!(du, mesh::Union{TreeMesh{3}, P4estMesh{3}}, equations::AbstractEquationsParabolic, dg::DG, cache) + @unpack inverse_jacobian = cache.elements + @threaded for element in eachelement(dg, cache) - factor = cache.elements.inverse_jacobian[element] + factor = inverse_jacobian[element] for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg) for v in eachvariable(equations) From cfbf048308b1074591e08f8627c0089871bf91f3 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 12 Sep 2023 12:11:06 +0200 Subject: [PATCH 089/263] remove JuliaCOn 2023 announcement (#1631) --- README.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/README.md b/README.md index 63540b1f640..c177ad2347f 100644 --- a/README.md +++ b/README.md @@ -17,16 +17,6 @@

-*** -**Trixi.jl at JuliaCon 2023**
-At this year's JuliaCon, we will be present with an online contribution that involves Trixi.jl: - -* [Scaling Trixi.jl to more than 10,000 cores using MPI](https://pretalx.com/juliacon2023/talk/PC8PZ8/), - 27th July 2023, 10:30–11:30 (US/Eastern), 32-G449 (Kiva) - -We are looking forward to seeing you there ♥️ -*** - **Trixi.jl** is a numerical simulation framework for hyperbolic conservation laws written in [Julia](https://julialang.org). A key objective for the framework is to be useful to both scientists and students. Therefore, next to From b9f3f3051c483e8ad09cb51857eec9bb228e267c Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 12 Sep 2023 12:50:44 +0200 Subject: [PATCH 090/263] set version to v0.5.42 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index d37c0548a6a..9f27fbb2710 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.5.42-pre" +version = "0.5.42" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From daf18a5352a80ca2fbb2077ace991b9e5cc33c16 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 12 Sep 2023 12:50:58 +0200 Subject: [PATCH 091/263] set development version to v0.5.43-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 9f27fbb2710..06fd29ba590 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.5.42" +version = "0.5.43-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 3523c49120d7c282518769a5b3d40ce7c9cc5882 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Tue, 12 Sep 2023 15:00:58 +0200 Subject: [PATCH 092/263] AMR for 1D Parabolic Eqs (Clean branch) (#1605) * Clean branch * Un-Comment * un-comment * test coarsen * remove redundancy * Remove support for passive terms * expand resize * comments * format * Avoid code duplication * Update src/callbacks_step/amr_dg1d.jl Co-authored-by: Michael Schlottke-Lakemper * comment * comment & format * Try to increase coverage * Slightly more expressive names * Apply suggestions from code review --------- Co-authored-by: Michael Schlottke-Lakemper --- ...ixir_navierstokes_convergence_walls_amr.jl | 172 ++++++++++++++++++ src/callbacks_step/amr.jl | 158 ++++++++++++++++ src/callbacks_step/amr_dg1d.jl | 73 ++++++++ .../dgsem_tree/container_viscous_1d.jl | 58 ++++++ src/solvers/dgsem_tree/dg.jl | 3 + src/solvers/dgsem_tree/dg_1d_parabolic.jl | 14 +- test/test_parabolic_1d.jl | 41 +++++ test/test_parabolic_2d.jl | 12 +- test/test_parabolic_3d.jl | 12 +- 9 files changed, 523 insertions(+), 20 deletions(-) create mode 100644 examples/tree_1d_dgsem/elixir_navierstokes_convergence_walls_amr.jl create mode 100644 src/solvers/dgsem_tree/container_viscous_1d.jl diff --git a/examples/tree_1d_dgsem/elixir_navierstokes_convergence_walls_amr.jl b/examples/tree_1d_dgsem/elixir_navierstokes_convergence_walls_amr.jl new file mode 100644 index 00000000000..1daeab04a71 --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_navierstokes_convergence_walls_amr.jl @@ -0,0 +1,172 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal compressible Navier-Stokes equations + +prandtl_number() = 0.72 +mu() = 0.01 + +equations = CompressibleEulerEquations1D(1.4) +equations_parabolic = CompressibleNavierStokesDiffusion1D(equations, mu=mu(), Prandtl=prandtl_number(), + gradient_variables=GradientVariablesEntropy()) + +# 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, + volume_integral=VolumeIntegralWeakForm()) + +coordinates_min = -1.0 +coordinates_max = 1.0 + +# Create a uniformly refined mesh with periodic boundaries +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=3, + periodicity=false, + n_cells_max=30_000) # set maximum capacity of tree data structure + +# Note: the initial condition cannot be specialized to `CompressibleNavierStokesDiffusion1D` +# since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesDiffusion1D`) +# and by the initial condition (which passes in `CompressibleEulerEquations1D`). +# This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) +function initial_condition_navier_stokes_convergence_test(x, t, equations) + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_t = pi * t + + rho = c + A * cos(pi_x) * cos(pi_t) + v1 = log(x[1] + 2.0) * (1.0 - exp(-A * (x[1] - 1.0)) ) * cos(pi_t) + p = rho^2 + + return prim2cons(SVector(rho, v1, p), equations) +end + +@inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) + x = x[1] + + # TODO: parabolic + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + mu_ = mu() + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * cos(pi_x) * cos(pi_t) + rho_t = -pi * A * cos(pi_x) * sin(pi_t) + rho_x = -pi * A * sin(pi_x) * cos(pi_t) + rho_xx = -pi * pi * A * cos(pi_x) * cos(pi_t) + + v1 = log(x + 2.0) * (1.0 - exp(-A * (x - 1.0))) * cos(pi_t) + v1_t = -pi * log(x + 2.0) * (1.0 - exp(-A * (x - 1.0))) * sin(pi_t) + v1_x = (A * log(x + 2.0) * exp(-A * (x - 1.0)) + (1.0 - exp(-A * (x - 1.0))) / (x + 2.0)) * cos(pi_t) + v1_xx = (( 2.0 * A * exp(-A * (x - 1.0)) / (x + 2.0) + - A * A * log(x + 2.0) * exp(-A * (x - 1.0)) + - (1.0 - exp(-A * (x - 1.0))) / ((x + 2.0) * (x + 2.0))) * cos(pi_t)) + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + + # Note this simplifies slightly because the ansatz assumes that v1 = v2 + E = p * inv_gamma_minus_one + 0.5 * rho * v1^2 + E_t = p_t * inv_gamma_minus_one + 0.5 * rho_t * v1^2 + rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + 0.5 * rho_x * v1^2 + rho * v1 * v1_x + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one / Pr + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + + # y-momentum equation + du2 = ( rho_t * v1 + rho * v1_t + + p_x + rho_x * v1^2 + 2.0 * rho * v1 * v1_x + # stress tensor from y-direction + - v1_xx * mu_) + + # total energy equation + du3 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) + # stress tensor and temperature gradient terms from x-direction + - v1_xx * v1 * mu_ + - v1_x * v1_x * mu_ + - T_const * inv_rho_cubed * ( p_xx * rho * rho + - 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x + - p * rho * rho_xx ) * mu_ ) + + return SVector(du1, du2, du3) +end + +initial_condition = initial_condition_navier_stokes_convergence_test + +# BC types +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) -> 0.0) + +boundary_condition_left = BoundaryConditionNavierStokesWall(velocity_bc_left_right, heat_bc_left) +boundary_condition_right = BoundaryConditionNavierStokesWall(velocity_bc_left_right, heat_bc_right) + +# define inviscid boundary conditions +boundary_conditions = (; x_neg = boundary_condition_slip_wall, + x_pos = boundary_condition_slip_wall) + +# define viscous boundary conditions +boundary_conditions_parabolic = (; x_neg = boundary_condition_left, + x_pos = boundary_condition_right) + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; + boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), + source_terms=source_terms_navier_stokes_convergence_test) + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span `tspan` +tspan = (0.0, 1.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() +alive_callback = AliveCallback(alive_interval=10) +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) + +amr_controller = ControllerThreeLevel(semi, + IndicatorLöhner(semi, variable=Trixi.density), + base_level=3, + med_level=4, med_threshold=0.005, + max_level=5, max_threshold=0.01) + +amr_callback = AMRCallback(semi, amr_controller, + interval=5, + adapt_initial_condition=true) + +# Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, amr_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, + ode_default_options()..., callback=callbacks) +summary_callback() # print the timer summary \ No newline at end of file diff --git a/src/callbacks_step/amr.jl b/src/callbacks_step/amr.jl index 4d80e6e1139..ba840ff9675 100644 --- a/src/callbacks_step/amr.jl +++ b/src/callbacks_step/amr.jl @@ -192,6 +192,16 @@ end amr_callback(u_ode, mesh_equations_solver_cache(semi)..., semi, t, iter; kwargs...) end +@inline function (amr_callback::AMRCallback)(u_ode::AbstractVector, + semi::SemidiscretizationHyperbolicParabolic, + t, iter; + kwargs...) + # Note that we don't `wrap_array` the vector `u_ode` to be able to `resize!` + # it when doing AMR while still dispatching on the `mesh` etc. + amr_callback(u_ode, mesh_equations_solver_cache(semi)..., semi.cache_parabolic, + semi, t, iter; kwargs...) +end + # `passive_args` is currently used for Euler with self-gravity to adapt the gravity solver # passively without querying its indicator, based on the assumption that both solvers use # the same mesh. That's a hack and should be improved in the future once we have more examples @@ -346,6 +356,154 @@ function (amr_callback::AMRCallback)(u_ode::AbstractVector, mesh::TreeMesh, return has_changed end +function (amr_callback::AMRCallback)(u_ode::AbstractVector, mesh::TreeMesh, + equations, dg::DG, + cache, cache_parabolic, + semi::SemidiscretizationHyperbolicParabolic, + t, iter; + only_refine = false, only_coarsen = false) + @unpack controller, adaptor = amr_callback + + u = wrap_array(u_ode, mesh, equations, dg, cache) + # Indicator kept based on hyperbolic variables + lambda = @trixi_timeit timer() "indicator" controller(u, mesh, equations, dg, cache, + t = t, iter = iter) + + if mpi_isparallel() + error("MPI has not been verified yet for parabolic AMR") + + # Collect lambda for all elements + lambda_global = Vector{eltype(lambda)}(undef, nelementsglobal(dg, cache)) + # Use parent because n_elements_by_rank is an OffsetArray + recvbuf = MPI.VBuffer(lambda_global, parent(cache.mpi_cache.n_elements_by_rank)) + MPI.Allgatherv!(lambda, recvbuf, mpi_comm()) + lambda = lambda_global + end + + leaf_cell_ids = leaf_cells(mesh.tree) + @boundscheck begin + @assert axes(lambda)==axes(leaf_cell_ids) ("Indicator (axes = $(axes(lambda))) and leaf cell (axes = $(axes(leaf_cell_ids))) arrays have different axes") + end + + @unpack to_refine, to_coarsen = amr_callback.amr_cache + empty!(to_refine) + empty!(to_coarsen) + for element in 1:length(lambda) + controller_value = lambda[element] + if controller_value > 0 + push!(to_refine, leaf_cell_ids[element]) + elseif controller_value < 0 + push!(to_coarsen, leaf_cell_ids[element]) + end + end + + @trixi_timeit timer() "refine" if !only_coarsen && !isempty(to_refine) + # refine mesh + refined_original_cells = @trixi_timeit timer() "mesh" refine!(mesh.tree, + to_refine) + + # Find all indices of elements whose cell ids are in refined_original_cells + # Note: This assumes same indices for hyperbolic and parabolic part. + elements_to_refine = findall(in(refined_original_cells), + cache.elements.cell_ids) + + # refine solver + @trixi_timeit timer() "solver" refine!(u_ode, adaptor, mesh, equations, dg, + cache, cache_parabolic, + elements_to_refine) + else + # If there is nothing to refine, create empty array for later use + refined_original_cells = Int[] + end + + @trixi_timeit timer() "coarsen" if !only_refine && !isempty(to_coarsen) + # Since the cells may have been shifted due to refinement, first we need to + # translate the old cell ids to the new cell ids + if !isempty(to_coarsen) + to_coarsen = original2refined(to_coarsen, refined_original_cells, mesh) + end + + # Next, determine the parent cells from which the fine cells are to be + # removed, since these are needed for the coarsen! function. However, since + # we only want to coarsen if *all* child cells are marked for coarsening, + # we count the coarsening indicators for each parent cell and only coarsen + # if all children are marked as such (i.e., where the count is 2^ndims). At + # the same time, check if a cell is marked for coarsening even though it is + # *not* a leaf cell -> this can only happen if it was refined due to 2:1 + # smoothing during the preceding refinement operation. + parents_to_coarsen = zeros(Int, length(mesh.tree)) + for cell_id in to_coarsen + # If cell has no parent, it cannot be coarsened + if !has_parent(mesh.tree, cell_id) + continue + end + + # If cell is not leaf (anymore), it cannot be coarsened + if !is_leaf(mesh.tree, cell_id) + continue + end + + # Increase count for parent cell + parent_id = mesh.tree.parent_ids[cell_id] + parents_to_coarsen[parent_id] += 1 + end + + # Extract only those parent cells for which all children should be coarsened + to_coarsen = collect(1:length(parents_to_coarsen))[parents_to_coarsen .== 2^ndims(mesh)] + + # Finally, coarsen mesh + coarsened_original_cells = @trixi_timeit timer() "mesh" coarsen!(mesh.tree, + to_coarsen) + + # Convert coarsened parent cell ids to the list of child cell ids that have + # been removed, since this is the information that is expected by the solver + removed_child_cells = zeros(Int, + n_children_per_cell(mesh.tree) * + length(coarsened_original_cells)) + for (index, coarse_cell_id) in enumerate(coarsened_original_cells) + for child in 1:n_children_per_cell(mesh.tree) + removed_child_cells[n_children_per_cell(mesh.tree) * (index - 1) + child] = coarse_cell_id + + child + end + end + + # Find all indices of elements whose cell ids are in removed_child_cells + # Note: This assumes same indices for hyperbolic and parabolic part. + elements_to_remove = findall(in(removed_child_cells), cache.elements.cell_ids) + + # coarsen solver + @trixi_timeit timer() "solver" coarsen!(u_ode, adaptor, mesh, equations, dg, + cache, cache_parabolic, + elements_to_remove) + else + # If there is nothing to coarsen, create empty array for later use + coarsened_original_cells = Int[] + end + + # Store whether there were any cells coarsened or refined + has_changed = !isempty(refined_original_cells) || !isempty(coarsened_original_cells) + if has_changed # TODO: Taal decide, where shall we set this? + # don't set it to has_changed since there can be changes from earlier calls + mesh.unsaved_changes = true + end + + # Dynamically balance computational load by first repartitioning the mesh and then redistributing the cells/elements + if has_changed && mpi_isparallel() && amr_callback.dynamic_load_balancing + error("MPI has not been verified yet for parabolic AMR") + + @trixi_timeit timer() "dynamic load balancing" begin + old_mpi_ranks_per_cell = copy(mesh.tree.mpi_ranks) + + partition!(mesh) + + rebalance_solver!(u_ode, mesh, equations, dg, cache, old_mpi_ranks_per_cell) + end + end + + # Return true if there were any cells coarsened or refined, otherwise false + return has_changed +end + # Copy controller values to quad user data storage, will be called below function copy_to_quad_iter_volume(info, user_data) info_pw = PointerWrapper(info) diff --git a/src/callbacks_step/amr_dg1d.jl b/src/callbacks_step/amr_dg1d.jl index e31a74730ea..e721ccc61cb 100644 --- a/src/callbacks_step/amr_dg1d.jl +++ b/src/callbacks_step/amr_dg1d.jl @@ -76,6 +76,44 @@ function refine!(u_ode::AbstractVector, adaptor, mesh::TreeMesh{1}, return nothing end +function refine!(u_ode::AbstractVector, adaptor, mesh::TreeMesh{1}, + equations, dg::DGSEM, cache, cache_parabolic, + elements_to_refine) + # Call `refine!` for the hyperbolic part, which does the heavy lifting of + # actually transferring the solution to the refined cells + refine!(u_ode, adaptor, mesh, equations, dg, cache, elements_to_refine) + + # The remaining function only handles the necessary adaptation of the data structures + # for the parabolic part of the semidiscretization + + # Get new list of leaf cells + leaf_cell_ids = local_leaf_cells(mesh.tree) + + @unpack elements, viscous_container = cache_parabolic + resize!(elements, length(leaf_cell_ids)) + init_elements!(elements, leaf_cell_ids, mesh, dg.basis) + + # Resize parabolic helper variables + resize!(viscous_container, equations, dg, cache) + + # re-initialize interfaces container + @unpack interfaces = cache_parabolic + resize!(interfaces, count_required_interfaces(mesh, leaf_cell_ids)) + init_interfaces!(interfaces, elements, mesh) + + # re-initialize boundaries container + @unpack boundaries = cache_parabolic + resize!(boundaries, count_required_boundaries(mesh, leaf_cell_ids)) + init_boundaries!(boundaries, elements, mesh) + + # Sanity check + if isperiodic(mesh.tree) + @assert ninterfaces(interfaces)==1 * nelements(dg, cache_parabolic) ("For 1D and periodic domains, the number of interfaces must be the same as the number of elements") + end + + return nothing +end + # TODO: Taal compare performance of different implementations # Refine solution data u for an element, using L2 projection (interpolation) function refine_element!(u::AbstractArray{<:Any, 3}, element_id, @@ -201,6 +239,41 @@ function coarsen!(u_ode::AbstractVector, adaptor, mesh::TreeMesh{1}, return nothing end +function coarsen!(u_ode::AbstractVector, adaptor, mesh::TreeMesh{1}, + equations, dg::DGSEM, cache, cache_parabolic, + elements_to_remove) + # Call `coarsen!` for the hyperbolic part, which does the heavy lifting of + # actually transferring the solution to the coarsened cells + coarsen!(u_ode, adaptor, mesh, equations, dg, cache, elements_to_remove) + + # Get new list of leaf cells + leaf_cell_ids = local_leaf_cells(mesh.tree) + + @unpack elements, viscous_container = cache_parabolic + resize!(elements, length(leaf_cell_ids)) + init_elements!(elements, leaf_cell_ids, mesh, dg.basis) + + # Resize parabolic helper variables + resize!(viscous_container, equations, dg, cache) + + # re-initialize interfaces container + @unpack interfaces = cache_parabolic + resize!(interfaces, count_required_interfaces(mesh, leaf_cell_ids)) + init_interfaces!(interfaces, elements, mesh) + + # re-initialize boundaries container + @unpack boundaries = cache_parabolic + resize!(boundaries, count_required_boundaries(mesh, leaf_cell_ids)) + init_boundaries!(boundaries, elements, mesh) + + # Sanity check + if isperiodic(mesh.tree) + @assert ninterfaces(interfaces)==1 * nelements(dg, cache_parabolic) ("For 1D and periodic domains, the number of interfaces must be the same as the number of elements") + end + + return nothing +end + # TODO: Taal compare performance of different implementations # Coarsen solution data u for two elements, using L2 projection function coarsen_elements!(u::AbstractArray{<:Any, 3}, element_id, diff --git a/src/solvers/dgsem_tree/container_viscous_1d.jl b/src/solvers/dgsem_tree/container_viscous_1d.jl new file mode 100644 index 00000000000..a4919f75396 --- /dev/null +++ b/src/solvers/dgsem_tree/container_viscous_1d.jl @@ -0,0 +1,58 @@ +mutable struct ViscousContainer1D{uEltype <: Real} + u_transformed::Array{uEltype, 3} + gradients::Array{uEltype, 3} + flux_viscous::Array{uEltype, 3} + + # internal `resize!`able storage + _u_transformed::Vector{uEltype} + _gradients::Vector{uEltype} + _flux_viscous::Vector{uEltype} + + function ViscousContainer1D{uEltype}(n_vars::Integer, n_nodes::Integer, + n_elements::Integer) where {uEltype <: Real} + new(Array{uEltype, 3}(undef, n_vars, n_nodes, n_elements), + Array{uEltype, 3}(undef, n_vars, n_nodes, n_elements), + Array{uEltype, 3}(undef, n_vars, n_nodes, n_elements), + Vector{uEltype}(undef, n_vars * n_nodes * n_elements), + Vector{uEltype}(undef, n_vars * n_nodes * n_elements), + Vector{uEltype}(undef, n_vars * n_nodes * n_elements)) + end +end + +function init_viscous_container(n_vars::Integer, n_nodes::Integer, + n_elements::Integer, + ::Type{uEltype}) where {uEltype <: Real} + return ViscousContainer1D{uEltype}(n_vars, n_nodes, n_elements) +end + +# Only one-dimensional `Array`s are `resize!`able in Julia. +# Hence, we use `Vector`s as internal storage and `resize!` +# them whenever needed. Then, we reuse the same memory by +# `unsafe_wrap`ping multi-dimensional `Array`s around the +# internal storage. +function Base.resize!(viscous_container::ViscousContainer1D, equations, dg, cache) + capacity = nvariables(equations) * nnodes(dg) * nelements(dg, cache) + resize!(viscous_container._u_transformed, capacity) + resize!(viscous_container._gradients, capacity) + resize!(viscous_container._flux_viscous, capacity) + + viscous_container.u_transformed = unsafe_wrap(Array, + pointer(viscous_container._u_transformed), + (nvariables(equations), + nnodes(dg), + nelements(dg, cache))) + + viscous_container.gradients = unsafe_wrap(Array, + pointer(viscous_container._gradients), + (nvariables(equations), + nnodes(dg), + nelements(dg, cache))) + + viscous_container.flux_viscous = unsafe_wrap(Array, + pointer(viscous_container._flux_viscous), + (nvariables(equations), + nnodes(dg), + nelements(dg, cache))) + + return nothing +end diff --git a/src/solvers/dgsem_tree/dg.jl b/src/solvers/dgsem_tree/dg.jl index 6e02bc1d94a..ff37bad3b3a 100644 --- a/src/solvers/dgsem_tree/dg.jl +++ b/src/solvers/dgsem_tree/dg.jl @@ -54,6 +54,9 @@ include("containers.jl") # Dimension-agnostic parallel setup include("dg_parallel.jl") +# Helper struct for parabolic AMR +include("container_viscous_1d.jl") + # 1D DG implementation include("dg_1d.jl") include("dg_1d_parabolic.jl") diff --git a/src/solvers/dgsem_tree/dg_1d_parabolic.jl b/src/solvers/dgsem_tree/dg_1d_parabolic.jl index 7602331d7c8..97e31e0e22b 100644 --- a/src/solvers/dgsem_tree/dg_1d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_1d_parabolic.jl @@ -17,7 +17,8 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{1}, equations_parabolic::AbstractEquationsParabolic, initial_condition, boundary_conditions_parabolic, source_terms, dg::DG, parabolic_scheme, cache, cache_parabolic) - @unpack u_transformed, gradients, flux_viscous = cache_parabolic + @unpack viscous_container = cache_parabolic + @unpack u_transformed, gradients, flux_viscous = viscous_container # Convert conservative variables to a form more suitable for viscous flux calculations @trixi_timeit timer() "transform variables" begin @@ -534,18 +535,15 @@ function create_cache_parabolic(mesh::TreeMesh{1}, elements = init_elements(leaf_cell_ids, mesh, equations_hyperbolic, dg.basis, RealT, uEltype) - n_vars = nvariables(equations_hyperbolic) - n_nodes = nnodes(elements) - n_elements = nelements(elements) - u_transformed = Array{uEltype}(undef, n_vars, n_nodes, n_elements) - gradients = similar(u_transformed) - flux_viscous = similar(u_transformed) + viscous_container = init_viscous_container(nvariables(equations_hyperbolic), + nnodes(elements), nelements(elements), + uEltype) interfaces = init_interfaces(leaf_cell_ids, mesh, elements) boundaries = init_boundaries(leaf_cell_ids, mesh, elements) - cache = (; elements, interfaces, boundaries, gradients, flux_viscous, u_transformed) + cache = (; elements, interfaces, boundaries, viscous_container) return cache end diff --git a/test/test_parabolic_1d.jl b/test/test_parabolic_1d.jl index 06a55100d62..3c2b8855ce8 100644 --- a/test/test_parabolic_1d.jl +++ b/test/test_parabolic_1d.jl @@ -20,6 +20,28 @@ isdir(outdir) && rm(outdir, recursive=true) ) end + @trixi_testset "TreeMesh1D: elixir_advection_diffusion.jl (AMR)" begin + @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", "elixir_advection_diffusion.jl"), + tspan=(0.0, 0.0), initial_refinement_level = 5) + tspan=(0.0, 1.0) + ode = semidiscretize(semi, tspan) + amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable=first), + base_level=4, + med_level=5, med_threshold=0.1, + max_level=6, max_threshold=0.6) + amr_callback = AMRCallback(semi, amr_controller, + interval=5, + adapt_initial_condition=true) + + # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver + callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, amr_callback) + sol = solve(ode, KenCarp4(autodiff=false), abstol=time_abs_tol, reltol=time_int_tol, + save_everystep=false, callback=callbacks) + l2_error, linf_error = analysis_callback(sol) + @test l2_error ≈ [6.4878111416468355e-6] + @test linf_error ≈ [3.258075790424364e-5] + end + @trixi_testset "TreeMesh1D: elixir_navierstokes_convergence_periodic.jl" begin @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", "elixir_navierstokes_convergence_periodic.jl"), l2 = [0.0001133835907077494, 6.226282245610444e-5, 0.0002820171699999139], @@ -53,6 +75,25 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [0.002754803146635787, 0.0028567714697580906, 0.012941794048176192] ) end + + @trixi_testset "TreeMesh1D: elixir_navierstokes_convergence_walls_amr.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", "elixir_navierstokes_convergence_walls_amr.jl"), + equations_parabolic = CompressibleNavierStokesDiffusion1D(equations, mu=mu(), + Prandtl=prandtl_number()), + l2 = [2.527877257772131e-5, 2.5539911566937718e-5, 0.0001211860451244785], + linf = [0.00014663867588948776, 0.00019422448348348196, 0.0009556439394007299] + ) + end + + @trixi_testset "TreeMesh1D: elixir_navierstokes_convergence_walls_amr.jl: GradientVariablesEntropy" begin + @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", "elixir_navierstokes_convergence_walls_amr.jl"), + equations_parabolic = CompressibleNavierStokesDiffusion1D(equations, mu=mu(), + Prandtl=prandtl_number(), + gradient_variables = GradientVariablesEntropy()), + l2 = [2.4593699163175966e-5, 2.392863645712634e-5, 0.00011252526651714956], + linf = [0.00011850555445525046, 0.0001898777490968537, 0.0009597561467877824] + ) + end end # Clean up afterwards: delete Trixi output directory diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 1564a33dc41..3fff4382cd1 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -143,9 +143,9 @@ isdir(outdir) && rm(outdir, recursive=true) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, ode_default_options()..., callback=callbacks) - ac_sol = analysis_callback(sol) - @test ac_sol.l2[1] ≈ 1.67452550744728e-6 - @test ac_sol.linf[1] ≈ 7.905059166368744e-6 + l2_error, linf_error = analysis_callback(sol) + @test l2_error ≈ [1.67452550744728e-6] + @test linf_error ≈ [7.905059166368744e-6] # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) @@ -229,9 +229,9 @@ isdir(outdir) && rm(outdir, recursive=true) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, ode_default_options()..., callback=callbacks) - ac_sol = analysis_callback(sol) - @test ac_sol.l2 ≈ [0.00024296959173852447; 0.0002093263158670915; 0.0005390572390977262; 0.00026753561392341537] - @test ac_sol.linf ≈ [0.0016210102053424436; 0.002593287648655501; 0.002953907343823712; 0.002077119120180271] + l2_error, linf_error = analysis_callback(sol) + @test l2_error ≈ [0.00024296959173852447; 0.0002093263158670915; 0.0005390572390977262; 0.00026753561392341537] + @test linf_error ≈ [0.0016210102053424436; 0.002593287648655501; 0.002953907343823712; 0.002077119120180271] end @trixi_testset "TreeMesh2D: elixir_navierstokes_lid_driven_cavity.jl" begin diff --git a/test/test_parabolic_3d.jl b/test/test_parabolic_3d.jl index d607962afa0..ded052fb9d3 100644 --- a/test/test_parabolic_3d.jl +++ b/test/test_parabolic_3d.jl @@ -94,9 +94,9 @@ isdir(outdir) && rm(outdir, recursive=true) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, ode_default_options()..., callback=callbacks) - ac_sol = analysis_callback(sol) - @test ac_sol.l2 ≈ [0.0003991794175622818; 0.0008853745163670504; 0.0010658655552066817; 0.0008785559918324284; 0.001403163458422815] - @test ac_sol.linf ≈ [0.0035306410538458177; 0.01505692306169911; 0.008862444161110705; 0.015065647972869856; 0.030402714743065218] + l2_error, linf_error = analysis_callback(sol) + @test l2_error ≈ [0.0003991794175622818; 0.0008853745163670504; 0.0010658655552066817; 0.0008785559918324284; 0.001403163458422815] + @test linf_error ≈ [0.0035306410538458177; 0.01505692306169911; 0.008862444161110705; 0.015065647972869856; 0.030402714743065218] end @trixi_testset "TreeMesh3D: elixir_navierstokes_taylor_green_vortex.jl" begin @@ -127,9 +127,9 @@ isdir(outdir) && rm(outdir, recursive=true) sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), dt=5e-3, save_everystep=false, callback=callbacks); - ac_sol = analysis_callback(sol) - @test ac_sol.l2 ≈ [0.0013666103707729502; 0.2313581629543744; 0.2308164306264533; 0.17460246787819503; 0.28121914446544005] - @test ac_sol.linf ≈ [0.006938093883741336; 1.028235074139312; 1.0345438209717241; 1.0821111605203542; 1.2669636522564645] + l2_error, linf_error = analysis_callback(sol) + @test l2_error ≈ [0.0013666103707729502; 0.2313581629543744; 0.2308164306264533; 0.17460246787819503; 0.28121914446544005] + @test linf_error ≈ [0.006938093883741336; 1.028235074139312; 1.0345438209717241; 1.0821111605203542; 1.2669636522564645] # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) From 27d4fd190bd7a8c76a56f9fefd062169a2682d46 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Tue, 12 Sep 2023 17:54:08 +0200 Subject: [PATCH 093/263] Shorten 3d parabolic test times (#1634) * Shorten 3d parabolic test times * fix typo * clear notation --- test/test_parabolic_3d.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/test_parabolic_3d.jl b/test/test_parabolic_3d.jl index ded052fb9d3..86076460294 100644 --- a/test/test_parabolic_3d.jl +++ b/test/test_parabolic_3d.jl @@ -85,7 +85,7 @@ isdir(outdir) && rm(outdir, recursive=true) num_leafs = length(LLID) @assert num_leafs % 16 == 0 Trixi.refine!(mesh.tree, LLID[1:Int(num_leafs/16)]) - tspan=(0.0, 1.0) + tspan=(0.0, 0.25) semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), source_terms=source_terms_navier_stokes_convergence_test) @@ -95,8 +95,8 @@ isdir(outdir) && rm(outdir, recursive=true) sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, ode_default_options()..., callback=callbacks) l2_error, linf_error = analysis_callback(sol) - @test l2_error ≈ [0.0003991794175622818; 0.0008853745163670504; 0.0010658655552066817; 0.0008785559918324284; 0.001403163458422815] - @test linf_error ≈ [0.0035306410538458177; 0.01505692306169911; 0.008862444161110705; 0.015065647972869856; 0.030402714743065218] + @test l2_error ≈ [0.0003109336253407314, 0.0006473493036803503, 0.0007705277238213672, 0.0006280517917198335, 0.000903927789884075] + @test linf_error ≈ [0.0023694155365339142, 0.010634932622402863, 0.006772070862236412, 0.010640551561726901, 0.019256819038719897] end @trixi_testset "TreeMesh3D: elixir_navierstokes_taylor_green_vortex.jl" begin @@ -114,7 +114,7 @@ isdir(outdir) && rm(outdir, recursive=true) num_leafs = length(LLID) @assert num_leafs % 32 == 0 Trixi.refine!(mesh.tree, LLID[1:Int(num_leafs/32)]) - tspan=(0.0, 10.0) + tspan=(0.0, 0.1) semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver) ode = semidiscretize(semi, tspan) @@ -128,8 +128,8 @@ isdir(outdir) && rm(outdir, recursive=true) dt=5e-3, save_everystep=false, callback=callbacks); l2_error, linf_error = analysis_callback(sol) - @test l2_error ≈ [0.0013666103707729502; 0.2313581629543744; 0.2308164306264533; 0.17460246787819503; 0.28121914446544005] - @test linf_error ≈ [0.006938093883741336; 1.028235074139312; 1.0345438209717241; 1.0821111605203542; 1.2669636522564645] + @test l2_error ≈ [7.314319856736271e-5, 0.006266480163542894, 0.006266489911815533, 0.008829222305770226, 0.0032859166842329228] + @test linf_error ≈ [0.0002943968186086554, 0.013876261980614757, 0.013883619864959451, 0.025201279960491936, 0.018679364985388247] # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) From d206b766e3e0aad36a9808ed65c5549b8b284f73 Mon Sep 17 00:00:00 2001 From: ArseniyKholod <119304909+ArseniyKholod@users.noreply.github.com> Date: Tue, 12 Sep 2023 19:16:44 +0200 Subject: [PATCH 094/263] Add load_timestep! for restart setup (#1614) * add load_timestep! * Update save_restart.jl * Update save_restart.jl * Update src/callbacks_step/save_restart.jl Co-authored-by: Michael Schlottke-Lakemper * use new function in elixirs and docs --------- Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Hendrik Ranocha --- docs/src/restart.md | 3 +-- examples/p4est_2d_dgsem/elixir_advection_restart.jl | 3 +-- examples/p4est_3d_dgsem/elixir_advection_restart.jl | 3 +-- .../structured_2d_dgsem/elixir_advection_restart.jl | 3 +-- .../structured_3d_dgsem/elixir_advection_restart.jl | 3 +-- examples/tree_2d_dgsem/elixir_advection_restart.jl | 3 +-- examples/tree_3d_dgsem/elixir_advection_restart.jl | 3 +-- .../unstructured_2d_dgsem/elixir_euler_restart.jl | 3 +-- src/Trixi.jl | 2 +- src/callbacks_step/save_restart.jl | 12 ++++++++++++ 10 files changed, 21 insertions(+), 17 deletions(-) diff --git a/docs/src/restart.md b/docs/src/restart.md index 767269ff27d..c7cbcd11852 100644 --- a/docs/src/restart.md +++ b/docs/src/restart.md @@ -77,8 +77,7 @@ and its time step number, e.g.: ```julia integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), dt=dt, save_everystep=false, callback=callbacks); -integrator.iter = load_timestep(restart_filename) -integrator.stats.naccept = integrator.iter +load_timestep!(integrator, restart_filename) ``` Now we can compute the solution: diff --git a/examples/p4est_2d_dgsem/elixir_advection_restart.jl b/examples/p4est_2d_dgsem/elixir_advection_restart.jl index 79a35199b83..52917616a6a 100644 --- a/examples/p4est_2d_dgsem/elixir_advection_restart.jl +++ b/examples/p4est_2d_dgsem/elixir_advection_restart.jl @@ -35,8 +35,7 @@ integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), save_everystep=false, callback=callbacks); # Get the last time index and work with that. -integrator.iter = load_timestep(restart_filename) -integrator.stats.naccept = integrator.iter +load_timestep!(integrator, restart_filename) ############################################################################### diff --git a/examples/p4est_3d_dgsem/elixir_advection_restart.jl b/examples/p4est_3d_dgsem/elixir_advection_restart.jl index b27eaab62e2..26d10cf8826 100644 --- a/examples/p4est_3d_dgsem/elixir_advection_restart.jl +++ b/examples/p4est_3d_dgsem/elixir_advection_restart.jl @@ -32,8 +32,7 @@ integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), save_everystep=false, callback=callbacks); # Get the last time index and work with that. -integrator.iter = load_timestep(restart_filename) -integrator.stats.naccept = integrator.iter +load_timestep!(integrator, restart_filename) ############################################################################### diff --git a/examples/structured_2d_dgsem/elixir_advection_restart.jl b/examples/structured_2d_dgsem/elixir_advection_restart.jl index 98c44fac71a..82eaa21333a 100644 --- a/examples/structured_2d_dgsem/elixir_advection_restart.jl +++ b/examples/structured_2d_dgsem/elixir_advection_restart.jl @@ -34,8 +34,7 @@ integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), save_everystep=false, callback=callbacks); # Get the last time index and work with that. -integrator.iter = load_timestep(restart_filename) -integrator.stats.naccept = integrator.iter +load_timestep!(integrator, restart_filename) ############################################################################### # run the simulation diff --git a/examples/structured_3d_dgsem/elixir_advection_restart.jl b/examples/structured_3d_dgsem/elixir_advection_restart.jl index 39d28848c77..921c5310340 100644 --- a/examples/structured_3d_dgsem/elixir_advection_restart.jl +++ b/examples/structured_3d_dgsem/elixir_advection_restart.jl @@ -32,8 +32,7 @@ integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), save_everystep=false, callback=callbacks); # Get the last time index and work with that. -integrator.iter = load_timestep(restart_filename) -integrator.stats.naccept = integrator.iter +load_timestep!(integrator, restart_filename) ############################################################################### diff --git a/examples/tree_2d_dgsem/elixir_advection_restart.jl b/examples/tree_2d_dgsem/elixir_advection_restart.jl index 72efb7d0c84..771ec5aefe7 100644 --- a/examples/tree_2d_dgsem/elixir_advection_restart.jl +++ b/examples/tree_2d_dgsem/elixir_advection_restart.jl @@ -32,8 +32,7 @@ integrator = init(ode, alg, save_everystep=false, callback=callbacks) # Get the last time index and work with that. -integrator.iter = load_timestep(restart_filename) -integrator.stats.naccept = integrator.iter +load_timestep!(integrator, restart_filename) ############################################################################### # run the simulation diff --git a/examples/tree_3d_dgsem/elixir_advection_restart.jl b/examples/tree_3d_dgsem/elixir_advection_restart.jl index 3061f165874..b7835ed061f 100644 --- a/examples/tree_3d_dgsem/elixir_advection_restart.jl +++ b/examples/tree_3d_dgsem/elixir_advection_restart.jl @@ -31,8 +31,7 @@ integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), save_everystep=false, callback=callbacks); # Get the last time index and work with that. -integrator.iter = load_timestep(restart_filename) -integrator.stats.naccept = integrator.iter +load_timestep!(integrator, restart_filename) ############################################################################### diff --git a/examples/unstructured_2d_dgsem/elixir_euler_restart.jl b/examples/unstructured_2d_dgsem/elixir_euler_restart.jl index b85cc2c6d70..6653f8662d9 100644 --- a/examples/unstructured_2d_dgsem/elixir_euler_restart.jl +++ b/examples/unstructured_2d_dgsem/elixir_euler_restart.jl @@ -33,8 +33,7 @@ integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), save_everystep=false, callback=callbacks); # Get the last time index and work with that. -integrator.iter = load_timestep(restart_filename) -integrator.stats.naccept = integrator.iter +load_timestep!(integrator, restart_filename) ############################################################################### diff --git a/src/Trixi.jl b/src/Trixi.jl index ec4d20558e5..be43c45b93d 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -253,7 +253,7 @@ export SummaryCallback, SteadyStateCallback, AnalysisCallback, AliveCallback, GlmSpeedCallback, LBMCollisionCallback, EulerAcousticsCouplingCallback, TrivialCallback, AnalysisCallbackCoupled -export load_mesh, load_time, load_timestep, load_dt +export load_mesh, load_time, load_timestep, load_timestep!, load_dt export ControllerThreeLevel, ControllerThreeLevelCombined, IndicatorLöhner, IndicatorLoehner, IndicatorMax, diff --git a/src/callbacks_step/save_restart.jl b/src/callbacks_step/save_restart.jl index f567a5c7fda..06817a9b730 100644 --- a/src/callbacks_step/save_restart.jl +++ b/src/callbacks_step/save_restart.jl @@ -141,6 +141,18 @@ function load_timestep(restart_file::AbstractString) end end +""" + load_timestep!(integrator, restart_file::AbstractString) + +Load the time step number saved in a `restart_file` and assign it to both the time step +number and and the number of accepted steps +(`iter` and `stats.naccept` in OrdinaryDiffEq.jl, respectively) in `integrator`. +""" +function load_timestep!(integrator, restart_file::AbstractString) + integrator.iter = load_timestep(restart_file) + integrator.stats.naccept = integrator.iter +end + """ load_dt(restart_file::AbstractString) From bc6736183271ec191645e9a38f95790a76671d25 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 13 Sep 2023 09:07:41 +0200 Subject: [PATCH 095/263] fix allocations of P4estMesh2D BCs (#1636) --- src/solvers/dgsem_p4est/dg_2d.jl | 4 ++-- test/test_p4est_2d.jl | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/solvers/dgsem_p4est/dg_2d.jl b/src/solvers/dgsem_p4est/dg_2d.jl index 97b931fa325..a665aa4b19d 100644 --- a/src/solvers/dgsem_p4est/dg_2d.jl +++ b/src/solvers/dgsem_p4est/dg_2d.jl @@ -275,9 +275,9 @@ function prolong2boundaries!(cache, u, return nothing end -function calc_boundary_flux!(cache, t, boundary_condition, boundary_indexing, +function calc_boundary_flux!(cache, t, boundary_condition::BC, boundary_indexing, mesh::Union{P4estMesh{2}, T8codeMesh{2}}, - equations, surface_integral, dg::DG) + equations, surface_integral, dg::DG) where {BC} @unpack boundaries = cache @unpack surface_flux_values = cache.elements index_range = eachnode(dg) diff --git a/test/test_p4est_2d.jl b/test/test_p4est_2d.jl index c4ce2619e15..31dfe1d35a5 100644 --- a/test/test_p4est_2d.jl +++ b/test/test_p4est_2d.jl @@ -24,7 +24,7 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [3.198940059144588e-5], linf = [0.00030636069494005547]) - # 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] @@ -102,6 +102,15 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.020291447969983396, 0.017479614254319948, 0.011387644425613437, 0.0514420126021293], linf = [0.3582779022370579, 0.32073537890751663, 0.221818049107692, 0.9209559420400415], tspan = (0.0, 0.15)) + + # 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_forward_step_amr.jl" begin From 547556dafd3c84ae8ed50fc1911e924cb4237468 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Wed, 13 Sep 2023 10:58:33 +0200 Subject: [PATCH 096/263] Avoid slicing (#1637) Co-authored-by: Hendrik Ranocha --- examples/p4est_2d_dgsem/elixir_navierstokes_convergence.jl | 5 ++++- examples/p4est_3d_dgsem/elixir_navierstokes_convergence.jl | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/p4est_2d_dgsem/elixir_navierstokes_convergence.jl b/examples/p4est_2d_dgsem/elixir_navierstokes_convergence.jl index 8111df8251a..b0c6086ad63 100644 --- a/examples/p4est_2d_dgsem/elixir_navierstokes_convergence.jl +++ b/examples/p4est_2d_dgsem/elixir_navierstokes_convergence.jl @@ -170,7 +170,10 @@ end initial_condition = initial_condition_navier_stokes_convergence_test # BC types -velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:3]) +velocity_bc_top_bottom = NoSlip() do x, t, equations + u = initial_condition_navier_stokes_convergence_test(x, t, equations) + return SVector(u[2], u[3]) +end heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, heat_bc_top_bottom) diff --git a/examples/p4est_3d_dgsem/elixir_navierstokes_convergence.jl b/examples/p4est_3d_dgsem/elixir_navierstokes_convergence.jl index c426fe95f5b..0109e58dfb3 100644 --- a/examples/p4est_3d_dgsem/elixir_navierstokes_convergence.jl +++ b/examples/p4est_3d_dgsem/elixir_navierstokes_convergence.jl @@ -220,7 +220,10 @@ end initial_condition = initial_condition_navier_stokes_convergence_test # BC types -velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:4]) +velocity_bc_top_bottom = NoSlip() do x, t, equations + u = initial_condition_navier_stokes_convergence_test(x, t, equations) + return SVector(u[2], u[3], u[4]) +end heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, heat_bc_top_bottom) From 32d837b0920c3cd9218f448080495c4a29d53566 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 13 Sep 2023 11:46:52 +0200 Subject: [PATCH 097/263] new tutorial on custom RHS functions and semidiscretizations (#1633) * fix list of tutorials * WIP: tutorial on semidiscretizations * WIP: tutorial on semidiscretizations * custom RHS * custom semidiscretization * update make.jl script * WIP: trying to make Literate.jl testsets safeer * fix * fix reference * comment on safe testsets * some minor fixes * the SciML ecosystem * mention package versions --- docs/literate/make.jl | 17 +- .../src/files/custom_semidiscretization.jl | 324 ++++++++++++++++++ docs/literate/src/files/index.jl | 24 +- docs/make.jl | 1 + docs/src/callbacks.md | 4 +- docs/src/overview.md | 2 +- docs/src/parallelization.md | 6 +- docs/src/performance.md | 2 +- 8 files changed, 366 insertions(+), 14 deletions(-) create mode 100644 docs/literate/src/files/custom_semidiscretization.jl diff --git a/docs/literate/make.jl b/docs/literate/make.jl index b620f85c975..a04d8a0b333 100644 --- a/docs/literate/make.jl +++ b/docs/literate/make.jl @@ -51,12 +51,25 @@ function create_tutorials(files) # Run tests on all tutorial files @testset "TrixiTutorials" begin for (i, (title, filename)) in enumerate(files) + # Evaluate each tutorial in its own module to avoid leaking of + # function/variable names, polluting the namespace of later tutorials + # by stuff defined in earlier tutorials. if filename isa Vector # Several files of one topic for j in eachindex(filename) - @testset "$(filename[j][2][2])" begin include(joinpath(repo_src, filename[j][2][1], filename[j][2][2])) end + mod = gensym(filename[j][2][2]) + @testset "$(filename[j][2][2])" begin + @eval module $mod + include(joinpath($repo_src, $(filename[j][2][1]), $(filename[j][2][2]))) + end + end end else # Single files - @testset "$title" begin include(joinpath(repo_src, filename)) end + mod = gensym(title) + @testset "$title" begin + @eval module $mod + include(joinpath($repo_src, $filename)) + end + end end end end diff --git a/docs/literate/src/files/custom_semidiscretization.jl b/docs/literate/src/files/custom_semidiscretization.jl new file mode 100644 index 00000000000..fd432fb0826 --- /dev/null +++ b/docs/literate/src/files/custom_semidiscretization.jl @@ -0,0 +1,324 @@ +#src # Custom semidiscretizations + +# As described in the [overview section](@ref overview-semidiscretizations), +# semidiscretizations are high-level descriptions of spatial discretizations +# in Trixi.jl. Trixi.jl's main focus is on hyperbolic conservation +# laws represented in a [`SemidiscretizationHyperbolic`](@ref). +# Hyperbolic-parabolic problems based on the advection-diffusion equation or +# the compressible Navier-Stokes equations can be represented in a +# [`SemidiscretizationHyperbolicParabolic`](@ref). This is described in the +# [basic tutorial on parabolic terms](@ref parabolic_terms) and its extension to +# [custom parabolic terms](@ref adding_new_parabolic_terms). +# In this tutorial, we will describe how these semidiscretizations work and how +# they can be used to create custom semidiscretizations involving also other tasks. + + +# ## Overview of the right-hand side evaluation + +# The semidiscretizations provided by Trixi.jl are set up to create `ODEProblem`s from the +# [SciML ecosystem for ordinary differential equations](https://diffeq.sciml.ai/latest/). +# In particular, a spatial semidiscretization can be wrapped in an ODE problem +# using [`semidiscretize`](@ref), which returns an `ODEProblem`. This `ODEProblem` +# bundles an initial condition, a right-hand side (RHS) function, the time span, +# and possible parameters. The `ODEProblem`s created by Trixi.jl use the semidiscretization +# passed to [`semidiscretize`](@ref) as a parameter. +# For a [`SemidiscretizationHyperbolic`](@ref), the `ODEProblem` wraps +# `Trixi.rhs!` as ODE RHS. +# For a [`SemidiscretizationHyperbolicParabolic`](@ref), Trixi.jl +# uses a `SplitODEProblem` combining `Trixi.rhs_parabolic!` for the +# (potentially) stiff part and `Trixi.rhs!` for the other part. + + +# ## Standard Trixi.jl setup + +# In this tutorial, we will consider the linear advection equation +# with source term +# ```math +# \partial_t u(t,x) + \partial_x u(t,x) = -\exp(-t) \sin\bigl(\pi (x - t) \bigr) +# ``` +# with periodic boundary conditions in the domain `[-1, 1]` as a +# model problem. +# The initial condition is +# ```math +# u(0,x) = \sin(\pi x). +# ``` +# The source term results in some damping and the analytical solution +# ```math +# u(t,x) = \exp(-t) \sin\bigl(\pi (x - t) \bigr). +# ``` +# First, we discretize this equation using the standard functionality +# of Trixi.jl. + +using Trixi, OrdinaryDiffEq, Plots + +# The linear scalar advection equation is already implemented in +# Trixi.jl as [`LinearScalarAdvectionEquation1D`](@ref). We construct +# it with an advection velocity `1.0`. + +equations = LinearScalarAdvectionEquation1D(1.0) + +# Next, we use a standard [`DGSEM`](@ref) solver. + +solver = DGSEM(polydeg = 3) + +# We create a simple [`TreeMesh`](@ref) in 1D. + +coordinates_min = (-1.0,) +coordinates_max = (+1.0,) +mesh = TreeMesh(coordinates_min, coordinates_max; + initial_refinement_level = 4, + n_cells_max = 10^4, + periodicity = true) + +# We wrap everything in in a semidiscretization and pass the source +# terms as a standard Julia function. Please note that Trixi.jl uses +# `SVector`s from +# [StaticArrays.jl](https://github.com/JuliaArrays/StaticArrays.jl) +# to store the conserved variables `u`. Thus, the return value of the +# source terms must be wrapped in an `SVector` - even if we consider +# just a scalar problem. + +function initial_condition(x, t, equations) + return SVector(exp(-t) * sinpi(x[1] - t)) +end + +function source_terms_standard(u, x, t, equations) + return -initial_condition(x, t, equations) +end + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, + solver; + source_terms = source_terms_standard) + +# Now, we can create the `ODEProblem`, solve the resulting ODE +# using a time integration method from +# [OrdinaryDiffEq.jl](https://github.com/SciML/OrdinaryDiffEq.jl), +# and visualize the numerical solution at the final time using +# [Plots.jl](https://github.com/JuliaPlots/Plots.jl). + +tspan = (0.0, 3.0) +ode = semidiscretize(semi, tspan) + +sol = solve(ode, RDPK3SpFSAL49(); ode_default_options()...) + +plot(sol; label = "numerical sol.", legend = :topright) + +# We can also plot the analytical solution for comparison. +# Since Trixi.jl uses `SVector`s for the variables, we take their `first` +# (and only) component to get the scalar value for manual plotting. + +let + x = range(-1.0, 1.0; length = 200) + plot!(x, first.(initial_condition.(x, sol.t[end], equations)), + label = "analytical sol.", linestyle = :dash, legend = :topright) +end + +# We can also add the initial condition to the plot. + +plot!(sol.u[1], semi, label = "u0", linestyle = :dot, legend = :topleft) + +# You can of course also use some +# [callbacks](https://trixi-framework.github.io/Trixi.jl/stable/callbacks/) +# provided by Trixi.jl as usual. + +summary_callback = SummaryCallback() +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi; interval = analysis_interval) +alive_callback = AliveCallback(; analysis_interval) +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback) + +sol = solve(ode, RDPK3SpFSAL49(); + ode_default_options()..., callback = callbacks) +summary_callback() + + +# ## Using a custom ODE right-hand side function + +# Next, we will solve the same problem but use our own ODE RHS function. +# To demonstrate this, we will artificially create a global variable +# containing the current time of the simulation. + +const GLOBAL_TIME = Ref(0.0) + +function source_terms_custom(u, x, t, equations) + t = GLOBAL_TIME[] + return -initial_condition(x, t, equations) +end + +# Next, we create our own RHS function to update the global time of +# the simulation before calling the RHS function from Trixi.jl. + +function rhs_source_custom!(du_ode, u_ode, semi, t) + GLOBAL_TIME[] = t + Trixi.rhs!(du_ode, u_ode, semi, t) +end + +# Next, we create an `ODEProblem` manually copying over the data from +# the one we got from [`semidiscretize`](@ref) earlier. + +ode_source_custom = ODEProblem(rhs_source_custom!, + ode.u0, + ode.tspan, + ode.p #= semi =#) +sol_source_custom = solve(ode_source_custom, RDPK3SpFSAL49(); + ode_default_options()...) + +plot(sol_source_custom; label = "numerical sol.") +let + x = range(-1.0, 1.0; length = 200) + plot!(x, first.(initial_condition.(x, sol_source_custom.t[end], equations)), + label = "analytical sol.", linestyle = :dash, legend = :topleft) +end +plot!(sol_source_custom.u[1], semi, label = "u0", linestyle = :dot, legend = :topleft) + +# This also works with callbacks as usual. + +summary_callback = SummaryCallback() +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi; interval = analysis_interval) +alive_callback = AliveCallback(; analysis_interval) +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback) + +sol = solve(ode_source_custom, RDPK3SpFSAL49(); + ode_default_options()..., callback = callbacks) +summary_callback() + + +# ## Setting up a custom semidiscretization + +# Using a global constant is of course not really nice from a software +# engineering point of view. Thus, it can often be useful to collect +# additional data in the parameters of the `ODEProblem`. Thus, it is +# time to create our own semidiscretization. Here, we create a small +# wrapper of a standard semidiscretization of Trixi.jl and the current +# global time of the simulation. + +struct CustomSemidiscretization{Semi, T} <: Trixi.AbstractSemidiscretization + semi::Semi + t::T +end + +semi_custom = CustomSemidiscretization(semi, Ref(0.0)) + +# To get pretty printing in the REPL, you can consider specializing +# +# - `Base.show(io::IO, parameters::CustomSemidiscretization)` +# - `Base.show(io::IO, ::MIME"text/plain", parameters::CustomSemidiscretization)` +# +# for your custom semidiscretiation. + +# Next, we create our own source terms that use the global time stored +# in the custom semidiscretiation. + +source_terms_custom_semi = let semi_custom = semi_custom + function source_terms_custom_semi(u, x, t, equations) + t = semi_custom.t[] + return -initial_condition(x, t, equations) + end +end + +# We also create a custom ODE RHS to update the current global time +# stored in the custom semidiscretization. We unpack the standard +# semidiscretization created by Trixi.jl and pass it to `Trixi.rhs!`. + +function rhs_semi_custom!(du_ode, u_ode, semi_custom, t) + semi_custom.t[] = t + Trixi.rhs!(du_ode, u_ode, semi_custom.semi, t) +end + +# Finally, we set up an `ODEProblem` and solve it numerically. + +ode_semi_custom = ODEProblem(rhs_semi_custom!, + ode.u0, + ode.tspan, + semi_custom) +sol_semi_custom = solve(ode_semi_custom, RDPK3SpFSAL49(); + ode_default_options()...) + +# If we want to make use of additional functionality provided by +# Trixi.jl, e.g., for plotting, we need to implement a few additional +# specializations. In this case, we forward everything to the standard +# semidiscretization provided by Trixi.jl wrapped in our custom +# semidiscretization. + +Base.ndims(semi::CustomSemidiscretization) = ndims(semi.semi) +function Trixi.mesh_equations_solver_cache(semi::CustomSemidiscretization) + Trixi.mesh_equations_solver_cache(semi.semi) +end + +# Now, we can plot the numerical solution as usual. + +plot(sol_semi_custom; label = "numerical sol.") +let + x = range(-1.0, 1.0; length = 200) + plot!(x, first.(initial_condition.(x, sol_semi_custom.t[end], equations)), + label = "analytical sol.", linestyle = :dash, legend = :topleft) +end +plot!(sol_semi_custom.u[1], semi, label = "u0", linestyle = :dot, legend = :topleft) + +# This also works with many callbacks as usual. However, the +# [`AnalysisCallback`](@ref) requires some special handling since it +# makes use of a performance counter contained in the standard +# semidiscretizations of Trixi.jl to report some +# [performance metrics](@ref performance-metrics). +# Here, we forward all accesses to the performance counter to the +# wrapped semidiscretization. + +function Base.getproperty(semi::CustomSemidiscretization, s::Symbol) + if s === :performance_counter + wrapped_semi = getfield(semi, :semi) + wrapped_semi.performance_counter + else + getfield(semi, s) + end +end + +# Moreover, the [`AnalysisCallback`](@ref) also performs some error +# calculations. We also need to forward them to the wrapped +# semidiscretization. + +function Trixi.calc_error_norms(func, u, t, analyzer, + semi::CustomSemidiscretization, + cache_analysis) + Trixi.calc_error_norms(func, u, t, analyzer, + semi.semi, + cache_analysis) +end + +# Now, we can work with the callbacks used before as usual. + +summary_callback = SummaryCallback() +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi_custom; + interval = analysis_interval) +alive_callback = AliveCallback(; analysis_interval) +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback) + +sol = solve(ode_semi_custom, RDPK3SpFSAL49(); + ode_default_options()..., callback = callbacks) +summary_callback() + +# For even more advanced usage of custom semidiscretizations, you +# may look at the source code of the ones contained in Trixi.jl, e.g., +# - [`SemidiscretizationHyperbolicParabolic`](@ref) +# - [`SemidiscretizationEulerGravity`](@ref) +# - [`SemidiscretizationEulerAcoustics`](@ref) +# - [`SemidiscretizationCoupled`](@ref) + + +# ## Package versions + +# These results were obtained using the following versions. + +using InteractiveUtils +versioninfo() + +using Pkg +Pkg.status(["Trixi", "OrdinaryDiffEq", "Plots"], + mode=PKGMODE_MANIFEST) diff --git a/docs/literate/src/files/index.jl b/docs/literate/src/files/index.jl index 0c8de66bf42..d42695611f6 100644 --- a/docs/literate/src/files/index.jl +++ b/docs/literate/src/files/index.jl @@ -76,21 +76,30 @@ # In this part, another physics model is implemented, the nonconservative linear advection equation. # We run two different simulations with different levels of refinement and compare the resulting errors. -# ### [10 Adaptive mesh refinement](@ref adaptive_mesh_refinement) +# ### [10 Parabolic terms](@ref parabolic_terms) +#- +# This tutorial describes how parabolic terms are implemented in Trixi.jl, e.g., +# to solve the advection-diffusion equation. + +# ### [11 Adding new parabolic terms](@ref adding_new_parabolic_terms) +#- +# This tutorial describes how new parabolic terms can be implemented using Trixi.jl. + +# ### [12 Adaptive mesh refinement](@ref adaptive_mesh_refinement) #- # Adaptive mesh refinement (AMR) helps to increase the accuracy in sensitive or turbolent regions while # not wasting resources for less interesting parts of the domain. This leads to much more efficient # simulations. This tutorial presents the implementation strategy of AMR in Trixi.jl, including the use of # different indicators and controllers. -# ### [11 Structured mesh with curvilinear mapping](@ref structured_mesh_mapping) +# ### [13 Structured mesh with curvilinear mapping](@ref structured_mesh_mapping) #- # In this tutorial, the use of Trixi.jl's structured curved mesh type [`StructuredMesh`](@ref) is explained. # We present the two basic option to initialize such a mesh. First, the curved domain boundaries # of a circular cylinder are set by explicit boundary functions. Then, a fully curved mesh is # defined by passing the transformation mapping. -# ### [12 Unstructured meshes with HOHQMesh.jl](@ref hohqmesh_tutorial) +# ### [14 Unstructured meshes with HOHQMesh.jl](@ref hohqmesh_tutorial) #- # The purpose of this tutorial is to demonstrate how to use the [`UnstructuredMesh2D`](@ref) # functionality of Trixi.jl. This begins by running and visualizing an available unstructured @@ -99,19 +108,24 @@ # software in the Trixi.jl ecosystem, and then run a simulation using Trixi.jl on said mesh. # In the end, the tutorial briefly explains how to simulate an example using AMR via `P4estMesh`. -# ### [13 Explicit time stepping](@ref time_stepping) +# ### [15 Explicit time stepping](@ref time_stepping) #- # This tutorial is about time integration using [OrdinaryDiffEq.jl](https://github.com/SciML/OrdinaryDiffEq.jl). # It explains how to use their algorithms and presents two types of time step choices - with error-based # and CFL-based adaptive step size control. -# ### [14 Differentiable programming](@ref differentiable_programming) +# ### [16 Differentiable programming](@ref differentiable_programming) #- # This part deals with some basic differentiable programming topics. For example, a Jacobian, its # eigenvalues and a curve of total energy (through the simulation) are calculated and plotted for # a few semidiscretizations. Moreover, we calculate an example for propagating errors with Measurement.jl # at the end. +# ### [17 Custom semidiscretization](@ref custom_semidiscretization) +#- +# This tutorial describes the [semidiscretiations](@ref overview-semidiscretizations) of Trixi.jl +# and explains how to extend them for custom tasks. + # ## Examples in Trixi.jl diff --git a/docs/make.jl b/docs/make.jl index 57629577ddb..f882fcf1219 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -68,6 +68,7 @@ files = [ # Topic: other stuff "Explicit time stepping" => "time_stepping.jl", "Differentiable programming" => "differentiable_programming.jl", + "Custom semidiscretizations" => "custom_semidiscretization.jl" ] tutorials = create_tutorials(files) diff --git a/docs/src/callbacks.md b/docs/src/callbacks.md index 1d3e5e34b51..7f44dfd5925 100644 --- a/docs/src/callbacks.md +++ b/docs/src/callbacks.md @@ -30,7 +30,7 @@ An example elixir using AMR can be found at [`examples/tree_2d_dgsem/elixir_adve The [`AnalysisCallback`](@ref) can be used to analyze the numerical solution, e.g. calculate errors or user-specified integrals, and print the results to the screen. The results can also be saved in a file. An example can be found at [`examples/tree_2d_dgsem/elixir_euler_vortex.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_euler_vortex.jl). -In [Performance metrics of the `AnalysisCallback`](@ref) you can find a detailed +In [Performance metrics of the `AnalysisCallback`](@ref performance-metrics) you can find a detailed description of the different performance metrics the `AnalysisCallback` computes. ### I/O @@ -106,7 +106,7 @@ will yield the following plot: the automated performance measurements, including an output of the recorded timers after a simulation. * The [`VisualizationCallback`](@ref) can be used for in-situ visualization. See [Visualizing results during a simulation](@ref). -* The [`TrivialCallback`](@ref) does nothing and can be used to to easily disable some callbacks +* The [`TrivialCallback`](@ref) does nothing and can be used to easily disable some callbacks via [`trixi_include`](@ref). ### Equation-specific callbacks diff --git a/docs/src/overview.md b/docs/src/overview.md index 46bc28b6025..51a6272ae8e 100644 --- a/docs/src/overview.md +++ b/docs/src/overview.md @@ -16,7 +16,7 @@ to solve a PDE numerically are the spatial semidiscretization and the time integration scheme. -## Semidiscretizations +## [Semidiscretizations](@id overview-semidiscretizations) Semidiscretizations are high-level descriptions of spatial discretizations specialized for certain PDEs. Trixi.jl's main focus is on hyperbolic conservation diff --git a/docs/src/parallelization.md b/docs/src/parallelization.md index d56777c9af4..e55471bb256 100644 --- a/docs/src/parallelization.md +++ b/docs/src/parallelization.md @@ -22,7 +22,7 @@ julia --threads=4 If both the environment variable and the command line argument are specified at the same time, the latter takes precedence. -If you use time integration methods from +If you use time integration methods from [OrdinaryDiffEq.jl](https://github.com/SciML/OrdinaryDiffEq.jl) and want to use multiple threads therein, you need to set the keyword argument `thread=OrdinaryDiffEq.True()` of the algorithms, as described in the @@ -143,7 +143,7 @@ To start Trixi.jl in parallel with MPI, there are three options: Switching between panes can be done by `Ctrl+b` followed by `o`. As of March 2022, newer versions of tmpi also support mpich, which is the default backend of MPI.jl (via MPICH_Jll.jl). To use this setup, you need to install - `mpiexecjl` as described in the + `mpiexecjl` as described in the [documentation of MPI.jl](https://juliaparallel.org/MPI.jl/v0.20/usage/#Julia-wrapper-for-mpiexec) and make it available as `mpirun`, e.g., via a symlink of the form ```bash @@ -161,7 +161,7 @@ To start Trixi.jl in parallel with MPI, there are three options: ### [Performance](@id parallel_performance) For information on how to evaluate the parallel performance of Trixi.jl, please -have a look at the [Performance metrics of the `AnalysisCallback`](@ref) +have a look at the [Performance metrics of the `AnalysisCallback`](@ref performance-metrics) section, specifically at the descriptions of the performance index (PID). diff --git a/docs/src/performance.md b/docs/src/performance.md index 428672ec75f..bbe3a3390b7 100644 --- a/docs/src/performance.md +++ b/docs/src/performance.md @@ -170,7 +170,7 @@ As a rule of thumb: - Consider using `@nospecialize` for methods like custom implementations of `Base.show`. -## Performance metrics of the `AnalysisCallback` +## [Performance metrics of the `AnalysisCallback`](@id performance-metrics) The [`AnalysisCallback`](@ref) computes two performance indicators that you can use to evaluate the serial and parallel performance of Trixi.jl. They represent measured run times that are normalized by the number of `rhs!` evaluations and From b942775af0677ac83d77934c2326ab2b5db5ba77 Mon Sep 17 00:00:00 2001 From: Krissh Chawla <127906314+KrisshChawla@users.noreply.github.com> Date: Wed, 13 Sep 2023 20:08:08 -0500 Subject: [PATCH 098/263] Adding quasi 1d shallow water equations (#1619) * implementation of quasi shallow water equations 1d. * added example elixer for shallow_water_quasi_1d * changed the names of Quasi1d equations * including and exported ShallowWaterEquationsQuasi1D * exporting flux_chan_etal and flux_chan_nonconservative_etal * minor comment fix * adding tests * Apply suggestions from code review * Apply suggestions from code review * Update src/equations/shallow_water_quasi_1d.jl * formatting * formatting * forgot comma * Apply suggestions from code review Co-authored-by: Hendrik Ranocha * renamed example elixir to elixir_shallow_water_quasi_1d_source_terms.jl * Apply suggestions from code review Co-authored-by: Andrew Winters * Update test_tree_1d_shallowwater.jl with renamed example elixir * comment fix * comment fix for elixir_shallow_water_quasi_1d_source_terms.jl * Added well-balancedness test for shallow_water_quasi_1d The initial condition in the elixir is intended to test a discontinuous channel width 'a(x)' and bottom topography 'b(x)' on a periodic mesh. * Added 'max_abs_speeds' function and 'lake_at_rest_error' * Updated test_tree_1d_shallowwater with quasi well-balancedness test * File name fix in test_tree_1d_shallowwater * Update examples/tree_1d_dgsem/elixir_shallowwater_quasi1d_well_balanced.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Renamed to "elixir_shallowwater_quasi_1d_well_balanced.jl" --------- Co-authored-by: Jesse Chan Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> Co-authored-by: Hendrik Ranocha Co-authored-by: Andrew Winters --- ...xir_shallow_water_quasi_1d_source_terms.jl | 60 ++++ ...xir_shallowwater_quasi_1d_well_balanced.jl | 84 +++++ src/Trixi.jl | 2 + src/equations/equations.jl | 1 + src/equations/shallow_water_quasi_1d.jl | 323 ++++++++++++++++++ test/test_tree_1d_shallowwater.jl | 14 + 6 files changed, 484 insertions(+) create mode 100644 examples/tree_1d_dgsem/elixir_shallow_water_quasi_1d_source_terms.jl create mode 100644 examples/tree_1d_dgsem/elixir_shallowwater_quasi_1d_well_balanced.jl create mode 100644 src/equations/shallow_water_quasi_1d.jl diff --git a/examples/tree_1d_dgsem/elixir_shallow_water_quasi_1d_source_terms.jl b/examples/tree_1d_dgsem/elixir_shallow_water_quasi_1d_source_terms.jl new file mode 100644 index 00000000000..72747c669e2 --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_shallow_water_quasi_1d_source_terms.jl @@ -0,0 +1,60 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# Semidiscretization of the quasi 1d shallow water equations +# See Chan et al. https://doi.org/10.48550/arXiv.2307.12089 for details + +equations = ShallowWaterEquationsQuasi1D(gravity_constant = 9.81) + +initial_condition = initial_condition_convergence_test + +############################################################################### +# Get the DG approximation space + +volume_flux = (flux_chan_etal, flux_nonconservative_chan_etal) +surface_flux = (FluxPlusDissipation(flux_chan_etal, DissipationLocalLaxFriedrichs()), + flux_nonconservative_chan_etal) +solver = DGSEM(polydeg = 3, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +############################################################################### +# Get the TreeMesh and setup a periodic mesh + +coordinates_min = 0.0 +coordinates_max = sqrt(2.0) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 3, + n_cells_max = 10_000, + periodicity = true) + +# create the semi discretization object +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_convergence_test) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 1.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 500 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 200, + save_initial_solution = true, + save_final_solution = true) + +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) + +############################################################################### +# run the simulation + +# use a Runge-Kutta method with automatic (error based) time step size control +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-8, reltol = 1.0e-8, + ode_default_options()..., callback = callbacks); +summary_callback() # print the timer summary diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_quasi_1d_well_balanced.jl b/examples/tree_1d_dgsem/elixir_shallowwater_quasi_1d_well_balanced.jl new file mode 100644 index 00000000000..d9f1a52b500 --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_shallowwater_quasi_1d_well_balanced.jl @@ -0,0 +1,84 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the shallow water equations with a discontinuous +# bottom topography function and channel width function + +equations = ShallowWaterEquationsQuasi1D(gravity_constant = 9.81, H0 = 2.0) + +# Setup a truly discontinuous bottom topography function and channel width for +# this academic testcase of well-balancedness. The errors from the analysis +# callback are not important but the error for this lake-at-rest test case +# `∑|H0-(h+b)|` should be around machine roundoff. +# Works as intended for TreeMesh1D with `initial_refinement_level=3`. If the mesh +# refinement level is changed the initial condition below may need changed as well to +# ensure that the discontinuities lie on an element interface. +function initial_condition_discontinuous_well_balancedness(x, t, + equations::ShallowWaterEquationsQuasi1D) + H = equations.H0 + v = 0.0 + + # for a periodic domain, this choice of `b` and `a` mimic + # discontinuity across the periodic boundary. + b = 0.5 * (x[1] + 1) + a = 2 + x[1] + + return prim2cons(SVector(H, v, b, a), equations) +end + +initial_condition = initial_condition_discontinuous_well_balancedness + +############################################################################### +# Get the DG approximation space + +volume_flux = (flux_chan_etal, flux_nonconservative_chan_etal) +surface_flux = volume_flux +solver = DGSEM(polydeg = 4, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +############################################################################### +# Get the TreeMesh and setup a periodic mesh + +coordinates_min = -1.0 +coordinates_max = 1.0 +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 3, + n_cells_max = 10_000) + +# Create the semi discretization object +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solver + +tspan = (0.0, 100.0) +ode = semidiscretize(semi, tspan) + +############################################################################### +# Callbacks + +summary_callback = SummaryCallback() + +analysis_interval = 1000 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (lake_at_rest_error,)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true) + +stepsize_callback = StepsizeCallback(cfl = 3.0) + +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, + 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/src/Trixi.jl b/src/Trixi.jl index be43c45b93d..c883c3bf19f 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -149,6 +149,7 @@ export AcousticPerturbationEquations2D, LatticeBoltzmannEquations2D, LatticeBoltzmannEquations3D, ShallowWaterEquations1D, ShallowWaterEquations2D, ShallowWaterTwoLayerEquations1D, ShallowWaterTwoLayerEquations2D, + ShallowWaterEquationsQuasi1D, LinearizedEulerEquations2D export LaplaceDiffusion1D, LaplaceDiffusion2D, @@ -164,6 +165,7 @@ 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_es_fjordholm_etal, flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal, + flux_chan_etal, flux_nonconservative_chan_etal, hydrostatic_reconstruction_audusse_etal, flux_nonconservative_audusse_etal, # TODO: TrixiShallowWater: move anything with "chen_noelle" to new file hydrostatic_reconstruction_chen_noelle, flux_nonconservative_chen_noelle, diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 570a25cece9..9bae563d85f 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -356,6 +356,7 @@ include("shallow_water_1d.jl") include("shallow_water_2d.jl") include("shallow_water_two_layer_1d.jl") include("shallow_water_two_layer_2d.jl") +include("shallow_water_quasi_1d.jl") # CompressibleEulerEquations abstract type AbstractCompressibleEulerEquations{NDIMS, NVARS} <: diff --git a/src/equations/shallow_water_quasi_1d.jl b/src/equations/shallow_water_quasi_1d.jl new file mode 100644 index 00000000000..217a764e173 --- /dev/null +++ b/src/equations/shallow_water_quasi_1d.jl @@ -0,0 +1,323 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +@doc raw""" + ShallowWaterEquationsQuasi1D(; gravity, H0 = 0, threshold_limiter = nothing threshold_wet = nothing) + +The quasi-1D shallow water equations (SWE). The equations are given by +```math +\begin{aligned} + \frac{\partial}{\partial t}(a h) + \frac{\partial}{\partial x}(a h v) &= 0 \\ + \frac{\partial}{\partial t}(a h v) + \frac{\partial}{\partial x}(a h v^2) + + g a h \frac{\partial}{\partial x}(h + b) &= 0 +\end{aligned} +``` +The unknown quantities of the Quasi-1D SWE are the water height ``h`` and the scaled velocity ``v``. +The gravitational constant is denoted by `g`, the (possibly) variable bottom topography function ``b(x)``, and (possibly) variable channel width ``a(x)``. The water height ``h`` is measured from the bottom topography ``b``, therefore one also defines the total water height as ``H = h + b``. + +The additional quantity ``H_0`` is also available to store a reference value for the total water height that +is useful to set initial conditions or test the "lake-at-rest" well-balancedness. + +Also, there are two thresholds which prevent numerical problems as well as instabilities. Both of them do not +have to be passed, as default values are defined within the struct. The first one, `threshold_limiter`, is +used in [`PositivityPreservingLimiterShallowWater`](@ref) on the water height, as a (small) shift on the initial +condition and cutoff before the next time step. The second one, `threshold_wet`, is applied on the water height to +define when the flow is "wet" before calculating the numerical flux. + +The bottom topography function ``b(x)`` and channel width ``a(x)`` are set inside the initial condition routine +for a particular problem setup. To test the conservative form of the SWE one can set the bottom topography +variable `b` to zero and ``a`` to one. + +In addition to the unknowns, Trixi.jl currently stores the bottom topography and channel width values at the approximation points +despite being fixed in time. This is done for convenience of computing the bottom topography gradients +on the fly during the approximation as well as computing auxiliary quantities like the total water height ``H`` +or the entropy variables. +This affects the implementation and use of these equations in various ways: +* The flux values corresponding to the bottom topography and channel width must be zero. +* The bottom topography and channel width values must be included when defining initial conditions, boundary conditions or + source terms. +* [`AnalysisCallback`](@ref) analyzes this variable. +* Trixi.jl's visualization tools will visualize the bottom topography and channel width by default. +""" +struct ShallowWaterEquationsQuasi1D{RealT <: Real} <: + AbstractShallowWaterEquations{1, 4} + gravity::RealT # gravitational constant + H0::RealT # constant "lake-at-rest" total water height + # `threshold_limiter` used in `PositivityPreservingLimiterShallowWater` on water height, + # as a (small) shift on the initial condition and cutoff before the next time step. + # Default is 500*eps() which in double precision is ≈1e-13. + threshold_limiter::RealT + # `threshold_wet` applied on water height to define when the flow is "wet" + # before calculating the numerical flux. + # Default is 5*eps() which in double precision is ≈1e-15. + threshold_wet::RealT +end + +# Allow for flexibility to set the gravitational constant within an elixir depending on the +# application where `gravity_constant=1.0` or `gravity_constant=9.81` are common values. +# The reference total water height H0 defaults to 0.0 but is used for the "lake-at-rest" +# well-balancedness test cases. +# Strict default values for thresholds that performed well in many numerical experiments +function ShallowWaterEquationsQuasi1D(; gravity_constant, H0 = zero(gravity_constant), + threshold_limiter = nothing, + threshold_wet = nothing) + T = promote_type(typeof(gravity_constant), typeof(H0)) + if threshold_limiter === nothing + threshold_limiter = 500 * eps(T) + end + if threshold_wet === nothing + threshold_wet = 5 * eps(T) + end + ShallowWaterEquationsQuasi1D(gravity_constant, H0, threshold_limiter, threshold_wet) +end + +have_nonconservative_terms(::ShallowWaterEquationsQuasi1D) = True() +function varnames(::typeof(cons2cons), ::ShallowWaterEquationsQuasi1D) + ("a_h", "a_h_v", "b", "a") +end +# Note, we use the total water height, H = h + b, as the first primitive variable for easier +# visualization and setting initial conditions +varnames(::typeof(cons2prim), ::ShallowWaterEquationsQuasi1D) = ("H", "v", "b", "a") + +# Set initial conditions at physical location `x` for time `t` +""" + initial_condition_convergence_test(x, t, equations::ShallowWaterEquationsQuasi1D) + +A smooth initial condition used for convergence tests in combination with +[`source_terms_convergence_test`](@ref) +(and [`BoundaryConditionDirichlet(initial_condition_convergence_test)`](@ref) in non-periodic domains). +""" +function initial_condition_convergence_test(x, t, + equations::ShallowWaterEquationsQuasi1D) + # generates a manufactured solution. + # some constants are chosen such that the function is periodic on the domain [0,sqrt(2)] + Omega = sqrt(2) * pi + H = 2.0 + 0.5 * sin(Omega * x[1] - t) + v = 0.25 + b = 0.2 - 0.05 * sin(Omega * x[1]) + a = 1 + 0.1 * cos(Omega * x[1]) + return prim2cons(SVector(H, v, b, a), equations) +end + +""" + source_terms_convergence_test(u, x, t, equations::ShallowWaterEquationsQuasi1D) + +Source terms used for convergence tests in combination with +[`initial_condition_convergence_test`](@ref) +(and [`BoundaryConditionDirichlet(initial_condition_convergence_test)`](@ref) in non-periodic domains). + +This manufactured solution source term is specifically designed for the bottom topography function +`b(x) = 0.2 - 0.05 * sin(sqrt(2) * pi *x[1])` and channel width 'a(x)= 1 + 0.1 * cos(sqrt(2) * pi * x[1])' +as defined in [`initial_condition_convergence_test`](@ref). +""" +@inline function source_terms_convergence_test(u, x, t, + equations::ShallowWaterEquationsQuasi1D) + # Same settings as in `initial_condition_convergence_test`. Some derivative simplify because + # this manufactured solution velocity is taken to be constant + Omega = sqrt(2) * pi + H = 2.0 + 0.5 * sin(Omega * x[1] - t) + H_x = 0.5 * cos(Omega * x[1] - t) * Omega + H_t = -0.5 * cos(Omega * x[1] - t) + + v = 0.25 + + b = 0.2 - 0.05 * sin(Omega * x[1]) + b_x = -0.05 * cos(Omega * x[1]) * Omega + + a = 1 + 0.1 * cos(Omega * x[1]) + a_x = -0.1 * sin(Omega * x[1]) * Omega + + du1 = a * H_t + v * (a_x * (H - b) + a * (H_x - b_x)) + du2 = v * du1 + a * (equations.gravity * (H - b) * H_x) + + return SVector(du1, du2, 0.0, 0.0) +end + +# Calculate 1D flux for a single point +# Note, the bottom topography and channel width have no flux +@inline function flux(u, orientation::Integer, equations::ShallowWaterEquationsQuasi1D) + a_h, a_h_v, _, a = u + h = waterheight(u, equations) + v = velocity(u, equations) + + p = 0.5 * a * equations.gravity * h^2 + + f1 = a_h_v + f2 = a_h_v * v + p + + return SVector(f1, f2, zero(eltype(u)), zero(eltype(u))) +end + +""" + flux_nonconservative_chan_etal(u_ll, u_rr, orientation::Integer, + equations::ShallowWaterEquationsQuasi1D) + +Non-symmetric two-point volume flux discretizing the nonconservative (source) term +that contains the gradient of the bottom topography [`ShallowWaterEquationsQuasi1D`](@ref) +and the channel width. + +Further details are available in the paper: +- Jesse Chan, Khemraj Shukla, Xinhui Wu, Ruofeng Liu, Prani Nalluri (2023) + High order entropy stable schemes for the quasi-one-dimensional + shallow water and compressible Euler equations + [DOI: 10.48550/arXiv.2307.12089](https://doi.org/10.48550/arXiv.2307.12089) +""" +@inline function flux_nonconservative_chan_etal(u_ll, u_rr, orientation::Integer, + equations::ShallowWaterEquationsQuasi1D) + a_h_ll, _, b_ll, a_ll = u_ll + a_h_rr, _, b_rr, a_rr = u_rr + + h_ll = waterheight(u_ll, equations) + h_rr = waterheight(u_rr, equations) + + z = zero(eltype(u_ll)) + + return SVector(z, equations.gravity * a_ll * h_ll * (h_rr + b_rr), z, z) +end + +""" + flux_chan_etal(u_ll, u_rr, orientation, + equations::ShallowWaterEquationsQuasi1D) + +Total energy conservative (mathematical entropy for quasi 1D 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., [`FluxPlusDissipation(flux_chan_etal, DissipationLocalLaxFriedrichs())`](@ref). + +Further details are available in the paper: +- Jesse Chan, Khemraj Shukla, Xinhui Wu, Ruofeng Liu, Prani Nalluri (2023) + High order entropy stable schemes for the quasi-one-dimensional + shallow water and compressible Euler equations + [DOI: 10.48550/arXiv.2307.12089](https://doi.org/10.48550/arXiv.2307.12089) +""" +@inline function flux_chan_etal(u_ll, u_rr, orientation::Integer, + equations::ShallowWaterEquationsQuasi1D) + a_h_ll, a_h_v_ll, _, _ = u_ll + a_h_rr, a_h_v_rr, _, _ = u_rr + + v_ll = velocity(u_ll, equations) + v_rr = velocity(u_rr, equations) + + f1 = 0.5 * (a_h_v_ll + a_h_v_rr) + f2 = f1 * 0.5 * (v_ll + v_rr) + + return SVector(f1, f2, zero(eltype(u_ll)), zero(eltype(u_ll))) +end + +# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation as the +# maximum velocity magnitude plus the maximum speed of sound +@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, + equations::ShallowWaterEquationsQuasi1D) + # Get the velocity quantities + v_ll = velocity(u_ll, equations) + v_rr = velocity(u_rr, equations) + + # Calculate the wave celerity on the left and right + h_ll = waterheight(u_ll, equations) + h_rr = waterheight(u_rr, equations) + c_ll = sqrt(equations.gravity * h_ll) + c_rr = sqrt(equations.gravity * h_rr) + + return max(abs(v_ll), abs(v_rr)) + max(c_ll, c_rr) +end + +# Specialized `DissipationLocalLaxFriedrichs` to avoid spurious dissipation in the bottom topography +# and channel width +@inline function (dissipation::DissipationLocalLaxFriedrichs)(u_ll, u_rr, + orientation_or_normal_direction, + equations::ShallowWaterEquationsQuasi1D) + λ = dissipation.max_abs_speed(u_ll, u_rr, orientation_or_normal_direction, + equations) + diss = -0.5 * λ * (u_rr - u_ll) + return SVector(diss[1], diss[2], zero(eltype(u_ll)), zero(eltype(u_ll))) +end + +@inline function max_abs_speeds(u, equations::ShallowWaterEquationsQuasi1D) + h = waterheight(u, equations) + v = velocity(u, equations) + + c = equations.gravity * sqrt(h) + return (abs(v) + c,) +end + +# Helper function to extract the velocity vector from the conservative variables +@inline function velocity(u, equations::ShallowWaterEquationsQuasi1D) + a_h, a_h_v, _, _ = u + + v = a_h_v / a_h + + return v +end + +# Convert conservative variables to primitive +@inline function cons2prim(u, equations::ShallowWaterEquationsQuasi1D) + a_h, _, b, a = u + h = a_h / a + H = h + b + v = velocity(u, equations) + return SVector(H, v, b, a) +end + +# Convert conservative variables to entropy variables +# Note, only the first two are the entropy variables, the third and fourth entries still +# just carry the bottom topography and channel width values for convenience +@inline function cons2entropy(u, equations::ShallowWaterEquationsQuasi1D) + a_h, a_h_v, b, a = u + h = waterheight(u, equations) + v = velocity(u, equations) + #entropy variables are the same as ones in standard shallow water equations + w1 = equations.gravity * (h + b) - 0.5 * v^2 + w2 = v + + return SVector(w1, w2, b, a) +end + +# Convert primitive to conservative variables +@inline function prim2cons(prim, equations::ShallowWaterEquationsQuasi1D) + H, v, b, a = prim + + a_h = a * (H - b) + a_h_v = a_h * v + return SVector(a_h, a_h_v, b, a) +end + +@inline function waterheight(u, equations::ShallowWaterEquationsQuasi1D) + return u[1] / u[4] +end + +# Entropy function for the shallow water equations is the total energy +@inline function entropy(cons, equations::ShallowWaterEquationsQuasi1D) + a = cons[4] + return a * energy_total(cons, equations) +end + +# Calculate total energy for a conservative state `cons` +@inline function energy_total(cons, equations::ShallowWaterEquationsQuasi1D) + a_h, a_h_v, b, a = cons + e = (a_h_v^2) / (2 * a * a_h) + 0.5 * equations.gravity * (a_h^2 / a) + + equations.gravity * a_h * b + return e +end + +# Calculate the error for the "lake-at-rest" test case where H = h+b should +# be a constant value over time. Note, assumes there is a single reference +# water height `H0` with which to compare. +# +# TODO: TrixiShallowWater: where should `threshold_limiter` live? May need +# to modify or have different versions of the `lake_at_rest_error` function +@inline function lake_at_rest_error(u, equations::ShallowWaterEquationsQuasi1D) + _, _, b, _ = u + h = waterheight(u, equations) + + # For well-balancedness testing with possible wet/dry regions the reference + # water height `H0` accounts for the possibility that the bottom topography + # can emerge out of the water as well as for the threshold offset to avoid + # division by a "hard" zero water heights as well. + H0_wet_dry = max(equations.H0, b + equations.threshold_limiter) + + return abs(H0_wet_dry - (h + b)) +end +end # @muladd diff --git a/test/test_tree_1d_shallowwater.jl b/test/test_tree_1d_shallowwater.jl index 1e5aeac1786..09fb2d9e432 100644 --- a/test/test_tree_1d_shallowwater.jl +++ b/test/test_tree_1d_shallowwater.jl @@ -112,6 +112,20 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") linf = [0.00041080213807871235, 0.00014823261488938177, 2.220446049250313e-16], tspan = (0.0, 0.05)) end + + @trixi_testset "elixir_shallow_water_quasi_1d_source_terms.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallow_water_quasi_1d_source_terms.jl"), + l2 = [6.37048760275098e-5, 0.0002745658116815704, 4.436491725647962e-6, 8.872983451152218e-6], + linf = [0.00026747526881631956, 0.0012106730729152249, 9.098379777500165e-6, 1.8196759554278685e-5], + tspan = (0.0, 0.05)) + end + + @trixi_testset "elixir_shallowwater_quasi_1d_well_balanced.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_quasi_1d_well_balanced.jl"), + l2 = [1.4250229186905198e-14, 2.495109919406496e-12, 7.408599286788738e-17, 2.7205812409138776e-16], + linf = [5.284661597215745e-14, 2.74056233065078e-12, 2.220446049250313e-16, 8.881784197001252e-16], + tspan = (0.0, 100.0)) + end end end # module From f7b09734e1a86077a35c9cab0b9e97e68aaeb232 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Thu, 14 Sep 2023 06:41:14 +0200 Subject: [PATCH 099/263] add package versions to tutorials (#1638) --- docs/literate/src/files/DGMulti_1.jl | 12 ++++++++++++ docs/literate/src/files/DGMulti_2.jl | 12 ++++++++++++ docs/literate/src/files/DGSEM_FluxDiff.jl | 12 ++++++++++++ .../literate/src/files/adaptive_mesh_refinement.jl | 12 ++++++++++++ .../src/files/adding_new_parabolic_terms.jl | 12 ++++++++++++ .../src/files/adding_new_scalar_equations.jl | 12 ++++++++++++ .../src/files/adding_nonconservative_equation.jl | 12 ++++++++++++ .../src/files/differentiable_programming.jl | 12 ++++++++++++ docs/literate/src/files/hohqmesh_tutorial.jl | 12 ++++++++++++ docs/literate/src/files/non_periodic_boundaries.jl | 12 ++++++++++++ docs/literate/src/files/parabolic_terms.jl | 11 +++++++++++ .../src/files/scalar_linear_advection_1d.jl | 12 ++++++++++++ docs/literate/src/files/shock_capturing.jl | 12 ++++++++++++ docs/literate/src/files/structured_mesh_mapping.jl | 12 ++++++++++++ docs/literate/src/files/time_stepping.jl | 14 +++++++++++++- docs/literate/src/files/upwind_fdsbp.jl | 12 ++++++++++++ 16 files changed, 192 insertions(+), 1 deletion(-) diff --git a/docs/literate/src/files/DGMulti_1.jl b/docs/literate/src/files/DGMulti_1.jl index 0d78e79907c..5ef577e8eeb 100644 --- a/docs/literate/src/files/DGMulti_1.jl +++ b/docs/literate/src/files/DGMulti_1.jl @@ -194,3 +194,15 @@ plot(pd["rho"]) plot!(getmesh(pd)) # For more information, please have a look in the [StartUpDG.jl documentation](https://jlchan.github.io/StartUpDG.jl/stable/). + + +# ## Package versions + +# These results were obtained using the following versions. + +using InteractiveUtils +versioninfo() + +using Pkg +Pkg.status(["Trixi", "StartUpDG", "OrdinaryDiffEq", "Plots"], + mode=PKGMODE_MANIFEST) diff --git a/docs/literate/src/files/DGMulti_2.jl b/docs/literate/src/files/DGMulti_2.jl index 92dce43cdab..06248562343 100644 --- a/docs/literate/src/files/DGMulti_2.jl +++ b/docs/literate/src/files/DGMulti_2.jl @@ -38,3 +38,15 @@ D = couple_continuously(legendre_derivative_operator(xmin=0.0, xmax=1.0, N=4), # For more information and other SBP operators, see the documentations of [StartUpDG.jl](https://jlchan.github.io/StartUpDG.jl/dev/) # and [SummationByPartsOperators.jl](https://ranocha.de/SummationByPartsOperators.jl/stable/). + + +# ## Package versions + +# These results were obtained using the following versions. + +using InteractiveUtils +versioninfo() + +using Pkg +Pkg.status(["Trixi", "StartUpDG", "SummationByPartsOperators"], + mode=PKGMODE_MANIFEST) diff --git a/docs/literate/src/files/DGSEM_FluxDiff.jl b/docs/literate/src/files/DGSEM_FluxDiff.jl index 5ec156ebbe3..a5769900269 100644 --- a/docs/literate/src/files/DGSEM_FluxDiff.jl +++ b/docs/literate/src/files/DGSEM_FluxDiff.jl @@ -236,3 +236,15 @@ plot(sol) # [`flux_chandrashekar`](@ref), [`flux_kennedy_gruber`](@ref). # As surface flux you can use all volume fluxes and additionally for instance [`flux_lax_friedrichs`](@ref), # [`flux_hll`](@ref), [`flux_hllc`](@ref). + + +# ## Package versions + +# These results were obtained using the following versions. + +using InteractiveUtils +versioninfo() + +using Pkg +Pkg.status(["Trixi", "OrdinaryDiffEq", "Plots"], + mode=PKGMODE_MANIFEST) diff --git a/docs/literate/src/files/adaptive_mesh_refinement.jl b/docs/literate/src/files/adaptive_mesh_refinement.jl index d6150e887a8..46af8f79523 100644 --- a/docs/literate/src/files/adaptive_mesh_refinement.jl +++ b/docs/literate/src/files/adaptive_mesh_refinement.jl @@ -202,3 +202,15 @@ plot!(getmesh(pd)) # Source: Trixi.jl's YouTube channel [`Trixi Framework`](https://www.youtube.com/channel/UCpd92vU2HjjTPup-AIN0pkg) # For more information, please have a look at the respective links. + + +# ## Package versions + +# These results were obtained using the following versions. + +using InteractiveUtils +versioninfo() + +using Pkg +Pkg.status(["Trixi", "OrdinaryDiffEq", "Plots"], + mode=PKGMODE_MANIFEST) diff --git a/docs/literate/src/files/adding_new_parabolic_terms.jl b/docs/literate/src/files/adding_new_parabolic_terms.jl index 882f73f66ff..f5c2b815f33 100644 --- a/docs/literate/src/files/adding_new_parabolic_terms.jl +++ b/docs/literate/src/files/adding_new_parabolic_terms.jl @@ -158,3 +158,15 @@ sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, using Plots plot(sol) + +# ## Package versions + +# These results were obtained using the following versions. + +using InteractiveUtils +versioninfo() + +using Pkg +Pkg.status(["Trixi", "OrdinaryDiffEq", "Plots"], + mode=PKGMODE_MANIFEST) + diff --git a/docs/literate/src/files/adding_new_scalar_equations.jl b/docs/literate/src/files/adding_new_scalar_equations.jl index fec7bcf667a..a65b4de7f1a 100644 --- a/docs/literate/src/files/adding_new_scalar_equations.jl +++ b/docs/literate/src/files/adding_new_scalar_equations.jl @@ -211,3 +211,15 @@ semi = remake(semi, solver=DGSEM(3, flux_godunov, VolumeIntegralFluxDifferencing ode = semidiscretize(semi, (0.0, 0.5)) sol = solve(ode, SSPRK43(); ode_default_options()...) plot(sol) + + +# ## Package versions + +# These results were obtained using the following versions. + +using InteractiveUtils +versioninfo() + +using Pkg +Pkg.status(["Trixi", "OrdinaryDiffEq", "Plots"], + mode=PKGMODE_MANIFEST) diff --git a/docs/literate/src/files/adding_nonconservative_equation.jl b/docs/literate/src/files/adding_nonconservative_equation.jl index 110fa486070..b40e21fb11a 100644 --- a/docs/literate/src/files/adding_nonconservative_equation.jl +++ b/docs/literate/src/files/adding_nonconservative_equation.jl @@ -288,3 +288,15 @@ sol = solve(ode, Tsit5(), abstol=1.0e-6, reltol=1.0e-6, ## Plot the numerical solution at the final time using Plots: plot plot(sol); + + +# ## Package versions + +# These results were obtained using the following versions. + +using InteractiveUtils +versioninfo() + +using Pkg +Pkg.status(["Trixi", "OrdinaryDiffEq", "Plots"], + mode=PKGMODE_MANIFEST) diff --git a/docs/literate/src/files/differentiable_programming.jl b/docs/literate/src/files/differentiable_programming.jl index 5c5a7cd7440..33427803afc 100644 --- a/docs/literate/src/files/differentiable_programming.jl +++ b/docs/literate/src/files/differentiable_programming.jl @@ -446,3 +446,15 @@ scatter(real.(λ), imag.(λ)) λ = eigvals(Matrix(A)) relative_maximum = maximum(real, λ) / maximum(abs, λ) @test relative_maximum < 1.0e-15 #src + + +# ## Package versions + +# These results were obtained using the following versions. + +using InteractiveUtils +versioninfo() + +using Pkg +Pkg.status(["Trixi", "OrdinaryDiffEq", "Plots", "ForwardDiff"], + mode=PKGMODE_MANIFEST) diff --git a/docs/literate/src/files/hohqmesh_tutorial.jl b/docs/literate/src/files/hohqmesh_tutorial.jl index 87076108d91..b19d363c4bf 100644 --- a/docs/literate/src/files/hohqmesh_tutorial.jl +++ b/docs/literate/src/files/hohqmesh_tutorial.jl @@ -566,3 +566,15 @@ mesh = UnstructuredMesh2D(mesh_file); # for details. # ![simulation_straight_sides_p4est_amr](https://user-images.githubusercontent.com/74359358/168049930-8abce6ac-cd47-4d04-b40b-0fa459bbd98d.png) + + +# ## Package versions + +# These results were obtained using the following versions. + +using InteractiveUtils +versioninfo() + +using Pkg +Pkg.status(["Trixi", "OrdinaryDiffEq", "Plots", "Trixi2Vtk", "HOHQMesh"], + mode=PKGMODE_MANIFEST) diff --git a/docs/literate/src/files/non_periodic_boundaries.jl b/docs/literate/src/files/non_periodic_boundaries.jl index 54da88a64aa..7ed6324ff99 100644 --- a/docs/literate/src/files/non_periodic_boundaries.jl +++ b/docs/literate/src/files/non_periodic_boundaries.jl @@ -155,3 +155,15 @@ end #
# ``` # Source: [`Video`](https://www.youtube.com/watch?v=w0A9X38cSe4) on Trixi.jl's YouTube channel [`Trixi Framework`](https://www.youtube.com/watch?v=WElqqdMhY4A) + + +# ## Package versions + +# These results were obtained using the following versions. + +using InteractiveUtils +versioninfo() + +using Pkg +Pkg.status(["Trixi", "OrdinaryDiffEq", "Plots"], + mode=PKGMODE_MANIFEST) diff --git a/docs/literate/src/files/parabolic_terms.jl b/docs/literate/src/files/parabolic_terms.jl index bac0098f8e9..d0a355bbc19 100644 --- a/docs/literate/src/files/parabolic_terms.jl +++ b/docs/literate/src/files/parabolic_terms.jl @@ -86,3 +86,14 @@ sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, using Plots plot(sol) + +# ## Package versions + +# These results were obtained using the following versions. + +using InteractiveUtils +versioninfo() + +using Pkg +Pkg.status(["Trixi", "OrdinaryDiffEq", "Plots"], + mode=PKGMODE_MANIFEST) diff --git a/docs/literate/src/files/scalar_linear_advection_1d.jl b/docs/literate/src/files/scalar_linear_advection_1d.jl index 42c831c98ba..77ba7b087cc 100644 --- a/docs/literate/src/files/scalar_linear_advection_1d.jl +++ b/docs/literate/src/files/scalar_linear_advection_1d.jl @@ -511,3 +511,15 @@ sol_trixi = solve(ode_trixi, RDPK3SpFSAL49(); abstol=1.0e-6, reltol=1.0e-6, ode plot!(sol_trixi, label="solution at t=$(tspan[2]) with Trixi.jl", legend=:topleft, linestyle=:dash, lw=2) @test maximum(abs.(vec(u0) - sol_trixi.u[end])) ≈ maximum(abs.(u0 - sol.u[end])) #src + + +# ## Package versions + +# These results were obtained using the following versions. + +using InteractiveUtils +versioninfo() + +using Pkg +Pkg.status(["Trixi", "OrdinaryDiffEq", "Plots"], + mode=PKGMODE_MANIFEST) diff --git a/docs/literate/src/files/shock_capturing.jl b/docs/literate/src/files/shock_capturing.jl index afa34cbf06a..dd6698c2a86 100644 --- a/docs/literate/src/files/shock_capturing.jl +++ b/docs/literate/src/files/shock_capturing.jl @@ -224,3 +224,15 @@ sol = solve(ode, CarpenterKennedy2N54(stage_limiter!, williamson_condition=false using Plots plot(sol) + + +# ## Package versions + +# These results were obtained using the following versions. + +using InteractiveUtils +versioninfo() + +using Pkg +Pkg.status(["Trixi", "OrdinaryDiffEq", "Plots"], + mode=PKGMODE_MANIFEST) diff --git a/docs/literate/src/files/structured_mesh_mapping.jl b/docs/literate/src/files/structured_mesh_mapping.jl index 0ae9cf723f8..c8da30bc2bf 100644 --- a/docs/literate/src/files/structured_mesh_mapping.jl +++ b/docs/literate/src/files/structured_mesh_mapping.jl @@ -201,3 +201,15 @@ plot!(getmesh(pd)) # unstructured mesh type [`UnstructuredMesh2D`] and its use of the # [High-Order Hex-Quad Mesh (HOHQMesh) generator](https://github.com/trixi-framework/HOHQMesh), # created and developed by David Kopriva. + + +# ## Package versions + +# These results were obtained using the following versions. + +using InteractiveUtils +versioninfo() + +using Pkg +Pkg.status(["Trixi", "OrdinaryDiffEq", "Plots"], + mode=PKGMODE_MANIFEST) diff --git a/docs/literate/src/files/time_stepping.jl b/docs/literate/src/files/time_stepping.jl index d400c4a94be..de7a2a83a41 100644 --- a/docs/literate/src/files/time_stepping.jl +++ b/docs/literate/src/files/time_stepping.jl @@ -49,7 +49,7 @@ # ```math # \Delta t_n = \text{CFL} * \min_i \frac{\Delta x_i}{\lambda_{\max}(u_i^n)} # ``` -# We compute $\Delta x_i$ by scaling the element size by a factor of $1/(N+1)$, cf. +# We compute $\Delta x_i$ by scaling the element size by a factor of $1/(N+1)$, cf. # [Gassner and Kopriva (2011)](https://doi.org/10.1137/100807211), Section 5. # Trixi.jl provides such a CFL-based step size control. It is implemented as the callback @@ -73,3 +73,15 @@ # You can find simple examples with a CFL-based step size control for instance in the elixirs # [`elixir_advection_basic.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_advection_basic.jl) # or [`elixir_euler_source_terms.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_euler_source_terms.jl). + + +# ## Package versions + +# These results were obtained using the following versions. + +using InteractiveUtils +versioninfo() + +using Pkg +Pkg.status(["Trixi", "OrdinaryDiffEq"], + mode=PKGMODE_MANIFEST) diff --git a/docs/literate/src/files/upwind_fdsbp.jl b/docs/literate/src/files/upwind_fdsbp.jl index 36ca1b57404..6d3379fa30d 100644 --- a/docs/literate/src/files/upwind_fdsbp.jl +++ b/docs/literate/src/files/upwind_fdsbp.jl @@ -62,3 +62,15 @@ Matrix(D_upw.plus) # flux vector splitting, e.g., # - [`elixir_euler_vortex.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_fdsbp/elixir_euler_vortex.jl) # - [`elixir_euler_taylor_green_vortex.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_3d_fdsbp/elixir_euler_taylor_green_vortex.jl) + + +# ## Package versions + +# These results were obtained using the following versions. + +using InteractiveUtils +versioninfo() + +using Pkg +Pkg.status(["Trixi", "SummationByPartsOperators"], + mode=PKGMODE_MANIFEST) From 15543f28b7070dbc403857a047d5dc2ca2d0c1c3 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Thu, 14 Sep 2023 06:45:19 +0200 Subject: [PATCH 100/263] set version to v0.5.43 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 06fd29ba590..943d0d48005 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.5.43-pre" +version = "0.5.43" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 92dedde81e12f8ac2259785a9eab40f475d82251 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Thu, 14 Sep 2023 06:45:34 +0200 Subject: [PATCH 101/263] set development version to v0.5.44-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 943d0d48005..d134a8e548b 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.5.43" +version = "0.5.44-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 6069149fef0590c824ddee54b6d12d7531b6c790 Mon Sep 17 00:00:00 2001 From: ArseniyKholod <119304909+ArseniyKholod@users.noreply.github.com> Date: Fri, 15 Sep 2023 08:10:03 +0200 Subject: [PATCH 102/263] Handles restarting problem of adaptive time integration methods (#1565) * Create test.jl * Delete test.jl * loadcallback * adding_parallel_support * formatting * minimize dependencies * combine loadrestart and saverestart * fix * Update test_threaded.jl * fix * test fix * fix * MODULE add * fix * runtime macros * Update test_threaded.jl * handle MPI issues * enable PIDController test * Update test_mpi_tree.jl * fix * add asserts * Update save_restart.jl * add IController tests * enable HDF5 parallel * fix shot * fix shot 2 * fix shot 3 * fix shot 4 * fix shot 5 * fix shot 6 * fix shot 7 * fix shot 8 * fix shot 9 * fix shot 10 * fix shot 11 * fix shot 12 * fix shot 13 * fix shot 14 * fix shot 15 * fix shot 16 * fix shot 17 * fix shot 18 * enable additional configuration only in mpi test on linux * enable environment * test coverage issue * disable mpi macOs CI because of failure * disable new configurations to test coverage * disable PID and I test to test coverage issue * enable old coverage all * undo last commit and enable coverage on windows * enable new tests, mpi macOs and HDF5 parallel * fix * enable coverage on threads * test HDF5 parallel * test HDF5 parallel 2 * test HDF5 parallel 3 * fix * Update save_restart_dg.jl * test HDF5 parallel 4 * test HDF5 parallel 5 * Update configure_packages.jl * delete unnecessary changes * Update save_restart_dg.jl * Update save_restart_dg.jl * remove dependency on OrdinaryDiffEq * format * discard unrelated changes * delete barrier * delete eval() * comments & delete mpi_parallel * format * Update runtests.jl * Update runtests.jl * simplify tests * test failing MPI on windiws and macOs * test with RDPK3SpFSAL49 * test with RDPK3SpFSAL35 * change tests * fix and new test * Update test_tree_2d_euler.jl * fix and delete unnecessary test * add printing format * add docstrings * Update src/callbacks_step/save_restart.jl Co-authored-by: Michael Schlottke-Lakemper * fix * formatting * Update src/callbacks_step/save_restart_dg.jl Co-authored-by: Michael Schlottke-Lakemper * Update src/callbacks_step/save_restart_dg.jl Co-authored-by: Michael Schlottke-Lakemper * Update src/callbacks_step/save_restart.jl Co-authored-by: Michael Schlottke-Lakemper * Update src/callbacks_step/save_restart.jl Co-authored-by: Michael Schlottke-Lakemper * Update src/callbacks_step/save_restart.jl Co-authored-by: Michael Schlottke-Lakemper * suggested changes * new test * fix * fix * Update test_tree_2d_advection.jl * fix * fix error mpi on windows * rerun * Update src/callbacks_step/save_restart.jl Co-authored-by: Hendrik Ranocha * Add comments * format --------- Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Hendrik Ranocha --- .../elixir_advection_extended.jl | 7 ++-- .../tree_2d_dgsem/elixir_advection_restart.jl | 19 +++++---- src/Trixi.jl | 3 +- src/callbacks_step/save_restart.jl | 36 +++++++++++++++++ src/callbacks_step/save_restart_dg.jl | 24 ++++++++++++ test/test_mpi_tree.jl | 20 ++++++++-- test/test_threaded.jl | 39 ++++++++++++------- test/test_tree_2d_advection.jl | 20 ++++++++-- 8 files changed, 135 insertions(+), 33 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_advection_extended.jl b/examples/tree_2d_dgsem/elixir_advection_extended.jl index 8c837957ffd..278dc85386d 100644 --- a/examples/tree_2d_dgsem/elixir_advection_extended.jl +++ b/examples/tree_2d_dgsem/elixir_advection_extended.jl @@ -54,7 +54,7 @@ analysis_callback = AnalysisCallback(semi, interval=analysis_interval, alive_callback = AliveCallback(analysis_interval=analysis_interval) # The SaveRestartCallback allows to save a file from which a Trixi.jl simulation can be restarted -save_restart = SaveRestartCallback(interval=100, +save_restart = SaveRestartCallback(interval=40, save_final_restart=true) # The SaveSolutionCallback allows to save the solution to a file in regular intervals @@ -77,9 +77,10 @@ callbacks = CallbackSet(summary_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), +alg = CarpenterKennedy2N54(williamson_condition=false) +sol = solve(ode, alg, dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); + save_everystep=false, callback=callbacks; ode_default_options()...); # Print the timer summary summary_callback() diff --git a/examples/tree_2d_dgsem/elixir_advection_restart.jl b/examples/tree_2d_dgsem/elixir_advection_restart.jl index 771ec5aefe7..b63a8d1f7bc 100644 --- a/examples/tree_2d_dgsem/elixir_advection_restart.jl +++ b/examples/tree_2d_dgsem/elixir_advection_restart.jl @@ -3,9 +3,10 @@ using OrdinaryDiffEq using Trixi ############################################################################### -# create a restart file - -trixi_include(@__MODULE__, joinpath(@__DIR__, "elixir_advection_extended.jl")) +# Define time integration algorithm +alg = CarpenterKennedy2N54(williamson_condition=false) +# Create a restart file +trixi_include(@__MODULE__, joinpath(@__DIR__, "elixir_advection_extended.jl"), alg = alg, tspan = (0.0, 10.0)) ############################################################################### @@ -14,22 +15,26 @@ trixi_include(@__MODULE__, joinpath(@__DIR__, "elixir_advection_extended.jl")) # Note: If you get a restart file from somewhere else, you need to provide # appropriate setups in the elixir loading a restart file -restart_filename = joinpath("out", "restart_000018.h5") +restart_filename = joinpath("out", "restart_000040.h5") mesh = load_mesh(restart_filename) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) -tspan = (load_time(restart_filename), 2.0) +tspan = (load_time(restart_filename), 10.0) dt = load_dt(restart_filename) ode = semidiscretize(semi, tspan, restart_filename); # Do not overwrite the initial snapshot written by elixir_advection_extended.jl. save_solution.condition.save_initial_solution = false -alg = CarpenterKennedy2N54(williamson_condition=false) integrator = init(ode, alg, dt=dt, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks) + save_everystep=false, callback=callbacks; ode_default_options()...) + +# Load saved context for adaptive time integrator +if integrator.opts.adaptive + load_adaptive_time_integrator!(integrator, restart_filename) +end # Get the last time index and work with that. load_timestep!(integrator, restart_filename) diff --git a/src/Trixi.jl b/src/Trixi.jl index c883c3bf19f..b65d03e7975 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -255,7 +255,8 @@ export SummaryCallback, SteadyStateCallback, AnalysisCallback, AliveCallback, GlmSpeedCallback, LBMCollisionCallback, EulerAcousticsCouplingCallback, TrivialCallback, AnalysisCallbackCoupled -export load_mesh, load_time, load_timestep, load_timestep!, load_dt +export load_mesh, load_time, load_timestep, load_timestep!, load_dt, + load_adaptive_time_integrator! export ControllerThreeLevel, ControllerThreeLevelCombined, IndicatorLöhner, IndicatorLoehner, IndicatorMax, diff --git a/src/callbacks_step/save_restart.jl b/src/callbacks_step/save_restart.jl index 06817a9b730..0d174d85805 100644 --- a/src/callbacks_step/save_restart.jl +++ b/src/callbacks_step/save_restart.jl @@ -105,6 +105,11 @@ function (restart_callback::SaveRestartCallback)(integrator) end save_restart_file(u_ode, t, dt, iter, semi, restart_callback) + # If using an adaptive time stepping scheme, store controller values for restart + if integrator.opts.adaptive + save_adaptive_time_integrator(integrator, integrator.opts.controller, + restart_callback) + end end # avoid re-evaluating possible FSAL stages @@ -168,5 +173,36 @@ function load_restart_file(semi::AbstractSemidiscretization, restart_file) load_restart_file(mesh_equations_solver_cache(semi)..., restart_file) end +""" + load_adaptive_time_integrator!(integrator, restart_file::AbstractString) + +Load the context information for time integrators with error-based step size control +saved in a `restart_file`. +""" +function load_adaptive_time_integrator!(integrator, restart_file::AbstractString) + controller = integrator.opts.controller + # Read context information for controller + h5open(restart_file, "r") do file + # Ensure that the necessary information was saved + if !("time_integrator_qold" in keys(attributes(file))) || + !("time_integrator_dtpropose" in keys(attributes(file))) || + (hasproperty(controller, :err) && + !("time_integrator_controller_err" in keys(attributes(file)))) + error("Missing data in restart file: check the consistency of adaptive time controller with initial setup!") + end + # Load data that is required both for PIController and PIDController + integrator.qold = read(attributes(file)["time_integrator_qold"]) + integrator.dtpropose = read(attributes(file)["time_integrator_dtpropose"]) + # Accept step to use dtpropose already in the first step + integrator.accept_step = true + # Reevaluate integrator.fsal_first on the first step + integrator.reeval_fsal = true + # Load additional parameters for PIDController + if hasproperty(controller, :err) # Distinguish PIDController from PIController + controller.err[:] = read(attributes(file)["time_integrator_controller_err"]) + end + end +end + include("save_restart_dg.jl") end # @muladd diff --git a/src/callbacks_step/save_restart_dg.jl b/src/callbacks_step/save_restart_dg.jl index 8db6db2d2b8..cddeef77bb2 100644 --- a/src/callbacks_step/save_restart_dg.jl +++ b/src/callbacks_step/save_restart_dg.jl @@ -327,4 +327,28 @@ function load_restart_file_on_root(mesh::Union{ParallelTreeMesh, ParallelP4estMe return u_ode end + +# Store controller values for an adaptive time stepping scheme +function save_adaptive_time_integrator(integrator, + controller, restart_callback) + # Save only on root + if mpi_isroot() + @unpack output_directory = restart_callback + timestep = integrator.stats.naccept + + # Filename based on current time step + filename = joinpath(output_directory, @sprintf("restart_%06d.h5", timestep)) + + # Open file (preserve existing content) + h5open(filename, "r+") do file + # Add context information as attributes both for PIController and PIDController + attributes(file)["time_integrator_qold"] = integrator.qold + attributes(file)["time_integrator_dtpropose"] = integrator.dtpropose + # For PIDController is necessary to save additional parameters + if hasproperty(controller, :err) # Distinguish PIDController from PIController + attributes(file)["time_integrator_controller_err"] = controller.err + end + end + end +end end # @muladd diff --git a/test/test_mpi_tree.jl b/test/test_mpi_tree.jl index 8403fcf1b04..8f08a9d72e7 100644 --- a/test/test_mpi_tree.jl +++ b/test/test_mpi_tree.jl @@ -23,10 +23,22 @@ CI_ON_WINDOWS = (get(ENV, "GITHUB_ACTIONS", false) == "true") && Sys.iswindows() end @trixi_testset "elixir_advection_restart.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), - # Expected errors are exactly the same as in the serial test! - l2 = [7.81674284320524e-6], - linf = [6.314906965243505e-5]) + using OrdinaryDiffEq: RDPK3SpFSAL49 + Trixi.mpi_isroot() && println("═"^100) + Trixi.mpi_isroot() && println(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl")) + trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), + alg = RDPK3SpFSAL49(), tspan = (0.0, 10.0)) + l2_expected, linf_expected = analysis_callback(sol) + + Trixi.mpi_isroot() && println("═"^100) + Trixi.mpi_isroot() && println(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl")) + # Errors are exactly the same as in the elixir_advection_extended.jl + trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), + alg = RDPK3SpFSAL49()) + l2_actual, linf_actual = analysis_callback(sol) + + Trixi.mpi_isroot() && @test l2_actual == l2_expected + Trixi.mpi_isroot() && @test linf_actual == linf_expected end @trixi_testset "elixir_advection_mortar.jl" begin diff --git a/test/test_threaded.jl b/test/test_threaded.jl index 9b30836d0ed..2337d73f30a 100644 --- a/test/test_threaded.jl +++ b/test/test_threaded.jl @@ -12,27 +12,38 @@ Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) @testset "Threaded tests" begin @testset "TreeMesh" begin @trixi_testset "elixir_advection_restart.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_restart.jl"), - # Expected errors are exactly the same as in the serial test! - l2 = [7.81674284320524e-6], - linf = [6.314906965243505e-5]) + elixir = joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_extended.jl") + Trixi.mpi_isroot() && println("═"^100) + Trixi.mpi_isroot() && println(elixir) + trixi_include(@__MODULE__, elixir, tspan = (0.0, 10.0)) + l2_expected, linf_expected = analysis_callback(sol) + + elixir = joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_restart.jl") + Trixi.mpi_isroot() && println("═"^100) + Trixi.mpi_isroot() && println(elixir) + # Errors are exactly the same as in the elixir_advection_extended.jl + trixi_include(@__MODULE__, elixir) + l2_actual, linf_actual = analysis_callback(sol) + + Trixi.mpi_isroot() && @test l2_actual == l2_expected + Trixi.mpi_isroot() && @test linf_actual == linf_expected - # 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)) < 5000 - end + # 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)) < 5000 + end end @trixi_testset "elixir_advection_restart.jl with threaded time integration" begin @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_restart.jl"), alg = CarpenterKennedy2N54(williamson_condition = false, thread = OrdinaryDiffEq.True()), # Expected errors are exactly the same as in the serial test! - l2 = [7.81674284320524e-6], - linf = [6.314906965243505e-5]) + l2 = [8.005068880114254e-6], + linf = [6.39093577996519e-5]) end @trixi_testset "elixir_advection_amr_refine_twice.jl" begin diff --git a/test/test_tree_2d_advection.jl b/test/test_tree_2d_advection.jl index 973d0caf88b..36cb1e882cc 100644 --- a/test/test_tree_2d_advection.jl +++ b/test/test_tree_2d_advection.jl @@ -25,10 +25,22 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") end @trixi_testset "elixir_advection_restart.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), - # Expected errors are exactly the same as in the parallel test! - l2 = [7.81674284320524e-6], - linf = [6.314906965243505e-5]) + using OrdinaryDiffEq: SSPRK43 + println("═"^100) + println(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl")) + trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), + alg = SSPRK43(), tspan = (0.0, 10.0)) + l2_expected, linf_expected = analysis_callback(sol) + + println("═"^100) + println(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl")) + # Errors are exactly the same as in the elixir_advection_extended.jl + trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), + alg = SSPRK43()) + l2_actual, linf_actual = analysis_callback(sol) + + @test l2_actual == l2_expected + @test linf_actual == linf_expected end @trixi_testset "elixir_advection_mortar.jl" begin From 73384acbf45cf10710cfc817bc91a1812a0db1fd Mon Sep 17 00:00:00 2001 From: Benjamin Bolm <74359358+bennibolm@users.noreply.github.com> Date: Sat, 16 Sep 2023 16:16:12 +0200 Subject: [PATCH 103/263] Assure conservation for SSP scheme (#1640) * Add denominator variable for SSP scheme * Fix format * Implement suggestions --- src/time_integration/methods_SSP.jl | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/time_integration/methods_SSP.jl b/src/time_integration/methods_SSP.jl index 8ecad69748b..a0ed889968a 100644 --- a/src/time_integration/methods_SSP.jl +++ b/src/time_integration/methods_SSP.jl @@ -24,14 +24,16 @@ The third-order SSP Runge-Kutta method of Shu and Osher. This is an experimental feature and may change in future releases. """ struct SimpleSSPRK33{StageCallbacks} <: SimpleAlgorithmSSP - a::SVector{3, Float64} - b::SVector{3, Float64} + numerator_a::SVector{3, Float64} + numerator_b::SVector{3, Float64} + denominator::SVector{3, Float64} c::SVector{3, Float64} stage_callbacks::StageCallbacks function SimpleSSPRK33(; stage_callbacks = ()) - a = SVector(0.0, 3 / 4, 1 / 3) - b = SVector(1.0, 1 / 4, 2 / 3) + numerator_a = SVector(0.0, 3.0, 1.0) # a = numerator_a / denominator + numerator_b = SVector(1.0, 1.0, 2.0) # b = numerator_b / denominator + denominator = SVector(1.0, 4.0, 3.0) c = SVector(0.0, 1.0, 1 / 2) # Butcher tableau @@ -42,7 +44,8 @@ struct SimpleSSPRK33{StageCallbacks} <: SimpleAlgorithmSSP # -------------------- # b | 1/6 1/6 2/3 - new{typeof(stage_callbacks)}(a, b, c, stage_callbacks) + new{typeof(stage_callbacks)}(numerator_a, numerator_b, denominator, c, + stage_callbacks) end end @@ -166,7 +169,9 @@ function solve!(integrator::SimpleIntegratorSSP) end # perform convex combination - @. integrator.u = alg.a[stage] * integrator.r0 + alg.b[stage] * integrator.u + @. integrator.u = (alg.numerator_a[stage] * integrator.r0 + + alg.numerator_b[stage] * integrator.u) / + alg.denominator[stage] end integrator.iter += 1 From a64004d98c7a1b0c4894663c176f21c2178a3630 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 19 Sep 2023 11:49:30 +0200 Subject: [PATCH 104/263] CompatHelper: bump compat for Documenter to 1 for package docs, (keep existing compat) (#1641) * CompatHelper: bump compat for Documenter to 1 for package docs, (keep existing compat) * remove strict since it is removed and active by default * allow only v1 of Documenter.jl * ignore size threshold for API reference of Trixi.jl * try to fix size_threshold_ignore --------- Co-authored-by: CompatHelper Julia Co-authored-by: Hendrik Ranocha Co-authored-by: Hendrik Ranocha --- docs/Project.toml | 2 +- docs/make.jl | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/Project.toml b/docs/Project.toml index 9fc974d6f38..ffa86e0b9f7 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -13,7 +13,7 @@ Trixi2Vtk = "bc1476a1-1ca6-4cc3-950b-c312b255ff95" [compat] CairoMakie = "0.6, 0.7, 0.8, 0.9, 0.10" -Documenter = "0.27" +Documenter = "1" ForwardDiff = "0.10" HOHQMesh = "0.1, 0.2" LaTeXStrings = "1.2" diff --git a/docs/make.jl b/docs/make.jl index f882fcf1219..df8ac04be12 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -77,7 +77,7 @@ makedocs( # Specify modules for which docstrings should be shown modules = [Trixi, Trixi2Vtk], # Set sitename to Trixi.jl - sitename="Trixi.jl", + sitename = "Trixi.jl", # Provide additional formatting options format = Documenter.HTML( # Disable pretty URLs during manual testing @@ -85,7 +85,8 @@ makedocs( # Explicitly add favicon as asset assets = ["assets/favicon.ico"], # Set canonical URL to GitHub pages URL - canonical = "https://trixi-framework.github.io/Trixi.jl/stable" + canonical = "https://trixi-framework.github.io/Trixi.jl/stable", + size_threshold_ignore = ["reference-trixi.md"] ), # Explicitly specify documentation structure pages = [ @@ -124,9 +125,8 @@ makedocs( "Authors" => "authors.md", "Contributing" => "contributing.md", "Code of Conduct" => "code_of_conduct.md", - "License" => "license.md" - ], - strict = true # to make the GitHub action fail when doctests fail, see https://github.com/neuropsychology/Psycho.jl/issues/34 + "License" => "license.md", + ] ) deploydocs( From 7e228985a993e6e50249e8a13d9116db9f14e3bb Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Wed, 20 Sep 2023 08:03:13 +0200 Subject: [PATCH 105/263] Increase type stab, avoid allocs (#1642) * Increase type stab, avoid allocs * format * test seems no longer broken * only essentials Co-authored-by: Hendrik Ranocha --- src/solvers/dgsem_unstructured/dg_2d.jl | 4 ++-- test/test_threaded.jl | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/solvers/dgsem_unstructured/dg_2d.jl b/src/solvers/dgsem_unstructured/dg_2d.jl index 7b8dafdddd2..b12a96c4c31 100644 --- a/src/solvers/dgsem_unstructured/dg_2d.jl +++ b/src/solvers/dgsem_unstructured/dg_2d.jl @@ -357,9 +357,9 @@ function calc_boundary_flux_by_type!(cache, t, BCs::Tuple{}, BC_indices::Tuple{} nothing end -function calc_boundary_flux!(cache, t, boundary_condition, boundary_indexing, +function calc_boundary_flux!(cache, t, boundary_condition::BC, boundary_indexing, mesh::UnstructuredMesh2D, equations, - surface_integral, dg::DG) + surface_integral, dg::DG) where {BC} @unpack surface_flux_values = cache.elements @unpack element_id, element_side_id = cache.boundaries diff --git a/test/test_threaded.jl b/test/test_threaded.jl index 2337d73f30a..b13b5d0f5fc 100644 --- a/test/test_threaded.jl +++ b/test/test_threaded.jl @@ -312,11 +312,7 @@ Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) t = sol.t[end] u_ode = sol.u[end] du_ode = similar(u_ode) - if (Threads.nthreads() < 2) || (VERSION < v"1.9") - @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 5000 - else - @test_broken (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 5000 - end + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 5000 end end From 09441e1c0553cfc1e88f582354457233d4d872b2 Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Wed, 20 Sep 2023 09:15:27 +0200 Subject: [PATCH 106/263] Add Aqua.jl testing (#1628) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Aqua.jl testing * [deps] before [compat] * Skip ambiguities (too many false positives) and account for @jlchan being a 🏴‍☠️ * Bump Flux minimum version * Adapt test values * Add back pre-v0.14 version for Flux.jl to satisfy Julia v1.8 * Add Aqua badge * Explain piracy exceptions --------- Co-authored-by: Hendrik Ranocha --- README.md | 1 + docs/src/index.md | 1 + test/Project.toml | 20 +++++++++++--------- test/runtests.jl | 1 + test/test_aqua.jl | 18 ++++++++++++++++++ test/test_tree_2d_euler.jl | 2 +- 6 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 test/test_aqua.jl diff --git a/README.md b/README.md index c177ad2347f..673708d8b89 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ [![Build Status](https://github.com/trixi-framework/Trixi.jl/workflows/CI/badge.svg)](https://github.com/trixi-framework/Trixi.jl/actions?query=workflow%3ACI) [![Codecov](https://codecov.io/gh/trixi-framework/Trixi.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/trixi-framework/Trixi.jl) [![Coveralls](https://coveralls.io/repos/github/trixi-framework/Trixi.jl/badge.svg?branch=main)](https://coveralls.io/github/trixi-framework/Trixi.jl?branch=main) +[![Aqua QA](https://raw.githubusercontent.com/JuliaTesting/Aqua.jl/master/badge.svg)](https://github.com/JuliaTesting/Aqua.jl) [![License: MIT](https://img.shields.io/badge/License-MIT-success.svg)](https://opensource.org/licenses/MIT) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.3996439.svg)](https://doi.org/10.5281/zenodo.3996439) [![Downloads](https://shields.io/endpoint?url=https://pkgs.genieframework.com/api/v1/badge/Trixi)](https://pkgs.genieframework.com?packages=Trixi) diff --git a/docs/src/index.md b/docs/src/index.md index bb2afd1019f..9ffaee26c40 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -7,6 +7,7 @@ [![Build Status](https://github.com/trixi-framework/Trixi.jl/workflows/CI/badge.svg)](https://github.com/trixi-framework/Trixi.jl/actions?query=workflow%3ACI) [![Codecov](https://codecov.io/gh/trixi-framework/Trixi.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/trixi-framework/Trixi.jl) [![Coveralls](https://coveralls.io/repos/github/trixi-framework/Trixi.jl/badge.svg?branch=main)](https://coveralls.io/github/trixi-framework/Trixi.jl?branch=main) +[![Aqua QA](https://raw.githubusercontent.com/JuliaTesting/Aqua.jl/master/badge.svg)](https://github.com/JuliaTesting/Aqua.jl) [![License: MIT](https://img.shields.io/badge/License-MIT-success.svg)](https://opensource.org/licenses/MIT) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.3996439.svg)](https://doi.org/10.5281/zenodo.3996439) diff --git a/test/Project.toml b/test/Project.toml index 7115a19b441..c45be49a5d0 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,13 +1,5 @@ -[compat] -BSON = "0.3.3" -CairoMakie = "0.6, 0.7, 0.8, 0.9, 0.10" -Flux = "0.13 - 0.13.12" # TODO: Return to "0.13" once https://github.com/FluxML/Flux.jl/issues/2204 is resolved -ForwardDiff = "0.10" -MPI = "0.20" -OrdinaryDiffEq = "6.49.1" -Plots = "1.16" - [deps] +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" BSON = "fbb218c0-5317-5bc6-957e-2ee96dd4b1f0" CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" @@ -21,6 +13,16 @@ Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +[compat] +Aqua = "0.7" +BSON = "0.3.3" +CairoMakie = "0.6, 0.7, 0.8, 0.9, 0.10" +Flux = "0.13.15, 0.14" +ForwardDiff = "0.10" +MPI = "0.20" +OrdinaryDiffEq = "6.49.1" +Plots = "1.16" + [preferences.OrdinaryDiffEq] PrecompileAutoSpecialize = false PrecompileAutoSwitch = false diff --git a/test/runtests.jl b/test/runtests.jl index f1adbaaf1df..7e195fe7402 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -109,6 +109,7 @@ const TRIXI_NTHREADS = clamp(Sys.CPU_THREADS, 2, 3) @time if TRIXI_TEST == "all" || TRIXI_TEST == "misc_part2" include("test_special_elixirs.jl") + include("test_aqua.jl") end @time if TRIXI_TEST == "all" || TRIXI_TEST == "performance_specializations_part1" diff --git a/test/test_aqua.jl b/test/test_aqua.jl new file mode 100644 index 00000000000..f7ab4f545d0 --- /dev/null +++ b/test/test_aqua.jl @@ -0,0 +1,18 @@ +module TestAqua + +using Aqua +using Test +using Trixi + +include("test_trixi.jl") + +@timed_testset "Aqua.jl" begin + Aqua.test_all(Trixi, + ambiguities = false, + # exceptions necessary for adding a new method `StartUpDG.estimate_h` + # in src/solvers/dgmulti/sbp.jl + piracy = (treat_as_own = [Trixi.StartUpDG.RefElemData, + Trixi.StartUpDG.MeshData],)) +end + +end #module diff --git a/test/test_tree_2d_euler.jl b/test/test_tree_2d_euler.jl index e1e3ad32e7d..1b8a261a60d 100644 --- a/test/test_tree_2d_euler.jl +++ b/test/test_tree_2d_euler.jl @@ -140,7 +140,7 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") @trixi_testset "elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl"), l2 = [0.0845430093623868, 0.09271459184623232, 0.09271459184623232, 0.4377291875101709], - linf = [1.3608553480069898, 1.6822884847136004, 1.6822884847135997, 4.220147414536653], + linf = [1.3608553480069898, 1.6822884847136004, 1.6822884847135997, 4.2201475428867035], maxiters = 30, coverage_override = (maxiters=6,)) end From ea4e2cd0863893c16ff5cb2b0091e76c5a9b9b4e Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Wed, 20 Sep 2023 16:15:47 +0200 Subject: [PATCH 107/263] @muladd for Navier Stokes (#1644) * introduce muladd, update AMR tests * format --- .../compressible_navier_stokes_1d.jl | 38 +++++++++---- .../compressible_navier_stokes_2d.jl | 56 +++++++++++++------ .../compressible_navier_stokes_3d.jl | 47 +++++++++++----- test/test_parabolic_1d.jl | 8 +-- 4 files changed, 106 insertions(+), 43 deletions(-) diff --git a/src/equations/compressible_navier_stokes_1d.jl b/src/equations/compressible_navier_stokes_1d.jl index dca846cac1e..74d672ce7ae 100644 --- a/src/equations/compressible_navier_stokes_1d.jl +++ b/src/equations/compressible_navier_stokes_1d.jl @@ -1,3 +1,10 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + @doc raw""" CompressibleNavierStokesDiffusion1D(equations; mu, Pr, gradient_variables=GradientVariablesPrimitive()) @@ -77,7 +84,8 @@ w_2 = \frac{\rho v1}{p},\, w_3 = -\frac{\rho}{p} This code is experimental and may be changed or removed in any future release. """ struct CompressibleNavierStokesDiffusion1D{GradientVariables, RealT <: Real, - E <: AbstractCompressibleEulerEquations{1}} <: + E <: AbstractCompressibleEulerEquations{1} + } <: AbstractCompressibleNavierStokesDiffusion{1, 3} # TODO: parabolic # 1) For now save gamma and inv(gamma-1) again, but could potentially reuse them from the Euler equations @@ -109,7 +117,8 @@ function CompressibleNavierStokesDiffusion1D(equations::CompressibleEulerEquatio CompressibleNavierStokesDiffusion1D{typeof(gradient_variables), typeof(gamma), typeof(equations)}(gamma, inv_gamma_minus_one, μ, Pr, kappa, - equations, gradient_variables) + equations, + gradient_variables) end # TODO: parabolic @@ -263,7 +272,8 @@ end u_inner, orientation::Integer, direction, - x, t, + x, + t, operator_type::Gradient, equations::CompressibleNavierStokesDiffusion1D{ GradientVariablesPrimitive @@ -278,7 +288,8 @@ end u_inner, orientation::Integer, direction, - x, t, + x, + t, operator_type::Divergence, equations::CompressibleNavierStokesDiffusion1D{ GradientVariablesPrimitive @@ -299,7 +310,8 @@ end u_inner, orientation::Integer, direction, - x, t, + x, + t, operator_type::Gradient, equations::CompressibleNavierStokesDiffusion1D{ GradientVariablesPrimitive @@ -316,7 +328,8 @@ end u_inner, orientation::Integer, direction, - x, t, + x, + t, operator_type::Divergence, equations::CompressibleNavierStokesDiffusion1D{ GradientVariablesPrimitive @@ -337,7 +350,8 @@ end w_inner, orientation::Integer, direction, - x, t, + x, + t, operator_type::Gradient, equations::CompressibleNavierStokesDiffusion1D{ GradientVariablesEntropy @@ -354,7 +368,8 @@ end w_inner, orientation::Integer, direction, - x, t, + x, + t, operator_type::Divergence, equations::CompressibleNavierStokesDiffusion1D{ GradientVariablesEntropy @@ -374,7 +389,8 @@ end w_inner, orientation::Integer, direction, - x, t, + x, + t, operator_type::Gradient, equations::CompressibleNavierStokesDiffusion1D{ GradientVariablesEntropy @@ -394,10 +410,12 @@ end w_inner, orientation::Integer, direction, - x, t, + x, + t, operator_type::Divergence, equations::CompressibleNavierStokesDiffusion1D{ GradientVariablesEntropy }) return SVector(flux_inner[1], flux_inner[2], flux_inner[3]) end +end # @muladd diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index f762fe5d5ee..b10ffa3b9d3 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -1,3 +1,10 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + @doc raw""" CompressibleNavierStokesDiffusion2D(equations; mu, Pr, gradient_variables=GradientVariablesPrimitive()) @@ -77,7 +84,8 @@ w_2 = \frac{\rho v_1}{p},\, w_3 = \frac{\rho v_2}{p},\, w_4 = -\frac{\rho}{p} This code is experimental and may be changed or removed in any future release. """ struct CompressibleNavierStokesDiffusion2D{GradientVariables, RealT <: Real, - E <: AbstractCompressibleEulerEquations{2}} <: + E <: AbstractCompressibleEulerEquations{2} + } <: AbstractCompressibleNavierStokesDiffusion{2, 4} # TODO: parabolic # 1) For now save gamma and inv(gamma-1) again, but could potentially reuse them from the Euler equations @@ -109,7 +117,8 @@ function CompressibleNavierStokesDiffusion2D(equations::CompressibleEulerEquatio CompressibleNavierStokesDiffusion2D{typeof(gradient_variables), typeof(gamma), typeof(equations)}(gamma, inv_gamma_minus_one, μ, Pr, kappa, - equations, gradient_variables) + equations, + gradient_variables) end # TODO: parabolic @@ -301,12 +310,14 @@ end <:Adiabatic})(flux_inner, u_inner, normal::AbstractVector, - x, t, + x, + t, operator_type::Gradient, equations::CompressibleNavierStokesDiffusion2D{ GradientVariablesPrimitive }) - v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, + v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, + t, equations) return SVector(u_inner[1], v1, v2, u_inner[4]) end @@ -315,7 +326,8 @@ end <:Adiabatic})(flux_inner, u_inner, normal::AbstractVector, - x, t, + x, + t, operator_type::Divergence, equations::CompressibleNavierStokesDiffusion2D{ GradientVariablesPrimitive @@ -324,7 +336,8 @@ end normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x, t, equations) - v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, + v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, + t, equations) _, tau_1n, tau_2n, _ = flux_inner # extract fluxes for 2nd and 3rd equations normal_energy_flux = v1 * tau_1n + v2 * tau_2n + normal_heat_flux @@ -335,12 +348,14 @@ end <:Isothermal})(flux_inner, u_inner, normal::AbstractVector, - x, t, + x, + t, operator_type::Gradient, equations::CompressibleNavierStokesDiffusion2D{ GradientVariablesPrimitive }) - v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, + v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, + t, equations) T = boundary_condition.boundary_condition_heat_flux.boundary_value_function(x, t, equations) @@ -351,7 +366,8 @@ end <:Isothermal})(flux_inner, u_inner, normal::AbstractVector, - x, t, + x, + t, operator_type::Divergence, equations::CompressibleNavierStokesDiffusion2D{ GradientVariablesPrimitive @@ -371,12 +387,14 @@ end <:Adiabatic})(flux_inner, w_inner, normal::AbstractVector, - x, t, + x, + t, operator_type::Gradient, equations::CompressibleNavierStokesDiffusion2D{ GradientVariablesEntropy }) - v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, + v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, + t, equations) negative_rho_inv_p = w_inner[4] # w_4 = -rho / p return SVector(w_inner[1], -v1 * negative_rho_inv_p, -v2 * negative_rho_inv_p, @@ -388,7 +406,8 @@ end <:Adiabatic})(flux_inner, w_inner, normal::AbstractVector, - x, t, + x, + t, operator_type::Divergence, equations::CompressibleNavierStokesDiffusion2D{ GradientVariablesEntropy @@ -396,7 +415,8 @@ end normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x, t, equations) - v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, + v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, + t, equations) _, tau_1n, tau_2n, _ = flux_inner # extract fluxes for 2nd and 3rd equations normal_energy_flux = v1 * tau_1n + v2 * tau_2n + normal_heat_flux @@ -407,12 +427,14 @@ end <:Isothermal})(flux_inner, w_inner, normal::AbstractVector, - x, t, + x, + t, operator_type::Gradient, equations::CompressibleNavierStokesDiffusion2D{ GradientVariablesEntropy }) - v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, + v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, + t, equations) T = boundary_condition.boundary_condition_heat_flux.boundary_value_function(x, t, equations) @@ -426,10 +448,12 @@ end <:Isothermal})(flux_inner, w_inner, normal::AbstractVector, - x, t, + x, + t, operator_type::Divergence, equations::CompressibleNavierStokesDiffusion2D{ GradientVariablesEntropy }) return SVector(flux_inner[1], flux_inner[2], flux_inner[3], flux_inner[4]) end +end # @muladd diff --git a/src/equations/compressible_navier_stokes_3d.jl b/src/equations/compressible_navier_stokes_3d.jl index 166b53bf615..de2cad99ea8 100644 --- a/src/equations/compressible_navier_stokes_3d.jl +++ b/src/equations/compressible_navier_stokes_3d.jl @@ -1,3 +1,10 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + @doc raw""" CompressibleNavierStokesDiffusion3D(equations; mu, Pr, gradient_variables=GradientVariablesPrimitive()) @@ -77,7 +84,8 @@ w_2 = \frac{\rho v_1}{p},\, w_3 = \frac{\rho v_2}{p},\, w_4 = \frac{\rho v_3}{p} This code is experimental and may be changed or removed in any future release. """ struct CompressibleNavierStokesDiffusion3D{GradientVariables, RealT <: Real, - E <: AbstractCompressibleEulerEquations{3}} <: + E <: AbstractCompressibleEulerEquations{3} + } <: AbstractCompressibleNavierStokesDiffusion{3, 5} # TODO: parabolic # 1) For now save gamma and inv(gamma-1) again, but could potentially reuse them from the Euler equations @@ -109,7 +117,8 @@ function CompressibleNavierStokesDiffusion3D(equations::CompressibleEulerEquatio CompressibleNavierStokesDiffusion3D{typeof(gradient_variables), typeof(gamma), typeof(equations)}(gamma, inv_gamma_minus_one, μ, Pr, kappa, - equations, gradient_variables) + equations, + gradient_variables) end # TODO: parabolic @@ -319,9 +328,12 @@ end @inline function vorticity(u, gradients, equations::CompressibleNavierStokesDiffusion3D) # Ensure that we have velocity `gradients` by way of the `convert_gradient_variables` function. - _, dv1dx, dv2dx, dv3dx, _ = convert_derivative_to_primitive(u, gradients[1], equations) - _, dv1dy, dv2dy, dv3dy, _ = convert_derivative_to_primitive(u, gradients[2], equations) - _, dv1dz, dv2dz, dv3dz, _ = convert_derivative_to_primitive(u, gradients[3], equations) + _, dv1dx, dv2dx, dv3dx, _ = convert_derivative_to_primitive(u, gradients[1], + equations) + _, dv1dy, dv2dy, dv3dy, _ = convert_derivative_to_primitive(u, gradients[2], + equations) + _, dv1dz, dv2dz, dv3dz, _ = convert_derivative_to_primitive(u, gradients[3], + equations) return SVector(dv3dy - dv2dz, dv1dz - dv3dx, dv2dx - dv1dy) end @@ -330,7 +342,8 @@ end <:Adiabatic})(flux_inner, u_inner, normal::AbstractVector, - x, t, + x, + t, operator_type::Gradient, equations::CompressibleNavierStokesDiffusion3D{ GradientVariablesPrimitive @@ -345,7 +358,8 @@ end <:Adiabatic})(flux_inner, u_inner, normal::AbstractVector, - x, t, + x, + t, operator_type::Divergence, equations::CompressibleNavierStokesDiffusion3D{ GradientVariablesPrimitive @@ -367,7 +381,8 @@ end <:Isothermal})(flux_inner, u_inner, normal::AbstractVector, - x, t, + x, + t, operator_type::Gradient, equations::CompressibleNavierStokesDiffusion3D{ GradientVariablesPrimitive @@ -384,7 +399,8 @@ end <:Isothermal})(flux_inner, u_inner, normal::AbstractVector, - x, t, + x, + t, operator_type::Divergence, equations::CompressibleNavierStokesDiffusion3D{ GradientVariablesPrimitive @@ -404,7 +420,8 @@ end <:Adiabatic})(flux_inner, w_inner, normal::AbstractVector, - x, t, + x, + t, operator_type::Gradient, equations::CompressibleNavierStokesDiffusion3D{ GradientVariablesEntropy @@ -422,7 +439,8 @@ end <:Adiabatic})(flux_inner, w_inner, normal::AbstractVector, - x, t, + x, + t, operator_type::Divergence, equations::CompressibleNavierStokesDiffusion3D{ GradientVariablesEntropy @@ -443,7 +461,8 @@ end <:Isothermal})(flux_inner, w_inner, normal::AbstractVector, - x, t, + x, + t, operator_type::Gradient, equations::CompressibleNavierStokesDiffusion3D{ GradientVariablesEntropy @@ -463,7 +482,8 @@ end <:Isothermal})(flux_inner, w_inner, normal::AbstractVector, - x, t, + x, + t, operator_type::Divergence, equations::CompressibleNavierStokesDiffusion3D{ GradientVariablesEntropy @@ -471,3 +491,4 @@ end return SVector(flux_inner[1], flux_inner[2], flux_inner[3], flux_inner[4], flux_inner[5]) end +end # @muladd diff --git a/test/test_parabolic_1d.jl b/test/test_parabolic_1d.jl index 3c2b8855ce8..f00138c698c 100644 --- a/test/test_parabolic_1d.jl +++ b/test/test_parabolic_1d.jl @@ -80,8 +80,8 @@ isdir(outdir) && rm(outdir, recursive=true) @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", "elixir_navierstokes_convergence_walls_amr.jl"), equations_parabolic = CompressibleNavierStokesDiffusion1D(equations, mu=mu(), Prandtl=prandtl_number()), - l2 = [2.527877257772131e-5, 2.5539911566937718e-5, 0.0001211860451244785], - linf = [0.00014663867588948776, 0.00019422448348348196, 0.0009556439394007299] + l2 = [2.5278824700860636e-5, 2.5540078777006958e-5, 0.00012118655083858043], + linf = [0.0001466387075579334, 0.00019422427462629705, 0.0009556446847707178] ) end @@ -90,8 +90,8 @@ isdir(outdir) && rm(outdir, recursive=true) equations_parabolic = CompressibleNavierStokesDiffusion1D(equations, mu=mu(), Prandtl=prandtl_number(), gradient_variables = GradientVariablesEntropy()), - l2 = [2.4593699163175966e-5, 2.392863645712634e-5, 0.00011252526651714956], - linf = [0.00011850555445525046, 0.0001898777490968537, 0.0009597561467877824] + l2 = [2.459359632523962e-5, 2.3928390718460263e-5, 0.00011252414117082376], + linf = [0.0001185052018830568, 0.00018987717854305393, 0.0009597503607920999] ) end end From 3bda0519dbd084937cd05eb339a4d35b1a6f4d9f Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Fri, 22 Sep 2023 13:14:40 +0200 Subject: [PATCH 108/263] Print leaf cells for tree meshes (#1645) --- src/meshes/tree_mesh.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/meshes/tree_mesh.jl b/src/meshes/tree_mesh.jl index 93ba982bce9..05699d17d16 100644 --- a/src/meshes/tree_mesh.jl +++ b/src/meshes/tree_mesh.jl @@ -199,6 +199,7 @@ function Base.show(io::IO, ::MIME"text/plain", "length" => mesh.tree.length_level_0, "periodicity" => mesh.tree.periodicity, "current #cells" => mesh.tree.length, + "#leaf-cells" => count_leaf_cells(mesh.tree), "maximum #cells" => mesh.tree.capacity, ] summary_box(io, "TreeMesh{" * string(NDIMS) * ", " * string(TreeType) * "}", From 5b203620b2b2b5eb009c2076a43d99b42f37f852 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 22 Sep 2023 14:40:55 +0200 Subject: [PATCH 109/263] set version to v0.5.44 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index d134a8e548b..fe062b1afaf 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.5.44-pre" +version = "0.5.44" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 0b4bf985846388b8cfee8dc4a2ce462b20b5d533 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 22 Sep 2023 14:41:17 +0200 Subject: [PATCH 110/263] set development version to v0.5.45-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index fe062b1afaf..69b2e872b6f 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.5.44" +version = "0.5.45-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From dc9b89fc48e2239dae1108d0719496d956ec19b3 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 26 Sep 2023 09:04:46 +0200 Subject: [PATCH 111/263] bump compat for SciMLBase.jl to v2 (#1647) --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 69b2e872b6f..d318389a6d2 100644 --- a/Project.toml +++ b/Project.toml @@ -71,7 +71,7 @@ PrecompileTools = "1.1" RecipesBase = "1.1" Reexport = "1.0" Requires = "1.1" -SciMLBase = "1.90" +SciMLBase = "1.90, 2" Setfield = "0.8, 1" SimpleUnPack = "1.1" StartUpDG = "0.17" From e45700d8453e848e069739ea3dee51d721185f71 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 20:48:04 +0200 Subject: [PATCH 112/263] Bump crate-ci/typos from 1.16.9 to 1.16.15 (#1652) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.16.9 to 1.16.15. - [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.16.9...v1.16.15) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-type: direct:production update-type: version-update:semver-patch ... 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 a06121e7ca1..e608dc8d7c1 100644 --- a/.github/workflows/SpellCheck.yml +++ b/.github/workflows/SpellCheck.yml @@ -10,4 +10,4 @@ jobs: - name: Checkout Actions Repository uses: actions/checkout@v3 - name: Check spelling - uses: crate-ci/typos@v1.16.9 + uses: crate-ci/typos@v1.16.15 From 0cf3e6768684f20e025411e5a10e4c6f41c928c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 22:17:39 +0200 Subject: [PATCH 113/263] Bump actions/checkout from 3 to 4 (#1653) Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Michael Schlottke-Lakemper --- .github/workflows/CacheNotebooks.yml | 2 +- .github/workflows/DocPreviewCleanup.yml | 2 +- .github/workflows/Documenter.yml | 2 +- .github/workflows/FormatCheck.yml | 2 +- .github/workflows/Invalidations.yml | 4 ++-- .github/workflows/ReviewChecklist.yml | 2 +- .github/workflows/SpellCheck.yml | 2 +- .github/workflows/benchmark.yml | 2 +- .github/workflows/ci.yml | 4 ++-- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/CacheNotebooks.yml b/.github/workflows/CacheNotebooks.yml index c8599d13f26..f89560d8158 100644 --- a/.github/workflows/CacheNotebooks.yml +++ b/.github/workflows/CacheNotebooks.yml @@ -11,7 +11,7 @@ jobs: steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Checkout caching branch - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: tutorial_notebooks diff --git a/.github/workflows/DocPreviewCleanup.yml b/.github/workflows/DocPreviewCleanup.yml index 66d0b342b2e..0850369c9cc 100644 --- a/.github/workflows/DocPreviewCleanup.yml +++ b/.github/workflows/DocPreviewCleanup.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout gh-pages branch - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: gh-pages diff --git a/.github/workflows/Documenter.yml b/.github/workflows/Documenter.yml index 6b557960c89..129c41a3b5c 100644 --- a/.github/workflows/Documenter.yml +++ b/.github/workflows/Documenter.yml @@ -33,7 +33,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: julia-actions/setup-julia@v1 with: version: '1.9' diff --git a/.github/workflows/FormatCheck.yml b/.github/workflows/FormatCheck.yml index 628d938dd76..ce46360b832 100644 --- a/.github/workflows/FormatCheck.yml +++ b/.github/workflows/FormatCheck.yml @@ -20,7 +20,7 @@ jobs: with: version: ${{ matrix.julia-version }} - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install JuliaFormatter and format # This will use the latest version by default but you can set the version like so: # diff --git a/.github/workflows/Invalidations.yml b/.github/workflows/Invalidations.yml index ba81f83e0ad..18048d26be8 100644 --- a/.github/workflows/Invalidations.yml +++ b/.github/workflows/Invalidations.yml @@ -19,12 +19,12 @@ jobs: - uses: julia-actions/setup-julia@v1 with: version: '1' - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: julia-actions/julia-buildpkg@v1 - uses: julia-actions/julia-invalidations@v1 id: invs_pr - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.event.repository.default_branch }} - uses: julia-actions/julia-buildpkg@v1 diff --git a/.github/workflows/ReviewChecklist.yml b/.github/workflows/ReviewChecklist.yml index 959a04752d7..d8854411804 100644 --- a/.github/workflows/ReviewChecklist.yml +++ b/.github/workflows/ReviewChecklist.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Add review checklist uses: trixi-framework/add-pr-review-checklist@v1 with: diff --git a/.github/workflows/SpellCheck.yml b/.github/workflows/SpellCheck.yml index e608dc8d7c1..eae6d8e0be9 100644 --- a/.github/workflows/SpellCheck.yml +++ b/.github/workflows/SpellCheck.yml @@ -8,6 +8,6 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Actions Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Check spelling uses: crate-ci/typos@v1.16.15 diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index c5c95558c8c..2ea30d6fddb 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -15,7 +15,7 @@ jobs: arch: - x64 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - run: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4790f93d913..cf8107736e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -101,7 +101,7 @@ jobs: arch: x64 trixi_test: threaded steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: julia-actions/setup-julia@v1 with: version: ${{ matrix.version }} @@ -175,7 +175,7 @@ jobs: # Instead, we use the more tedious approach described above. # At first, we check out the repository and download all artifacts # (and list files for debugging). - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/download-artifact@v3 - run: ls -R # Next, we merge the individual coverage files and upload From 9e41775351ddf1d92b32bbd6c685536ee004466c Mon Sep 17 00:00:00 2001 From: Jesse Chan <1156048+jlchan@users.noreply.github.com> Date: Mon, 2 Oct 2023 01:16:37 -0500 Subject: [PATCH 114/263] Add updates and "parabolic terms" row to overview.md (#1651) * update overview.md * add note on parabolic terms --- docs/src/overview.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/src/overview.md b/docs/src/overview.md index 51a6272ae8e..9cd11a5df93 100644 --- a/docs/src/overview.md +++ b/docs/src/overview.md @@ -55,14 +55,15 @@ different features on different mesh types. | Element type | line, square, cube | line, quadᵃ, hexᵃ | quadᵃ | quadᵃ, hexᵃ | simplex, quadᵃ, hexᵃ | | Adaptive mesh refinement | ✅ | ❌ | ❌ | ✅ | ❌ | [`AMRCallback`](@ref) | Solver type | [`DGSEM`](@ref) | [`DGSEM`](@ref) | [`DGSEM`](@ref) | [`DGSEM`](@ref) | [`DGMulti`](@ref) | -| Domain | hypercube | mapped hypercube | arbitrary | arbitrary | arbitraryᵇ | +| Domain | hypercube | mapped hypercube | arbitrary | arbitrary | arbitrary | | Weak form | ✅ | ✅ | ✅ | ✅ | ✅ | [`VolumeIntegralWeakForm`](@ref) | Flux differencing | ✅ | ✅ | ✅ | ✅ | ✅ | [`VolumeIntegralFluxDifferencing`](@ref) | Shock capturing | ✅ | ✅ | ✅ | ✅ | ❌ | [`VolumeIntegralShockCapturingHG`](@ref) | Nonconservative equations | ✅ | ✅ | ✅ | ✅ | ✅ | e.g., GLM MHD or shallow water equations +| Parabolic termsᵇ | ✅ | ✅ | ❌ | ✅ | ✅ | e.g., [`CompressibleNavierStokesDiffusion2D`](@ref) ᵃ: quad = quadrilateral, hex = hexahedron -ᵇ: curved meshes supported for `SBP` and `GaussSBP` approximation types for `VolumeIntegralFluxDifferencing` solvers on quadrilateral and hexahedral `DGMultiMesh`es (non-conservative terms not yet supported) +ᵇ: Parabolic terms do not currently support adaptivity. ## Time integration methods From 7ba1f2ef98768f297442b026e4acf168bad73ff8 Mon Sep 17 00:00:00 2001 From: Benjamin Bolm <74359358+bennibolm@users.noreply.github.com> Date: Wed, 4 Oct 2023 10:00:36 +0200 Subject: [PATCH 115/263] Fix n_elements in resizing containers (#1655) --- src/time_integration/methods_SSP.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/time_integration/methods_SSP.jl b/src/time_integration/methods_SSP.jl index a0ed889968a..33eb6ebf926 100644 --- a/src/time_integration/methods_SSP.jl +++ b/src/time_integration/methods_SSP.jl @@ -226,7 +226,9 @@ function Base.resize!(integrator::SimpleIntegratorSSP, new_size) resize!(integrator.r0, new_size) # Resize container - resize!(integrator.p, new_size) + # new_size = n_variables * n_nodes^n_dims * n_elements + n_elements = nelements(integrator.p.solver, integrator.p.cache) + resize!(integrator.p, n_elements) end function Base.resize!(semi::AbstractSemidiscretization, new_size) From e245dc2638e22a0ec396786ad86992f4de189192 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Wed, 4 Oct 2023 16:07:09 +0200 Subject: [PATCH 116/263] Use Analysis CB (#1650) * Use Analysis CB * Apply suggestions from code review --------- Co-authored-by: Hendrik Ranocha --- examples/tree_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tree_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl b/examples/tree_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl index 81e48737e79..3314343ccca 100644 --- a/examples/tree_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl +++ b/examples/tree_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl @@ -66,7 +66,7 @@ summary_callback = SummaryCallback() alive_callback = AliveCallback(alive_interval=100) analysis_interval = 100 analysis_callback = AnalysisCallback(semi, interval=analysis_interval) -callbacks = CallbackSet(summary_callback, alive_callback) +callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation From 3f4b0f445493df3cf122e20e7a8d71b1f7def686 Mon Sep 17 00:00:00 2001 From: Jesse Chan <1156048+jlchan@users.noreply.github.com> Date: Thu, 5 Oct 2023 00:32:50 -0500 Subject: [PATCH 117/263] add comments on sign flips (#1657) --- src/solvers/dgsem_p4est/dg_2d.jl | 5 +++++ src/solvers/dgsem_p4est/dg_3d.jl | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/solvers/dgsem_p4est/dg_2d.jl b/src/solvers/dgsem_p4est/dg_2d.jl index a665aa4b19d..36624f2ce8a 100644 --- a/src/solvers/dgsem_p4est/dg_2d.jl +++ b/src/solvers/dgsem_p4est/dg_2d.jl @@ -501,6 +501,11 @@ 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 + # "mortar_fluxes_to_elements!" instead. mortar_fluxes_to_elements!(surface_flux_values, mesh, equations, mortar_l2, dg, cache, mortar, fstar, u_buffer) diff --git a/src/solvers/dgsem_p4est/dg_3d.jl b/src/solvers/dgsem_p4est/dg_3d.jl index dc69329474f..4c0845ba9af 100644 --- a/src/solvers/dgsem_p4est/dg_3d.jl +++ b/src/solvers/dgsem_p4est/dg_3d.jl @@ -580,6 +580,11 @@ 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 + # "mortar_fluxes_to_elements!" instead. mortar_fluxes_to_elements!(surface_flux_values, mesh, equations, mortar_l2, dg, cache, mortar, fstar, u_buffer, fstar_tmp) From bd98469a827b0d0d5a9be50b95e841738ef85c6c Mon Sep 17 00:00:00 2001 From: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Date: Thu, 5 Oct 2023 07:37:05 +0200 Subject: [PATCH 118/263] add docs of set_libraries! for setting custom HDF5 library (#1658) --- docs/src/parallelization.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/src/parallelization.md b/docs/src/parallelization.md index e55471bb256..610aa2cbd95 100644 --- a/docs/src/parallelization.md +++ b/docs/src/parallelization.md @@ -186,6 +186,11 @@ julia> set_preferences!( "libhdf5" => "/path/to/your/libhdf5.so", "libhdf5_hl" => "/path/to/your/libhdf5_hl.so", force = true) ``` +Alternatively, with HDF5.jl v0.17.1 or higher you can use +```julia +julia> using HDF5 +julia> HDF5.API.set_libraries!("/path/to/your/libhdf5.so", "/path/to/your/libhdf5_hl.so") +``` For more information see also the [documentation of HDF5.jl](https://juliaio.github.io/HDF5.jl/stable/mpi/). In total, you should have a file called LocalPreferences.toml in the project directory that contains a section From adce486c11fb20adc4802c959f3b63be3df6bb8a Mon Sep 17 00:00:00 2001 From: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> Date: Thu, 5 Oct 2023 07:39:33 +0200 Subject: [PATCH 119/263] Fix mapping string in `StructuredMesh` (#1654) * Fix mapping string in `StructuredMesh` * `eval` full string to avoid using `Meta.parseall` * Make `mapping_as_string` consistent --------- Co-authored-by: Hendrik Ranocha --- src/meshes/mesh_io.jl | 23 +++++++++-------------- src/meshes/structured_mesh.jl | 19 ++++++++++++------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/meshes/mesh_io.jl b/src/meshes/mesh_io.jl index b9895e7d454..92e38ce1bf3 100644 --- a/src/meshes/mesh_io.jl +++ b/src/meshes/mesh_io.jl @@ -263,32 +263,27 @@ function load_mesh_serial(mesh_file::AbstractString; n_cells_max, RealT) size = Tuple(size_) # TODO: `@eval` is evil - # A temporary workaround to evaluate the code that defines the domain mapping in a local scope. - # This prevents errors when multiple restart elixirs are executed in one session, where one - # defines `mapping` as a variable, while the other defines it as a function. # # This should be replaced with something more robust and secure, # see https://github.com/trixi-framework/Trixi.jl/issues/541). - expr = Meta.parse(mapping_as_string) - if expr.head == :toplevel - expr.head = :block - end - if ndims == 1 - mapping = @eval function (xi) - $expr + mapping = eval(Meta.parse("""function (xi) + $mapping_as_string mapping(xi) end + """)) elseif ndims == 2 - mapping = @eval function (xi, eta) - $expr + mapping = eval(Meta.parse("""function (xi, eta) + $mapping_as_string mapping(xi, eta) end + """)) else # ndims == 3 - mapping = @eval function (xi, eta, zeta) - $expr + mapping = eval(Meta.parse("""function (xi, eta, zeta) + $mapping_as_string mapping(xi, eta, zeta) end + """)) end mesh = StructuredMesh(size, mapping; RealT = RealT, unsaved_changes = false, diff --git a/src/meshes/structured_mesh.jl b/src/meshes/structured_mesh.jl index df067db833d..553aabbbc20 100644 --- a/src/meshes/structured_mesh.jl +++ b/src/meshes/structured_mesh.jl @@ -96,13 +96,17 @@ function StructuredMesh(cells_per_dimension, faces::Tuple; RealT = Float64, # Collect definitions of face functions in one string (separated by semicolons) face2substring(face) = code_string(face, ntuple(_ -> Float64, NDIMS - 1)) - join_semicolon(strings) = join(strings, "; ") + join_newline(strings) = join(strings, "\n") - faces_definition = faces .|> face2substring .|> string |> join_semicolon + faces_definition = faces .|> face2substring .|> string |> join_newline # Include faces definition in `mapping_as_string` to allow for evaluation # without knowing the face functions - mapping_as_string = "$faces_definition; faces = $(string(faces)); mapping = transfinite_mapping(faces)" + mapping_as_string = """ + $faces_definition + faces = $(string(faces)) + mapping = transfinite_mapping(faces) + """ return StructuredMesh(cells_per_dimension, mapping; RealT = RealT, periodicity = periodicity, @@ -123,13 +127,14 @@ Create a StructuredMesh that represents a uncurved structured mesh with a rectan """ function StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max; periodicity = true) - NDIMS = length(cells_per_dimension) RealT = promote_type(eltype(coordinates_min), eltype(coordinates_max)) mapping = coordinates2mapping(coordinates_min, coordinates_max) - mapping_as_string = "coordinates_min = $coordinates_min; " * - "coordinates_max = $coordinates_max; " * - "mapping = coordinates2mapping(coordinates_min, coordinates_max)" + mapping_as_string = """ + coordinates_min = $coordinates_min + coordinates_max = $coordinates_max + mapping = coordinates2mapping(coordinates_min, coordinates_max) + """ return StructuredMesh(cells_per_dimension, mapping; RealT = RealT, periodicity = periodicity, mapping_as_string = mapping_as_string) From 67ddfbba006f40334e415e1bb4e60aea413d8388 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Thu, 5 Oct 2023 15:52:49 +0200 Subject: [PATCH 120/263] Avoid allocations due to usage of broadcasting operation (#1656) * Avoid allocations due to usage of broadcasting operation * Comments & correcting copy-paste error --------- Co-authored-by: Hendrik Ranocha --- src/solvers/dgmulti/dg.jl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/solvers/dgmulti/dg.jl b/src/solvers/dgmulti/dg.jl index bc76aa1a9d2..182a486dce5 100644 --- a/src/solvers/dgmulti/dg.jl +++ b/src/solvers/dgmulti/dg.jl @@ -302,7 +302,12 @@ function calc_volume_integral!(du, u, mesh::DGMultiMesh, @threaded for e in eachelement(mesh, dg, cache) flux_values = local_values_threaded[Threads.threadid()] for i in eachdim(mesh) - flux_values .= flux.(view(u_values, :, e), i, equations) + # Here, the broadcasting operation does allocate + #flux_values .= flux.(view(u_values, :, e), i, equations) + # Use loop instead + for j in eachindex(flux_values) + flux_values[j] = flux(u_values[j, e], i, equations) + end for j in eachdim(mesh) apply_to_each_field(mul_by_accum!(weak_differentiation_matrices[j], dxidxhatj[i, j][1, e]), @@ -327,6 +332,7 @@ function calc_volume_integral!(du, u, mesh::DGMultiMesh{NDIMS, <:NonAffine}, @threaded for e in eachelement(mesh, dg, cache) flux_values = cache.flux_threaded[Threads.threadid()] for i in eachdim(mesh) + # Here, the broadcasting operation does not allocate flux_values[i] .= flux.(view(u_values, :, e), i, equations) end From 22856f4af27a06d38935d4f373a46f3492a4bf08 Mon Sep 17 00:00:00 2001 From: Ahmad Peyvan <115842305+apey236@users.noreply.github.com> Date: Sun, 8 Oct 2023 03:22:36 -0400 Subject: [PATCH 121/263] Adding primitive variable Dirichlet BCs for Navier-Stokes parabolic terms for `P4estMesh{2}` (#1553) * Adding parabolic Dirichlet boundary condition example * add test * Correcting the format * Update src/equations/compressible_navier_stokes_2d.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Update src/equations/compressible_navier_stokes_2d.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> --------- Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> Co-authored-by: Hendrik Ranocha --- ...ir_navierstokes_convergence_nonperiodic.jl | 215 ++++++++++++++++++ .../compressible_navier_stokes_2d.jl | 29 +++ test/test_parabolic_2d.jl | 8 + 3 files changed, 252 insertions(+) create mode 100644 examples/p4est_2d_dgsem/elixir_navierstokes_convergence_nonperiodic.jl diff --git a/examples/p4est_2d_dgsem/elixir_navierstokes_convergence_nonperiodic.jl b/examples/p4est_2d_dgsem/elixir_navierstokes_convergence_nonperiodic.jl new file mode 100644 index 00000000000..935f132ba4b --- /dev/null +++ b/examples/p4est_2d_dgsem/elixir_navierstokes_convergence_nonperiodic.jl @@ -0,0 +1,215 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal compressible Navier-Stokes equations + +prandtl_number() = 0.72 +mu() = 0.01 + +equations = CompressibleEulerEquations2D(1.4) +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu=mu(), Prandtl=prandtl_number(), + gradient_variables=GradientVariablesPrimitive()) + +# 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, + volume_integral=VolumeIntegralWeakForm()) + +coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) +coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) + +trees_per_dimension = (4, 4) +mesh = P4estMesh(trees_per_dimension, + polydeg=3, initial_refinement_level=2, + coordinates_min=coordinates_min, coordinates_max=coordinates_max, + periodicity=(false, false)) + +# Note: the initial condition cannot be specialized to `CompressibleNavierStokesDiffusion2D` +# since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesDiffusion2D`) +# and by the initial condition (which passes in `CompressibleEulerEquations2D`). +# This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) +function initial_condition_navier_stokes_convergence_test(x, t, equations) + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0)) ) * cos(pi_t) + v2 = v1 + p = rho^2 + + return prim2cons(SVector(rho, v1, v2, p), equations) +end + +@inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) + y = x[2] + + # TODO: parabolic + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + mu_ = mu() + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) + rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) + rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) + rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + + v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) + v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_y = sin(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_xy = pi * cos(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_yy = (sin(pi_x) * ( 2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) + - A * A * log(y + 2.0) * exp(-A * (y - 1.0)) + - (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_xx = v1_xx + v2_xy = v1_xy + v2_yy = v1_yy + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y + + # Note this simplifies slightly because the ansatz assumes that v1 = v2 + E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) + E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x + E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one / Pr + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y + + # x-momentum equation + du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y + # stress tensor from x-direction + - 4.0 / 3.0 * v1_xx * mu_ + + 2.0 / 3.0 * v2_xy * mu_ + - v1_yy * mu_ + - v2_xy * mu_ ) + # y-momentum equation + du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y + # stress tensor from y-direction + - v1_xy * mu_ + - v2_xx * mu_ + - 4.0 / 3.0 * v2_yy * mu_ + + 2.0 / 3.0 * v1_xy * mu_ ) + # total energy equation + du4 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) + # stress tensor and temperature gradient terms from x-direction + - 4.0 / 3.0 * v1_xx * v1 * mu_ + + 2.0 / 3.0 * v2_xy * v1 * mu_ + - 4.0 / 3.0 * v1_x * v1_x * mu_ + + 2.0 / 3.0 * v2_y * v1_x * mu_ + - v1_xy * v2 * mu_ + - v2_xx * v2 * mu_ + - v1_y * v2_x * mu_ + - v2_x * v2_x * mu_ + - T_const * inv_rho_cubed * ( p_xx * rho * rho + - 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x + - p * rho * rho_xx ) * mu_ + # stress tensor and temperature gradient terms from y-direction + - v1_yy * v1 * mu_ + - v2_xy * v1 * mu_ + - v1_y * v1_y * mu_ + - v2_x * v1_y * mu_ + - 4.0 / 3.0 * v2_yy * v2 * mu_ + + 2.0 / 3.0 * v1_xy * v2 * mu_ + - 4.0 / 3.0 * v2_y * v2_y * mu_ + + 2.0 / 3.0 * v1_x * v2_y * mu_ + - T_const * inv_rho_cubed * ( p_yy * rho * rho + - 2.0 * p_y * rho * rho_y + + 2.0 * p * rho_y * rho_y + - p * rho * rho_yy ) * mu_ ) + + return SVector(du1, du2, du3, du4) +end + +initial_condition = initial_condition_navier_stokes_convergence_test + +# BC types +velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:3]) +heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) +boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, heat_bc_top_bottom) + +boundary_condition_left_right = BoundaryConditionDirichlet(initial_condition_navier_stokes_convergence_test) + +# define inviscid boundary conditions +boundary_conditions = Dict(:x_neg => boundary_condition_left_right, + :x_pos => boundary_condition_left_right, + :y_neg => boundary_condition_slip_wall, + :y_pos => boundary_condition_slip_wall) + +# define viscous boundary conditions +boundary_conditions_parabolic = Dict(:x_neg => boundary_condition_left_right, + :x_pos => boundary_condition_left_right, + :y_neg => boundary_condition_top_bottom, + :y_pos => boundary_condition_top_bottom) + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; + boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), + source_terms=source_terms_navier_stokes_convergence_test) + +# ############################################################################### +# # ODE solvers, callbacks etc. + +# Create ODE problem with time span `tspan` +tspan = (0.0, 0.5) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() +alive_callback = AliveCallback(alive_interval=10) +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, + ode_default_options()..., callback=callbacks) +summary_callback() # print the timer summary + diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index b10ffa3b9d3..80857999017 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -456,4 +456,33 @@ end }) return SVector(flux_inner[1], flux_inner[2], flux_inner[3], flux_inner[4]) end + +# Dirichlet Boundary Condition for P4est mesh + +@inline function (boundary_condition::BoundaryConditionDirichlet)(flux_inner, + u_inner, + normal::AbstractVector, + x, t, + operator_type::Gradient, + equations::CompressibleNavierStokesDiffusion2D{ + GradientVariablesPrimitive + }) + # BCs are usually specified as conservative variables so we convert them to primitive variables + # because the gradients are assumed to be with respect to the primitive variables + u_boundary = boundary_condition.boundary_value_function(x, t, equations) + + return cons2prim(u_boundary, equations) +end + +@inline function (boundary_condition::BoundaryConditionDirichlet)(flux_inner, + u_inner, + normal::AbstractVector, + x, t, + operator_type::Divergence, + equations::CompressibleNavierStokesDiffusion2D{ + GradientVariablesPrimitive + }) + # for Dirichlet boundary conditions, we do not impose any conditions on the viscous fluxes + return flux_inner +end end # @muladd diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 3fff4382cd1..967aa1069a0 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -289,6 +289,14 @@ isdir(outdir) && rm(outdir, recursive=true) ) end + @trixi_testset "P4estMesh2D: elixir_navierstokes_convergence_nonperiodic.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_navierstokes_convergence_nonperiodic.jl"), + initial_refinement_level = 1, tspan=(0.0, 0.2), + l2 = [0.00040364962558511795, 0.0005869762481506936, 0.00091488537427274, 0.0011984191566376762], + linf = [0.0024993634941723464, 0.009487866203944725, 0.004505829506628117, 0.011634902776245681] + ) + end + @trixi_testset "P4estMesh2D: elixir_navierstokes_lid_driven_cavity.jl" begin @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_navierstokes_lid_driven_cavity.jl"), initial_refinement_level = 2, tspan=(0.0, 0.5), From 1ce4c328bbb8e1552c63306547decdee3656ffeb Mon Sep 17 00:00:00 2001 From: Jesse Chan <1156048+jlchan@users.noreply.github.com> Date: Sun, 8 Oct 2023 23:20:48 -0500 Subject: [PATCH 122/263] remove StartUpDG type piracy (#1665) --- src/solvers/dgmulti/sbp.jl | 330 ------------------------------------- 1 file changed, 330 deletions(-) diff --git a/src/solvers/dgmulti/sbp.jl b/src/solvers/dgmulti/sbp.jl index ba02d812041..d434d3146ce 100644 --- a/src/solvers/dgmulti/sbp.jl +++ b/src/solvers/dgmulti/sbp.jl @@ -36,312 +36,6 @@ function DGMulti(element_type::AbstractElemShape, surface_integral = surface_integral, volume_integral = volume_integral) end -function construct_1d_operators(D::AbstractDerivativeOperator, tol) - nodes_1d = collect(grid(D)) - M = SummationByPartsOperators.mass_matrix(D) - if M isa UniformScaling - weights_1d = M * ones(Bool, length(nodes_1d)) - else - weights_1d = diag(M) - end - - # StartUpDG assumes nodes from -1 to +1. Thus, we need to re-scale everything. - # We can adjust the grid spacing as follows. - xmin = SummationByPartsOperators.xmin(D) - xmax = SummationByPartsOperators.xmax(D) - factor = 2 / (xmax - xmin) - @. nodes_1d = factor * (nodes_1d - xmin) - 1 - @. weights_1d = factor * weights_1d - - D_1d = droptol!(inv(factor) * sparse(D), tol) - I_1d = Diagonal(ones(Bool, length(nodes_1d))) - - return nodes_1d, weights_1d, D_1d, I_1d -end - -function StartUpDG.RefElemData(element_type::Line, - D::AbstractDerivativeOperator; - tol = 100 * eps()) - approximation_type = D - N = SummationByPartsOperators.accuracy_order(D) # kind of polynomial degree - - # 1D operators - nodes_1d, weights_1d, D_1d = construct_1d_operators(D, tol) - - # volume - rq = r = nodes_1d - wq = weights_1d - Dr = D_1d - M = Diagonal(wq) - Pq = LinearAlgebra.I - Vq = LinearAlgebra.I - - VDM = nothing # unused generalized Vandermonde matrix - - rst = (r,) - rstq = (rq,) - Drst = (Dr,) - - # face - face_vertices = StartUpDG.face_vertices(element_type) - face_mask = [1, length(nodes_1d)] - - rf = [-1.0; 1.0] - nrJ = [-1.0; 1.0] - wf = [1.0; 1.0] - if D isa AbstractPeriodicDerivativeOperator - # we do not need any face stuff for periodic operators - Vf = spzeros(length(wf), length(wq)) - else - Vf = sparse([1, 2], [1, length(nodes_1d)], [1.0, 1.0]) - end - LIFT = Diagonal(wq) \ (Vf' * Diagonal(wf)) - - rstf = (rf,) - nrstJ = (nrJ,) - - # low order interpolation nodes - r1 = StartUpDG.nodes(element_type, 1) - V1 = StartUpDG.vandermonde(element_type, 1, r) / - StartUpDG.vandermonde(element_type, 1, r1) - - return RefElemData(element_type, approximation_type, N, - face_vertices, V1, - rst, VDM, face_mask, - rst, LinearAlgebra.I, # plotting - rstq, wq, Vq, # quadrature - rstf, wf, Vf, nrstJ, # faces - M, Pq, Drst, LIFT) -end - -function StartUpDG.RefElemData(element_type::Quad, - D::AbstractDerivativeOperator; - tol = 100 * eps()) - approximation_type = D - N = SummationByPartsOperators.accuracy_order(D) # kind of polynomial degree - - # 1D operators - nodes_1d, weights_1d, D_1d, I_1d = construct_1d_operators(D, tol) - - # volume - s, r = vec.(StartUpDG.NodesAndModes.meshgrid(nodes_1d)) # this is to match - # ordering of nrstJ - rq = r - sq = s - wr, ws = vec.(StartUpDG.NodesAndModes.meshgrid(weights_1d)) - wq = wr .* ws - Dr = kron(I_1d, D_1d) - Ds = kron(D_1d, I_1d) - M = Diagonal(wq) - Pq = LinearAlgebra.I - Vq = LinearAlgebra.I - - VDM = nothing # unused generalized Vandermonde matrix - - rst = (r, s) - rstq = (rq, sq) - Drst = (Dr, Ds) - - # face - face_vertices = StartUpDG.face_vertices(element_type) - face_mask = vcat(StartUpDG.find_face_nodes(element_type, r, s)...) - - rf, sf, wf, nrJ, nsJ = StartUpDG.init_face_data(element_type, - quad_rule_face = (nodes_1d, weights_1d)) - if D isa AbstractPeriodicDerivativeOperator - # we do not need any face stuff for periodic operators - Vf = spzeros(length(wf), length(wq)) - else - Vf = sparse(eachindex(face_mask), face_mask, ones(Bool, length(face_mask))) - end - LIFT = Diagonal(wq) \ (Vf' * Diagonal(wf)) - - rstf = (rf, sf) - nrstJ = (nrJ, nsJ) - - # low order interpolation nodes - r1, s1 = StartUpDG.nodes(element_type, 1) - V1 = StartUpDG.vandermonde(element_type, 1, r, s) / - StartUpDG.vandermonde(element_type, 1, r1, s1) - - return RefElemData(element_type, approximation_type, N, - face_vertices, V1, - rst, VDM, face_mask, - rst, LinearAlgebra.I, # plotting - rstq, wq, Vq, # quadrature - rstf, wf, Vf, nrstJ, # faces - M, Pq, Drst, LIFT) -end - -function StartUpDG.RefElemData(element_type::Hex, - D::AbstractDerivativeOperator; - tol = 100 * eps()) - approximation_type = D - N = SummationByPartsOperators.accuracy_order(D) # kind of polynomial degree - - # 1D operators - nodes_1d, weights_1d, D_1d, I_1d = construct_1d_operators(D, tol) - - # volume - # to match ordering of nrstJ - s, r, t = vec.(StartUpDG.NodesAndModes.meshgrid(nodes_1d, nodes_1d, nodes_1d)) - rq = r - sq = s - tq = t - wr, ws, wt = vec.(StartUpDG.NodesAndModes.meshgrid(weights_1d, weights_1d, weights_1d)) - wq = wr .* ws .* wt - Dr = kron(I_1d, I_1d, D_1d) - Ds = kron(I_1d, D_1d, I_1d) - Dt = kron(D_1d, I_1d, I_1d) - M = Diagonal(wq) - Pq = LinearAlgebra.I - Vq = LinearAlgebra.I - - VDM = nothing # unused generalized Vandermonde matrix - - rst = (r, s, t) - rstq = (rq, sq, tq) - Drst = (Dr, Ds, Dt) - - # face - face_vertices = StartUpDG.face_vertices(element_type) - face_mask = vcat(StartUpDG.find_face_nodes(element_type, r, s, t)...) - - rf, sf, tf, wf, nrJ, nsJ, ntJ = let - rf, sf = vec.(StartUpDG.NodesAndModes.meshgrid(nodes_1d, nodes_1d)) - wr, ws = vec.(StartUpDG.NodesAndModes.meshgrid(weights_1d, weights_1d)) - wf = wr .* ws - StartUpDG.init_face_data(element_type, quad_rule_face = (rf, sf, wf)) - end - Vf = sparse(eachindex(face_mask), face_mask, ones(Bool, length(face_mask))) - LIFT = Diagonal(wq) \ (Vf' * Diagonal(wf)) - - rstf = (rf, sf, tf) - nrstJ = (nrJ, nsJ, ntJ) - - # low order interpolation nodes - r1, s1, t1 = StartUpDG.nodes(element_type, 1) - V1 = StartUpDG.vandermonde(element_type, 1, r, s, t) / - StartUpDG.vandermonde(element_type, 1, r1, s1, t1) - - return RefElemData(element_type, approximation_type, N, - face_vertices, V1, - rst, VDM, face_mask, - rst, LinearAlgebra.I, # plotting - rstq, wq, Vq, # quadrature - rstf, wf, Vf, nrstJ, # faces - M, Pq, Drst, LIFT) -end - -# specialized Hex constructor in 3D to reduce memory usage. -function StartUpDG.RefElemData(element_type::Hex, - D::AbstractPeriodicDerivativeOperator; - tol = 100 * eps()) - approximation_type = D - N = SummationByPartsOperators.accuracy_order(D) # kind of polynomial degree - - # 1D operators - nodes_1d, weights_1d, D_1d, I_1d = construct_1d_operators(D, tol) - - # volume - # to match ordering of nrstJ - s, r, t = vec.(StartUpDG.NodesAndModes.meshgrid(nodes_1d, nodes_1d, nodes_1d)) - rq = r - sq = s - tq = t - wr, ws, wt = vec.(StartUpDG.NodesAndModes.meshgrid(weights_1d, weights_1d, weights_1d)) - wq = wr .* ws .* wt - Dr = kron(I_1d, I_1d, D_1d) - Ds = kron(I_1d, D_1d, I_1d) - Dt = kron(D_1d, I_1d, I_1d) - M = Diagonal(wq) - Pq = LinearAlgebra.I - Vq = LinearAlgebra.I - - VDM = nothing # unused generalized Vandermonde matrix - - rst = (r, s, t) - rstq = (rq, sq, tq) - Drst = (Dr, Ds, Dt) - - # face - # We do not need any face data for periodic operators. Thus, we just - # pass `nothing` to save memory. - face_vertices = ntuple(_ -> nothing, 3) - face_mask = nothing - wf = nothing - rstf = ntuple(_ -> nothing, 3) - nrstJ = ntuple(_ -> nothing, 3) - Vf = nothing - LIFT = nothing - - # low order interpolation nodes - V1 = nothing # do not need to store V1, since we specialize StartUpDG.MeshData to avoid using it. - - return RefElemData(element_type, approximation_type, N, - face_vertices, V1, - rst, VDM, face_mask, - rst, LinearAlgebra.I, # plotting - rstq, wq, Vq, # quadrature - rstf, wf, Vf, nrstJ, # faces - M, Pq, Drst, LIFT) -end - -function Base.show(io::IO, mime::MIME"text/plain", - rd::RefElemData{NDIMS, ElementType, ApproximationType}) where {NDIMS, - ElementType <: - StartUpDG.AbstractElemShape, - ApproximationType <: - AbstractDerivativeOperator - } - @nospecialize rd - print(io, "RefElemData for an approximation using an ") - show(IOContext(io, :compact => true), rd.approximation_type) - print(io, " on $(rd.element_type) element") -end - -function Base.show(io::IO, - rd::RefElemData{NDIMS, ElementType, ApproximationType}) where {NDIMS, - ElementType <: - StartUpDG.AbstractElemShape, - ApproximationType <: - AbstractDerivativeOperator - } - @nospecialize rd - print(io, "RefElemData{", summary(rd.approximation_type), ", ", rd.element_type, "}") -end - -function StartUpDG.inverse_trace_constant(rd::RefElemData{NDIMS, ElementType, - ApproximationType}) where {NDIMS, - ElementType <: - Union{ - Line, - Quad, - Hex - }, - ApproximationType <: - AbstractDerivativeOperator - } - D = rd.approximation_type - - # the inverse trace constant is the maximum eigenvalue corresponding to - # M_f * v = λ * M * v - # where M_f is the face mass matrix and M is the volume mass matrix. - # Since M is diagonal and since M_f is just the boundary "mask" matrix - # (which extracts the first and last entries of a vector), the maximum - # eigenvalue is the inverse of the first or last mass matrix diagonal. - left_weight = SummationByPartsOperators.left_boundary_weight(D) - right_weight = SummationByPartsOperators.right_boundary_weight(D) - max_eigenvalue = max(inv(left_weight), inv(right_weight)) - - # For tensor product elements, the trace constant for higher dimensional - # elements is the one-dimensional trace constant multiplied by `NDIMS`. See - # "GPU-accelerated discontinuous Galerkin methods on hybrid meshes." - # Chan, Jesse, et al (2016), https://doi.org/10.1016/j.jcp.2016.04.003 - # for more details (specifically, Appendix A.1, Theorem A.4). - return NDIMS * max_eigenvalue -end - # type alias for specializing on a periodic SBP operator const DGMultiPeriodicFDSBP{NDIMS, ApproxType, ElemType} = DGMulti{NDIMS, ElemType, ApproxType, @@ -450,30 +144,6 @@ end @muladd begin #! format: noindent -# This is used in `estimate_dt`. `estimate_h` uses that `Jf / J = O(h^{NDIMS-1}) / O(h^{NDIMS}) = O(1/h)`. -# However, since we do not initialize `Jf` for periodic FDSBP operators, we specialize `estimate_h` -# based on the reference grid provided by SummationByPartsOperators.jl and information about the domain size -# provided by `md::MeshData``. -function StartUpDG.estimate_h(e, rd::RefElemData{NDIMS, ElementType, ApproximationType}, - md::MeshData) where {NDIMS, - ElementType <: - StartUpDG.AbstractElemShape, - ApproximationType <: - SummationByPartsOperators.AbstractPeriodicDerivativeOperator - } - D = rd.approximation_type - x = grid(D) - - # we assume all SummationByPartsOperators.jl reference grids are rescaled to [-1, 1] - xmin = SummationByPartsOperators.xmin(D) - xmax = SummationByPartsOperators.xmax(D) - factor = 2 / (xmax - xmin) - - # If the domain has size L^NDIMS, then `minimum(md.J)^(1 / NDIMS) = L`. - # WARNING: this is not a good estimate on anisotropic grids. - return minimum(diff(x)) * factor * minimum(md.J)^(1 / NDIMS) -end - # specialized for DGMultiPeriodicFDSBP since there are no face nodes # and thus no inverse trace constant for periodic domains. function estimate_dt(mesh::DGMultiMesh, dg::DGMultiPeriodicFDSBP) From ae3a0530d2edcd6c22fd3292319d771bd53e18c1 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 9 Oct 2023 06:22:16 +0200 Subject: [PATCH 123/263] set version to v0.5.45 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index d318389a6d2..ecb515b27ed 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.5.45-pre" +version = "0.5.45" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 00292d1bde0d4c6eb1b38d9ae7134b6853d5e9e0 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 9 Oct 2023 06:22:34 +0200 Subject: [PATCH 124/263] set development version to v0.5.46-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index ecb515b27ed..4efbc40b098 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.5.45" +version = "0.5.46-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 10c8d948a9fce3991bf6f21ac761f513de978a56 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Tue, 10 Oct 2023 11:59:50 +0200 Subject: [PATCH 125/263] Print addition to DOF count (#1669) --- src/callbacks_step/analysis.jl | 2 +- src/semidiscretization/semidiscretization_coupled.jl | 2 +- src/semidiscretization/semidiscretization_hyperbolic.jl | 2 +- .../semidiscretization_hyperbolic_parabolic.jl | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/callbacks_step/analysis.jl b/src/callbacks_step/analysis.jl index fad42b11098..a3e49007fb6 100644 --- a/src/callbacks_step/analysis.jl +++ b/src/callbacks_step/analysis.jl @@ -297,7 +297,7 @@ function (analysis_callback::AnalysisCallback)(u_ode, du_ode, integrator, semi) mpi_println(" " * " " * " " * " PID: " * @sprintf("%10.8e s", performance_index)) - mpi_println(" #DOF: " * @sprintf("% 14d", ndofs(semi)) * + mpi_println(" #DOFs per field:" * @sprintf("% 14d", ndofs(semi)) * " " * " alloc'd memory: " * @sprintf("%14.3f MiB", memory_use)) mpi_println(" #elements: " * diff --git a/src/semidiscretization/semidiscretization_coupled.jl b/src/semidiscretization/semidiscretization_coupled.jl index b7adff78425..49763b12e5d 100644 --- a/src/semidiscretization/semidiscretization_coupled.jl +++ b/src/semidiscretization/semidiscretization_coupled.jl @@ -71,7 +71,7 @@ function Base.show(io::IO, ::MIME"text/plain", semi::SemidiscretizationCoupled) summary_line(increment_indent(io), "source terms", semi.semis[i].source_terms) summary_line(increment_indent(io), "solver", solver |> typeof |> nameof) end - summary_line(io, "total #DOFs", ndofs(semi)) + summary_line(io, "total #DOFs per field", ndofs(semi)) summary_footer(io) end end diff --git a/src/semidiscretization/semidiscretization_hyperbolic.jl b/src/semidiscretization/semidiscretization_hyperbolic.jl index 50b2c21c14e..9d465bfcc5f 100644 --- a/src/semidiscretization/semidiscretization_hyperbolic.jl +++ b/src/semidiscretization/semidiscretization_hyperbolic.jl @@ -243,7 +243,7 @@ function Base.show(io::IO, ::MIME"text/plain", semi::SemidiscretizationHyperboli summary_line(io, "source terms", semi.source_terms) summary_line(io, "solver", semi.solver |> typeof |> nameof) - summary_line(io, "total #DOFs", ndofs(semi)) + summary_line(io, "total #DOFs per field", ndofs(semi)) summary_footer(io) end end diff --git a/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl b/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl index b12ecadb58b..35340d65b1e 100644 --- a/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl +++ b/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl @@ -228,7 +228,7 @@ function Base.show(io::IO, ::MIME"text/plain", summary_line(io, "source terms", semi.source_terms) summary_line(io, "solver", semi.solver |> typeof |> nameof) summary_line(io, "parabolic solver", semi.solver_parabolic |> typeof |> nameof) - summary_line(io, "total #DOFs", ndofs(semi)) + summary_line(io, "total #DOFs per field", ndofs(semi)) summary_footer(io) end end From 8bc5469b3d883be0ce088386e1ec794e448003ef Mon Sep 17 00:00:00 2001 From: Jesse Chan <1156048+jlchan@users.noreply.github.com> Date: Wed, 11 Oct 2023 06:22:49 -0500 Subject: [PATCH 126/263] fix bug in `apply_jacobian_parabolic!` for `P4estMesh` (#1668) * fix bug in parabolic jacobian computations * formatting * updating test results and removing duplicate test --------- Co-authored-by: Hendrik Ranocha --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 20 +++++++++++++++++++- src/solvers/dgsem_tree/dg_3d_parabolic.jl | 23 +++++++++++++++++++++-- test/test_parabolic_2d.jl | 16 ++++------------ 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 3dbc55412ad..1c32703c7c3 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -935,7 +935,7 @@ end # This is because the parabolic fluxes are assumed to be of the form # `du/dt + df/dx = dg/dx + source(x,t)`, # where f(u) is the inviscid flux and g(u) is the viscous flux. -function apply_jacobian_parabolic!(du, mesh::Union{TreeMesh{2}, P4estMesh{2}}, +function apply_jacobian_parabolic!(du, mesh::TreeMesh{2}, equations::AbstractEquationsParabolic, dg::DG, cache) @unpack inverse_jacobian = cache.elements @@ -951,4 +951,22 @@ function apply_jacobian_parabolic!(du, mesh::Union{TreeMesh{2}, P4estMesh{2}}, return nothing end + +function apply_jacobian_parabolic!(du, mesh::P4estMesh{2}, + equations::AbstractEquationsParabolic, + dg::DG, cache) + @unpack inverse_jacobian = cache.elements + + @threaded for element in eachelement(dg, cache) + for j in eachnode(dg), i in eachnode(dg) + factor = inverse_jacobian[i, j, element] + + for v in eachvariable(equations) + du[v, i, j, element] *= factor + end + end + end + + return nothing +end end # @muladd diff --git a/src/solvers/dgsem_tree/dg_3d_parabolic.jl b/src/solvers/dgsem_tree/dg_3d_parabolic.jl index 9817e0e5f0e..37492dbcb91 100644 --- a/src/solvers/dgsem_tree/dg_3d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_3d_parabolic.jl @@ -1125,8 +1125,9 @@ end # This is because the parabolic fluxes are assumed to be of the form # `du/dt + df/dx = dg/dx + source(x,t)`, # where f(u) is the inviscid flux and g(u) is the viscous flux. -function apply_jacobian_parabolic!(du, mesh::Union{TreeMesh{3}, P4estMesh{3}}, - equations::AbstractEquationsParabolic, dg::DG, cache) +function apply_jacobian_parabolic!(du, mesh::TreeMesh{3}, + equations::AbstractEquationsParabolic, + dg::DG, cache) @unpack inverse_jacobian = cache.elements @threaded for element in eachelement(dg, cache) @@ -1141,4 +1142,22 @@ function apply_jacobian_parabolic!(du, mesh::Union{TreeMesh{3}, P4estMesh{3}}, return nothing end + +function apply_jacobian_parabolic!(du, mesh::P4estMesh{3}, + equations::AbstractEquationsParabolic, + dg::DG, cache) + @unpack inverse_jacobian = cache.elements + + @threaded for element in eachelement(dg, cache) + for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg) + factor = inverse_jacobian[i, j, k, element] + + for v in eachvariable(equations) + du[v, i, j, k, element] *= factor + end + end + end + + return nothing +end end # @muladd diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 967aa1069a0..98aa337afb4 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -260,24 +260,16 @@ isdir(outdir) && rm(outdir, recursive=true) @trixi_testset "P4estMesh2D: elixir_advection_diffusion_periodic_curved.jl" begin @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_advection_diffusion_periodic_curved.jl"), trees_per_dimension = (1, 1), initial_refinement_level = 2, tspan=(0.0, 0.5), - l2 = [0.012380458938507371], - linf = [0.10860506906472567] - ) - end - - @trixi_testset "P4estMesh2D: elixir_advection_diffusion_periodic_curved.jl" begin - @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_advection_diffusion_periodic_curved.jl"), - trees_per_dimension = (1, 1), initial_refinement_level = 2, tspan=(0.0, 0.5), - l2 = [0.012380458938507371], - linf = [0.10860506906472567] + l2 = [0.006708147442490916], + linf = [0.04807038397976693] ) end @trixi_testset "P4estMesh2D: elixir_advection_diffusion_nonperiodic_curved.jl" begin @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_advection_diffusion_nonperiodic_curved.jl"), trees_per_dimension = (1, 1), initial_refinement_level = 2, tspan=(0.0, 0.5), - l2 = [0.04933902988507035], - linf = [0.2550261714590271] + l2 = [0.00919917034843865], + linf = [0.14186297438393505] ) end From 1727b072fa9f269bcde73b516bc7b00f13fc9c99 Mon Sep 17 00:00:00 2001 From: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Date: Wed, 11 Oct 2023 16:23:12 +0200 Subject: [PATCH 127/263] Show percentage of simulation progress (#1659) * show percentage of simulation progress * add notes about AnalysisCallback in docs * generalize for general initial time --------- Co-authored-by: Hendrik Ranocha --- docs/src/callbacks.md | 5 +++++ src/callbacks_step/alive.jl | 10 ++++++++-- src/callbacks_step/analysis.jl | 10 ++++++++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/docs/src/callbacks.md b/docs/src/callbacks.md index 7f44dfd5925..f018bcf7c39 100644 --- a/docs/src/callbacks.md +++ b/docs/src/callbacks.md @@ -30,6 +30,11 @@ An example elixir using AMR can be found at [`examples/tree_2d_dgsem/elixir_adve The [`AnalysisCallback`](@ref) can be used to analyze the numerical solution, e.g. calculate errors or user-specified integrals, and print the results to the screen. The results can also be saved in a file. An example can be found at [`examples/tree_2d_dgsem/elixir_euler_vortex.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_euler_vortex.jl). +Note that the errors (e.g. `L2 error` or `Linf error`) are computed with respect to the initial condition. +The percentage of the simulation time refers to the ratio of the current time and the final time, i.e. it does +not consider the maximal number of iterations. So the simulation could finish before 100% are reached. +Note that, e.g., due to AMR or smaller time step sizes, the simulation can actually take longer than +the percentage indicates. In [Performance metrics of the `AnalysisCallback`](@ref performance-metrics) you can find a detailed description of the different performance metrics the `AnalysisCallback` computes. diff --git a/src/callbacks_step/alive.jl b/src/callbacks_step/alive.jl index eeacd9681d8..9df7181521e 100644 --- a/src/callbacks_step/alive.jl +++ b/src/callbacks_step/alive.jl @@ -86,9 +86,15 @@ function (alive_callback::AliveCallback)(integrator) println("─"^100) println() elseif mpi_isroot() + t = integrator.t + t_initial = first(integrator.sol.prob.tspan) + t_final = last(integrator.sol.prob.tspan) + sim_time_percentage = (t - t_initial) / (t_final - t_initial) * 100 runtime_absolute = 1.0e-9 * (time_ns() - alive_callback.start_time) - @printf("#timesteps: %6d │ Δt: %.4e │ sim. time: %.4e │ run time: %.4e s\n", - integrator.stats.naccept, integrator.dt, integrator.t, runtime_absolute) + println(rpad(@sprintf("#timesteps: %6d │ Δt: %.4e │ sim. time: %.4e (%5.3f%%)", + integrator.stats.naccept, integrator.dt, t, + sim_time_percentage), 71) * + @sprintf("│ run time: %.4e s", runtime_absolute)) end # avoid re-evaluating possible FSAL stages diff --git a/src/callbacks_step/analysis.jl b/src/callbacks_step/analysis.jl index a3e49007fb6..e5b4a01a885 100644 --- a/src/callbacks_step/analysis.jl +++ b/src/callbacks_step/analysis.jl @@ -232,6 +232,12 @@ function (analysis_callback::AnalysisCallback)(u_ode, du_ode, integrator, semi) @unpack dt, t = integrator iter = integrator.stats.naccept + # Compute the percentage of the simulation that is done + t = integrator.t + t_initial = first(integrator.sol.prob.tspan) + t_final = last(integrator.sol.prob.tspan) + sim_time_percentage = (t - t_initial) / (t_final - t_initial) * 100 + # Record performance measurements and compute performance index (PID) runtime_since_last_analysis = 1.0e-9 * (time_ns() - analysis_callback.start_time_last_analysis) @@ -291,8 +297,8 @@ function (analysis_callback::AnalysisCallback)(u_ode, du_ode, integrator, semi) " " * " └── GC time: " * @sprintf("%10.8e s (%5.3f%%)", gc_time_absolute, gc_time_percentage)) - mpi_println(" sim. time: " * @sprintf("%10.8e", t) * - " " * + mpi_println(rpad(" sim. time: " * + @sprintf("%10.8e (%5.3f%%)", t, sim_time_percentage), 46) * " time/DOF/rhs!: " * @sprintf("%10.8e s", runtime_relative)) mpi_println(" " * " " * " " * From 7fd4503af9dfdf7022ae75f7398cac8fda811c85 Mon Sep 17 00:00:00 2001 From: Benjamin Bolm <74359358+bennibolm@users.noreply.github.com> Date: Thu, 12 Oct 2023 15:31:43 +0200 Subject: [PATCH 128/263] Subcell limiting: Revise order of bounds using a `Dict` (#1649) * Implement order of bounds as Dict * Implement `variable_bounds` directly as Dictionary * Remove unnecessary line of code * Use Symbols instead of Strings --- src/solvers/dgsem_tree/containers_2d.jl | 31 ++++++++++--------- src/solvers/dgsem_tree/subcell_limiters.jl | 5 +-- src/solvers/dgsem_tree/subcell_limiters_2d.jl | 31 ++++++++----------- 3 files changed, 32 insertions(+), 35 deletions(-) diff --git a/src/solvers/dgsem_tree/containers_2d.jl b/src/solvers/dgsem_tree/containers_2d.jl index 9148b936312..fc916b41dd2 100644 --- a/src/solvers/dgsem_tree/containers_2d.jl +++ b/src/solvers/dgsem_tree/containers_2d.jl @@ -1325,16 +1325,16 @@ mutable struct ContainerSubcellLimiterIDP2D{uEltype <: Real} alpha::Array{uEltype, 3} # [i, j, element] alpha1::Array{uEltype, 3} alpha2::Array{uEltype, 3} - variable_bounds::Vector{Array{uEltype, 3}} + variable_bounds::Dict{Symbol, Array{uEltype, 3}} # internal `resize!`able storage _alpha::Vector{uEltype} _alpha1::Vector{uEltype} _alpha2::Vector{uEltype} - _variable_bounds::Vector{Vector{uEltype}} + _variable_bounds::Dict{Symbol, Vector{uEltype}} end function ContainerSubcellLimiterIDP2D{uEltype}(capacity::Integer, n_nodes, - length) where {uEltype <: Real} + bound_keys) where {uEltype <: Real} nan_uEltype = convert(uEltype, NaN) # Initialize fields with defaults @@ -1345,12 +1345,12 @@ function ContainerSubcellLimiterIDP2D{uEltype}(capacity::Integer, n_nodes, _alpha2 = fill(nan_uEltype, n_nodes * (n_nodes + 1) * capacity) alpha2 = unsafe_wrap(Array, pointer(_alpha2), (n_nodes, n_nodes + 1, capacity)) - _variable_bounds = Vector{Vector{uEltype}}(undef, length) - variable_bounds = Vector{Array{uEltype, 3}}(undef, length) - for i in 1:length - _variable_bounds[i] = fill(nan_uEltype, n_nodes * n_nodes * capacity) - variable_bounds[i] = unsafe_wrap(Array, pointer(_variable_bounds[i]), - (n_nodes, n_nodes, capacity)) + _variable_bounds = Dict{Symbol, Vector{uEltype}}() + variable_bounds = Dict{Symbol, Array{uEltype, 3}}() + for key in bound_keys + _variable_bounds[key] = fill(nan_uEltype, n_nodes * n_nodes * capacity) + variable_bounds[key] = unsafe_wrap(Array, pointer(_variable_bounds[key]), + (n_nodes, n_nodes, capacity)) end return ContainerSubcellLimiterIDP2D{uEltype}(alpha, alpha1, alpha2, @@ -1369,7 +1369,7 @@ nnodes(container::ContainerSubcellLimiterIDP2D) = size(container.alpha, 1) function Base.resize!(container::ContainerSubcellLimiterIDP2D, capacity) n_nodes = nnodes(container) - @unpack _alpha, _alpha1, _alpha2 = container + (; _alpha, _alpha1, _alpha2) = container resize!(_alpha, n_nodes * n_nodes * capacity) container.alpha = unsafe_wrap(Array, pointer(_alpha), (n_nodes, n_nodes, capacity)) resize!(_alpha1, (n_nodes + 1) * n_nodes * capacity) @@ -1379,11 +1379,12 @@ function Base.resize!(container::ContainerSubcellLimiterIDP2D, capacity) container.alpha2 = unsafe_wrap(Array, pointer(_alpha2), (n_nodes, n_nodes + 1, capacity)) - @unpack _variable_bounds = container - for i in 1:length(_variable_bounds) - resize!(_variable_bounds[i], n_nodes * n_nodes * capacity) - container.variable_bounds[i] = unsafe_wrap(Array, pointer(_variable_bounds[i]), - (n_nodes, n_nodes, capacity)) + (; _variable_bounds) = container + for (key, _) in _variable_bounds + resize!(_variable_bounds[key], n_nodes * n_nodes * capacity) + container.variable_bounds[key] = unsafe_wrap(Array, + pointer(_variable_bounds[key]), + (n_nodes, n_nodes, capacity)) end return nothing diff --git a/src/solvers/dgsem_tree/subcell_limiters.jl b/src/solvers/dgsem_tree/subcell_limiters.jl index 3a707de3bc7..4d9eec25a89 100644 --- a/src/solvers/dgsem_tree/subcell_limiters.jl +++ b/src/solvers/dgsem_tree/subcell_limiters.jl @@ -52,9 +52,10 @@ function SubcellLimiterIDP(equations::AbstractEquations, basis; positivity_variables_cons = [], positivity_correction_factor = 0.1) positivity = (length(positivity_variables_cons) > 0) - number_bounds = length(positivity_variables_cons) - cache = create_cache(SubcellLimiterIDP, equations, basis, number_bounds) + bound_keys = Tuple(Symbol("$(i)_min") for i in positivity_variables_cons) + + cache = create_cache(SubcellLimiterIDP, equations, basis, bound_keys) SubcellLimiterIDP{typeof(positivity_correction_factor), typeof(cache)}(positivity, positivity_variables_cons, diff --git a/src/solvers/dgsem_tree/subcell_limiters_2d.jl b/src/solvers/dgsem_tree/subcell_limiters_2d.jl index 09ab84ed11a..4497217fb56 100644 --- a/src/solvers/dgsem_tree/subcell_limiters_2d.jl +++ b/src/solvers/dgsem_tree/subcell_limiters_2d.jl @@ -6,17 +6,14 @@ #! format: noindent # this method is used when the limiter is constructed as for shock-capturing volume integrals -function create_cache(indicator::Type{SubcellLimiterIDP}, - equations::AbstractEquations{2}, - basis::LobattoLegendreBasis, number_bounds) +function create_cache(limiter::Type{SubcellLimiterIDP}, equations::AbstractEquations{2}, + basis::LobattoLegendreBasis, bound_keys) subcell_limiter_coefficients = Trixi.ContainerSubcellLimiterIDP2D{real(basis) }(0, nnodes(basis), - number_bounds) + bound_keys) - cache = (; subcell_limiter_coefficients) - - return cache + return (; subcell_limiter_coefficients) end function (limiter::SubcellLimiterIDP)(u::AbstractArray{<:Any, 4}, semi, dg::DGSEM, t, @@ -26,8 +23,7 @@ function (limiter::SubcellLimiterIDP)(u::AbstractArray{<:Any, 4}, semi, dg::DGSE alpha .= zero(eltype(alpha)) if limiter.positivity - @trixi_timeit timer() "positivity" idp_positivity!(alpha, limiter, u, dt, - semi) + @trixi_timeit timer() "positivity" idp_positivity!(alpha, limiter, u, dt, semi) end # Calculate alpha1 and alpha2 @@ -50,22 +46,21 @@ end @inline function idp_positivity!(alpha, limiter, u, dt, semi) # Conservative variables - for (index, variable) in enumerate(limiter.positivity_variables_cons) - idp_positivity!(alpha, limiter, u, dt, semi, variable, index) + for variable in limiter.positivity_variables_cons + idp_positivity!(alpha, limiter, u, dt, semi, variable) end return nothing end -@inline function idp_positivity!(alpha, limiter, u, dt, semi, variable, index) +@inline function idp_positivity!(alpha, limiter, u, dt, semi, variable) mesh, equations, dg, cache = mesh_equations_solver_cache(semi) - @unpack antidiffusive_flux1, antidiffusive_flux2 = cache.antidiffusive_fluxes - @unpack inverse_weights = dg.basis - @unpack positivity_correction_factor = limiter - - @unpack variable_bounds = limiter.cache.subcell_limiter_coefficients + (; antidiffusive_flux1, antidiffusive_flux2) = cache.antidiffusive_fluxes + (; inverse_weights) = dg.basis + (; positivity_correction_factor) = limiter - var_min = variable_bounds[index] + (; variable_bounds) = limiter.cache.subcell_limiter_coefficients + var_min = variable_bounds[Symbol("$(variable)_min")] @threaded for element in eachelement(dg, semi.cache) inverse_jacobian = cache.elements.inverse_jacobian[element] From dfdaef5adc243fcd6c55262a69ede59fe3a32a8f Mon Sep 17 00:00:00 2001 From: Benjamin Bolm <74359358+bennibolm@users.noreply.github.com> Date: Wed, 18 Oct 2023 16:58:17 +0200 Subject: [PATCH 129/263] Node-level visualization support for coefficients of Subcell limiting (#1611) * Add node-level visualization for IDP limiting * Fix renaming error * Init alphas with 0 after resizing * Remove note * Relocate overwriting of alphas * Implement suggestions * Add comment about split into nominator/denominator * Set uninitialized alphas to NaN --- src/callbacks_step/save_solution.jl | 11 ++++++++-- src/callbacks_step/save_solution_dg.jl | 18 +++++++++++++++-- src/semidiscretization/semidiscretization.jl | 4 ++++ src/solvers/dg.jl | 21 ++++++++++++++++++++ src/solvers/dgsem_tree/containers_2d.jl | 1 + src/solvers/dgsem_tree/subcell_limiters.jl | 7 +++++++ src/time_integration/methods_SSP.jl | 5 +++++ utils/trixi2txt.jl | 13 ++++++++++-- 8 files changed, 74 insertions(+), 6 deletions(-) diff --git a/src/callbacks_step/save_solution.jl b/src/callbacks_step/save_solution.jl index 14ea33368f8..31fe0e87c77 100644 --- a/src/callbacks_step/save_solution.jl +++ b/src/callbacks_step/save_solution.jl @@ -222,21 +222,28 @@ end end end + node_variables = Dict{Symbol, Any}() + @trixi_timeit timer() "get node variables" get_node_variables!(node_variables, + semi) + @trixi_timeit timer() "save solution" save_solution_file(u_ode, t, dt, iter, semi, solution_callback, element_variables, + node_variables, system = system) end @inline function save_solution_file(u_ode, t, dt, iter, semi::AbstractSemidiscretization, solution_callback, - element_variables = Dict{Symbol, Any}(); + element_variables = Dict{Symbol, Any}(), + node_variables = Dict{Symbol, Any}(); system = "") mesh, equations, solver, cache = mesh_equations_solver_cache(semi) u = wrap_array_native(u_ode, mesh, equations, solver, cache) save_solution_file(u, t, dt, iter, mesh, equations, solver, cache, solution_callback, - element_variables; system = system) + element_variables, + node_variables; system = system) end # TODO: Taal refactor, move save_mesh_file? diff --git a/src/callbacks_step/save_solution_dg.jl b/src/callbacks_step/save_solution_dg.jl index 6d5004ff65f..7c015999035 100644 --- a/src/callbacks_step/save_solution_dg.jl +++ b/src/callbacks_step/save_solution_dg.jl @@ -10,7 +10,9 @@ function save_solution_file(u, time, dt, timestep, UnstructuredMesh2D, SerialP4estMesh, SerialT8codeMesh}, equations, dg::DG, cache, - solution_callback, element_variables = Dict{Symbol, Any}(); + solution_callback, + element_variables = Dict{Symbol, Any}(), + node_variables = Dict{Symbol, Any}(); system = "") @unpack output_directory, solution_variables = solution_callback @@ -73,6 +75,16 @@ function save_solution_file(u, time, dt, timestep, var = file["element_variables_$v"] attributes(var)["name"] = string(key) end + + # Store node variables + for (v, (key, node_variable)) in enumerate(node_variables) + # Add to file + file["node_variables_$v"] = node_variable + + # Add variable name as attribute + var = file["node_variables_$v"] + attributes(var)["name"] = string(key) + end end return filename @@ -81,7 +93,9 @@ end function save_solution_file(u, time, dt, timestep, mesh::Union{ParallelTreeMesh, ParallelP4estMesh}, equations, dg::DG, cache, - solution_callback, element_variables = Dict{Symbol, Any}(); + solution_callback, + element_variables = Dict{Symbol, Any}(), + node_variables = Dict{Symbol, Any}(); system = "") @unpack output_directory, solution_variables = solution_callback diff --git a/src/semidiscretization/semidiscretization.jl b/src/semidiscretization/semidiscretization.jl index c784f716426..fe7858e31ee 100644 --- a/src/semidiscretization/semidiscretization.jl +++ b/src/semidiscretization/semidiscretization.jl @@ -335,6 +335,10 @@ function get_element_variables!(element_variables, u_ode, get_element_variables!(element_variables, u, mesh_equations_solver_cache(semi)...) end +function get_node_variables!(node_variables, semi::AbstractSemidiscretization) + get_node_variables!(node_variables, mesh_equations_solver_cache(semi)...) +end + # To implement AMR and use OrdinaryDiffEq.jl etc., we have to be a bit creative. # Since the caches of the SciML ecosystem are immutable structs, we cannot simply # change the underlying arrays therein. Hence, to support changing the number of diff --git a/src/solvers/dg.jl b/src/solvers/dg.jl index 36bbc6de361..30b4f67474f 100644 --- a/src/solvers/dg.jl +++ b/src/solvers/dg.jl @@ -12,6 +12,11 @@ function get_element_variables!(element_variables, u, mesh, equations, nothing end +function get_node_variables!(node_variables, mesh, equations, + volume_integral::AbstractVolumeIntegral, dg, cache) + nothing +end + """ VolumeIntegralStrongForm() @@ -214,6 +219,18 @@ function Base.show(io::IO, mime::MIME"text/plain", end end +function get_node_variables!(node_variables, mesh, equations, + volume_integral::VolumeIntegralSubcellLimiting, dg, cache) + # While for the element-wise limiting with `VolumeIntegralShockCapturingHG` the indicator is + # called here to get up-to-date values for IO, this is not easily possible in this case + # because the calculation is very integrated into the method. + # See also https://github.com/trixi-framework/Trixi.jl/pull/1611#discussion_r1334553206. + # Therefore, the coefficients at `t=t^{n-1}` are saved. Thus, the coefficients of the first + # stored solution (initial condition) are not yet defined and were manually set to `NaN`. + get_node_variables!(node_variables, volume_integral.limiter, volume_integral, + equations) +end + # TODO: FD. Should this definition live in a different file because it is # not strictly a DG method? """ @@ -403,6 +420,10 @@ function get_element_variables!(element_variables, u, mesh, equations, dg::DG, c dg, cache) end +function get_node_variables!(node_variables, mesh, equations, dg::DG, cache) + get_node_variables!(node_variables, mesh, equations, dg.volume_integral, dg, cache) +end + const MeshesDGSEM = Union{TreeMesh, StructuredMesh, UnstructuredMesh2D, P4estMesh, T8codeMesh} diff --git a/src/solvers/dgsem_tree/containers_2d.jl b/src/solvers/dgsem_tree/containers_2d.jl index fc916b41dd2..9e9fe88c15b 100644 --- a/src/solvers/dgsem_tree/containers_2d.jl +++ b/src/solvers/dgsem_tree/containers_2d.jl @@ -1372,6 +1372,7 @@ function Base.resize!(container::ContainerSubcellLimiterIDP2D, capacity) (; _alpha, _alpha1, _alpha2) = container resize!(_alpha, n_nodes * n_nodes * capacity) container.alpha = unsafe_wrap(Array, pointer(_alpha), (n_nodes, n_nodes, capacity)) + container.alpha .= convert(eltype(container.alpha), NaN) resize!(_alpha1, (n_nodes + 1) * n_nodes * capacity) container.alpha1 = unsafe_wrap(Array, pointer(_alpha1), (n_nodes + 1, n_nodes, capacity)) diff --git a/src/solvers/dgsem_tree/subcell_limiters.jl b/src/solvers/dgsem_tree/subcell_limiters.jl index 4d9eec25a89..6197ca6b85d 100644 --- a/src/solvers/dgsem_tree/subcell_limiters.jl +++ b/src/solvers/dgsem_tree/subcell_limiters.jl @@ -101,4 +101,11 @@ function Base.show(io::IO, ::MIME"text/plain", limiter::SubcellLimiterIDP) summary_box(io, "SubcellLimiterIDP", setup) end end + +function get_node_variables!(node_variables, limiter::SubcellLimiterIDP, + ::VolumeIntegralSubcellLimiting, equations) + node_variables[:limiting_coefficient] = limiter.cache.subcell_limiter_coefficients.alpha + + return nothing +end end # @muladd diff --git a/src/time_integration/methods_SSP.jl b/src/time_integration/methods_SSP.jl index 33eb6ebf926..5b72682d48e 100644 --- a/src/time_integration/methods_SSP.jl +++ b/src/time_integration/methods_SSP.jl @@ -31,6 +31,11 @@ struct SimpleSSPRK33{StageCallbacks} <: SimpleAlgorithmSSP stage_callbacks::StageCallbacks function SimpleSSPRK33(; stage_callbacks = ()) + # Mathematically speaking, it is not necessary for the algorithm to split the factors + # into numerator and denominator. Otherwise, however, rounding errors of the order of + # the machine accuracy will occur, which will add up over time and thus endanger the + # conservation of the simulation. + # See also https://github.com/trixi-framework/Trixi.jl/pull/1640. numerator_a = SVector(0.0, 3.0, 1.0) # a = numerator_a / denominator numerator_b = SVector(1.0, 1.0, 2.0) # b = numerator_b / denominator denominator = SVector(1.0, 4.0, 3.0) diff --git a/utils/trixi2txt.jl b/utils/trixi2txt.jl index b386f150da4..12a3d46760e 100644 --- a/utils/trixi2txt.jl +++ b/utils/trixi2txt.jl @@ -70,7 +70,7 @@ function trixi2txt(filename::AbstractString...; center_level_0, length_level_0, leaf_cells, coordinates, levels = read_meshfile(meshfile) # Read data - labels, data, n_elements, n_nodes, element_variables, time = read_datafile(filename) + labels, data, n_elements, n_nodes, element_variables, node_variables, time = read_datafile(filename) # Check if dimensions match if length(leaf_cells) != n_elements @@ -263,7 +263,16 @@ function read_datafile(filename::String) index += 1 end - return labels, data, n_elements, n_nodes, element_variables, time + # Extract node variable arrays + node_variables = Dict{String, Union{Vector{Float64}, Vector{Int}}}() + index = 1 + while haskey(file, "node_variables_$index") + varname = read(attributes(file["node_variables_$index"])["name"]) + node_variables[varname] = read(file["node_variables_$index"]) + index += 1 + end + + return labels, data, n_elements, n_nodes, element_variables, node_variables, time end end From bb60b5d973ff4d4e00c37476ef858d37083d2209 Mon Sep 17 00:00:00 2001 From: Simon Candelaresi <10759273+SimonCan@users.noreply.github.com> Date: Thu, 19 Oct 2023 04:51:53 +0100 Subject: [PATCH 130/263] Sc/polytropic (#1526) * Added polytropic Euler equations. * Added polytropic Euler equations. * Added polytropic Euler equations. * Minor clean up in polytropic equations. * Added example for the compressible polytropic Euler equations in 2d on a structured mesh. * Cleaned up example elicir for polytropic Euler in 2d. * Added polytrropic Euler in 2d in tests. * Remoed unused routines. * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Michael Schlottke-Lakemper * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Michael Schlottke-Lakemper * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Michael Schlottke-Lakemper * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Michael Schlottke-Lakemper * Added compressible Euler equations in news. * Auto-reformatted equations. * Auto-reformatted docs for polytropic equations. * Added example elixir for polytropic and isothermal coupling. * Corrected typos. * Update examples/structured_2d_dgsem/elixir_euler_polytropic.jl Co-authored-by: Michael Schlottke-Lakemper * Update NEWS.md Co-authored-by: Michael Schlottke-Lakemper * Renamed elixir_euler_polytropic.jl to elixir_euler_polytropic.jl. * Renamed Euler polytropic elixir in test. * Renamed coupled polytropic example elixir. * Reformatted the boundary conditions for the couple polytropic example elixir. * Removed redundant inv_gamma_minus_one variable. * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Michael Schlottke-Lakemper * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Michael Schlottke-Lakemper * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Michael Schlottke-Lakemper * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Michael Schlottke-Lakemper * Update examples/structured_2d_dgsem/elixir_eulerpolytropic_coupled.jl Yes. That was necessary in an old version for Trixi.jl. Co-authored-by: Michael Schlottke-Lakemper * Update examples/structured_2d_dgsem/elixir_eulerpolytropic_coupled.jl Co-authored-by: Michael Schlottke-Lakemper * Update examples/structured_2d_dgsem/elixir_eulerpolytropic_coupled.jl Co-authored-by: Michael Schlottke-Lakemper * Update examples/structured_2d_dgsem/elixir_eulerpolytropic_coupled.jl Co-authored-by: Michael Schlottke-Lakemper * Removed flux Ranocha for polytropic equations. * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Michael Schlottke-Lakemper * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Hendrik Ranocha * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Hendrik Ranocha * Added Andrew's flux implementation flux_winters_etal. * Added couped polytropic tests. * Added Winter's fluxes for coupled polytropic elixir. * Added flux_winters_etal. * Added convergence test for polytropic Euler. * Renamed polytropic uler convergence Elixir. * Added convergence test initial condition. * Corrected variable names in convergence test for polytropic equations. * Update src/auxiliary/math.jl Co-authored-by: Hendrik Ranocha * Added isotropic Eulre wave test case. * Removed isotropic option in purely polytropic test case. * Implmented Andrew's efficient way of computing coefficients. * Added isotropic Euler wave as test case. * Reformatted polytrropic_2d. * Update examples/structured_2d_dgsem/elixir_eulerpolytropic_wave.jl Co-authored-by: Michael Schlottke-Lakemper * Update src/auxiliary/math.jl Co-authored-by: Andrew Winters * Reformatted example elixir for polytropic/isothermal equations. * Updated errors for elixir_eulerpolytropic_coupled.jl. * Added polytropic convergence test and renamed isothermal file. * Corrected gamma and kappa. * Added source terms for EOC. * Added source term for ECO. * Minor corrections. * Added source terms. * Corrected primary variables. * Removed redundant kappa and gamme redefinitions. * Improved style by using gamma and kappa from equations. * Improved convergence test for polytropic. * Corrected convergence test residual for polytropic equations. * Allow use of flux_lax_friedrichs * Fix comment * Added flux calculation for polytropic Euler. * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Andrew Winters * Update examples/structured_2d_dgsem/elixir_eulerpolytropic_wave.jl Co-authored-by: Andrew Winters * Moved initial condition and source term before flux function. * Update examples/structured_2d_dgsem/elixir_eulerisothermal_wave.jl Co-authored-by: Andrew Winters * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Andrew Winters * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Andrew Winters * Change kappa and gamma in some polytropic Euler elixirs. * Correcte source for Euler polytropic convergence test. * Changed parameters gamma and kappa in Euler polytropic convergence test to other than 1.0. * Reformatted polytropic Euler. * Spelling errors. * Reformatted. * Added elixir for testing entropy conservation for polytropic Euler equations. * Added weak blast wave as initial condition for the polytropic Euler equations. * Added entropy conservation test. * Typo in tests. * Auto reformat. * Corrected polytropic Euler test reults. * Renamed entropy test for Euler polytropic. * Renamed elixir for shock test. * Added coupled Euler polytropic to the tests. * Removed redundant flux function. * Changed example parameters for coupled polytropic Euler. * Removed max-speed calculations, as they are not being used. * Removed coupled polytropic elixir, since this PR is on the polytropic equations only. * Correcte entropy variables for polytropic Euler. This fixes the entropy conservation issue. * Update examples/structured_2d_dgsem/elixir_eulerpolytropic_convergence.jl Co-authored-by: Andrew Winters * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Andrew Winters * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Andrew Winters * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Andrew Winters * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Andrew Winters * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Andrew Winters * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Andrew Winters * Format of comment. * Update src/Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Updated polytropic wave test results after removing stage limiter. * Removed stqage limiter. * Reformatted Trixi.jl. * Corrected removed exports in Trixi.jl. * Fix for broadcasting. * Renamed elixir for isothermal wave. * Update test/test_structured_2d.jl Co-authored-by: Michael Schlottke-Lakemper * Added comment about isothermal system in elixir. --------- Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Hendrik Ranocha Co-authored-by: Andrew Winters --- NEWS.md | 1 + .../elixir_eulerpolytropic_convergence.jl | 63 +++++ .../elixir_eulerpolytropic_ec.jl | 80 ++++++ .../elixir_eulerpolytropic_isothermal_wave.jl | 83 ++++++ .../elixir_eulerpolytropic_wave.jl | 80 ++++++ src/Trixi.jl | 5 +- src/auxiliary/math.jl | 67 +++++ src/equations/equations.jl | 5 + src/equations/polytropic_euler_2d.jl | 257 ++++++++++++++++++ test/test_structured_2d.jl | 24 ++ 10 files changed, 663 insertions(+), 2 deletions(-) create mode 100644 examples/structured_2d_dgsem/elixir_eulerpolytropic_convergence.jl create mode 100644 examples/structured_2d_dgsem/elixir_eulerpolytropic_ec.jl create mode 100644 examples/structured_2d_dgsem/elixir_eulerpolytropic_isothermal_wave.jl create mode 100644 examples/structured_2d_dgsem/elixir_eulerpolytropic_wave.jl create mode 100644 src/equations/polytropic_euler_2d.jl diff --git a/NEWS.md b/NEWS.md index 4b96e1e2834..0c78484a782 100644 --- a/NEWS.md +++ b/NEWS.md @@ -12,6 +12,7 @@ for human readability. - Non-uniform `TreeMesh` available for hyperbolic-parabolic equations. - Capability to set truly discontinuous initial conditions in 1D. - Wetting and drying feature and examples for 1D and 2D shallow water equations +- Implementation of the polytropic Euler equations in 2D - Subcell positivity limiting support for conservative variables in 2D for `TreeMesh` #### Changed diff --git a/examples/structured_2d_dgsem/elixir_eulerpolytropic_convergence.jl b/examples/structured_2d_dgsem/elixir_eulerpolytropic_convergence.jl new file mode 100644 index 00000000000..4fc9281e7a0 --- /dev/null +++ b/examples/structured_2d_dgsem/elixir_eulerpolytropic_convergence.jl @@ -0,0 +1,63 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the polytropic Euler equations + +gamma = 1.4 +kappa = 0.5 # Scaling factor for the pressure. +equations = PolytropicEulerEquations2D(gamma, kappa) + +initial_condition = initial_condition_convergence_test + +volume_flux = flux_winters_etal +solver = DGSEM(polydeg = 3, surface_flux = flux_hll, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = (0.0, 0.0) +coordinates_max = (1.0, 1.0) + +cells_per_dimension = (4, 4) + +mesh = StructuredMesh(cells_per_dimension, + coordinates_min, + coordinates_max) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_convergence_test) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.1) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:l2_error_primitive, + :linf_error_primitive)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 0.1) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + 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/structured_2d_dgsem/elixir_eulerpolytropic_ec.jl b/examples/structured_2d_dgsem/elixir_eulerpolytropic_ec.jl new file mode 100644 index 00000000000..de15f6b2bc3 --- /dev/null +++ b/examples/structured_2d_dgsem/elixir_eulerpolytropic_ec.jl @@ -0,0 +1,80 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the polytropic Euler equations + +gamma = 1.4 +kappa = 0.5 # Scaling factor for the pressure. +equations = PolytropicEulerEquations2D(gamma, kappa) + +initial_condition = initial_condition_weak_blast_wave + +############################################################################### +# Get the DG approximation space + +volume_flux = flux_winters_etal +solver = DGSEM(polydeg=4, surface_flux=flux_winters_etal, + volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) + +############################################################################### +# Get the curved quad mesh from a mapping function + +# Mapping as described in https://arxiv.org/abs/2012.12040, but reduced to 2D +function mapping(xi_, eta_) + # Transform input variables between -1 and 1 onto [0,3] + xi = 1.5 * xi_ + 1.5 + eta = 1.5 * eta_ + 1.5 + + y = eta + 3/8 * (cos(1.5 * pi * (2 * xi - 3)/3) * + cos(0.5 * pi * (2 * eta - 3)/3)) + + x = xi + 3/8 * (cos(0.5 * pi * (2 * xi - 3)/3) * + cos(2 * pi * (2 * y - 3)/3)) + + return SVector(x, y) +end + +cells_per_dimension = (16, 16) + +# Create curved mesh with 16 x 16 elements +mesh = StructuredMesh(cells_per_dimension, mapping) + +############################################################################### +# create the semi discretization object + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 2.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) + +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +save_solution = SaveSolutionCallback(interval=100, + save_initial_solution=true, + save_final_solution=true) + +stepsize_callback = StepsizeCallback(cfl=1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + 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/structured_2d_dgsem/elixir_eulerpolytropic_isothermal_wave.jl b/examples/structured_2d_dgsem/elixir_eulerpolytropic_isothermal_wave.jl new file mode 100644 index 00000000000..4ab90957579 --- /dev/null +++ b/examples/structured_2d_dgsem/elixir_eulerpolytropic_isothermal_wave.jl @@ -0,0 +1,83 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the polytropic Euler equations + +gamma = 1.0 # With gamma = 1 the system is isothermal. +kappa = 1.0 # Scaling factor for the pressure. +equations = PolytropicEulerEquations2D(gamma, kappa) + +# Linear pressure wave in the negative x-direction. +function initial_condition_wave(x, t, equations::PolytropicEulerEquations2D) + rho = 1.0 + v1 = 0.0 + if x[1] > 0.0 + rho = ((1.0 + 0.01 * sin(x[1] * 2 * pi)) / equations.kappa)^(1 / equations.gamma) + v1 = ((0.01 * sin((x[1] - 1 / 2) * 2 * pi)) / equations.kappa) + end + v2 = 0.0 + + return prim2cons(SVector(rho, v1, v2), equations) +end +initial_condition = initial_condition_wave + +volume_flux = flux_winters_etal +solver = DGSEM(polydeg = 2, surface_flux = flux_hll, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = (-2.0, -1.0) +coordinates_max = (2.0, 1.0) + +cells_per_dimension = (64, 32) + +boundary_conditions = (x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_periodic, + y_pos = boundary_condition_periodic) + +mesh = StructuredMesh(cells_per_dimension, + coordinates_min, + coordinates_max) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 1.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 200 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 50, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 1.7) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback) + +stage_limiter! = PositivityPreservingLimiterZhangShu(thresholds = (1.0e-4, 1.0e-4), + variables = (Trixi.density, pressure)) + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(stage_limiter!, 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); + +# Print the timer summary +summary_callback() diff --git a/examples/structured_2d_dgsem/elixir_eulerpolytropic_wave.jl b/examples/structured_2d_dgsem/elixir_eulerpolytropic_wave.jl new file mode 100644 index 00000000000..fd332b20aef --- /dev/null +++ b/examples/structured_2d_dgsem/elixir_eulerpolytropic_wave.jl @@ -0,0 +1,80 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the polytropic Euler equations + +gamma = 2.0 # Adiabatic monatomic gas in 2d. +kappa = 0.5 # Scaling factor for the pressure. +equations = PolytropicEulerEquations2D(gamma, kappa) + +# Linear pressure wave in the negative x-direction. +function initial_condition_wave(x, t, equations::PolytropicEulerEquations2D) + rho = 1.0 + v1 = 0.0 + if x[1] > 0.0 + rho = ((1.0 + 0.01 * sin(x[1] * 2 * pi)) / equations.kappa)^(1 / equations.gamma) + v1 = ((0.01 * sin((x[1] - 1 / 2) * 2 * pi)) / equations.kappa) + end + v2 = 0.0 + + return prim2cons(SVector(rho, v1, v2), equations) +end +initial_condition = initial_condition_wave + +volume_flux = flux_winters_etal +solver = DGSEM(polydeg = 2, surface_flux = flux_hll, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = (-2.0, -1.0) +coordinates_max = (2.0, 1.0) + +cells_per_dimension = (64, 32) + +boundary_conditions = (x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_periodic, + y_pos = boundary_condition_periodic) + +mesh = StructuredMesh(cells_per_dimension, + coordinates_min, + coordinates_max) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 1.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 200 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 50, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 1.7) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + 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); + +# Print the timer summary +summary_callback() diff --git a/src/Trixi.jl b/src/Trixi.jl index b65d03e7975..4169700898a 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -150,7 +150,8 @@ export AcousticPerturbationEquations2D, ShallowWaterEquations1D, ShallowWaterEquations2D, ShallowWaterTwoLayerEquations1D, ShallowWaterTwoLayerEquations2D, ShallowWaterEquationsQuasi1D, - LinearizedEulerEquations2D + LinearizedEulerEquations2D, + PolytropicEulerEquations2D export LaplaceDiffusion1D, LaplaceDiffusion2D, CompressibleNavierStokesDiffusion1D, CompressibleNavierStokesDiffusion2D, @@ -165,7 +166,7 @@ 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_es_fjordholm_etal, flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal, - flux_chan_etal, flux_nonconservative_chan_etal, + flux_chan_etal, flux_nonconservative_chan_etal, flux_winters_etal, hydrostatic_reconstruction_audusse_etal, flux_nonconservative_audusse_etal, # TODO: TrixiShallowWater: move anything with "chen_noelle" to new file hydrostatic_reconstruction_chen_noelle, flux_nonconservative_chen_noelle, diff --git a/src/auxiliary/math.jl b/src/auxiliary/math.jl index 4ecf7dd3fcc..38ea0bda8c8 100644 --- a/src/auxiliary/math.jl +++ b/src/auxiliary/math.jl @@ -211,4 +211,71 @@ Return `x` if `x` is negative, else zero. In other words, return @inline function negative_part(x) return min(x, zero(x)) end + +""" + stolarsky_mean(x, y, gamma) + +Compute an instance of a weighted Stolarsky mean of the form + + stolarsky_mean(x, y, gamma) = (gamma - 1)/gamma * (y^gamma - x^gamma) / (y^(gamma-1) - x^(gamma-1)) + +where `gamma > 1`. + +Problem: The formula above has a removable singularity at `x == y`. Thus, +some care must be taken to implement it correctly without problems or loss +of accuracy when `x ≈ y`. Here, we use the approach proposed by +Winters et al. (2020). +Set f = (y - x) / (y + x) and g = gamma (for compact notation). +Then, we use the expansions + + ((1+f)^g - (1-f)^g) / g = 2*f + (g-1)(g-2)/3 * f^3 + (g-1)(g-2)(g-3)(g-4)/60 * f^5 + O(f^7) + +and + + ((1+f)^(g-1) - (1-f)^(g-1)) / (g-1) = 2*f + (g-2)(g-3)/3 * f^3 + (g-2)(g-3)(g-4)(g-5)/60 * f^5 + O(f^7) + +Inserting the first few terms of these expansions and performing polynomial long division +we find that + + stolarsky_mean(x, y, gamma) ≈ (y + x) / 2 * (1 + (g-2)/3 * f^2 - (g+1)(g-2)(g-3)/45 * f^4 + (g+1)(g-2)(g-3)(2g(g-2)-9)/945 * f^6) + +Since divisions are usually more expensive on modern hardware than +multiplications (Agner Fog), we try to avoid computing two divisions. Thus, +we use + + f^2 = (y - x)^2 / (x + y)^2 + = (x * (x - 2 * y) + y * y) / (x * (x + 2 * y) + y * y) + +Given ε = 1.0e-4, we use the following algorithm. + + if f^2 < ε + # use the expansion above + else + # use the direct formula (gamma - 1)/gamma * (y^gamma - x^gamma) / (y^(gamma-1) - x^(gamma-1)) + end + +# References +- Andrew R. Winters, Christof Czernik, Moritz B. Schily & Gregor J. Gassner (2020) + Entropy stable numerical approximations for the isothermal and polytropic + Euler equations + [DOI: 10.1007/s10543-019-00789-w](https://doi.org/10.1007/s10543-019-00789-w) +- Agner Fog. + Lists of instruction latencies, throughputs and micro-operation breakdowns + 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 + 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) + else + return (gamma - 1) / gamma * (y^gamma - x^gamma) / + (y^(gamma - 1) - x^(gamma - 1)) + end +end end # @muladd diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 9bae563d85f..3142dcc2765 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -371,6 +371,11 @@ abstract type AbstractCompressibleEulerMulticomponentEquations{NDIMS, NVARS, NCO include("compressible_euler_multicomponent_1d.jl") include("compressible_euler_multicomponent_2d.jl") +# PolytropicEulerEquations +abstract type AbstractPolytropicEulerEquations{NDIMS, NVARS} <: + AbstractEquations{NDIMS, NVARS} end +include("polytropic_euler_2d.jl") + # Retrieve number of components from equation instance for the multicomponent case @inline function ncomponents(::AbstractCompressibleEulerMulticomponentEquations{NDIMS, NVARS, diff --git a/src/equations/polytropic_euler_2d.jl b/src/equations/polytropic_euler_2d.jl new file mode 100644 index 00000000000..d4902bbafb2 --- /dev/null +++ b/src/equations/polytropic_euler_2d.jl @@ -0,0 +1,257 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +@doc raw""" + PolytropicEulerEquations2D(gamma, kappa) + +The polytropic Euler equations +```math +\frac{\partial}{\partial t} +\begin{pmatrix} +\rho \\ \rho v_1 \\ \rho v_2 +\end{pmatrix} ++ +\frac{\partial}{\partial x} +\begin{pmatrix} + \rho v_1 \\ \rho v_1^2 + \kappa\rho^\gamma \\ \rho v_1 v_2 +\end{pmatrix} ++ +\frac{\partial}{\partial y} +\begin{pmatrix} +\rho v_2 \\ \rho v_1 v_2 \\ \rho v_2^2 + \kappa\rho^\gamma +\end{pmatrix} += +\begin{pmatrix} +0 \\ 0 \\ 0 +\end{pmatrix} +``` +for an ideal gas with ratio of specific heats `gamma` +in two space dimensions. +Here, ``\rho`` is the density and ``v_1`` and`v_2` the velocities and +```math +p = \kappa\rho^\gamma +``` +the pressure, which we replaced using this relation. +""" +struct PolytropicEulerEquations2D{RealT <: Real} <: + AbstractPolytropicEulerEquations{2, 3} + gamma::RealT # ratio of specific heats + kappa::RealT # fluid scaling factor + + function PolytropicEulerEquations2D(gamma, kappa) + gamma_, kappa_ = promote(gamma, kappa) + new{typeof(gamma_)}(gamma_, kappa_) + end +end + +function varnames(::typeof(cons2cons), ::PolytropicEulerEquations2D) + ("rho", "rho_v1", "rho_v2") +end +varnames(::typeof(cons2prim), ::PolytropicEulerEquations2D) = ("rho", "v1", "v2") + +""" + initial_condition_convergence_test(x, t, equations::PolytropicEulerEquations2D) + +Manufactured smooth initial condition used for convergence tests +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) + + return SVector(h, h / 2, 3 * h / 2) +end + +""" + source_terms_convergence_test(u, x, t, equations::PolytropicEulerEquations2D) + +Source terms used for convergence tests in combination with +[`initial_condition_convergence_test`](@ref). +""" +@inline function source_terms_convergence_test(u, x, t, + equations::PolytropicEulerEquations2D) + 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) + + 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 + + return SVector(r_1, r_2, r_3) +end + +""" + initial_condition_weak_blast_wave(x, t, equations::PolytropicEulerEquations2D) + +A weak blast wave adapted from +- Sebastian Hennemann, Gregor J. Gassner (2020) + A provably entropy stable subcell shock capturing approach for high order split form DG + [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) +""" +function initial_condition_weak_blast_wave(x, t, equations::PolytropicEulerEquations2D) + # Adapted MHD version of the weak blast wave from Hennemann & Gassner JCP paper 2020 (Sec. 6.3) + # Set up polar coordinates + inicenter = (0, 0) + 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) + + # 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) + + return prim2cons(SVector(rho, v1, v2), equations) +end + +# Calculate 1D flux for a single point in the normal direction +# Note, this directional vector is not normalized +@inline function flux(u, normal_direction::AbstractVector, + equations::PolytropicEulerEquations2D) + rho, v1, v2 = cons2prim(u, equations) + p = pressure(u, equations) + + v_normal = v1 * normal_direction[1] + v2 * normal_direction[2] + rho_v_normal = rho * v_normal + f1 = rho_v_normal + f2 = rho_v_normal * v1 + p * normal_direction[1] + f3 = rho_v_normal * v2 + p * normal_direction[2] + return SVector(f1, f2, f3) +end + +""" + flux_winters_etal(u_ll, u_rr, normal_direction, + equations::PolytropicEulerEquations2D) + +Entropy conserving two-point flux for isothermal or polytropic gases. +Requires a special weighted Stolarsky mean for the evaluation of the density +denoted here as `stolarsky_mean`. Note, for isothermal gases where `gamma = 1` +this `stolarsky_mean` becomes the [`ln_mean`](@ref). + +For details see Section 3.2 of the following reference +- Andrew R. Winters, Christof Czernik, Moritz B. Schily & Gregor J. Gassner (2020) + Entropy stable numerical approximations for the isothermal and polytropic + Euler equations + [DOI: 10.1007/s10543-019-00789-w](https://doi.org/10.1007/s10543-019-00789-w) +""" +@inline function flux_winters_etal(u_ll, u_rr, normal_direction::AbstractVector, + equations::PolytropicEulerEquations2D) + # Unpack left and right state + rho_ll, v1_ll, v2_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr = cons2prim(u_rr, equations) + p_ll = equations.kappa * rho_ll^equations.gamma + p_rr = equations.kappa * rho_rr^equations.gamma + v_dot_n_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] + 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 + 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) + + # Calculate fluxes depending on normal_direction + f1 = rho_mean * 0.5 * (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] + + return SVector(f1, f2, f3) +end + +@inline function min_max_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, + equations::PolytropicEulerEquations2D) + rho_ll, v1_ll, v2_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr = cons2prim(u_rr, equations) + p_ll = equations.kappa * rho_ll^equations.gamma + p_rr = equations.kappa * rho_rr^equations.gamma + + v_normal_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] + v_normal_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] + + norm_ = norm(normal_direction) + # The v_normals are already scaled by the norm + lambda_min = v_normal_ll - sqrt(equations.gamma * p_ll / rho_ll) * norm_ + lambda_max = v_normal_rr + sqrt(equations.gamma * p_rr / rho_rr) * norm_ + + return lambda_min, lambda_max +end + +@inline function max_abs_speeds(u, equations::PolytropicEulerEquations2D) + rho, v1, v2 = cons2prim(u, equations) + c = sqrt(equations.gamma * equations.kappa * rho^(equations.gamma - 1)) + + return abs(v1) + c, abs(v2) + c +end + +# Convert conservative variables to primitive +@inline function cons2prim(u, equations::PolytropicEulerEquations2D) + rho, rho_v1, rho_v2 = u + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + + return SVector(rho, v1, v2) +end + +# Convert conservative variables to entropy +@inline function cons2entropy(u, equations::PolytropicEulerEquations2D) + rho, rho_v1, rho_v2 = u + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + 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 + internal_energy = equations.kappa * log(rho) + else # equations.gamma > 1 # polytropic gas + internal_energy = equations.kappa * rho^(equations.gamma - 1) / + (equations.gamma - 1.0) + end + + w1 = internal_energy + p / rho - 0.5 * v_square + w2 = v1 + w3 = v2 + + return SVector(w1, w2, w3) +end + +# Convert primitive to conservative variables +@inline function prim2cons(prim, equations::PolytropicEulerEquations2D) + rho, v1, v2 = prim + rho_v1 = rho * v1 + rho_v2 = rho * v2 + return SVector(rho, rho_v1, rho_v2) +end + +@inline function density(u, equations::PolytropicEulerEquations2D) + rho = u[1] + return rho +end + +@inline function pressure(u, equations::PolytropicEulerEquations2D) + rho, rho_v1, rho_v2 = u + p = equations.kappa * rho^equations.gamma + return p +end +end # @muladd diff --git a/test/test_structured_2d.jl b/test/test_structured_2d.jl index 75937ba82ad..6d528abc7af 100644 --- a/test/test_structured_2d.jl +++ b/test/test_structured_2d.jl @@ -220,6 +220,30 @@ isdir(outdir) && rm(outdir, recursive=true) tspan = (0.0, 0.3)) end + @trixi_testset "elixir_eulerpolytropic_convergence.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulerpolytropic_convergence.jl"), + l2 = [0.0016688820596537988, 0.0025921681885685425, 0.003280950351435014], + linf = [0.010994679664394269, 0.01331197845637, 0.020080117011346488]) + end + + @trixi_testset "elixir_eulerpolytropic_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulerpolytropic_ec.jl"), + l2 = [0.03647890611450939, 0.025284915444045052, 0.025340697771609126], + linf = [0.32516731565355583, 0.37509762516540046, 0.29812843284727336]) + end + + @trixi_testset "elixir_eulerpolytropic_isothermal_wave.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulerpolytropic_isothermal_wave.jl"), + l2 = [0.004998778491726366, 0.004998916000294425, 9.259136963058664e-17], + linf = [0.010001103673834888, 0.010051165098399503, 7.623942913643681e-16]) + end + + @trixi_testset "elixir_eulerpolytropic_wave.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulerpolytropic_wave.jl"), + l2 = [0.23642682112204072, 0.20904264390331334, 8.174982691297391e-17], + linf = [0.4848250368349989, 0.253350873815695, 4.984552457753618e-16]) + end + @trixi_testset "elixir_hypdiff_nonperiodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_nonperiodic.jl"), l2 = [0.8799744480157664, 0.8535008397034816, 0.7851383019164209], From fc00ac1bd8a527ac7ed14d9b274b222c874dbf46 Mon Sep 17 00:00:00 2001 From: Benjamin Bolm <74359358+bennibolm@users.noreply.github.com> Date: Fri, 20 Oct 2023 16:16:49 +0200 Subject: [PATCH 131/263] Add implementation of subcell bounds check (#1672) * Add implementation of bounds check * Shorten code by relocate use of `interval` * Add note in docstring * Fix note in docstring of `SubcellLimiterIDP` * Add test for deviations file * Adapt last commit to specific setup in test * Adapt test * Disable test if `!coverage` * Remove non-needed code * Implement first suggestions * Dispatch `init/finalize_callback()` routines * Revise docstring * Rework calculation of bounds * Fix typo * Add comment * Replace construction of `Symbol`s * Implement suggestions for docstring --- .../elixir_euler_shockcapturing_subcell.jl | 2 +- ...ubble_shockcapturing_subcell_positivity.jl | 4 +- src/Trixi.jl | 2 +- src/callbacks_stage/callbacks_stage.jl | 1 + src/callbacks_stage/subcell_bounds_check.jl | 130 ++++++++++++++++++ .../subcell_bounds_check_2d.jl | 49 +++++++ src/solvers/dgsem_tree/subcell_limiters.jl | 4 +- src/solvers/dgsem_tree/subcell_limiters_2d.jl | 12 +- test/test_tree_2d_eulermulti.jl | 7 +- 9 files changed, 203 insertions(+), 8 deletions(-) create mode 100644 src/callbacks_stage/subcell_bounds_check.jl create mode 100644 src/callbacks_stage/subcell_bounds_check_2d.jl diff --git a/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl b/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl index 6b69e4db563..c696e2de416 100644 --- a/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl +++ b/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl @@ -84,7 +84,7 @@ callbacks = CallbackSet(summary_callback, ############################################################################### # run the simulation -stage_callbacks = (SubcellLimiterIDPCorrection(),) +stage_callbacks = (SubcellLimiterIDPCorrection(), BoundsCheckCallback(save_errors=false)) sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks=stage_callbacks); dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback diff --git a/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl index a67eaeb5b2b..c5a7a5932e6 100644 --- a/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl +++ b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl @@ -132,7 +132,9 @@ callbacks = CallbackSet(summary_callback, ############################################################################### # run the simulation -stage_callbacks = (SubcellLimiterIDPCorrection(),) +output_directory = "out" +stage_callbacks = (SubcellLimiterIDPCorrection(), + BoundsCheckCallback(save_errors=true, interval=100, output_directory=output_directory)) sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks=stage_callbacks); dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback diff --git a/src/Trixi.jl b/src/Trixi.jl index 4169700898a..457d9dc336d 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -232,7 +232,7 @@ export DG, SurfaceIntegralUpwind, MortarL2 -export VolumeIntegralSubcellLimiting, +export VolumeIntegralSubcellLimiting, BoundsCheckCallback, SubcellLimiterIDP, SubcellLimiterIDPCorrection export nelements, nnodes, nvariables, diff --git a/src/callbacks_stage/callbacks_stage.jl b/src/callbacks_stage/callbacks_stage.jl index 976af327e6f..70d60de7914 100644 --- a/src/callbacks_stage/callbacks_stage.jl +++ b/src/callbacks_stage/callbacks_stage.jl @@ -7,6 +7,7 @@ include("positivity_zhang_shu.jl") include("subcell_limiter_idp_correction.jl") +include("subcell_bounds_check.jl") # TODO: TrixiShallowWater: move specific limiter file include("positivity_shallow_water.jl") end # @muladd diff --git a/src/callbacks_stage/subcell_bounds_check.jl b/src/callbacks_stage/subcell_bounds_check.jl new file mode 100644 index 00000000000..c86f266147c --- /dev/null +++ b/src/callbacks_stage/subcell_bounds_check.jl @@ -0,0 +1,130 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +""" + BoundsCheckCallback(; output_directory="out", save_errors=false, interval=1) + +Subcell limiting techniques with [`SubcellLimiterIDP`](@ref) are constructed to adhere certain +local or global bounds. To make sure that these bounds are actually met, this callback calculates +the maximum deviation from the bounds. The maximum deviation per applied bound is printed to +the screen at the end of the simulation. +For more insights, when setting `save_errors=true` the occurring errors are exported every +`interval` time steps during the simulation. Then, the maximum deviations since the last +export are saved in "`output_directory`/deviations.txt". +The `BoundsCheckCallback` has to be applied as a stage callback for the SSPRK time integration scheme. + +!!! note + For `SubcellLimiterIDP`, the solution is corrected in the a posteriori correction stage + [`SubcellLimiterIDPCorrection`](@ref). So, to check the final solution, this bounds check + callback must be called after the correction stage. +""" +struct BoundsCheckCallback + output_directory::String + save_errors::Bool + interval::Int +end + +function BoundsCheckCallback(; output_directory = "out", save_errors = false, + interval = 1) + BoundsCheckCallback(output_directory, save_errors, interval) +end + +function (callback::BoundsCheckCallback)(u_ode, integrator, stage) + mesh, equations, solver, cache = mesh_equations_solver_cache(integrator.p) + (; t, iter, alg) = integrator + u = wrap_array(u_ode, mesh, equations, solver, cache) + + save_errors = callback.save_errors && (callback.interval > 0) && + (stage == length(alg.c)) && + (iter % callback.interval == 0 || integrator.finalstep) + @trixi_timeit timer() "check_bounds" check_bounds(u, mesh, equations, solver, cache, + solver.volume_integral, t, + iter + 1, + callback.output_directory, + save_errors) +end + +function check_bounds(u, mesh, equations, solver, cache, + volume_integral::AbstractVolumeIntegral, t, iter, + output_directory, save_errors) + return nothing +end + +function check_bounds(u, mesh, equations, solver, cache, + volume_integral::VolumeIntegralSubcellLimiting, t, iter, + output_directory, save_errors) + check_bounds(u, mesh, equations, solver, cache, volume_integral.limiter, t, iter, + output_directory, save_errors) +end + +function init_callback(callback::BoundsCheckCallback, semi) + init_callback(callback, semi, semi.solver.volume_integral) +end + +init_callback(callback::BoundsCheckCallback, semi, volume_integral::AbstractVolumeIntegral) = nothing + +function init_callback(callback::BoundsCheckCallback, semi, + volume_integral::VolumeIntegralSubcellLimiting) + init_callback(callback, semi, volume_integral.limiter) +end + +function init_callback(callback::BoundsCheckCallback, semi, limiter::SubcellLimiterIDP) + if !callback.save_errors || (callback.interval == 0) + return nothing + end + + (; positivity) = limiter + (; output_directory) = callback + variables = varnames(cons2cons, semi.equations) + + mkpath(output_directory) + open("$output_directory/deviations.txt", "a") do f + print(f, "# iter, simu_time") + if positivity + for v in limiter.positivity_variables_cons + print(f, ", " * string(variables[v]) * "_min") + end + end + println(f) + end + + return nothing +end + +function finalize_callback(callback::BoundsCheckCallback, semi) + finalize_callback(callback, semi, semi.solver.volume_integral) +end + +finalize_callback(callback::BoundsCheckCallback, semi, volume_integral::AbstractVolumeIntegral) = nothing + +function finalize_callback(callback::BoundsCheckCallback, semi, + volume_integral::VolumeIntegralSubcellLimiting) + finalize_callback(callback, semi, volume_integral.limiter) +end + +@inline function finalize_callback(callback::BoundsCheckCallback, semi, + limiter::SubcellLimiterIDP) + (; positivity) = limiter + (; idp_bounds_delta) = limiter.cache + variables = varnames(cons2cons, semi.equations) + + println("─"^100) + println("Maximum deviation from bounds:") + println("─"^100) + if positivity + for v in limiter.positivity_variables_cons + println(string(variables[v]) * ":\n- positivity: ", + idp_bounds_delta[Symbol(string(v), "_min")][2]) + end + end + println("─"^100 * "\n") + + return nothing +end + +include("subcell_bounds_check_2d.jl") +end # @muladd diff --git a/src/callbacks_stage/subcell_bounds_check_2d.jl b/src/callbacks_stage/subcell_bounds_check_2d.jl new file mode 100644 index 00000000000..8159becb503 --- /dev/null +++ b/src/callbacks_stage/subcell_bounds_check_2d.jl @@ -0,0 +1,49 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +@inline function check_bounds(u, mesh::AbstractMesh{2}, equations, solver, cache, + limiter::SubcellLimiterIDP, + time, iter, output_directory, save_errors) + (; positivity) = solver.volume_integral.limiter + (; variable_bounds) = limiter.cache.subcell_limiter_coefficients + (; idp_bounds_delta) = limiter.cache + + if positivity + for v in limiter.positivity_variables_cons + key = Symbol(string(v), "_min") + deviation = idp_bounds_delta[key] + for element in eachelement(solver, cache), j in eachnode(solver), + i in eachnode(solver) + + var = u[v, i, j, element] + deviation[1] = max(deviation[1], + variable_bounds[key][i, j, element] - var) + end + deviation[2] = max(deviation[2], deviation[1]) + end + end + if save_errors + # Print to output file + open("$output_directory/deviations.txt", "a") do f + print(f, iter, ", ", time) + if positivity + for v in limiter.positivity_variables_cons + key = Symbol(string(v), "_min") + print(f, ", ", idp_bounds_delta[key][1]) + end + end + println(f) + end + # Reset first entries of idp_bounds_delta + for (key, _) in idp_bounds_delta + idp_bounds_delta[key][1] = zero(eltype(idp_bounds_delta[key][1])) + end + end + + return nothing +end +end # @muladd diff --git a/src/solvers/dgsem_tree/subcell_limiters.jl b/src/solvers/dgsem_tree/subcell_limiters.jl index 6197ca6b85d..55d402954bf 100644 --- a/src/solvers/dgsem_tree/subcell_limiters.jl +++ b/src/solvers/dgsem_tree/subcell_limiters.jl @@ -26,7 +26,7 @@ The bounds are calculated using the low-order FV solution. The positivity limite !!! note This limiter and the correction callback [`SubcellLimiterIDPCorrection`](@ref) only work together. - Without the callback, no limiting takes place, leading to a standard flux-differencing DGSEM scheme. + Without the callback, no correction takes place, leading to a standard low-order FV scheme. ## References @@ -53,7 +53,7 @@ function SubcellLimiterIDP(equations::AbstractEquations, basis; positivity_correction_factor = 0.1) positivity = (length(positivity_variables_cons) > 0) - bound_keys = Tuple(Symbol("$(i)_min") for i in positivity_variables_cons) + bound_keys = Tuple(Symbol(string(v), "_min") for v in positivity_variables_cons) cache = create_cache(SubcellLimiterIDP, equations, basis, bound_keys) diff --git a/src/solvers/dgsem_tree/subcell_limiters_2d.jl b/src/solvers/dgsem_tree/subcell_limiters_2d.jl index 4497217fb56..5e00ab4e903 100644 --- a/src/solvers/dgsem_tree/subcell_limiters_2d.jl +++ b/src/solvers/dgsem_tree/subcell_limiters_2d.jl @@ -13,7 +13,15 @@ function create_cache(limiter::Type{SubcellLimiterIDP}, equations::AbstractEquat nnodes(basis), bound_keys) - return (; subcell_limiter_coefficients) + # Memory for bounds checking routine with `BoundsCheckCallback`. + # The first entry of each vector contains the maximum deviation since the last export. + # The second one contains the total maximum deviation. + idp_bounds_delta = Dict{Symbol, Vector{real(basis)}}() + for key in bound_keys + idp_bounds_delta[key] = zeros(real(basis), 2) + end + + return (; subcell_limiter_coefficients, idp_bounds_delta) end function (limiter::SubcellLimiterIDP)(u::AbstractArray{<:Any, 4}, semi, dg::DGSEM, t, @@ -60,7 +68,7 @@ end (; positivity_correction_factor) = limiter (; variable_bounds) = limiter.cache.subcell_limiter_coefficients - var_min = variable_bounds[Symbol("$(variable)_min")] + var_min = variable_bounds[Symbol(string(variable), "_min")] @threaded for element in eachelement(dg, semi.cache) inverse_jacobian = cache.elements.inverse_jacobian[element] diff --git a/test/test_tree_2d_eulermulti.jl b/test/test_tree_2d_eulermulti.jl index 606afca1034..0ae46a92ef8 100644 --- a/test/test_tree_2d_eulermulti.jl +++ b/test/test_tree_2d_eulermulti.jl @@ -20,11 +20,16 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") end @trixi_testset "elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl" begin + rm("out/deviations.txt", force=true) @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl"), l2 = [81.52845664909304, 2.5455678559421346, 63229.190712645846, 0.19929478404550321, 0.011068604228443425], linf = [249.21708417382013, 40.33299887640794, 174205.0118831558, 0.6881458768113586, 0.11274401158173972], initial_refinement_level = 3, - tspan = (0.0, 0.001)) + tspan = (0.0, 0.001), + output_directory="out") + lines = readlines("out/deviations.txt") + @test lines[1] == "# iter, simu_time, rho1_min, rho2_min" + @test startswith(lines[end], "1") end @trixi_testset "elixir_eulermulti_ec.jl" begin From fcab6a9e50531e5a77e0de77f2f369d75c5a7716 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Sat, 21 Oct 2023 17:58:50 +0200 Subject: [PATCH 132/263] Add comments explaining why weak form is only for conserved terms (#1676) * Add comments explaining why weak form is only for conserved terms * Update src/solvers/dg.jl Co-authored-by: Andrew Winters * Update src/solvers/dgsem_structured/dg_2d.jl Co-authored-by: Andrew Winters * Update src/solvers/dg.jl Co-authored-by: Andrew Winters * Update src/solvers/dgsem_structured/dg_3d.jl Co-authored-by: Andrew Winters * Update src/solvers/dgsem_structured/dg_2d.jl Co-authored-by: Andrew Winters * Update src/solvers/dgsem_tree/dg_2d.jl Co-authored-by: Andrew Winters * Update src/solvers/dgsem_tree/dg_1d.jl Co-authored-by: Andrew Winters * Update src/solvers/dgsem_tree/dg_3d.jl Co-authored-by: Andrew Winters * Update src/solvers/dgsem_tree/dg_2d.jl Co-authored-by: Andrew Winters * Update src/solvers/dgsem_tree/dg_3d.jl Co-authored-by: Andrew Winters * Update src/solvers/dgsem_structured/dg_3d.jl Co-authored-by: Andrew Winters * Update src/solvers/dgsem_tree/dg_1d.jl Co-authored-by: Andrew Winters * Update src/solvers/dg.jl Co-authored-by: Hendrik Ranocha --------- Co-authored-by: Andrew Winters Co-authored-by: Hendrik Ranocha --- src/solvers/dg.jl | 5 +++++ src/solvers/dgsem_structured/dg_2d.jl | 7 +++++++ src/solvers/dgsem_structured/dg_3d.jl | 7 +++++++ src/solvers/dgsem_tree/dg_1d.jl | 7 +++++++ src/solvers/dgsem_tree/dg_2d.jl | 7 +++++++ src/solvers/dgsem_tree/dg_3d.jl | 7 +++++++ 6 files changed, 40 insertions(+) diff --git a/src/solvers/dg.jl b/src/solvers/dg.jl index 30b4f67474f..91ad59b76b6 100644 --- a/src/solvers/dg.jl +++ b/src/solvers/dg.jl @@ -40,6 +40,11 @@ standard textbooks. Nodal Discontinuous Galerkin Methods: Algorithms, Analysis, and Applications [doi: 10.1007/978-0-387-72067-8](https://doi.org/10.1007/978-0-387-72067-8) + +`VolumeIntegralWeakForm()` is only implemented for conserved terms as +non-conservative terms should always be discretized in conjunction with a flux-splitting scheme, +see [`VolumeIntegralFluxDifferencing`](@ref). +This treatment is required to achieve, e.g., entropy-stability or well-balancedness. """ struct VolumeIntegralWeakForm <: AbstractVolumeIntegral end diff --git a/src/solvers/dgsem_structured/dg_2d.jl b/src/solvers/dgsem_structured/dg_2d.jl index 3e8ce759b30..25a0eea096f 100644 --- a/src/solvers/dgsem_structured/dg_2d.jl +++ b/src/solvers/dgsem_structured/dg_2d.jl @@ -49,6 +49,13 @@ function rhs!(du, u, t, return nothing 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, +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 +=# @inline function weak_form_kernel!(du, u, element, mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, diff --git a/src/solvers/dgsem_structured/dg_3d.jl b/src/solvers/dgsem_structured/dg_3d.jl index 0e6bf8a2ac0..cdb085e9008 100644 --- a/src/solvers/dgsem_structured/dg_3d.jl +++ b/src/solvers/dgsem_structured/dg_3d.jl @@ -49,6 +49,13 @@ function rhs!(du, u, t, return nothing 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, +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 +=# @inline function weak_form_kernel!(du, u, element, mesh::Union{StructuredMesh{3}, P4estMesh{3}}, diff --git a/src/solvers/dgsem_tree/dg_1d.jl b/src/solvers/dgsem_tree/dg_1d.jl index b5bb076f3b7..4a0747d1c09 100644 --- a/src/solvers/dgsem_tree/dg_1d.jl +++ b/src/solvers/dgsem_tree/dg_1d.jl @@ -144,6 +144,13 @@ function calc_volume_integral!(du, u, return nothing 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, +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 +=# @inline function weak_form_kernel!(du, u, element, mesh::Union{TreeMesh{1}, StructuredMesh{1}}, nonconservative_terms::False, equations, diff --git a/src/solvers/dgsem_tree/dg_2d.jl b/src/solvers/dgsem_tree/dg_2d.jl index c30d0a8e01a..7ecf4c00032 100644 --- a/src/solvers/dgsem_tree/dg_2d.jl +++ b/src/solvers/dgsem_tree/dg_2d.jl @@ -194,6 +194,13 @@ function calc_volume_integral!(du, u, return nothing 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, +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 +=# @inline function weak_form_kernel!(du, u, element, mesh::TreeMesh{2}, nonconservative_terms::False, equations, diff --git a/src/solvers/dgsem_tree/dg_3d.jl b/src/solvers/dgsem_tree/dg_3d.jl index acdab900cd1..3364187e93c 100644 --- a/src/solvers/dgsem_tree/dg_3d.jl +++ b/src/solvers/dgsem_tree/dg_3d.jl @@ -223,6 +223,13 @@ function calc_volume_integral!(du, u, return nothing 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, +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 +=# @inline function weak_form_kernel!(du, u, element, mesh::TreeMesh{3}, nonconservative_terms::False, equations, From a70f1afd5f11afca1e9f1172717d4d3bd51e2753 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Sat, 21 Oct 2023 22:32:35 +0200 Subject: [PATCH 133/263] Passing Allocation tests (#1682) * Passing Allocation tests * neural networks allocate * remove alloc tests for neural networks, bring back deleted stuff * confused test * add if clause for coverage * out-comment kpp --------- Co-authored-by: Hendrik Ranocha --- test/test_dgmulti_1d.jl | 48 ++++ test/test_dgmulti_3d.jl | 113 ++++++++- test/test_p4est_3d.jl | 161 ++++++++++++- test/test_parabolic_1d.jl | 64 ++++++ test/test_parabolic_2d.jl | 181 ++++++++++++++- test/test_parabolic_3d.jl | 99 +++++++- test/test_structured_1d.jl | 56 +++++ test/test_structured_3d.jl | 112 +++++++++ test/test_t8code_2d.jl | 120 +++++++++- test/test_tree_1d_advection.jl | 32 +++ test/test_tree_1d_burgers.jl | 32 +++ test/test_tree_1d_euler.jl | 136 +++++++++++ test/test_tree_1d_eulergravity.jl | 8 + test/test_tree_1d_eulermulti.jl | 52 ++++- test/test_tree_1d_fdsbp.jl | 36 +++ test/test_tree_1d_mhd.jl | 72 ++++++ test/test_tree_1d_mhdmulti.jl | 42 +++- test/test_tree_1d_shallowwater.jl | 128 +++++++++++ test/test_tree_1d_shallowwater_twolayer.jl | 32 +++ test/test_tree_2d_acoustics.jl | 40 ++++ test/test_tree_2d_euler.jl | 253 ++++++++++++++++++++- test/test_tree_2d_euleracoustics.jl | 8 + test/test_tree_2d_eulermulti.jl | 56 +++++ test/test_tree_2d_fdsbp.jl | 27 +++ test/test_tree_2d_kpp.jl | 11 + test/test_tree_2d_lbm.jl | 51 ++++- test/test_tree_2d_linearizedeuler.jl | 17 ++ test/test_tree_2d_mhd.jl | 72 ++++++ test/test_tree_2d_mhdmulti.jl | 40 ++++ test/test_tree_2d_shallowwater.jl | 80 +++++++ test/test_tree_2d_shallowwater_twolayer.jl | 32 +++ test/test_tree_3d_advection.jl | 49 ++++ test/test_tree_3d_euler.jl | 136 +++++++++++ test/test_tree_3d_eulergravity.jl | 8 + test/test_tree_3d_fdsbp.jl | 18 ++ test/test_tree_3d_lbm.jl | 16 ++ test/test_tree_3d_mhd.jl | 66 +++++- test/test_unstructured_2d.jl | 192 ++++++++++++++++ utils/add_alloctest.py | 43 ++++ 39 files changed, 2703 insertions(+), 36 deletions(-) create mode 100644 utils/add_alloctest.py diff --git a/test/test_dgmulti_1d.jl b/test/test_dgmulti_1d.jl index 7cc31c33040..180838158ea 100644 --- a/test/test_dgmulti_1d.jl +++ b/test/test_dgmulti_1d.jl @@ -19,6 +19,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [2.9953644500009865e-5], linf = [4.467840577382365e-5] ) + # 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_flux_diff.jl " begin @@ -28,11 +36,27 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [7.853842541289665e-7, 9.609905503440606e-7, 2.832322219966481e-6] ./ sqrt(2.0), linf = [1.5003758788711963e-6, 1.802998748523521e-6, 4.83599270806323e-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 end @trixi_testset "elixir_euler_flux_diff.jl (convergence)" begin mean_convergence = convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "elixir_euler_flux_diff.jl"), 3) @test isapprox(mean_convergence[:l2], [4.1558759698638434, 3.977911306037128, 4.041421206468769], rtol=0.05) + # 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_flux_diff.jl (SBP) " begin @@ -42,6 +66,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [6.437827414849647e-6, 2.1840558851820947e-6, 1.3245669629438228e-5], linf = [2.0715843751295537e-5, 8.519520630301258e-6, 4.2642194098885255e-5] ) + # 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_flux_diff.jl (FD SBP)" begin @@ -56,6 +88,14 @@ isdir(outdir) && rm(outdir, recursive=true) ) show(stdout, semi.solver.basis) show(stdout, MIME"text/plain"(), semi.solver.basis) + # 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_fdsbp_periodic.jl" begin @@ -65,6 +105,14 @@ isdir(outdir) && rm(outdir, recursive=true) ) show(stdout, semi.solver.basis) show(stdout, MIME"text/plain"(), semi.solver.basis) + # 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 "DGMulti with periodic SBP unit test" begin diff --git a/test/test_dgmulti_3d.jl b/test/test_dgmulti_3d.jl index 68fa1d13304..d2556ae434b 100644 --- a/test/test_dgmulti_3d.jl +++ b/test/test_dgmulti_3d.jl @@ -19,6 +19,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0010029534292051608, 0.0011682205957721673, 0.001072975385793516, 0.000997247778892257, 0.0039364354651358294] ./ sqrt(8), linf = [0.003660737033303718, 0.005625620600749226, 0.0030566354814669516, 0.0041580358824311325, 0.019326660236036464] ) + # 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_weakform.jl (EC)" begin @@ -29,6 +37,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.014932088450136542, 0.017080219613061526, 0.016589517840793006, 0.015905000907070196, 0.03903416208587798] ./ sqrt(8), linf = [0.06856547797256729, 0.08225664880340489, 0.06925055630951782, 0.06913016119820181, 0.19161418499621874] ) + # 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_weakform.jl (Hexahedral elements)" begin @@ -38,6 +54,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.00030580190715769566, 0.00040146357607439464, 0.00040146357607564597, 0.000401463576075708, 0.0015749412434154315] ./ sqrt(8), linf = [0.00036910287847780054, 0.00042659774184228283, 0.0004265977427213574, 0.00042659774250686233, 0.00143803344597071] ) + # 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_curved.jl (Hex elements, SBP, flux differencing)" begin @@ -45,6 +69,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.018354883045936066, 0.024412704052042846, 0.024408520416087945, 0.01816314570880129, 0.039342805507972006], linf = [0.14862225990775757, 0.28952368161864683, 0.2912054484817035, 0.1456603133854122, 0.3315354586775472] ) + # 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_curved.jl (Hex elements, GaussSBP, flux differencing)" begin @@ -53,6 +85,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.002631131519508634, 0.0029144224044954105, 0.002913889110662827, 0.002615140832314194, 0.006881528610614373], linf = [0.020996114874140215, 0.021314522450134543, 0.021288322783006297, 0.020273381695435244, 0.052598740390024545] ) + # 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_weakform_periodic.jl" begin @@ -61,6 +101,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0010317074322517949, 0.0012277090547035293, 0.0011273991123913515, 0.0010418496196130177, 0.004058878478404962] ./ sqrt(8), linf = [0.003227752881827861, 0.005620317864620361, 0.0030514833972379307, 0.003987027618439498, 0.019282224709831652] ) + # 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_weakform_periodic.jl (Hexahedral elements)" begin @@ -70,6 +118,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.00034230612468547436, 0.00044397204714598747, 0.0004439720471461567, 0.0004439720471464591, 0.0016639410646990126] ./ sqrt(8), linf = [0.0003674374460325147, 0.0004253921341716982, 0.0004253921340786615, 0.0004253921340831024, 0.0014333414071048267] ) + # 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_weakform_periodic.jl (Hexahedral elements, SBP, EC)" begin @@ -82,6 +138,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.001712443468716032, 0.002491315550718859, 0.0024913155507195303, 0.002491315550720031, 0.008585818982343299] ./ sqrt(8), linf = [0.003810078279323559, 0.004998778644230928, 0.004998778643986235, 0.0049987786444081195, 0.016455044373650196] ) + # 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_taylor_green_vortex.jl" begin @@ -90,6 +154,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0003612827827560599, 0.06219350883951729, 0.062193508839503864, 0.08121963221634831, 0.07082703570808184], linf = [0.0007893509649821162, 0.1481953939988877, 0.14819539399791176, 0.14847291108358926, 0.21313533492212855] ) + # 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_taylor_green_vortex.jl (GaussSBP)" begin @@ -98,6 +170,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.00036128278275524326, 0.062193508839511434, 0.06219350883949677, 0.08121963221635205, 0.07082703570765223], linf = [0.000789350964946367, 0.14819539399525805, 0.14819539399590542, 0.14847291107658706, 0.21313533492059378] ) + # 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_weakform_periodic.jl (FD SBP)" begin @@ -111,6 +191,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0024092707138829925, 0.003318758964118284, 0.0033187589641182386, 0.003318758964118252, 0.012689348410504253], linf = [0.006118565824207778, 0.008486456080185167, 0.008486456080180282, 0.008486456080185611, 0.035113544599208346] ) + # 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_weakform_periodic.jl (FD SBP, EC)" begin @@ -126,6 +214,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0034543609010604407, 0.004944363692625066, 0.0049443636926250435, 0.004944363692625037, 0.01788695279620914], linf = [0.013861851418853988, 0.02126572106620328, 0.021265721066209053, 0.021265721066210386, 0.0771455289446683] ) + # 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_fdsbp_periodic.jl" begin @@ -133,14 +229,29 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [7.561896970325353e-5, 6.884047859361093e-5, 6.884047859363204e-5, 6.884047859361148e-5, 0.000201107274617457], linf = [0.0001337520020225913, 0.00011571467799287305, 0.0001157146779990903, 0.00011571467799376123, 0.0003446082308800058] ) + # 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_tensor_wedge.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_tensor_wedge.jl"), l2 = [2.30487910e-04] , linf = [6.31795281e-04] ) + # 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 diff --git a/test/test_p4est_3d.jl b/test/test_p4est_3d.jl index f22e98456ae..370f864b5aa 100644 --- a/test/test_p4est_3d.jl +++ b/test/test_p4est_3d.jl @@ -17,27 +17,42 @@ isdir(outdir) && rm(outdir, recursive=true) # Expected errors are exactly the same as with TreeMesh! l2 = [0.00016263963870641478], linf = [0.0014537194925779984]) + # 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_unstructured_curved.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_unstructured_curved.jl"), l2 = [0.0004750004258546538], linf = [0.026527551737137167]) + # 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_nonconforming.jl" begin @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 - # (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 + # 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_amr.jl" begin @@ -46,6 +61,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [9.773852895157622e-6], linf = [0.0005853874124926162], 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 + # (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_amr_unstructured_curved.jl" begin @@ -54,18 +77,42 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [0.0010554006923731395], 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 + # (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_cubed_sphere.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_cubed_sphere.jl"), l2 = [0.002006918015656413], linf = [0.027655117058380085]) + # 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_restart.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), l2 = [0.002590388934758452], linf = [0.01840757696885409]) + # 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_source_terms_nonconforming_unstructured_curved.jl" begin @@ -73,6 +120,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [4.070355207909268e-5, 4.4993257426833716e-5, 5.10588457841744e-5, 5.102840924036687e-5, 0.00019986264001630542], linf = [0.0016987332417202072, 0.003622956808262634, 0.002029576258317789, 0.0024206977281964193, 0.008526972236273522], tspan = (0.0, 0.01)) + # 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_source_terms_nonperiodic.jl" begin @@ -80,6 +135,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0015106060984283647, 0.0014733349038567685, 0.00147333490385685, 0.001473334903856929, 0.0028149479453087093], linf = [0.008070806335238156, 0.009007245083113125, 0.009007245083121784, 0.009007245083102688, 0.01562861968368434], tspan = (0.0, 1.0)) + # 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.jl" begin @@ -87,6 +150,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [5.162664597942288e-15, 1.941857343642486e-14, 2.0232366394187278e-14, 2.3381518645408552e-14, 7.083114561232324e-14], linf = [7.269740365245525e-13, 3.289868377720495e-12, 4.440087186807773e-12, 3.8686831516088205e-12, 9.412914891981927e-12], tspan = (0.0, 0.03)) + # 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" begin @@ -94,6 +165,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [8.444868392439035e-16, 4.889826056731442e-15, 2.2921260987087585e-15, 4.268460455702414e-15, 1.1356712092620279e-14], linf = [7.749356711883593e-14, 2.8792246364872653e-13, 1.1121659149182506e-13, 3.3228975127030935e-13, 9.592326932761353e-13], tspan=(0.0, 0.1)) + # 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_ec.jl" begin @@ -102,6 +181,14 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [0.3326911600075694, 0.2824952141320467, 0.41401037398065543, 0.45574161423218573, 0.8099577682187109], tspan = (0.0, 0.2), coverage_override = (polydeg=3,)) # Prevent long compile time in CI + # 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 @@ -110,6 +197,14 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [7.45329845e-01, 3.21754792e-01, 3.21754792e-01, 3.21754792e-01, 4.76151527e+00], tspan = (0.0, 0.3), coverage_override = (polydeg=3,)) # Prevent long compile time in CI + # 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_source_terms_nonconforming_earth.jl" begin @@ -119,6 +214,14 @@ isdir(outdir) && rm(outdir, recursive=true) # Decrease tolerance of adaptive time stepping to get similar results across different systems abstol=1.0e-11, reltol=1.0e-11, coverage_override = (trees_per_cube_face=(1, 1), polydeg=3)) # Prevent long compile time in CI + # 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_circular_wind_nonconforming.jl" begin @@ -127,6 +230,14 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [2.2695202613887133e-6, 0.0005314968179916946, 0.0005314969614147458, 0.0005130280733059617, 0.7944959432352334], tspan = (0.0, 2e2), coverage_override = (trees_per_cube_face=(1, 1), polydeg=3)) # Prevent long compile time in CI + # 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_baroclinic_instability.jl" begin @@ -137,12 +248,28 @@ isdir(outdir) && rm(outdir, recursive=true) # Decrease tolerance of adaptive time stepping to get similar results across different systems abstol=1.0e-9, reltol=1.0e-9, coverage_override = (trees_per_cube_face=(1, 1), polydeg=3)) # Prevent long compile time in CI + # 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_source_terms_nonperiodic_hohqmesh.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonperiodic_hohqmesh.jl"), l2 = [0.0042023406458005464, 0.004122532789279737, 0.0042448149597303616, 0.0036361316700401765, 0.007389845952982495], linf = [0.04530610539892499, 0.02765695110527666, 0.05670295599308606, 0.048396544302230504, 0.1154589758186293]) + # 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_mhd_alfven_wave_nonconforming.jl" begin @@ -155,6 +282,14 @@ isdir(outdir) && rm(outdir, recursive=true) 1.3475027166309006e-5], tspan = (0.0, 0.25), coverage_override = (trees_per_dimension=(1, 1, 1),)) + # 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_mhd_shockcapturing_amr.jl" begin @@ -167,6 +302,14 @@ isdir(outdir) && rm(outdir, recursive=true) 0.000535219040687628], tspan = (0.0, 0.04), coverage_override = (maxiters=6, initial_refinement_level=1, base_level=1, max_level=2)) + # 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 diff --git a/test/test_parabolic_1d.jl b/test/test_parabolic_1d.jl index f00138c698c..d1f8b4d8057 100644 --- a/test/test_parabolic_1d.jl +++ b/test/test_parabolic_1d.jl @@ -18,6 +18,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [8.389498188525518e-06], linf = [2.847421658558336e-05] ) + # 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 "TreeMesh1D: elixir_advection_diffusion.jl (AMR)" begin @@ -40,6 +48,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2_error, linf_error = analysis_callback(sol) @test l2_error ≈ [6.4878111416468355e-6] @test linf_error ≈ [3.258075790424364e-5] + # 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 "TreeMesh1D: elixir_navierstokes_convergence_periodic.jl" begin @@ -47,6 +63,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0001133835907077494, 6.226282245610444e-5, 0.0002820171699999139], linf = [0.0006255102377159538, 0.00036195501456059986, 0.0016147729485886941] ) + # 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 "TreeMesh1D: elixir_navierstokes_convergence_periodic.jl: GradientVariablesEntropy" begin @@ -57,6 +81,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.00011310615871043463, 6.216495207074201e-5, 0.00028195843110817814], linf = [0.0006240837363233886, 0.0003616694320713876, 0.0016147339542413874] ) + # 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 "TreeMesh1D: elixir_navierstokes_convergence_walls.jl" begin @@ -64,6 +96,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.00047023310868269237, 0.00032181736027057234, 0.0014966266486095025], linf = [0.002996375101363302, 0.002863904256059634, 0.012691132946258676] ) + # 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 "TreeMesh1D: elixir_navierstokes_convergence_walls.jl: GradientVariablesEntropy" begin @@ -74,6 +114,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0004608500483647771, 0.00032431091222851285, 0.0015159733360626845], linf = [0.002754803146635787, 0.0028567714697580906, 0.012941794048176192] ) + # 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 "TreeMesh1D: elixir_navierstokes_convergence_walls_amr.jl" begin @@ -83,6 +131,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [2.5278824700860636e-5, 2.5540078777006958e-5, 0.00012118655083858043], linf = [0.0001466387075579334, 0.00019422427462629705, 0.0009556446847707178] ) + # 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 "TreeMesh1D: elixir_navierstokes_convergence_walls_amr.jl: GradientVariablesEntropy" begin @@ -93,6 +149,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [2.459359632523962e-5, 2.3928390718460263e-5, 0.00011252414117082376], linf = [0.0001185052018830568, 0.00018987717854305393, 0.0009597503607920999] ) + # 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 diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 98aa337afb4..046494e1000 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -47,7 +47,7 @@ isdir(outdir) && rm(outdir, recursive=true) @unpack gradients = cache_parabolic for dim in eachindex(gradients) fill!(gradients[dim], zero(eltype(gradients[dim]))) - end + end t = 0.0 # pass in `boundary_condition_periodic` to skip boundary flux/integral evaluation @@ -75,6 +75,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.2485803335154642], linf = [1.079606969242132] ) + # 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 "DGMulti: elixir_advection_diffusion_periodic.jl" begin @@ -83,6 +91,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.03180371984888462], linf = [0.2136821621370909] ) + # 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 "DGMulti: elixir_advection_diffusion_nonperiodic.jl" begin @@ -91,6 +107,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.002123168335604323], linf = [0.00963640423513712] ) + # 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 "DGMulti: elixir_navierstokes_convergence.jl" begin @@ -99,6 +123,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0015355076812510957, 0.0033843168272696756, 0.0036531858107443434, 0.009948436427519214], linf = [0.005522560467190019, 0.013425258500730508, 0.013962115643482154, 0.027483102120502423] ) + # 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 "DGMulti: elixir_navierstokes_convergence_curved.jl" begin @@ -107,6 +139,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.004255101916146187, 0.011118488923215765, 0.011281831283462686, 0.03573656447388509], linf = [0.015071710669706473, 0.04103132025858458, 0.03990424085750277, 0.1309401718598764], ) + # 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 "DGMulti: elixir_navierstokes_lid_driven_cavity.jl" begin @@ -115,6 +155,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.00022156125227115747, 0.028318325921401, 0.009509168701070296, 0.028267900513550506], linf = [0.001562278941298234, 0.14886653390744856, 0.0716323565533752, 0.19472785105241996] ) + # 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 "TreeMesh2D: elixir_advection_diffusion.jl" begin @@ -123,6 +171,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [4.0915532997994255e-6], linf = [2.3040850347877395e-5] ) + # 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 "TreeMesh2D: elixir_advection_diffusion.jl (Refined mesh)" begin @@ -155,7 +211,7 @@ isdir(outdir) && rm(outdir, recursive=true) du_ode = similar(u_ode) @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 100 @test (@allocated Trixi.rhs_parabolic!(du_ode, u_ode, semi, t)) < 100 - end + end end @trixi_testset "TreeMesh2D: elixir_advection_diffusion_nonperiodic.jl" begin @@ -164,6 +220,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.007646800618485118], linf = [0.10067621050468958] ) + # 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 "TreeMesh2D: elixir_navierstokes_convergence.jl" begin @@ -176,6 +240,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.002111672530658797, 0.0034322351490857846, 0.0038742528195910416, 0.012469246082568561], linf = [0.012006418939223495, 0.035520871209746126, 0.024512747492231427, 0.11191122588756564] ) + # 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 "TreeMesh2D: elixir_navierstokes_convergence.jl (isothermal walls)" begin @@ -185,6 +257,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.002103629650383915, 0.003435843933396454, 0.00386735987813341, 0.012670355349235728], linf = [0.012006261793147788, 0.03550212518982032, 0.025107947319661185, 0.11647078036571124] ) + # 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 "TreeMesh2D: elixir_navierstokes_convergence.jl (Entropy gradient variables)" begin @@ -193,6 +273,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0021403742517389513, 0.0034258287094908572, 0.0038915122886898517, 0.012506862343013842], linf = [0.012244412004628336, 0.03507559186162224, 0.024580892345558894, 0.11425600758350107] ) + # 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 "TreeMesh2D: elixir_navierstokes_convergence.jl (Entropy gradient variables, isothermal walls)" begin @@ -202,6 +290,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0021349737347844907, 0.0034301388278203033, 0.0038928324474291572, 0.012693611436230873], linf = [0.01224423627586213, 0.035054066314102905, 0.025099598504931965, 0.11795616324751634] ) + # 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 "TreeMesh2D: elixir_navierstokes_convergence.jl (flux differencing)" begin @@ -211,6 +307,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0021116725306633594, 0.0034322351490827557, 0.0038742528196093542, 0.012469246082526909], linf = [0.012006418939291663, 0.035520871209594115, 0.024512747491801577, 0.11191122588591007] ) + # 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 "TreeMesh2D: elixir_navierstokes_convergence.jl (Refined mesh)" begin @@ -232,6 +336,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2_error, linf_error = analysis_callback(sol) @test l2_error ≈ [0.00024296959173852447; 0.0002093263158670915; 0.0005390572390977262; 0.00026753561392341537] @test linf_error ≈ [0.0016210102053424436; 0.002593287648655501; 0.002953907343823712; 0.002077119120180271] + # 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 "TreeMesh2D: elixir_navierstokes_lid_driven_cavity.jl" begin @@ -240,6 +352,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.00015144571529699053, 0.018766076072331623, 0.007065070765652574, 0.0208399005734258], linf = [0.0014523369373669048, 0.12366779944955864, 0.05532450997115432, 0.16099927805328207] ) + # 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 "TreeMesh2D: elixir_navierstokes_taylor_green_vortex.jl" begin @@ -247,6 +367,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0009279657228109691, 0.012454661988687185, 0.012454661988689886, 0.030487112728612178], linf = [0.002435582543096171, 0.024824039368199546, 0.024824039368212758, 0.06731583711777489] ) + # 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 "P4estMesh2D: elixir_advection_diffusion_periodic.jl" begin @@ -255,6 +383,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0023754695605828443], linf = [0.008154128363741964] ) + # 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 "P4estMesh2D: elixir_advection_diffusion_periodic_curved.jl" begin @@ -263,6 +399,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.006708147442490916], linf = [0.04807038397976693] ) + # 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 "P4estMesh2D: elixir_advection_diffusion_nonperiodic_curved.jl" begin @@ -271,6 +415,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.00919917034843865], linf = [0.14186297438393505] ) + # 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 "P4estMesh2D: elixir_navierstokes_convergence.jl" begin @@ -279,6 +431,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0003811978985836709, 0.0005874314969169538, 0.0009142898787923481, 0.0011613918899727263], linf = [0.0021633623982135752, 0.009484348274135372, 0.004231572066492217, 0.011661660275365193] ) + # 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 "P4estMesh2D: elixir_navierstokes_convergence_nonperiodic.jl" begin @@ -287,6 +447,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.00040364962558511795, 0.0005869762481506936, 0.00091488537427274, 0.0011984191566376762], linf = [0.0024993634941723464, 0.009487866203944725, 0.004505829506628117, 0.011634902776245681] ) + # 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 "P4estMesh2D: elixir_navierstokes_lid_driven_cavity.jl" begin @@ -295,8 +463,15 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.00028716166408816073, 0.08101204560401647, 0.02099595625377768, 0.05008149754143295], linf = [0.014804500261322406, 0.9513271652357098, 0.7223919625994717, 1.4846907331004786] ) + # 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 diff --git a/test/test_parabolic_3d.jl b/test/test_parabolic_3d.jl index 86076460294..f74546d0146 100644 --- a/test/test_parabolic_3d.jl +++ b/test/test_parabolic_3d.jl @@ -17,6 +17,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0005532847115849239, 0.000659263490965341, 0.0007776436127362806, 0.0006592634909662951, 0.0038073628897809185], linf = [0.0017039861523615585, 0.002628561703560073, 0.003531057425112172, 0.0026285617036090336, 0.015587829540351095] ) + # 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 "DGMulti: elixir_navierstokes_convergence_curved.jl" begin @@ -25,6 +33,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0014027227251207474, 0.0021322235533273513, 0.0027873741447455194, 0.0024587473070627423, 0.00997836818019202], linf = [0.006341750402837576, 0.010306014252246865, 0.01520740250924979, 0.010968264045485565, 0.047454389831591115] ) + # 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 "DGMulti: elixir_navierstokes_taylor_green_vortex.jl" begin @@ -33,6 +49,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0001825713444029892, 0.015589736382772248, 0.015589736382771884, 0.021943924667273653, 0.01927370280244222], linf = [0.0006268463584697681, 0.03218881662749007, 0.03218881662697948, 0.053872495395614256, 0.05183822000984151] ) + # 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 "TreeMesh3D: elixir_navierstokes_convergence.jl" begin @@ -41,6 +65,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0019582188528512257, 0.002653449504302844, 0.002898264205184629, 0.002653449504302853, 0.009511572365085706], linf = [0.013680656759085918, 0.0356910450154318, 0.023526343547736236, 0.035691045015431855, 0.11482570604041165] ) + # 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 "TreeMesh3D: elixir_navierstokes_convergence.jl (isothermal walls)" begin @@ -50,6 +82,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.00195468651965362, 0.0026554367897028506, 0.002892730402724066, 0.002655436789702817, 0.009596351796609566], linf = [0.013680508110645473, 0.035673446359424356, 0.024024936779729028, 0.03567344635942474, 0.11839497110809383] ) + # 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 "TreeMesh3D: elixir_navierstokes_convergence.jl (Entropy gradient variables)" begin @@ -58,6 +98,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0019770444875099307, 0.0026524750946399327, 0.00290860030832445, 0.0026524750946399396, 0.009509568981439294], linf = [0.01387936112914212, 0.03526260609304053, 0.023554197097368997, 0.035262606093040896, 0.11719963716509518] ) + # 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 "TreeMesh3D: elixir_navierstokes_convergence.jl (Entropy gradient variables, isothermal walls)" begin @@ -67,6 +115,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.001974631423398113, 0.002654768259143932, 0.002907031063651286, 0.002654768259143901, 0.009587792882971452], linf = [0.01387919380137137, 0.035244084526358944, 0.02398614622061363, 0.03524408452635828, 0.12005056512506407] ) + # 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 "TreeMesh3D: elixir_navierstokes_convergence.jl (flux differencing)" begin @@ -76,6 +132,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0019582188528180213, 0.002653449504301736, 0.0028982642051960006, 0.0026534495043017384, 0.009511572364811033], linf = [0.013680656758949583, 0.035691045015224444, 0.02352634354676752, 0.035691045015223424, 0.11482570603751441] ) + # 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 "TreeMesh3D: elixir_navierstokes_convergence.jl (Refined mesh)" begin @@ -97,6 +161,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2_error, linf_error = analysis_callback(sol) @test l2_error ≈ [0.0003109336253407314, 0.0006473493036803503, 0.0007705277238213672, 0.0006280517917198335, 0.000903927789884075] @test linf_error ≈ [0.0023694155365339142, 0.010634932622402863, 0.006772070862236412, 0.010640551561726901, 0.019256819038719897] + # 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 "TreeMesh3D: elixir_navierstokes_taylor_green_vortex.jl" begin @@ -105,6 +177,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.00024173250389635442, 0.015684268393762454, 0.01568426839376248, 0.021991909545192333, 0.02825413672911425], linf = [0.0008410587892853094, 0.04740176181772552, 0.04740176181772507, 0.07483494924031157, 0.150181591534448] ) + # 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 "TreeMesh3D: elixir_navierstokes_taylor_green_vortex.jl (Refined mesh)" begin @@ -130,7 +210,6 @@ isdir(outdir) && rm(outdir, recursive=true) l2_error, linf_error = analysis_callback(sol) @test l2_error ≈ [7.314319856736271e-5, 0.006266480163542894, 0.006266489911815533, 0.008829222305770226, 0.0032859166842329228] @test linf_error ≈ [0.0002943968186086554, 0.013876261980614757, 0.013883619864959451, 0.025201279960491936, 0.018679364985388247] - # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let @@ -139,7 +218,7 @@ isdir(outdir) && rm(outdir, recursive=true) du_ode = similar(u_ode) @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 100 @test (@allocated Trixi.rhs_parabolic!(du_ode, u_ode, semi, t)) < 100 - end + end end @trixi_testset "P4estMesh3D: elixir_navierstokes_convergence.jl" begin @@ -148,6 +227,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.00026599105554982194, 0.000461877794472316, 0.0005424899076052261, 0.0004618777944723191, 0.0015846392581126832], linf = [0.0025241668929956163, 0.006308461681816373, 0.004334939663169113, 0.006308461681804009, 0.03176343480493493] ) + # 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 "P4estMesh3D: elixir_navierstokes_taylor_green_vortex.jl" begin @@ -156,6 +243,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0001547509861140407, 0.015637861347119624, 0.015637861347119687, 0.022024699158522523, 0.009711013505930812], linf = [0.0006696415247340326, 0.03442565722527785, 0.03442565722577423, 0.06295407168705314, 0.032857472756916195] ) + # 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 diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index d280e2a5e01..85b26192fb5 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -17,12 +17,28 @@ isdir(outdir) && rm(outdir, recursive=true) # Expected errors are exactly the same as with TreeMesh! l2 = [6.0388296447998465e-6], linf = [3.217887726258972e-5]) + # 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_nonperiodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_nonperiodic.jl"), l2 = [5.641921365468918e-5], linf = [0.00021049780975179733]) + # 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_shockcapturing.jl" begin @@ -30,6 +46,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.08015029105233593], linf = [0.610709468736576], atol = 1.0e-5) + # 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 @@ -37,6 +61,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [3.67478226e-01, 3.49491179e-01, 8.08910759e-01], linf = [1.58971947e+00, 1.59812384e+00, 1.94732969e+00], tspan = (0.0, 0.3)) + # 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_hll_davis.jl" begin @@ -45,6 +77,14 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [3.1661064228547255, 0.16256363944708607, 2.667676158812806], tspan = (0.0, 12.5), surface_flux = FluxHLL(min_max_speed_davis)) + # 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_source_terms.jl" begin @@ -52,12 +92,28 @@ isdir(outdir) && rm(outdir, recursive=true) # Expected errors are exactly the same as with TreeMesh! l2 = [2.2527950196212703e-8, 1.8187357193835156e-8, 7.705669939973104e-8], linf = [1.6205433861493646e-7, 1.465427772462391e-7, 5.372255111879554e-7]) + # 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_source_terms_nonperiodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonperiodic.jl"), l2 = [3.8099996914101204e-6, 1.6745575717106341e-6, 7.732189531480852e-6], linf = [1.2971473393186272e-5, 9.270328934274374e-6, 3.092514399671842e-5]) + # 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 diff --git a/test/test_structured_3d.jl b/test/test_structured_3d.jl index 124c073f2d6..07910e1119b 100644 --- a/test/test_structured_3d.jl +++ b/test/test_structured_3d.jl @@ -17,6 +17,14 @@ isdir(outdir) && rm(outdir, recursive=true) # Expected errors are exactly the same as with TreeMesh! l2 = [0.00016263963870641478], linf = [0.0014537194925779984]) + # 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_free_stream.jl" begin @@ -25,18 +33,42 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [1.0262901639634947e-12], atol = 8e-13, # required to make tests pass on Windows ) + # 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_nonperiodic_curved.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_nonperiodic_curved.jl"), l2 = [0.0004483892474201268], linf = [0.009201820593762955]) + # 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_restart.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), l2 = [0.0025903889347585777], linf = [0.018407576968841655]) + # 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_source_terms.jl" begin @@ -44,12 +76,28 @@ isdir(outdir) && rm(outdir, recursive=true) # Expected errors are exactly the same as with TreeMesh! l2 = [0.010385936842224346, 0.009776048833895767, 0.00977604883389591, 0.009776048833895733, 0.01506687097416608], linf = [0.03285848350791731, 0.0321792316408982, 0.032179231640894645, 0.032179231640895534, 0.0655408023333299]) + # 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.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_free_stream.jl"), l2 = [2.8815700334367128e-15, 9.361915278236651e-15, 9.95614203619935e-15, 1.6809941842374106e-14, 1.4815037041566735e-14], linf = [4.1300296516055823e-14, 2.0444756998472258e-13, 1.0133560657266116e-13, 2.0627943797535409e-13, 2.8954616482224083e-13]) + # 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.jl with FluxRotated(flux_lax_friedrichs)" begin @@ -57,12 +105,28 @@ isdir(outdir) && rm(outdir, recursive=true) surface_flux=FluxRotated(flux_lax_friedrichs), l2 = [2.8815700334367128e-15, 9.361915278236651e-15, 9.95614203619935e-15, 1.6809941842374106e-14, 1.4815037041566735e-14], linf = [4.1300296516055823e-14, 2.0444756998472258e-13, 1.0133560657266116e-13, 2.0627943797535409e-13, 2.8954616482224083e-13]) + # 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_source_terms_nonperiodic_curved.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonperiodic_curved.jl"), l2 = [0.0032940531178824463, 0.003275679548217804, 0.0030020672748714084, 0.00324007343451744, 0.005721986362580164], linf = [0.03156756290660656, 0.033597629023726316, 0.02095783702361409, 0.03353574465232212, 0.05873635745032857]) + # 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_ec.jl" begin @@ -71,6 +135,14 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [0.2761764220925329, 0.20286331858055706, 0.18763944865434593, 0.19313636558790004, 0.707563913727584], tspan = (0.0, 0.25), coverage_override = (polydeg=3,)) # Prevent long compile time in CI + # 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 @@ -78,6 +150,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [5.30310390e-02, 2.53167260e-02, 2.64276438e-02, 2.52195992e-02, 3.56830295e-01], linf = [6.16356950e-01, 2.50600049e-01, 2.74796377e-01, 2.46448217e-01, 4.77888479e+00], tspan = (0.0, 0.3)) + # 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_mhd_ec.jl" begin @@ -89,6 +169,14 @@ isdir(outdir) && rm(outdir, recursive=true) 1.1370443512475847, 0.1278041831463388, 0.13347391885068594, 0.1457563463643099, 0.0021174246048172563], tspan = (0.0, 0.25)) + # 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_mhd_alfven_wave.jl" begin @@ -101,6 +189,14 @@ isdir(outdir) && rm(outdir, recursive=true) 0.01888303191983353], # Use same polydeg as everything else to prevent long compile times in CI coverage_override = (polydeg=3,)) + # 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_mhd_alfven_wave.jl with flux_lax_friedrichs" begin @@ -114,6 +210,14 @@ isdir(outdir) && rm(outdir, recursive=true) surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell), # Use same polydeg as everything else to prevent long compile times in CI coverage_override = (polydeg=3,)) + # 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_mhd_ec_shockcapturing.jl" begin @@ -127,6 +231,14 @@ isdir(outdir) && rm(outdir, recursive=true) tspan = (0.0, 0.25), # Use same polydeg as everything else to prevent long compile times in CI coverage_override = (polydeg=3,)) + # 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 diff --git a/test/test_t8code_2d.jl b/test/test_t8code_2d.jl index a424c9df84b..660d7bc0a1d 100644 --- a/test/test_t8code_2d.jl +++ b/test/test_t8code_2d.jl @@ -34,20 +34,44 @@ mkdir(outdir) # Expected errors are exactly the same as with TreeMesh! l2=[8.311947673061856e-6], linf=[6.627000273229378e-5]) - end + # 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_nonconforming_flag.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_nonconforming_flag.jl"), l2=[3.198940059144588e-5], linf=[0.00030636069494005547]) - end + # 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_unstructured_flag.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_unstructured_flag.jl"), l2=[0.0005379687442422346], linf=[0.007438525029884735]) - end + # 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_amr_unstructured_flag.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, @@ -55,7 +79,15 @@ mkdir(outdir) l2=[0.001993165013217687], linf=[0.032891018571625796], coverage_override=(maxiters = 6,)) - end + # 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_amr_solution_independent.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, @@ -64,7 +96,15 @@ mkdir(outdir) l2=[4.949660644033807e-5], linf=[0.0004867846262313763], coverage_override=(maxiters = 6,)) - end + # 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_source_terms_nonconforming_unstructured_flag.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, @@ -81,7 +121,15 @@ mkdir(outdir) 0.03759938693042297, 0.08039824959535657, ]) - end + # 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.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_free_stream.jl"), @@ -93,7 +141,15 @@ mkdir(outdir) ], linf=[1.9539925233402755e-14, 2e-12, 4.8e-12, 4e-12], atol=2.0e-12,) - end + # 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_shockcapturing_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing_ec.jl"), @@ -110,7 +166,15 @@ mkdir(outdir) 1.08142520e+00, ], tspan=(0.0, 1.0)) - end + # 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"), @@ -127,7 +191,15 @@ mkdir(outdir) 6.20638482e+00, ], tspan=(0.0, 0.3)) - end + # 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_source_terms.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), @@ -144,7 +216,15 @@ mkdir(outdir) 1.2129488214718265e-5, ], tspan=(0.0, 0.1)) - end + # 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_mhd_alfven_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), @@ -158,7 +238,15 @@ mkdir(outdir) 5.4791097160444835e-6, 5.18922042269665e-6, 5.189220422141538e-6, 9.552667261422676e-6, 1.4237578427628152e-6]) - end + # 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_mhd_rotor.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_rotor.jl"), @@ -173,7 +261,15 @@ mkdir(outdir) 0.0, 0.002261930217575465], tspan=(0.0, 0.02)) - end + # 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 diff --git a/test/test_tree_1d_advection.jl b/test/test_tree_1d_advection.jl index 0cf0f2c1170..681fea4a8ae 100644 --- a/test/test_tree_1d_advection.jl +++ b/test/test_tree_1d_advection.jl @@ -12,6 +12,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), l2 = [6.0388296447998465e-6], linf = [3.217887726258972e-5]) + # 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_amr.jl" begin @@ -19,6 +27,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [0.3540206249507417], linf = [0.9999896603382347], 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 end @trixi_testset "elixir_advection_amr_nonperiodic.jl" begin @@ -26,12 +42,28 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [4.283508859843524e-6], linf = [3.235356127918171e-5], 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 end @trixi_testset "elixir_advection_finite_volume.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_finite_volume.jl"), l2 = [0.011662300515980219], linf = [0.01647256923710194]) + # 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 diff --git a/test/test_tree_1d_burgers.jl b/test/test_tree_1d_burgers.jl index 8c4cfaa406d..eb4ece05b7e 100644 --- a/test/test_tree_1d_burgers.jl +++ b/test/test_tree_1d_burgers.jl @@ -12,24 +12,56 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_basic.jl"), l2 = [2.967470209082194e-5], linf = [0.00016152468882624227]) + # 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_burgers_linear_stability.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_linear_stability.jl"), l2 = [0.5660569881106876], linf = [1.9352238038313998]) + # 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_burgers_shock.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_shock.jl"), l2 = [0.4422505602587537], linf = [1.0000000000000009]) + # 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_burgers_rarefaction.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_rarefaction.jl"), l2 = [0.4038224690923722], linf = [1.0049201454652736]) + # 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 diff --git a/test/test_tree_1d_euler.jl b/test/test_tree_1d_euler.jl index 5fb74b80bce..92a917d0622 100644 --- a/test/test_tree_1d_euler.jl +++ b/test/test_tree_1d_euler.jl @@ -12,18 +12,42 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms.jl"), l2 = [2.2527950196212703e-8, 1.8187357193835156e-8, 7.705669939973104e-8], linf = [1.6205433861493646e-7, 1.465427772462391e-7, 5.372255111879554e-7]) + # 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_convergence_pure_fv.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence_pure_fv.jl"), l2 = [0.019355699748523896, 0.022326984561234497, 0.02523665947241734], linf = [0.02895961127645519, 0.03293442484199227, 0.04246098278632804]) + # 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_density_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_density_wave.jl"), l2 = [0.0011482554820217855, 0.00011482554830323462, 5.741277429325267e-6], linf = [0.004090978306812376, 0.0004090978313582294, 2.045489210189544e-5]) + # 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_density_wave.jl with initial_condition_constant" begin @@ -31,18 +55,42 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [7.71293052584723e-16, 1.9712947511091717e-14, 7.50672833504266e-15], linf = [3.774758283725532e-15, 6.733502644351574e-14, 2.4868995751603507e-14], initial_condition = initial_condition_constant) + # 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_source_terms_nonperiodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonperiodic.jl"), l2 = [3.8099996914101204e-6, 1.6745575717106341e-6, 7.732189531480852e-6], linf = [1.2971473393186272e-5, 9.270328934274374e-6, 3.092514399671842e-5]) + # 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_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), l2 = [0.11821957357197649, 0.15330089521538678, 0.4417674632047301], linf = [0.24280567569982958, 0.29130548795961936, 0.8847009003152442]) + # 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_ec.jl with flux_kennedy_gruber" begin @@ -52,6 +100,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") maxiters = 10, surface_flux = flux_kennedy_gruber, volume_flux = flux_kennedy_gruber) + # 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_ec.jl with flux_shima_etal" begin @@ -61,6 +117,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") maxiters = 10, surface_flux = flux_shima_etal, volume_flux = flux_shima_etal) + # 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_ec.jl with flux_chandrashekar" begin @@ -70,6 +134,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") maxiters = 10, surface_flux = flux_chandrashekar, volume_flux = flux_chandrashekar) + # 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_ec.jl with flux_hll" begin @@ -79,12 +151,28 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") maxiters = 10, surface_flux = flux_hll, volume_flux = flux_ranocha) + # 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_shockcapturing.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing.jl"), l2 = [0.11606096465319675, 0.15028768943458806, 0.4328230323046703], linf = [0.18031710091067965, 0.2351582421501841, 0.6776805692092567]) + # 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_blast_wave.jl" begin @@ -92,6 +180,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [1.250005061244617, 0.06878411345533507, 0.9264328311018613], linf = [2.9766770877037168, 0.16838100902295852, 2.6655773445485798], 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 end @trixi_testset "elixir_euler_sedov_blast_wave_pure_fv.jl" begin @@ -100,6 +196,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") linf = [3.4296365168219216, 0.17635583964559245, 2.6574584326179505], # Let this test run longer to cover some lines in flux_hllc coverage_override = (maxiters=10^5, tspan=(0.0, 0.1))) + # 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_blast_wave.jl with pressure" begin @@ -109,6 +213,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") shock_indicator_variable = pressure, cfl = 0.2, 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 end @trixi_testset "elixir_euler_sedov_blast_wave.jl with density" begin @@ -118,6 +230,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") shock_indicator_variable = density, cfl = 0.2, 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 end @trixi_testset "elixir_euler_positivity.jl" begin @@ -125,6 +245,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [1.6493820253458906, 0.19793887460986834, 0.9783506076125921], linf = [4.71751203912051, 0.5272411022735763, 2.7426163947635844], coverage_override = (maxiters=3,)) + # 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_blast_wave.jl" begin @@ -132,6 +260,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [0.21934822867340323, 0.28131919126002686, 0.554361702716662], linf = [1.5180897390290355, 1.3967085956620369, 2.0663825294019595], maxiters = 30) + # 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_blast_wave_neuralnetwork_perssonperaire.jl" begin diff --git a/test/test_tree_1d_eulergravity.jl b/test/test_tree_1d_eulergravity.jl index 966add0cdf3..7738d847d31 100644 --- a/test/test_tree_1d_eulergravity.jl +++ b/test/test_tree_1d_eulergravity.jl @@ -12,6 +12,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulergravity_convergence.jl"), l2 = [0.0002170799126638106, 0.0002913792848717502, 0.0006112320856262327], linf = [0.0004977401033188222, 0.0013594223337776157, 0.002041891084400227]) + # 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 diff --git a/test/test_tree_1d_eulermulti.jl b/test/test_tree_1d_eulermulti.jl index e880f98e2d0..7e0d69cea1c 100644 --- a/test/test_tree_1d_eulermulti.jl +++ b/test/test_tree_1d_eulermulti.jl @@ -15,18 +15,42 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") 0.06755404204112954], linf = [0.29130548795961864, 0.8847009003152357, 0.034686525099975274, 0.06937305019995055, 0.1387461003999011]) + # 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_eulermulti_es.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_es.jl"), l2 = [0.1522380497572071, 0.43830846465313206, 0.03907262116499431, 0.07814524232998862], linf = [0.24939193075537294, 0.7139395740052739, 0.06324208768391237, 0.12648417536782475]) + # 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_eulermulti_convergence_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_ec.jl"), l2 = [8.575236038539227e-5, 0.00016387804318585358, 1.9412699303977585e-5, 3.882539860795517e-5], linf = [0.00030593277277124464, 0.0006244803933350696, 7.253121435135679e-5, 0.00014506242870271358]) + # 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_eulermulti_convergence_es.jl" begin @@ -35,6 +59,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") 6.186482304747219e-6, 1.2372964609494437e-5], linf = [0.00012014372605895218, 0.0003313207215800418, 6.50836791016296e-6, 1.301673582032592e-5, 2.603347164065184e-5, 5.206694328130368e-5]) + # 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_eulermulti_convergence_es.jl with flux_chandrashekar" begin @@ -44,6 +76,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") linf = [0.00011622351152063004, 0.0003079221967086099, 3.2177423254231563e-6, 6.435484650846313e-6, 1.2870969301692625e-5, 2.574193860338525e-5], volume_flux = flux_chandrashekar) + # 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_eulermulti_two_interacting_blast_waves.jl" begin @@ -53,11 +93,15 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") linf = [29.6413044707026, 1322.5844802186496, 0.09191919374782143, 0.31092970966717925, 0.4417989757182038], tspan = (0.0, 0.0001)) + # 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 - - end # module diff --git a/test/test_tree_1d_fdsbp.jl b/test/test_tree_1d_fdsbp.jl index ce0ca660d35..d11bf277807 100644 --- a/test/test_tree_1d_fdsbp.jl +++ b/test/test_tree_1d_fdsbp.jl @@ -72,6 +72,15 @@ end l2 = [0.9999995642691271], linf = [1.824702804788453], tspan = (0.0, 0.25)) + + # 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 @@ -98,6 +107,15 @@ end linf = [1.4228079689537765e-5, 1.3249887941046978e-5, 3.201552933251861e-5], tspan = (0.0, 0.5), flux_splitting = splitting_vanleer_haenel) + + # 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_convergence.jl with VolumeIntegralStrongForm" begin @@ -106,6 +124,15 @@ end linf = [6.707982777909294e-5, 3.487256699541419e-5, 0.00010170331350556339], tspan = (0.0, 0.5), solver = DG(D_upw.central, nothing, SurfaceIntegralStrongForm(), VolumeIntegralStrongForm())) + + # 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_density_wave.jl" begin @@ -113,6 +140,15 @@ end l2 = [1.5894925236031034e-5, 9.428412101106044e-6, 0.0008986477358789918], linf = [4.969438024382544e-5, 2.393091812063694e-5, 0.003271817388146303], tspan = (0.0, 0.005), abstol = 1.0e-9, reltol = 1.0e-9) + + # 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 diff --git a/test/test_tree_1d_mhd.jl b/test/test_tree_1d_mhd.jl index e3a0cda3250..77158001275 100644 --- a/test/test_tree_1d_mhd.jl +++ b/test/test_tree_1d_mhd.jl @@ -15,12 +15,28 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") linf = [1.9984014443252818e-15, 1.3405943022348765e-14, 3.3584246494910985e-15, 3.164135620181696e-15, 7.815970093361102e-14, 8.881784197001252e-16, 2.886579864025407e-15, 2.942091015256665e-15], initial_condition = initial_condition_constant, tspan = (0.0,1.0)) + # 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_mhd_alfven_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), l2 = [1.0375628983659061e-5, 6.571144191446236e-7, 3.5833569836289104e-5, 3.583356983615859e-5, 5.084863194951084e-6, 1.1963224165731992e-16, 3.598916927583752e-5, 3.598916927594727e-5], linf = [2.614095879338585e-5, 9.577266731216823e-7, 0.00012406198007461344, 0.00012406198007509917, 1.5066209528846741e-5, 2.220446049250313e-16, 0.00012658678753942054, 0.00012658678753908748]) + # 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_mhd_alfven_wave.jl with flux_derigs_etal" begin @@ -28,12 +44,28 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [1.4396053943470756e-5, 1.1211016739165248e-5, 3.577870687983967e-5, 3.577870687982181e-5, 1.967962220860377e-6, 1.1963224165731992e-16, 3.583562899483433e-5, 3.583562899486565e-5], linf = [5.830577969345718e-5, 3.280495696370357e-5, 0.00012279619948236953, 0.00012279619948227238, 6.978806516122482e-6, 2.220446049250313e-16, 0.00012564003648959932, 0.00012564003648994626], volume_flux = flux_derigs_etal) + # 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_mhd_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ec.jl"), l2 = [0.05815183849746399, 0.08166807325621023, 0.054659228513541165, 0.054659228513541165, 0.15578125987042743, 4.130462730494e-17, 0.05465258887150046, 0.05465258887150046], linf = [0.12165312668363826, 0.1901920742264952, 0.10059813883022554, 0.10059813883022554, 0.44079257431070706, 1.1102230246251565e-16, 0.10528911365809579, 0.10528911365809579]) + # 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_mhd_briowu_shock_tube.jl" begin @@ -41,12 +73,28 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [0.17477712356961989, 0.19489623595086944, 0.3596546157640463, 0.0, 0.3723215736814466, 1.2060075775846403e-15, 0.36276754492568164, 0.0], linf = [0.5797109945880677, 0.4372991899547103, 1.0906536287185835, 0.0, 1.0526758874956808, 5.995204332975845e-15, 1.5122922036932964, 0.0], 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 end @trixi_testset "elixir_mhd_torrilhon_shock_tube.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_torrilhon_shock_tube.jl"), l2 = [0.45700904847931145, 0.4792535936512035, 0.340651203521865, 0.4478034694296928, 0.9204708961093411, 1.3216517820475193e-16, 0.28897419402047725, 0.25521206483145126], linf = [1.2185238171352286, 0.8913202384963431, 0.8488793580488431, 0.973083603686, 1.660723397705417, 2.220446049250313e-16, 0.6874726847741993, 0.65536978110274]) + # 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_mhd_ryujones_shock_tube.jl" begin @@ -54,6 +102,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [0.23469781891518154, 0.3916675299696121, 0.08245195301016353, 0.1745346945706147, 0.9606363432904367, 6.608258910237605e-17, 0.21542929107153735, 0.10705457908737925], linf = [0.6447951791685409, 0.9461857095377463, 0.35074627554617605, 0.8515177411529542, 2.0770652030507053, 1.1102230246251565e-16, 0.49670855513788204, 0.24830199967863564], tspan = (0.0, 0.1)) + # 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_mhd_shu_osher_shock_tube.jl" begin @@ -62,6 +118,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") linf = [2.87172004e+00, 2.26438057e+01, 4.16672442e+00, 0.00000000e+00, 1.35152372e+02, 3.44169138e-15, 2.83556069e+00, 0.00000000e+00], tspan = (0.0, 0.2), 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 end @trixi_testset "elixir_mhd_shu_osher_shock_tube.jl with flipped shock direction" begin @@ -74,6 +138,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") boundary_conditions=BoundaryConditionDirichlet(initial_condition_shu_osher_shock_tube_flipped), tspan = (0.0, 0.2), 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 end end diff --git a/test/test_tree_1d_mhdmulti.jl b/test/test_tree_1d_mhdmulti.jl index 5214ed26d38..9d0dbc65744 100644 --- a/test/test_tree_1d_mhdmulti.jl +++ b/test/test_tree_1d_mhdmulti.jl @@ -17,6 +17,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") linf = [0.19019207422649645, 0.10059813883022888, 0.10059813883022888, 0.4407925743107146, 1.1102230246251565e-16, 0.10528911365809623, 0.10528911365809623, 0.01737901809766182, 0.03475803619532364, 0.06951607239064728]) + # 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_mhdmulti_ec.jl with flux_derigs_etal" begin @@ -28,6 +36,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") 1.1102230246251565e-16, 0.09558639591092555, 0.09558639591092555, 0.017364773041550624, 0.03472954608310125, 0.0694590921662025], volume_flux = flux_derigs_etal) + # 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_mhdmulti_es.jl" begin @@ -38,6 +54,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") linf = [0.14101014428198477, 0.07762441749521025, 0.07762441749521025, 0.3381334453289866, 1.1102230246251565e-16, 0.07003646400675223, 0.07003646400675223, 0.014962483760600165, 0.02992496752120033, 0.05984993504240066]) + # 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_mhdmulti_convergence.jl" begin @@ -48,7 +72,15 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") linf = [3.877554303711845e-5, 0.0012437848638874956, 0.0012437848638876898, 0.00016431262020277781, 1.1102230246251565e-16, 0.0012443734922607112, 0.001244373492260704, 5.691007974162332e-5, 0.00011382015948324664, 0.00022764031896649328]) - end + # 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_mhdmulti_briowu_shock_tube.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmulti_briowu_shock_tube.jl"), @@ -59,6 +91,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") 5.773159728050814e-15, 1.4595119339458051, 0.0, 0.18201910908829552, 0.36403821817659104], 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 end end diff --git a/test/test_tree_1d_shallowwater.jl b/test/test_tree_1d_shallowwater.jl index 09fb2d9e432..27fe98c7d42 100644 --- a/test/test_tree_1d_shallowwater.jl +++ b/test/test_tree_1d_shallowwater.jl @@ -15,6 +15,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [0.244729018751225, 0.8583565222389505, 0.07330427577586297], linf = [2.1635021283528504, 3.8717508164234453, 1.7711213427919539], tspan = (0.0, 0.25)) + # 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_ec.jl with initial_condition_weak_blast_wave" begin @@ -23,6 +31,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") linf = [0.778905801278281, 3.2409883402608273, 7.419800190922032e-10], initial_condition=initial_condition_weak_blast_wave, tspan = (0.0, 0.25)) + # 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 @@ -30,6 +46,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [0.10416666834254829, 1.4352935256803184e-14, 0.10416666834254838], linf = [1.9999999999999996, 3.248036646353028e-14, 2.0], tspan = (0.0, 0.25)) + # 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 with FluxHydrostaticReconstruction" begin @@ -38,6 +62,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") linf = [2.0000000000000018, 2.4019608337954543e-14, 2.0], surface_flux=(FluxHydrostaticReconstruction(flux_lax_friedrichs, hydrostatic_reconstruction_audusse_etal), flux_nonconservative_audusse_etal), tspan = (0.0, 0.25)) + # 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_wet_dry.jl with FluxHydrostaticReconstruction" begin @@ -45,6 +77,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [0.00965787167169024, 5.345454081916856e-14, 0.03857583749209928], linf = [0.4999999999998892, 2.2447689894899726e-13, 1.9999999999999714], tspan = (0.0, 0.25)) + # 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_source_terms.jl" begin @@ -52,6 +92,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [0.0022363707373868713, 0.01576799981934617, 4.436491725585346e-5], linf = [0.00893601803417754, 0.05939797350246456, 9.098379777405796e-5], tspan = (0.0, 0.025)) + # 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_source_terms.jl with flux_hll" begin @@ -59,6 +107,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [0.0022758146627220154, 0.015864082886204556, 4.436491725585346e-5], linf = [0.008457195427364006, 0.057201667446161064, 9.098379777405796e-5], tspan = (0.0, 0.025), surface_flux=(flux_hll, flux_nonconservative_fjordholm_etal)) + # 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_source_terms_dirichlet.jl" begin @@ -66,6 +122,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [0.0022851099219788917, 0.01560453773635554, 4.43649172558535e-5], linf = [0.008934615705174398, 0.059403169140869405, 9.098379777405796e-5], tspan = (0.0, 0.025)) + # 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_source_terms_dirichlet.jl with FluxHydrostaticReconstruction" begin @@ -74,6 +138,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") linf = [0.008460440313118323, 0.05720939349382359, 9.098379777405796e-5], surface_flux=(FluxHydrostaticReconstruction(flux_hll, hydrostatic_reconstruction_audusse_etal), flux_nonconservative_audusse_etal), tspan = (0.0, 0.025)) + # 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_nonperiodic.jl with Dirichlet boundary" begin @@ -81,6 +153,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [1.725964362045055e-8, 5.0427180314307505e-16, 1.7259643530442137e-8], linf = [3.844551077492042e-8, 3.469453422316143e-15, 3.844551077492042e-8], tspan = (0.0, 0.25)) + # 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_nonperiodic.jl with wall boundary" begin @@ -89,6 +169,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") linf = [3.844551010878661e-8, 9.846474508971374e-16, 3.844551077492042e-8], tspan = (0.0, 0.25), boundary_condition = boundary_condition_slip_wall) + # 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_shock_capturing.jl" begin @@ -96,6 +184,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [0.07424140641160326, 0.2148642632748155, 0.0372579849000542], linf = [1.1209754279344226, 1.3230788645853582, 0.8646939843534251], tspan = (0.0, 0.05)) + # 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_beach.jl" begin @@ -104,6 +200,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") linf = [0.845938394800688, 3.3740800777086575, 4.4541473087633676e-7], tspan = (0.0, 0.05), atol = 3e-10) # see https://github.com/trixi-framework/Trixi.jl/issues/1617 + # 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_parabolic_bowl.jl" begin @@ -111,6 +215,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [8.965981683033589e-5, 1.8565707397810857e-5, 4.1043039226164336e-17], linf = [0.00041080213807871235, 0.00014823261488938177, 2.220446049250313e-16], tspan = (0.0, 0.05)) + # 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_shallow_water_quasi_1d_source_terms.jl" begin @@ -118,6 +230,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [6.37048760275098e-5, 0.0002745658116815704, 4.436491725647962e-6, 8.872983451152218e-6], linf = [0.00026747526881631956, 0.0012106730729152249, 9.098379777500165e-6, 1.8196759554278685e-5], tspan = (0.0, 0.05)) + # 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_quasi_1d_well_balanced.jl" begin @@ -125,6 +245,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [1.4250229186905198e-14, 2.495109919406496e-12, 7.408599286788738e-17, 2.7205812409138776e-16], linf = [5.284661597215745e-14, 2.74056233065078e-12, 2.220446049250313e-16, 8.881784197001252e-16], tspan = (0.0, 100.0)) + # 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 diff --git a/test/test_tree_1d_shallowwater_twolayer.jl b/test/test_tree_1d_shallowwater_twolayer.jl index 8372d0d4676..93b8a6f70a5 100644 --- a/test/test_tree_1d_shallowwater_twolayer.jl +++ b/test/test_tree_1d_shallowwater_twolayer.jl @@ -17,6 +17,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") linf = [0.022256679217306008, 0.005421833004652266, 0.02233993939574197, 0.008765261497422516, 0.0008992474511784199], tspan = (0.0, 0.25)) + # 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_twolayer_convergence.jl with flux_es_fjordholm_etal" begin @@ -27,6 +35,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") 0.0008992474511784199], surface_flux=(flux_es_fjordholm_etal, flux_nonconservative_fjordholm_etal), tspan = (0.0, 0.25)) + # 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_twolayer_well_balanced.jl" begin @@ -36,6 +52,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") linf = [2.6229018956769323e-15, 1.878451903240623e-16, 0.005119880996670156, 8.003199803957679e-16, 0.005119880996670666], tspan = (0.0, 0.25)) + # 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_twolayer_dam_break.jl with flux_lax_friedrichs" begin @@ -45,6 +69,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") linf = [0.5854202777756559, 2.1278930820498934, 0.5193686074348809, 1.8071213168086229, 0.5], surface_flux = (flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), tspan = (0.0, 0.25)) + # 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 diff --git a/test/test_tree_2d_acoustics.jl b/test/test_tree_2d_acoustics.jl index b443573e3ac..dbfe38dbde2 100644 --- a/test/test_tree_2d_acoustics.jl +++ b/test/test_tree_2d_acoustics.jl @@ -12,18 +12,42 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_acoustics_convergence.jl"), l2 = [0.0019921138796370834, 0.002090394698052287, 0.0006091925854593805, 0.0, 0.0, 0.0, 0.0], linf = [0.00769282588065634, 0.008276649669227254, 0.004196479023954813, 0.0, 0.0, 0.0, 0.0]) + # 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_acoustics_gauss.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_acoustics_gauss.jl"), l2 = [0.08005276517890283, 0.08005276517890268, 0.4187202920734123, 0.0, 0.0, 0.0, 0.0], linf = [0.17261097190220992, 0.17261097190220973, 1.13601894068238, 0.0, 0.0, 0.0, 0.0]) + # 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_acoustics_gaussian_source.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_acoustics_gaussian_source.jl"), l2 = [0.004296394903650806, 0.004241280404758938, 0.006269684906035964, 0.0, 0.0, 0.0, 0.0], linf = [0.03970270697049378, 0.04151096349298151, 0.0640019829058819, 0.0, 0.0, 0.0, 0.0]) + # 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_acoustics_gauss_wall.jl" begin @@ -32,6 +56,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") 7.382060834820337e-17, 0.0, 1.4764121669640674e-16, 1.4764121669640674e-16], linf = [0.18193631937316496, 0.1877464607867628, 1.0355388011792845, 2.220446049250313e-16, 0.0, 4.440892098500626e-16, 4.440892098500626e-16]) + # 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_acoustics_monopole.jl" begin @@ -41,6 +73,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") linf = [1.000633375007386, 0.5599788929862504, 0.5738432957070382, 0.015590137026938428, 0.0, 2.220446049250313e-16, 2.220446049250313e-16], maxiters=50) + # 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 diff --git a/test/test_tree_2d_euler.jl b/test/test_tree_2d_euler.jl index 1b8a261a60d..660e4dcf1be 100644 --- a/test/test_tree_2d_euler.jl +++ b/test/test_tree_2d_euler.jl @@ -12,12 +12,28 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms.jl"), l2 = [9.321181253186009e-7, 1.4181210743438511e-6, 1.4181210743487851e-6, 4.824553091276693e-6], linf = [9.577246529612893e-6, 1.1707525976012434e-5, 1.1707525976456523e-5, 4.8869615580926506e-5]) + # 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_convergence_pure_fv.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence_pure_fv.jl"), l2 = [0.026440292358506527, 0.013245905852168414, 0.013245905852168479, 0.03912520302609374], linf = [0.042130817806361964, 0.022685499230187034, 0.022685499230187922, 0.06999771202145322]) + # 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_density_wave.jl" begin @@ -25,18 +41,42 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [0.0010600778457964775, 0.00010600778457634275, 0.00021201556915872665, 2.650194614399671e-5], linf = [0.006614198043413566, 0.0006614198043973507, 0.001322839608837334, 0.000165354951256802], tspan = (0.0, 0.5)) + # 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_source_terms_nonperiodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonperiodic.jl"), l2 = [2.259440511766445e-6, 2.318888155713922e-6, 2.3188881557894307e-6, 6.3327863238858925e-6], linf = [1.498738264560373e-5, 1.9182011928187137e-5, 1.918201192685487e-5, 6.0526717141407005e-5]) + # 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_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), l2 = [0.061751715597716854, 0.05018223615408711, 0.05018989446443463, 0.225871559730513], linf = [0.29347582879608825, 0.31081249232844693, 0.3107380389947736, 1.0540358049885143]) + # 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_ec.jl with flux_kennedy_gruber" begin @@ -46,6 +86,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") maxiters = 10, surface_flux = flux_kennedy_gruber, volume_flux = flux_kennedy_gruber) + # 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_ec.jl with flux_chandrashekar" begin @@ -55,18 +103,42 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") maxiters = 10, surface_flux = flux_chandrashekar, volume_flux = flux_chandrashekar) + # 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_shockcapturing.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing.jl"), l2 = [0.05380629130119074, 0.04696798008325309, 0.04697067787841479, 0.19687382235494968], linf = [0.18527440131928286, 0.2404798030563736, 0.23269573860381076, 0.6874012187446894]) + # 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_shockcapturing_subcell.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing_subcell.jl"), l2 = [0.08508147906199143, 0.04510299017724501, 0.045103019801950375, 0.6930704343869766], linf = [0.31123546471463326, 0.5616274869594462, 0.5619692712224448, 2.88670199345138]) + # 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_blast_wave.jl" begin @@ -74,6 +146,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [0.14170569763947993, 0.11647068900798814, 0.11647072556898294, 0.3391989213659599], linf = [1.6544204510794196, 1.35194638484646, 1.3519463848472744, 1.831228461662809], maxiters = 30) + # 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_blast_wave_neuralnetwork_perssonperaire.jl" begin @@ -119,6 +199,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") tspan = (0.0, 0.5), # Let this test run longer to cover some lines in flux_hllc coverage_override = (maxiters=10^5, tspan=(0.0, 0.1))) + # 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_blast_wave_amr.jl" begin @@ -127,6 +215,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") linf = [3.0969614882801393, 1.7967947300740248, 1.7967508302506658, 3.040149575567518], tspan = (0.0, 1.0), 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 end @trixi_testset "elixir_euler_sedov_blast_wave.jl" begin @@ -135,6 +231,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") linf = [2.6724832723962053, 1.2916089288910635, 1.2916089289001427, 6.474699399394252], tspan = (0.0, 1.0), 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 end @trixi_testset "elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl" begin @@ -151,6 +255,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") linf = [2.6766520821013002, 1.2910938760258996, 1.2910938760258899, 6.473385481404865], tspan = (0.0, 1.0), coverage_override = (maxiters=3,)) + # 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_blob_mortar.jl" begin @@ -158,6 +270,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [0.22271619518391986, 0.6284824759323494, 0.24864213447943648, 2.9591811489995474], linf = [9.15245400430106, 24.96562810334389, 10.388109127032374, 101.20581544156934], tspan = (0.0, 0.5)) + # 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_blob_amr.jl" begin @@ -167,6 +287,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") tspan = (0.0, 0.12), # Let this test run longer to cover the ControllerThreeLevelCombined lines coverage_override = (maxiters=10^5,)) + # 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_kelvin_helmholtz_instability_fjordholm_etal.jl" begin @@ -174,6 +302,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [0.1057230211245312, 0.10621112311257341, 0.07260957505339989, 0.11178239111065721], linf = [2.998719417992662, 2.1400285015556166, 1.1569648700415078, 1.8922492268110913], tspan = (0.0, 0.1)) + # 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_kelvin_helmholtz_instability.jl" begin @@ -181,6 +317,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [0.055691508271624536, 0.032986009333751655, 0.05224390923711999, 0.08009536362771563], linf = [0.24043622527087494, 0.1660878796929941, 0.12355946691711608, 0.2694290787257758], tspan = (0.0, 0.2)) + # 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_kelvin_helmholtz_instability_amr.jl" begin @@ -189,6 +333,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") linf = [0.2535807803900303, 0.17397028249895308, 0.12321616095649354, 0.269046666668995], tspan = (0.0, 0.2), coverage_override = (maxiters=2,)) + # 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_kelvin_helmholtz_instability_amr_neuralnetwork_perssonperaire.jl" begin @@ -207,6 +359,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [0.007237139090503349, 0.044887582765386916, 1.0453570959003603e-6, 0.6627307840935432], linf = [0.19437260992446315, 0.5554343646648533, 5.943891455255412e-5, 15.188919846360125], tspan = (0.0, 0.1)) + # 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_colliding_flow_amr.jl" begin @@ -215,6 +375,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") linf = [0.2508663007713608, 0.4097017076529792, 0.0003528986458217968, 22.435474993016918], tspan = (0.0, 0.1), coverage_override = (maxiters=2,)) + # 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_astro_jet_amr.jl" begin @@ -223,12 +391,28 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") linf = [3.3178633141984193, 2993.6445033486402, 8.031723414357423, 1.1918867260293828e6], tspan = (0.0, 1.0e-7), 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 end @trixi_testset "elixir_euler_vortex.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex.jl"), l2 = [0.00013492249515826863, 0.006615696236378061, 0.006782108219800376, 0.016393831451740604], linf = [0.0020782600954247776, 0.08150078921935999, 0.08663621974991986, 0.2829930622010579]) + # 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_vortex_mortar.jl" begin @@ -236,24 +420,56 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") # Expected errors are exactly the same as in the parallel test! l2 = [0.0017208369388227673, 0.09628684992237334, 0.09620157717330868, 0.1758809552387432], linf = [0.021869936355319086, 0.9956698009442038, 1.0002507727219028, 2.223249697515648]) + # 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_vortex_mortar_split.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex_mortar_split.jl"), l2 = [0.0017203323613648241, 0.09628962878682261, 0.09621241164155782, 0.17585995600340926], linf = [0.021740570456931674, 0.9938841665880938, 1.004140123355135, 2.224108857746245]) + # 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_vortex_shockcapturing.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex_shockcapturing.jl"), l2 = [0.0017158367642679273, 0.09619888722871434, 0.09616432767924141, 0.17553381166255197], linf = [0.021853862449723982, 0.9878047229255944, 0.9880191167111795, 2.2154030488035588]) + # 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_vortex_mortar_shockcapturing.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex_mortar_shockcapturing.jl"), l2 = [0.0017203324051381415, 0.09628962899999398, 0.0962124115572114, 0.1758599596626405], linf = [0.021740568112562086, 0.9938841624655501, 1.0041401179009877, 2.2241087041100798]) + # 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_vortex_amr.jl" begin @@ -263,6 +479,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") linf = [0.0012880114865917447, 0.03857193149447702, 0.031090457959835893, 0.12125130332971423], # Let this test run longer to cover some lines in the AMR indicator coverage_override = (maxiters=10^5, tspan=(0.0, 10.5))) + # 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_ec.jl with boundary_condition_slip_wall" begin @@ -271,8 +495,15 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") linf = [0.3290981764688339, 0.3812055782309788, 0.3812041851225023, 1.168251216556933], periodicity = false, boundary_conditions = boundary_condition_slip_wall, cfl = 0.3, tspan = (0.0, 0.1)) # this test is sensitive to the CFL factor + # 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 # Coverage test for all initial conditions @testset "Compressible Euler: Tests for initial conditions" begin @@ -282,6 +513,14 @@ end linf = [3.3306690738754696e-16, 2.220446049250313e-16, 5.273559366969494e-16, 3.552713678800501e-15], maxiters = 1, initial_condition = initial_condition_constant) + # 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_blast_wave.jl one step" begin @@ -289,7 +528,17 @@ end l2 = [0.0021196114178949396, 0.010703549234544042, 0.01070354923454404, 0.10719124037195142], linf = [0.11987270645890724, 0.7468615461136827, 0.7468615461136827, 3.910689155287799], maxiters=1) + + # 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 +end -end # module +end # module \ No newline at end of file diff --git a/test/test_tree_2d_euleracoustics.jl b/test/test_tree_2d_euleracoustics.jl index 01ac939f8aa..df4bd5d7bfc 100644 --- a/test/test_tree_2d_euleracoustics.jl +++ b/test/test_tree_2d_euleracoustics.jl @@ -15,6 +15,14 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") l2 = [0.00013268029905807722, 0.0001335062197031223, 0.00021776333678401362, 13.000001753042364, 26.00000080243847, 38.00000884725549, 51.000000003859995], linf = [0.22312716933051027, 0.1579924424942319, 0.25194831158255576, 13.468872744263273, 26.54666679978679, 38.139032147739684, 51.378134660241294] ) + # 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 diff --git a/test/test_tree_2d_eulermulti.jl b/test/test_tree_2d_eulermulti.jl index 0ae46a92ef8..c38c78ba6fd 100644 --- a/test/test_tree_2d_eulermulti.jl +++ b/test/test_tree_2d_eulermulti.jl @@ -17,6 +17,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [73.78467629094177, 0.9174752929795251, 57942.83587826468, 0.1828847253029943, 0.011127037850925347], linf = [196.81051991521073, 7.8456811648529605, 158891.88930113698, 0.811379581519794, 0.08011973559187913], tspan = (0.0, 0.001)) + # 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_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl" begin @@ -30,30 +38,70 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") lines = readlines("out/deviations.txt") @test lines[1] == "# iter, simu_time, rho1_min, rho2_min" @test startswith(lines[end], "1") + # 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_eulermulti_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_ec.jl"), l2 = [0.050182236154087095, 0.050189894464434635, 0.2258715597305131, 0.06175171559771687], linf = [0.3108124923284472, 0.3107380389947733, 1.054035804988521, 0.29347582879608936]) + # 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_eulermulti_es.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_es.jl"), l2 = [0.0496546258404055, 0.04965550099933263, 0.22425206549856372, 0.004087155041747821, 0.008174310083495642, 0.016348620166991283, 0.032697240333982566], linf = [0.2488251110766228, 0.24832493304479406, 0.9310354690058298, 0.017452870465607374, 0.03490574093121475, 0.0698114818624295, 0.139622963724859]) + # 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_eulermulti_convergence_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_ec.jl"), l2 = [0.00012290225488326508, 0.00012290225488321876, 0.00018867397906337653, 4.8542321753649044e-5, 9.708464350729809e-5], linf = [0.0006722819239133315, 0.0006722819239128874, 0.0012662292789555885, 0.0002843844182700561, 0.0005687688365401122]) + # 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_eulermulti_convergence_es.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_es.jl"), l2 = [2.2661773867001696e-6, 2.266177386666318e-6, 6.593514692980009e-6, 8.836308667348217e-7, 1.7672617334696433e-6], linf = [1.4713170997993075e-5, 1.4713170997104896e-5, 5.115618808515521e-5, 5.3639516094383666e-6, 1.0727903218876733e-5]) + # 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_eulermulti_convergence_es.jl with flux_chandrashekar" begin @@ -61,6 +109,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [1.8621737639352465e-6, 1.862173764098385e-6, 5.942585713809631e-6, 6.216263279534722e-7, 1.2432526559069443e-6], linf = [1.6235495582606063e-5, 1.6235495576388814e-5, 5.854523678827661e-5, 5.790274858807898e-6, 1.1580549717615796e-5], volume_flux = flux_chandrashekar) + # 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 diff --git a/test/test_tree_2d_fdsbp.jl b/test/test_tree_2d_fdsbp.jl index e81c82f3f34..efb24562e57 100644 --- a/test/test_tree_2d_fdsbp.jl +++ b/test/test_tree_2d_fdsbp.jl @@ -65,6 +65,15 @@ end l2 = [2.1149087345799973e-6, 1.9391438806845798e-6, 1.9391438806759794e-6, 5.842833764682604e-6], linf = [1.3679037540903494e-5, 1.1770587849069258e-5, 1.1770587848403125e-5, 4.68952678644996e-5], tspan = (0.0, 0.1), flux_splitting = splitting_lax_friedrichs) + + # 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_kelvin_helmholtz_instability.jl" begin @@ -72,6 +81,15 @@ end l2 = [0.02607850081951497, 0.020357717558016252, 0.028510191844948945, 0.02951535039734857], linf = [0.12185328623662173, 0.1065055387595834, 0.06257122956937419, 0.11992349951978643], tspan = (0.0, 0.1)) + + # 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_vortex.jl" begin @@ -79,6 +97,15 @@ end l2 = [0.0005330228930711585, 0.028475888529345014, 0.02847513865894387, 0.056259951995581196], linf = [0.007206088611304784, 0.31690373882847234, 0.31685665067192326, 0.7938167296134893], tspan = (0.0, 0.25)) + + # 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 diff --git a/test/test_tree_2d_kpp.jl b/test/test_tree_2d_kpp.jl index 26074ea487f..16d240d4a9f 100644 --- a/test/test_tree_2d_kpp.jl +++ b/test/test_tree_2d_kpp.jl @@ -17,6 +17,17 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") atol = 1e-6, rtol = 1e-6, skip_coverage = true) + + #= Does fail in coverage run (since it is not executed) + # 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 diff --git a/test/test_tree_2d_lbm.jl b/test/test_tree_2d_lbm.jl index b516708e6cd..690c04ceae3 100644 --- a/test/test_tree_2d_lbm.jl +++ b/test/test_tree_2d_lbm.jl @@ -16,6 +16,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") linf = [5.551115123125783e-15, 5.662137425588298e-15, 1.2212453270876722e-15, 1.27675647831893e-15, 2.4980018054066022e-15, 7.494005416219807e-16, 4.3021142204224816e-16, 8.881784197001252e-16, 1.0436096431476471e-14]) + # 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_lbm_couette.jl" begin @@ -27,6 +35,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") 0.00011747787108790098, 0.00084326349695725, 0.000795551892211168, 0.001956482118303543, 0.0020739599893902436, 0.00032606270109525326], tspan = (0.0, 1.0)) + # 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_lbm_lid_driven_cavity.jl" begin @@ -38,6 +54,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") 0.004031686575556803, 0.0038728927083346437, 0.020038695575169005, 0.02061789496737146, 0.05568236920459335], tspan = (0.0, 1.0)) + # 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_lbm_couette.jl with initial_condition_couette_steady" begin @@ -58,8 +82,24 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") v2 = 0 return equilibrium_distribution(rho, v1, v2, equations) - end, + # 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, tspan = (0.0, 1.0)) + # 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_lbm_lid_driven_cavity.jl with stationary walls" begin @@ -72,6 +112,15 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") 2.185751579730777e-16, 2.393918396847994e-16, 1.887379141862766e-15], boundary_conditions=boundary_condition_noslip_wall, tspan = (0, 0.1)) + + # 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 diff --git a/test/test_tree_2d_linearizedeuler.jl b/test/test_tree_2d_linearizedeuler.jl index 2c5f6dc2cd1..93da887e73f 100644 --- a/test/test_tree_2d_linearizedeuler.jl +++ b/test/test_tree_2d_linearizedeuler.jl @@ -12,11 +12,28 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [0.00020601485381444888, 0.00013380483421751216, 0.0001338048342174503, 0.00020601485381444888], linf = [0.0011006084408365924, 0.0005788678074691855, 0.0005788678074701847, 0.0011006084408365924] ) + # 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_linearizedeuler_gauss_wall.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_linearizedeuler_gauss_wall.jl"), l2 = [0.048185623945503485, 0.01941899333212175, 0.019510224816991825, 0.048185623945503485], linf = [1.0392165942153189, 0.18188777290819994, 0.1877028372108587, 1.0392165942153189]) + + # 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 diff --git a/test/test_tree_2d_mhd.jl b/test/test_tree_2d_mhd.jl index 3e104da3e91..270bdc19fa3 100644 --- a/test/test_tree_2d_mhd.jl +++ b/test/test_tree_2d_mhd.jl @@ -12,6 +12,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), l2 = [0.00011149543672225127, 5.888242524520296e-6, 5.888242524510072e-6, 8.476931432519067e-6, 1.3160738644036652e-6, 1.2542675002588144e-6, 1.2542675002747718e-6, 1.8705223407238346e-6, 4.651717010670585e-7], linf = [0.00026806333988971254, 1.6278838272418272e-5, 1.627883827305665e-5, 2.7551183488072617e-5, 5.457878055614707e-6, 8.130129322880819e-6, 8.130129322769797e-6, 1.2406302192291552e-5, 2.373765544951732e-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 end @trixi_testset "elixir_mhd_alfven_wave.jl with flux_derigs_etal" begin @@ -19,6 +27,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [1.7201098719531215e-6, 8.692057393373005e-7, 8.69205739320643e-7, 1.2726508184718958e-6, 1.040607127595208e-6, 1.07029565814218e-6, 1.0702956581404748e-6, 1.3291748105236525e-6, 4.6172239295786824e-7], linf = [9.865325754310206e-6, 7.352074675170961e-6, 7.352074674185638e-6, 1.0675656902672803e-5, 5.112498347226158e-6, 7.789533065905019e-6, 7.789533065905019e-6, 1.0933531593274037e-5, 2.340244047768378e-6], volume_flux = (flux_derigs_etal, flux_nonconservative_powell)) + # 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_mhd_alfven_wave_mortar.jl" begin @@ -26,12 +42,28 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [3.7762324533854616e-6, 1.5534623833573546e-6, 1.4577234868196855e-6, 1.7647724628707057e-6, 1.4831911814574333e-6, 1.456369119716533e-6, 1.4115666913995062e-6, 1.804758237422838e-6, 8.320469738087189e-7], linf = [3.670661330201774e-5, 1.530289442645827e-5, 1.3592183785327006e-5, 1.5173897443654383e-5, 9.43771379136038e-6, 1.0906323046233624e-5, 1.0603954940346938e-5, 1.5900499596113726e-5, 5.978772247650426e-6], tspan = (0.0, 1.0)) + # 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_mhd_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ec.jl"), l2 = [0.03637302248881514, 0.043002991956758996, 0.042987505670836056, 0.02574718055258975, 0.1621856170457943, 0.01745369341302589, 0.017454552320664566, 0.026873190440613117, 5.336243933079389e-16], linf = [0.23623816236321427, 0.3137152204179957, 0.30378397831730597, 0.21500228807094865, 0.9042495730546518, 0.09398098096581875, 0.09470282020962917, 0.15277253978297378, 4.307694418935709e-15]) + # 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_mhd_orszag_tang.jl" begin @@ -39,6 +71,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [0.21967600768935716, 0.2643126515795721, 0.31488287201980875, 0.0, 0.5160141621186931, 0.23028914748088603, 0.34413527376463915, 0.0, 0.003178793090381426], linf = [1.2749969218080568, 0.6737013368774057, 0.8604154399895696, 0.0, 2.799342099887639, 0.6473347557712643, 0.9691773375490476, 0.0, 0.05729832038724348], tspan = (0.0, 0.09)) + # 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_mhd_orszag_tang.jl with flux_hll" begin @@ -46,6 +86,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [0.10806619664693064, 0.20199136742199922, 0.22984589847526207, 0.0, 0.29950152196422647, 0.15688413207147794, 0.24293641543490646, 0.0, 0.003246181006326598], linf = [0.560316034595759, 0.5095520363866776, 0.6536748458764621, 0.0, 0.9627447086204038, 0.3981375420906146, 0.673472146198816, 0.0, 0.04879208429337193], tspan = (0.0, 0.06), surface_flux = (flux_hll, flux_nonconservative_powell)) + # 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_mhd_alfven_wave.jl one step with initial_condition_constant" begin @@ -55,6 +103,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") maxiters = 1, initial_condition = initial_condition_constant, atol = 2.0e-13) + # 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_mhd_rotor.jl" begin @@ -62,6 +118,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [1.2623319195262743, 1.8273050553090515, 1.7004151198284634, 0.0, 2.2978570581460818, 0.2147235065899803, 0.23558337696054493, 0.0, 0.0032515115395693483], linf = [11.003677581472843, 14.70614192714736, 15.687648666952708, 0.0, 17.098104835553823, 1.3283750501377847, 1.4365828094434892, 0.0, 0.07886241196068537], tspan = (0.0, 0.05)) + # 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_mhd_blast_wave.jl" begin @@ -72,6 +136,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") # Calling the AnalysisCallback before iteration 9 causes the interpolation # of this IC to have negative density/pressure values, crashing the simulation. coverage_override = (maxiters=9,)) + # 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 diff --git a/test/test_tree_2d_mhdmulti.jl b/test/test_tree_2d_mhdmulti.jl index 09c26569d46..a73e39a6d6d 100644 --- a/test/test_tree_2d_mhdmulti.jl +++ b/test/test_tree_2d_mhdmulti.jl @@ -17,6 +17,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") linf = [0.31371522041799105, 0.3037839783173047, 0.21500228807094351, 0.904249573054642, 0.0939809809658183, 0.09470282020962761, 0.1527725397829759, 8.245701827530042e-15, 0.0787460541210726, 0.1574921082421452]) + # 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_mhdmulti_ec.jl with flux_derigs_etal" begin @@ -31,6 +39,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") 0.1567857511190207], volume_flux = (flux_derigs_etal, flux_nonconservative_powell), surface_flux = (flux_derigs_etal, flux_nonconservative_powell)) + # 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_mhdmulti_es.jl" begin @@ -41,6 +57,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") linf = [0.23454607703107877, 0.23464789247380322, 0.11898832084115452, 0.5331209602648022, 0.061744814466827336, 0.061767127585091286, 0.09595041452184983, 0.004421037168524759, 0.06186597801911198, 0.12373195603822396]) + # 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_mhdmulti_convergence.jl" begin @@ -51,6 +75,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") linf = [0.0013324014301672943, 0.0013324014301669181, 0.002684449324758791, 0.0016236816790307085, 0.0019172373117153363, 0.0019172373117148922, 0.002664932274107224, 0.0011872396664042962, 0.0002855492944235094, 0.0005710985888470188, 0.0011421971776940376]) + # 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_mhdmulti_rotor.jl" begin @@ -62,6 +94,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") 0.6628317732399827, 1.4185626901435056, 0.0, 0.06914316292003836, 3.328770801731456, 1.664385400865728], tspan = (0.0, 0.01)) + # 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 diff --git a/test/test_tree_2d_shallowwater.jl b/test/test_tree_2d_shallowwater.jl index 7670d28f43a..126c16e3356 100644 --- a/test/test_tree_2d_shallowwater.jl +++ b/test/test_tree_2d_shallowwater.jl @@ -15,6 +15,14 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") l2 = [0.991181203601035, 0.734130029040644, 0.7447696147162621, 0.5875351036989047], linf = [2.0117744577945413, 2.9962317608172127, 2.6554999727293653, 3.0], tspan = (0.0, 0.25)) + # 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 @@ -22,6 +30,14 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") l2 = [0.9130579602987144, 1.0602847041965408e-14, 1.082225645390032e-14, 0.9130579602987147], linf = [2.113062037615659, 4.6613606802974e-14, 5.4225772771633196e-14, 2.1130620376156584], tspan = (0.0, 0.25)) + # 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_wall.jl" begin @@ -29,6 +45,14 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") l2 = [0.9130579602987144, 1.0602847041965408e-14, 1.082225645390032e-14, 0.9130579602987147], linf = [2.113062037615659, 4.6613606802974e-14, 5.4225772771633196e-14, 2.1130620376156584], tspan = (0.0, 0.25)) + # 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 with FluxHydrostaticReconstruction" begin @@ -37,6 +61,14 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") linf = [2.1130620376156584, 2.3875905654916432e-14, 2.2492839032269154e-14, 2.1130620376156584], surface_flux=(FluxHydrostaticReconstruction(flux_lax_friedrichs, hydrostatic_reconstruction_audusse_etal), flux_nonconservative_audusse_etal), tspan = (0.0, 0.25)) + # 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_wet_dry.jl with FluxHydrostaticReconstruction" begin @@ -44,6 +76,14 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") l2 = [0.030186039395610056, 2.513287752536758e-14, 1.3631397744897607e-16, 0.10911781485920438], linf = [0.49999999999993505, 5.5278950497971455e-14, 7.462550826772548e-16, 2.0], tspan = (0.0, 0.25)) + # 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_source_terms.jl" begin @@ -51,6 +91,14 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") l2 = [0.001868474306068482, 0.01731687445878443, 0.017649083171490863, 6.274146767717023e-5], linf = [0.016962486402209986, 0.08768628853889782, 0.09038488750767648, 0.0001819675955490041], tspan = (0.0, 0.025)) + # 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_source_terms_dirichlet.jl" begin @@ -58,6 +106,14 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") l2 = [0.0018746929418489125, 0.017332321628469628, 0.01634953679145536, 6.274146767717023e-5], linf = [0.016262353691956388, 0.08726160620859424, 0.09043621801418844, 0.0001819675955490041], tspan = (0.0, 0.025)) + # 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_source_terms.jl with flux_hll" begin @@ -65,6 +121,14 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") l2 = [0.0018957692481057034, 0.016943229710439864, 0.01755623297390675, 6.274146767717414e-5], linf = [0.015156105797771602, 0.07964811135780492, 0.0839787097210376, 0.0001819675955490041], tspan = (0.0, 0.025), surface_flux=(flux_hll, flux_nonconservative_fjordholm_etal)) + # 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_conical_island.jl" begin @@ -72,6 +136,14 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") l2 = [0.0459315416430658, 0.1644534881916991, 0.16445348819169914, 0.0011537702354532694], linf = [0.21100717610846464, 0.9501592344310412, 0.9501592344310417, 0.021790250683516282], tspan = (0.0, 0.025)) + # 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_parabolic_bowl.jl" begin @@ -80,6 +152,14 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") linf = [0.004664246019836723, 0.0004972780116736669, 0.0028735707270457628, 6.866729407306593e-14], tspan = (0.0, 0.025), basis = LobattoLegendreBasis(3)) + # 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 diff --git a/test/test_tree_2d_shallowwater_twolayer.jl b/test/test_tree_2d_shallowwater_twolayer.jl index 7ad5b0f7316..d98d682506e 100644 --- a/test/test_tree_2d_shallowwater_twolayer.jl +++ b/test/test_tree_2d_shallowwater_twolayer.jl @@ -17,6 +17,14 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") linf = [0.002822006686981293, 0.014859895905040332, 0.017590546190827894, 0.0016323702636176218, 0.009361402900653015, 0.008411036357379165, 3.361991620143279e-5], tspan = (0.0, 0.25)) + # 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_twolayer_convergence.jl with flux_es_fjordholm_etal" begin @@ -29,6 +37,14 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") 3.361991620143279e-5], surface_flux = (flux_es_fjordholm_etal, flux_nonconservative_fjordholm_etal), tspan = (0.0, 0.25)) + # 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_twolayer_well_balanced.jl" begin @@ -40,6 +56,14 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") 0.026474051138910493, 9.237568031609006e-16, 7.520758026187046e-16, 0.026474051138910267], tspan = (0.0, 0.25)) + # 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_twolayer_well_balanced with flux_lax_friedrichs.jl" begin @@ -52,6 +76,14 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") 0.026474051138910267], surface_flux = (flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), tspan = (0.0, 0.25)) + # 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 diff --git a/test/test_tree_3d_advection.jl b/test/test_tree_3d_advection.jl index c2e74f8312d..24e65934e60 100644 --- a/test/test_tree_3d_advection.jl +++ b/test/test_tree_3d_advection.jl @@ -12,12 +12,28 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), l2 = [0.00016263963870641478], linf = [0.0014537194925779984]) + # 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_restart.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), l2 = [0.00016017848135651983], linf = [0.0014175368788298393]) + # 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_extended.jl with initial_condition_sin" begin @@ -25,6 +41,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") l2 = [0.002647730309275237], linf = [0.02114324070353557], initial_condition=Trixi.initial_condition_sin) + # 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_extended.jl with initial_condition_constant" begin @@ -32,6 +56,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") l2 = [7.728011630010656e-16], linf = [3.9968028886505635e-15], initial_condition=initial_condition_constant) + # 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_extended.jl with initial_condition_linear_z and periodicity=false" begin @@ -40,6 +72,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") linf = [2.886579864025407e-15], initial_condition=Trixi.initial_condition_linear_z, boundary_conditions=Trixi.boundary_condition_linear_z, periodicity=false) + # 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_mortar.jl" begin @@ -62,6 +102,15 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") l2 = [9.773852895157622e-6], linf = [0.0005853874124926162], coverage_override = (maxiters=6, initial_refinement_level=1, base_level=1, med_level=1, max_level=3)) + + # 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 diff --git a/test/test_tree_3d_euler.jl b/test/test_tree_3d_euler.jl index 2beb6fc7bed..fe5e42843f8 100644 --- a/test/test_tree_3d_euler.jl +++ b/test/test_tree_3d_euler.jl @@ -12,12 +12,28 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms.jl"), l2 = [0.010385936842224346, 0.009776048833895767, 0.00977604883389591, 0.009776048833895733, 0.01506687097416608], linf = [0.03285848350791731, 0.0321792316408982, 0.032179231640894645, 0.032179231640895534, 0.0655408023333299]) + # 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_convergence_pure_fv.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence_pure_fv.jl"), l2 = [0.037182410351406, 0.032062252638283974, 0.032062252638283974, 0.03206225263828395, 0.12228177813586687], linf = [0.0693648413632646, 0.0622101894740843, 0.06221018947408474, 0.062210189474084965, 0.24196451799555962]) + # 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_source_terms.jl with split_form" begin @@ -25,18 +41,42 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") l2 = [0.010385936842223388, 0.009776048833894784, 0.009776048833894784, 0.009776048833894765, 0.015066870974164096], linf = [0.03285848350791687, 0.032179231640897754, 0.0321792316408942, 0.0321792316408982, 0.06554080233333615], volume_integral=VolumeIntegralFluxDifferencing(flux_central)) + # 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_convergence.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), l2 = [0.0003637241020254405, 0.0003955570866382718, 0.0003955570866383613, 0.00039555708663834417, 0.0007811613481640202], linf = [0.0024000660244674066, 0.0029635410025339315, 0.0029635410025292686, 0.002963541002525938, 0.007191437359396424]) + # 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_mortar.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_mortar.jl"), l2 = [0.0019428114665068841, 0.0018659907926698422, 0.0018659907926698589, 0.0018659907926698747, 0.0034549095578444056], linf = [0.011355360771142298, 0.011526889155693887, 0.011526889155689002, 0.011526889155701436, 0.02299726519821288]) + # 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_amr.jl" begin @@ -45,6 +85,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") linf = [0.07390396464027349, 0.07390396464027305, 0.07390396464027305, 0.07390396464027305, 0.11085594696041134], tspan=(0.0, 0.1), coverage_override = (maxiters=6, initial_refinement_level=0, base_level=0, med_level=0, max_level=1)) + # 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_taylor_green_vortex.jl" begin @@ -52,12 +100,28 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") l2 = [0.00034949871748737876, 0.03133384111621587, 0.03133384111621582, 0.04378599329988925, 0.015796137903453026], linf = [0.0013935237751798724, 0.0724080091006194, 0.07240800910061806, 0.12795921224174792, 0.07677156293692633], tspan = (0.0, 0.5)) + # 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_shockcapturing.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing.jl"), l2 = [0.02570137197844877, 0.016179934130642552, 0.01617993413064253, 0.016172648598753545, 0.09261669328795467], linf = [0.3954458125573179, 0.26876916180359345, 0.26876916180359345, 0.26933123042178553, 1.3724137121660251]) + # 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_shockcapturing_amr.jl" begin @@ -69,18 +133,42 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") linf = [0.4047819603427084, 0.27493532130155474, 0.2749353213015551, 0.2749304638368023, 1.4053942765487641], maxiters=10, coverage_override = (maxiters=2,)) + # 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_density_pulse.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_density_pulse.jl"), l2 = [0.057196526814004715, 0.057196526814004715, 0.05719652681400473, 0.057196526814004736, 0.08579479022100575], linf = [0.27415246703018203, 0.2741524670301829, 0.2741524670301827, 0.27415246703018226, 0.41122870054527816]) + # 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_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), l2 = [0.02526341317987378, 0.016632068583699623, 0.016632068583699623, 0.01662548715216875, 0.0913477018048886], linf = [0.4372549540810414, 0.28613118232798984, 0.28613118232799006, 0.28796686065271876, 1.5072828647309124]) + # 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_ec.jl with initial_condition=initial_condition_constant" begin @@ -88,6 +176,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") l2 = [4.183721551616214e-16, 6.059779958716338e-16, 4.916596221090319e-16, 9.739943366304456e-16, 3.7485908743251566e-15], linf = [2.4424906541753444e-15, 3.733124920302089e-15, 4.440892098500626e-15, 5.329070518200751e-15, 2.4868995751603507e-14], initial_condition=initial_condition_constant) + # 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_ec.jl with flux_chandrashekar" begin @@ -95,6 +191,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") l2 = [0.025265721172813106, 0.016649800693500427, 0.01664980069350042, 0.01664379306708522, 0.09137248646784184], linf = [0.4373399329742198, 0.28434487167605427, 0.28434487167605427, 0.28522678968890774, 1.532471676033761], surface_flux=flux_chandrashekar, volume_flux=flux_chandrashekar) + # 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_ec.jl with flux_kennedy_gruber" begin @@ -102,6 +206,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") l2 = [0.025280033869871984, 0.016675487948639846, 0.016675487948639853, 0.016668992714991282, 0.091455613470441], linf = [0.43348628145015766, 0.28853549062014217, 0.28853549062014217, 0.2903943042772536, 1.5236557526482426], surface_flux=flux_kennedy_gruber, volume_flux=flux_kennedy_gruber) + # 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_ec.jl with flux_shima_etal" begin @@ -109,6 +221,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") l2 = [0.025261716925811403, 0.016637655557848952, 0.01663765555784895, 0.01663105921013437, 0.09136239054024566], linf = [0.43692416928732536, 0.28622033209064734, 0.28622033209064746, 0.2881197143457632, 1.506534270303663], surface_flux=flux_shima_etal, volume_flux=flux_shima_etal) + # 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_blob_amr.jl" begin @@ -119,6 +239,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") # Let this test run longer to cover some lines in the positivity preserving limiter # and some AMR lines coverage_override = (maxiters=10^5,)) + # 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_blast_wave.jl" begin @@ -127,6 +255,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") linf = [0.06344190883105805, 0.6292607955969378, 0.6292607955969377, 0.6292607955969377, 2.397746252817731], maxiters=5, max_level=6, coverage_override = (maxiters=2, initial_refinement_level=1, base_level=1, max_level=3)) + # 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 diff --git a/test/test_tree_3d_eulergravity.jl b/test/test_tree_3d_eulergravity.jl index 635a06a718b..3146b88aeb0 100644 --- a/test/test_tree_3d_eulergravity.jl +++ b/test/test_tree_3d_eulergravity.jl @@ -13,6 +13,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") l2 = [0.0004276779201667428, 0.00047204222332596204, 0.00047204222332608705, 0.0004720422233259819, 0.0010987026250960728], linf = [0.003496616916238704, 0.003764418290373106, 0.003764418290377103, 0.0037644182903766588, 0.008370424899251105], resid_tol = 1.0e-4, tspan = (0.0, 0.2)) + # 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 diff --git a/test/test_tree_3d_fdsbp.jl b/test/test_tree_3d_fdsbp.jl index 106dd007b09..f45f2b0f78a 100644 --- a/test/test_tree_3d_fdsbp.jl +++ b/test/test_tree_3d_fdsbp.jl @@ -66,6 +66,15 @@ end linf = [0.0001963934848161486, 0.00020239883896255861, 0.0002023988389729947, 0.00020239883896766564, 0.00052605624510349], tspan = (0.0, 0.2), solver = DG(D_upw.central, nothing, SurfaceIntegralStrongForm(), VolumeIntegralStrongForm())) + + # 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_taylor_green_vortex.jl" begin @@ -73,6 +82,15 @@ end l2 = [3.529693407280806e-6, 0.0004691301922633193, 0.00046913019226332234, 0.0006630180220973541, 0.0015732759680929076], linf = [3.4253965106145756e-5, 0.0010033197685090707, 0.0010033197685091054, 0.0018655642702542635, 0.008479800046757191], tspan = (0.0, 0.0075), abstol = 1.0e-9, reltol = 1.0e-9) + + # 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 diff --git a/test/test_tree_3d_lbm.jl b/test/test_tree_3d_lbm.jl index 0e92c5436af..af7b147e609 100644 --- a/test/test_tree_3d_lbm.jl +++ b/test/test_tree_3d_lbm.jl @@ -29,6 +29,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") 1.4224732503009818e-16, 1.214306433183765e-16, 1.3877787807814457e-16, 8.673617379884035e-17, 9.71445146547012e-17, 2.7755575615628914e-15], tspan=(0.0, 0.5)) + # 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_lbm_taylor_green_vortex.jl" begin @@ -53,6 +61,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") 1.3570400471224833e-5, 1.4249297322244114e-5], tspan=(0.0, 0.1), initial_refinement_level=3) + # 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 diff --git a/test/test_tree_3d_mhd.jl b/test/test_tree_3d_mhd.jl index a06d721b525..708f2a1a038 100644 --- a/test/test_tree_3d_mhd.jl +++ b/test/test_tree_3d_mhd.jl @@ -12,6 +12,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ec.jl"), l2 = [0.017590099293094203, 0.017695875823827714, 0.017695875823827686, 0.017698038279620777, 0.07495006099352074, 0.010391801950005755, 0.010391801950005759, 0.010393502246627087, 2.524766553484067e-16], linf = [0.28173002819718196, 0.3297583616136297, 0.32975836161363004, 0.356862935505337, 1.2893514981209626, 0.10950981489747313, 0.10950981489747136, 0.11517234329681891, 2.0816911067714202e-15]) + # 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_mhd_ec.jl with initial_condition=initial_condition_constant" begin @@ -20,12 +28,28 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") linf = [2.4424906541753444e-15, 2.881028748902281e-14, 2.4646951146678475e-14, 2.3092638912203256e-14, 2.3447910280083306e-13, 1.7763568394002505e-14, 1.0436096431476471e-14, 2.042810365310288e-14, 7.057203733035201e-15], atol = 1000*eps(), initial_condition=initial_condition_constant) + # 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_mhd_alfven_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), l2 = [0.0032217291057246157, 0.009511644936958913, 0.004217358459420256, 0.011591709179125335, 0.009456218722393708, 0.00916500047763897, 0.005069863732625444, 0.011503011541926135, 0.003988175543749985], linf = [0.01188593784273051, 0.03638015998373141, 0.01568200398945724, 0.04666974730787579, 0.031235294705421968, 0.03316343064943483, 0.011539436992528018, 0.04896687646520839, 0.018714054039927555]) + # 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_mhd_alfven_wave.jl with flux_derigs_etal" begin @@ -33,6 +57,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") l2 = [0.003755235939722358, 0.009062519246840721, 0.004096299856228109, 0.011429935838448906, 0.006897420817511043, 0.00900886245212482, 0.004926537542780259, 0.01153285554590683, 0.0037842060148666886], linf = [0.012982853115883541, 0.0320228076558316, 0.011575276754611022, 0.04425778643430531, 0.02478109022285846, 0.03198699034954189, 0.009761077061886558, 0.04433669321441455, 0.01618905441148782], volume_flux = (flux_derigs_etal, flux_nonconservative_powell)) + # 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_mhd_alfven_wave_mortar.jl" begin @@ -40,6 +72,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") l2 = [0.001879021634926363, 0.007032724521848316, 0.0032793932234187325, 0.009056594733320348, 0.007514150120617965, 0.007328739509868727, 0.00309794018112387, 0.009026356949274878, 0.0035732583778049776], linf = [0.013734346970999622, 0.06173467158736011, 0.02183946452704291, 0.06258216169457917, 0.03672304497348122, 0.055120532123884625, 0.018202716205672487, 0.06133688282205586, 0.019888161885935608], tspan = (0.0, 0.25)) + # 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_mhd_alfven_wave.jl with Orszag-Tang setup + flux_hll" begin @@ -66,7 +106,15 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") B3 = sin(4.0*pi*x[2]) / (4.0*pi) psi = 0.0 return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3, psi), equations) - end, + # 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, surface_flux = (flux_hll, flux_nonconservative_powell), volume_flux = (flux_central, flux_nonconservative_powell), coordinates_min = (0.0, 0.0, 0.0), @@ -74,12 +122,28 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") initial_refinement_level=3, cfl = 1.1, tspan = (0.0, 0.06)) + # 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_mhd_ec_shockcapturing.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ec_shockcapturing.jl"), l2 = [0.0186712969755079, 0.01620736832264799, 0.01620736832264803, 0.016207474382769683, 0.07306422729650594, 0.007355137041002365, 0.0073551370410023425, 0.00735520932001833, 0.000506140942330923], linf = [0.28040713666979633, 0.27212885844703694, 0.2721288584470349, 0.2837380205051839, 0.7915852408267114, 0.08770240288089526, 0.08770240288089792, 0.08773409387876674, 0.050221095224119834]) + # 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 diff --git a/test/test_unstructured_2d.jl b/test/test_unstructured_2d.jl index fbe88a2a0a3..567cbd9ea57 100644 --- a/test/test_unstructured_2d.jl +++ b/test/test_unstructured_2d.jl @@ -18,6 +18,14 @@ isdir(outdir) && rm(outdir, recursive=true) @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_periodic.jl"), l2 = [0.00010978828464875207, 0.00013010359527356914, 0.00013010359527326057, 0.0002987656724828824], linf = [0.00638626102818618, 0.009804042508242183, 0.009804042508253286, 0.02183139311614468]) + # 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.jl" begin @@ -26,6 +34,14 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [8.804734719092266e-12, 6.261270668606045e-11, 2.93670088247211e-11, 1.205400224080222e-10], tspan = (0.0, 0.1), atol = 3.0e-13) + # 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_wall_bc.jl" begin @@ -33,6 +49,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.040189107976346644, 0.04256154998030852, 0.03734120743842209, 0.10057425897733507], linf = [0.24455374304626365, 0.2970686406973577, 0.29339040847600434, 0.5915610037764794], tspan = (0.0, 0.25)) + # 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_basic.jl" begin @@ -40,12 +64,28 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0007213418215265047, 0.0006752337675043779, 0.0006437485997536973, 0.0014782883071363362], linf = [0.004301288971032324, 0.005243995459478956, 0.004685630332338153, 0.01750217718347713], tspan = (0.0, 1.0)) + # 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_restart.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_restart.jl"), l2 = [0.0007213418215265047, 0.0006752337675043779, 0.0006437485997536973, 0.0014782883071363362], linf = [0.004301288971032324, 0.005243995459478956, 0.004685630332338153, 0.01750217718347713]) + # 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_ec.jl" begin @@ -53,12 +93,28 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.06594600495903137, 0.10803914821786433, 0.10805946357846291, 0.1738171782368222], linf = [0.31880214280781305, 0.3468488554333352, 0.34592958184413264, 0.784555926860546], tspan = (0.0, 1.0)) + # 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_basic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), l2 = [0.00018729339078205488], linf = [0.0018997287705734278]) + # 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 @@ -66,6 +122,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [2.19945600e-01, 1.71050453e-01, 1.71050453e-01, 1.21719195e+00], linf = [7.44218635e-01, 7.02887039e-01, 7.02887039e-01, 6.11732719e+00], tspan = (0.0, 0.3)) + # 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_acoustics_gauss_wall.jl" begin @@ -75,6 +139,14 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [0.36236334472179443, 0.3690785638275256, 0.8475748723784078, 0.0, 8.881784197001252e-16, 1.7763568394002505e-15, 1.7763568394002505e-15], tspan = (0.0, 5.0)) + # 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_mhd_ec.jl" begin @@ -86,6 +158,14 @@ isdir(outdir) && rm(outdir, recursive=true) 0.44230628074326406, 0.16743171716317784, 0.16745989278866702, 0.17700588224362557, 0.02692320090677309], tspan = (0.0, 0.5)) + # 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_mhd_alfven_wave.jl" begin @@ -97,6 +177,14 @@ isdir(outdir) && rm(outdir, recursive=true) 6.826863293230012e-5, 0.14146512909995967, 0.14146512909994702, 0.20006706837452526, 0.00013645610312810813], tspan = (0.0, 0.5)) + # 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_ec.jl" begin @@ -104,6 +192,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.6106939484178353, 0.48586236867426724, 0.48234490854514356, 0.29467422718511727], linf = [2.775979948281604, 3.1721242154451548, 3.5713448319601393, 2.052861364219655], tspan = (0.0, 0.25)) + # 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 @@ -111,6 +207,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [1.2164292510839076, 2.6118925543469468e-12, 1.1636046671473883e-12, 1.2164292510839079], linf = [1.5138512282315846, 4.998482888288039e-11, 2.0246214978154587e-11, 1.513851228231574], tspan = (0.0, 0.25)) + # 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 with FluxHydrostaticReconstruction" begin @@ -119,6 +223,14 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [1.513851228231562, 1.6287765844373185e-11, 6.8766999132716964e-12, 1.513851228231574], surface_flux=(FluxHydrostaticReconstruction(flux_lax_friedrichs, hydrostatic_reconstruction_audusse_etal), flux_nonconservative_audusse_etal), tspan = (0.0, 0.2)) + # 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_source_terms.jl" begin @@ -126,6 +238,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0011197623982310795, 0.04456344888447023, 0.014317376629669337, 5.089218476758975e-6], linf = [0.007835284004819698, 0.3486891284278597, 0.11242778979399048, 2.6407324614119432e-5], tspan = (0.0, 0.025)) + # 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_source_terms.jl with FluxHydrostaticReconstruction" begin @@ -134,6 +254,14 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [0.014300809338967824, 0.12783372461225184, 0.17625472321992852, 2.6407324614341476e-5], surface_flux=(FluxHydrostaticReconstruction(flux_hll, hydrostatic_reconstruction_audusse_etal), flux_nonconservative_audusse_etal), tspan = (0.0, 0.025)) + # 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_source_terms.jl with flux_hll" begin @@ -142,6 +270,14 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [0.014300809338967824, 0.12783372461224918, 0.17625472321993918, 2.6407324614341476e-5], surface_flux=(flux_hll, flux_nonconservative_fjordholm_etal), tspan = (0.0, 0.025)) + # 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_dirichlet.jl" begin @@ -149,6 +285,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [1.1577518608940115e-5, 4.867189932537344e-13, 4.647273240470541e-13, 1.1577518608933468e-5], linf = [8.394063878602864e-5, 1.1469760027632646e-10, 1.1146619484429974e-10, 8.394063879602065e-5], tspan = (0.0, 2.0)) + # 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_wall_bc_shockcapturing.jl" begin @@ -156,6 +300,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.04444388691670699, 0.1527771788033111, 0.1593763537203512, 6.225080476986749e-8], linf = [0.6526506870169639, 1.980765893182952, 2.4807635459119757, 3.982097158683473e-7], tspan = (0.0, 0.05)) + # 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_ec_shockcapturing.jl" begin @@ -163,6 +315,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.6124656312639043, 0.504371951785709, 0.49180896200746366, 0.29467422718511727], linf = [2.7639232436274392, 3.3985508653311767, 3.3330308209196224, 2.052861364219655], tspan = (0.0, 0.25)) + # 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_three_mound_dam_break.jl" begin @@ -171,6 +331,14 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [0.850329472915091, 2.330631694956507, 5.783660020252348e-14, 0.04326237921249021], basis = LobattoLegendreBasis(3), tspan = (0.0, 0.25)) + # 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_twolayer_convergence.jl" begin @@ -181,6 +349,14 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [0.00592559068081977, 0.08072451118697077, 0.0344854497419107, 0.005892196680485795, 0.04262651217675306, 0.014006223513881366, 2.5829318284764646e-5], tspan = (0.0, 0.25)) + # 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_twolayer_well_balanced.jl" begin @@ -192,6 +368,14 @@ isdir(outdir) && rm(outdir, recursive=true) 0.024280130945632084, 6.68910907640583e-14, 4.7000983997100496e-14, 0.024280130945632732], tspan = (0.0, 0.25)) + # 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_twolayer_dam_break.jl with flux_lax_friedrichs" begin @@ -203,6 +387,14 @@ isdir(outdir) && rm(outdir, recursive=true) 0.11138723974511211, 0.03640850605444494, 0.014368386516056392, 0.10000000000000003], surface_flux = (flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), tspan = (0.0, 0.25)) + # 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 diff --git a/utils/add_alloctest.py b/utils/add_alloctest.py new file mode 100644 index 00000000000..184ad280ea0 --- /dev/null +++ b/utils/add_alloctest.py @@ -0,0 +1,43 @@ +import argparse + +def add_code_after_end(input_file, output_file, code_to_add): + with open(input_file, 'r') as f: + julia_code = f.read() + + # Split the Julia code by "end" keywords + code_lines = julia_code.split("end") + + # Initialize the modified code with the first part of the code + modified_code = code_lines[0] + + # Loop through each "end" and add the code after it, excluding the last "end" + for i in range(1, len(code_lines) - 1): + # Check for consecutive "end" keywords + if code_lines[i].strip() == "": + continue + + modified_code += f"{code_to_add}{code_lines[i]}" + + # Add the last "end" without the code + modified_code += code_lines[-1] + + with open(output_file, 'w') as f: + f.write(modified_code) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Add code after 'end' keyword in a Julia source file.") + parser.add_argument("input_file", help="Input Julia source file") + + args = parser.parse_args() + + code_to_add = """ # 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""" + + add_code_after_end(args.input_file, args.input_file, code_to_add) From 38404f1a65ae725dbfbcd252edc965e31f4f4cdc Mon Sep 17 00:00:00 2001 From: Jesse Chan <1156048+jlchan@users.noreply.github.com> Date: Sun, 22 Oct 2023 04:03:17 -0500 Subject: [PATCH 134/263] Add example LocalPreferences.toml file to parallelization.md (#1660) * Add example LocalPreferences.toml file to parallelization.md * Update docs/src/parallelization.md Co-authored-by: Michael Schlottke-Lakemper --------- Co-authored-by: Michael Schlottke-Lakemper --- docs/src/parallelization.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/docs/src/parallelization.md b/docs/src/parallelization.md index 610aa2cbd95..fa6fc1a5d32 100644 --- a/docs/src/parallelization.md +++ b/docs/src/parallelization.md @@ -70,7 +70,32 @@ the same for P4est.jl and T8code.jl. This could e.g. be `libp4est.so` that usual in `lib/` or `local/lib/` in the installation directory of `t8code`. In total, in your active Julia project you should have a LocalPreferences.toml file with sections `[MPIPreferences]`, `[T8code]` and `[P4est]` as well as an entry `MPIPreferences` in your -Project.toml to use a custom MPI installation. +Project.toml to use a custom MPI installation. A `LocalPreferences.toml` file +created as described above might look something like the following: +```toml +[HDF5] +libhdf5 = "/usr/lib/x86_64-linux-gnu/hdf5/openmpi/libhdf5.so" +libhdf5_hl = "/usr/lib/x86_64-linux-gnu/hdf5/openmpi/libhdf5_hl.so" + +[MPIPreferences] +__clear__ = ["preloads_env_switch"] +_format = "1.0" +abi = "OpenMPI" +binary = "system" +cclibs = [] +libmpi = "/lib/x86_64-linux-gnu/libmpi.so" +mpiexec = "mpiexec" +preloads = [] + +[P4est] +libp4est = "/home/mschlott/hackathon/libtrixi/t8code/install/lib/libp4est.so" +libsc = "/home/mschlott/hackathon/libtrixi/t8code/install/lib/libsc.so" + +[T8code] +libp4est = "/home/mschlott/hackathon/libtrixi/t8code/install/lib/libp4est.so" +libsc = "/home/mschlott/hackathon/libtrixi/t8code/install/lib/libsc.so" +libt8 = "/home/mschlott/hackathon/libtrixi/t8code/install/lib/libt8.so" +``` ### [Usage](@id parallel_usage) From 93c1f33314941b758d0c8bf94c857584e3eac5d1 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 23 Oct 2023 07:48:15 +0200 Subject: [PATCH 135/263] set version to v0.5.46 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 4efbc40b098..4053a54e206 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.5.46-pre" +version = "0.5.46" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From c2f0095a3c65fb075177721f3005a678a8b72826 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 23 Oct 2023 07:48:29 +0200 Subject: [PATCH 136/263] set development version to v0.5.47-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 4053a54e206..48bb6b30182 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.5.46" +version = "0.5.47-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 6daf446fec1b3835fb1f1c6e32d89b955bfe0f82 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 23 Oct 2023 14:34:07 +0200 Subject: [PATCH 137/263] fix allocations in boundary condition of Euler double Mach elixir (#1685) --- examples/p4est_2d_dgsem/elixir_euler_double_mach_amr.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/p4est_2d_dgsem/elixir_euler_double_mach_amr.jl b/examples/p4est_2d_dgsem/elixir_euler_double_mach_amr.jl index 6d00aa91ba3..70a0e10c296 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_double_mach_amr.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_double_mach_amr.jl @@ -27,15 +27,15 @@ See Section IV c on the paper below for details. phi = pi / 6 sin_phi, cos_phi = sincos(phi) - rho = 8 + rho = 8.0 v1 = 8.25 * cos_phi v2 = -8.25 * sin_phi p = 116.5 else rho = 1.4 - v1 = 0 - v2 = 0 - p = 1 + v1 = 0.0 + v2 = 0.0 + p = 1.0 end prim = SVector(rho, v1, v2, p) From a0cf926a19e42f61938daf7feaf82154a6a86671 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 23 Oct 2023 16:59:37 +0200 Subject: [PATCH 138/263] fix type instability when iterating over callbacks in simple integrators (#1684) * fix type instability when iterating over callbacks in simple integrators * adapt remaining iterations over callbacks * Apply suggestions from code review Co-authored-by: Daniel Doehring --------- Co-authored-by: Daniel Doehring --- src/callbacks_step/save_solution.jl | 4 ++-- src/callbacks_step/summary.jl | 7 ++++--- src/time_integration/methods_2N.jl | 7 ++++--- src/time_integration/methods_3Sstar.jl | 7 ++++--- src/time_integration/methods_SSP.jl | 6 +++--- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/callbacks_step/save_solution.jl b/src/callbacks_step/save_solution.jl index 31fe0e87c77..0092360cb20 100644 --- a/src/callbacks_step/save_solution.jl +++ b/src/callbacks_step/save_solution.jl @@ -211,11 +211,11 @@ end get_element_variables!(element_variables, u_ode, semi) callbacks = integrator.opts.callback if callbacks isa CallbackSet - for cb in callbacks.continuous_callbacks + foreach(callbacks.continuous_callbacks) do cb get_element_variables!(element_variables, u_ode, semi, cb; t = integrator.t, iter = iter) end - for cb in callbacks.discrete_callbacks + foreach(callbacks.discrete_callbacks) do cb get_element_variables!(element_variables, u_ode, semi, cb; t = integrator.t, iter = iter) end diff --git a/src/callbacks_step/summary.jl b/src/callbacks_step/summary.jl index 26981a58b73..566f2c03418 100644 --- a/src/callbacks_step/summary.jl +++ b/src/callbacks_step/summary.jl @@ -168,16 +168,17 @@ function initialize_summary_callback(cb::DiscreteCallback, u, t, integrator; callbacks = integrator.opts.callback if callbacks isa CallbackSet - for cb in callbacks.continuous_callbacks + foreach(callbacks.continuous_callbacks) do cb show(io_context, MIME"text/plain"(), cb) println(io, "\n") end - for cb in callbacks.discrete_callbacks + foreach(callbacks.discrete_callbacks) do cb # Do not show ourselves - cb.affect! === summary_callback && continue + cb.affect! === summary_callback && return nothing show(io_context, MIME"text/plain"(), cb) println(io, "\n") + return nothing end else show(io_context, MIME"text/plain"(), callbacks) diff --git a/src/time_integration/methods_2N.jl b/src/time_integration/methods_2N.jl index 557e8272128..d2f22679c4f 100644 --- a/src/time_integration/methods_2N.jl +++ b/src/time_integration/methods_2N.jl @@ -119,10 +119,10 @@ function solve(ode::ODEProblem, alg::T; # initialize callbacks if callback isa CallbackSet - for cb in callback.continuous_callbacks + foreach(callback.continuous_callbacks) do cb error("unsupported") end - for cb in callback.discrete_callbacks + foreach(callback.discrete_callbacks) do cb cb.initialize(cb, integrator.u, integrator.t, integrator) end elseif !isnothing(callback) @@ -172,10 +172,11 @@ function solve!(integrator::SimpleIntegrator2N) # handle callbacks if callbacks isa CallbackSet - for cb in callbacks.discrete_callbacks + foreach(callbacks.discrete_callbacks) do cb if cb.condition(integrator.u, integrator.t, integrator) cb.affect!(integrator) end + return nothing end end diff --git a/src/time_integration/methods_3Sstar.jl b/src/time_integration/methods_3Sstar.jl index 03232c04122..b0ce5930514 100644 --- a/src/time_integration/methods_3Sstar.jl +++ b/src/time_integration/methods_3Sstar.jl @@ -189,10 +189,10 @@ function solve(ode::ODEProblem, alg::T; # initialize callbacks if callback isa CallbackSet - for cb in callback.continuous_callbacks + foreach(callback.continuous_callbacks) do cb error("unsupported") end - for cb in callback.discrete_callbacks + foreach(callback.discrete_callbacks) do cb cb.initialize(cb, integrator.u, integrator.t, integrator) end elseif !isnothing(callback) @@ -248,10 +248,11 @@ function solve!(integrator::SimpleIntegrator3Sstar) # handle callbacks if callbacks isa CallbackSet - for cb in callbacks.discrete_callbacks + foreach(callbacks.discrete_callbacks) do cb if cb.condition(integrator.u, integrator.t, integrator) cb.affect!(integrator) end + return nothing end end diff --git a/src/time_integration/methods_SSP.jl b/src/time_integration/methods_SSP.jl index 5b72682d48e..6424dde7d31 100644 --- a/src/time_integration/methods_SSP.jl +++ b/src/time_integration/methods_SSP.jl @@ -124,10 +124,10 @@ function solve(ode::ODEProblem, alg = SimpleSSPRK33()::SimpleAlgorithmSSP; # initialize callbacks if callback isa CallbackSet - for cb in callback.continuous_callbacks + foreach(callback.continuous_callbacks) do cb error("unsupported") end - for cb in callback.discrete_callbacks + foreach(callback.discrete_callbacks) do cb cb.initialize(cb, integrator.u, integrator.t, integrator) end elseif !isnothing(callback) @@ -184,7 +184,7 @@ function solve!(integrator::SimpleIntegratorSSP) # handle callbacks if callbacks isa CallbackSet - for cb in callbacks.discrete_callbacks + foreach(callbacks.discrete_callbacks) do cb if cb.condition(integrator.u, integrator.t, integrator) cb.affect!(integrator) end From e90026244079270008594450ebfea2ed8d33c333 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Tue, 24 Oct 2023 07:23:13 +0200 Subject: [PATCH 139/263] Add timer for outer RK loop for SSPRK33 (#1686) * Add timer for outer RK loop * Increase alloc check --------- Co-authored-by: Hendrik Ranocha --- src/time_integration/methods_SSP.jl | 2 +- test/test_tree_2d_euler.jl | 2 +- test/test_tree_2d_eulermulti.jl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/time_integration/methods_SSP.jl b/src/time_integration/methods_SSP.jl index 6424dde7d31..733f89c2158 100644 --- a/src/time_integration/methods_SSP.jl +++ b/src/time_integration/methods_SSP.jl @@ -148,7 +148,7 @@ function solve!(integrator::SimpleIntegratorSSP) callbacks = integrator.opts.callback integrator.finalstep = false - while !integrator.finalstep + @trixi_timeit timer() "main loop" while !integrator.finalstep if isnan(integrator.dt) error("time step size `dt` is NaN") end diff --git a/test/test_tree_2d_euler.jl b/test/test_tree_2d_euler.jl index 660e4dcf1be..79a650ded8a 100644 --- a/test/test_tree_2d_euler.jl +++ b/test/test_tree_2d_euler.jl @@ -137,7 +137,7 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") 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 + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 15000 end end diff --git a/test/test_tree_2d_eulermulti.jl b/test/test_tree_2d_eulermulti.jl index c38c78ba6fd..c454a6bcfbf 100644 --- a/test/test_tree_2d_eulermulti.jl +++ b/test/test_tree_2d_eulermulti.jl @@ -44,7 +44,7 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") 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 + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 15000 end end From 9303956e0c677587cffa752dec03b7e4c25d31eb Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Tue, 24 Oct 2023 16:29:22 +0200 Subject: [PATCH 140/263] Allocation tests (#1687) * Passing allocation tests * Passing tests * Update tests * add check for coverage * more tests * more tests * comments --------- Co-authored-by: Hendrik Ranocha --- test/test_p4est_2d.jl | 184 +++++++++- ...est_paper_self_gravitating_gas_dynamics.jl | 104 ++++++ test/test_structured_2d.jl | 336 +++++++++++++++++- test/test_tree_1d_hypdiff.jl | 16 + test/test_tree_2d_advection.jl | 154 +++++++- test/test_tree_2d_hypdiff.jl | 32 ++ test/test_tree_2d_kpp.jl | 19 +- test/test_tree_3d_hypdiff.jl | 24 ++ 8 files changed, 828 insertions(+), 41 deletions(-) diff --git a/test/test_p4est_2d.jl b/test/test_p4est_2d.jl index 31dfe1d35a5..5baa090c8d7 100644 --- a/test/test_p4est_2d.jl +++ b/test/test_p4est_2d.jl @@ -17,27 +17,42 @@ isdir(outdir) && rm(outdir, recursive=true) # Expected errors are exactly the same as with TreeMesh! l2 = [8.311947673061856e-6], linf = [6.627000273229378e-5]) + # 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_nonconforming_flag.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_nonconforming_flag.jl"), l2 = [3.198940059144588e-5], linf = [0.00030636069494005547]) - - # 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 + # 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_unstructured_flag.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_unstructured_flag.jl"), l2 = [0.0005379687442422346], linf = [0.007438525029884735]) + # 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_amr_solution_independent.jl" begin @@ -46,6 +61,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [4.949660644033807e-5], linf = [0.0004867846262313763], 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 end @trixi_testset "elixir_advection_amr_unstructured_flag.jl" begin @@ -53,18 +76,42 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0012766060609964525], linf = [0.01750280631586159], 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 end @trixi_testset "elixir_advection_restart.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), l2 = [4.507575525876275e-6], linf = [6.21489667023134e-5]) + # 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_source_terms_nonconforming_unstructured_flag.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), l2 = [0.0034516244508588046, 0.0023420334036925493, 0.0024261923964557187, 0.004731710454271893], linf = [0.04155789011775046, 0.024772109862748914, 0.03759938693042297, 0.08039824959535657]) + # 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.jl" begin @@ -73,6 +120,14 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [1.9539925233402755e-14, 2e-12, 4.8e-12, 4e-12], atol = 2.0e-12, # required to make CI tests pass on macOS ) + # 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_shockcapturing_ec.jl" begin @@ -80,6 +135,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [9.53984675e-02, 1.05633455e-01, 1.05636158e-01, 3.50747237e-01], linf = [2.94357464e-01, 4.07893014e-01, 3.97334516e-01, 1.08142520e+00], tspan = (0.0, 1.0)) + # 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 @@ -87,6 +150,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [3.76149952e-01, 2.46970327e-01, 2.46970327e-01, 1.28889042e+00], linf = [1.22139001e+00, 1.17742626e+00, 1.17742626e+00, 6.20638482e+00], tspan = (0.0, 0.3)) + # 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_blast_wave_amr.jl" begin @@ -95,6 +166,14 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [2.76020890e+00, 2.32659890e+00, 2.32580837e+00, 2.15778188e+00], tspan = (0.0, 0.3), 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 end @trixi_testset "elixir_euler_wall_bc_amr.jl" begin @@ -102,15 +181,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.020291447969983396, 0.017479614254319948, 0.011387644425613437, 0.0514420126021293], linf = [0.3582779022370579, 0.32073537890751663, 0.221818049107692, 0.9209559420400415], tspan = (0.0, 0.15)) - - # 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 + # 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_forward_step_amr.jl" begin @@ -120,6 +198,16 @@ isdir(outdir) && rm(outdir, recursive=true) tspan = (0.0, 0.0001), rtol = 1.0e-7, skip_coverage=true) + if @isdefined sol # Skipped in coverage run + # 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 @trixi_testset "elixir_euler_double_mach_amr.jl" begin @@ -128,6 +216,16 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [6.902000373057003, 53.95714139820832, 24.241610279839758, 561.0630401858057], tspan = (0.0, 0.0001), skip_coverage=true) + if @isdefined sol # Skipped in coverage run + # 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 @trixi_testset "elixir_euler_supersonic_cylinder.jl" begin @@ -136,6 +234,16 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [3.653905721692421, 4.285035711361009, 6.8544353186357645, 31.748244912257533], tspan = (0.0, 0.001), skip_coverage=true) + if @isdefined sol # Skipped in coverage run + # 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 @trixi_testset "elixir_eulergravity_convergence.jl" begin @@ -143,6 +251,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.00024871265138964204, 0.0003370077102132591, 0.0003370077102131964, 0.0007231525513793697], linf = [0.0015813032944647087, 0.0020494288423820173, 0.0020494288423824614, 0.004793821195083758], tspan = (0.0, 0.1)) + # 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_source_terms.jl" begin @@ -150,6 +266,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [9.168126407325352e-5, 0.0009795410115453788, 0.002546408320320785, 3.941189812642317e-6], linf = [0.0009903782521019089, 0.0059752684687262025, 0.010941106525454103, 1.2129488214718265e-5], tspan = (0.0, 0.1)) + # 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_mhd_alfven_wave.jl" begin @@ -160,6 +284,14 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [4.255466285174592e-5, 1.0029706745823264e-5, 1.0029706747467781e-5, 1.2122265939010224e-5, 5.4791097160444835e-6, 5.18922042269665e-6, 5.189220422141538e-6, 9.552667261422676e-6, 1.4237578427628152e-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 end @trixi_testset "elixir_mhd_rotor.jl" begin @@ -171,12 +303,28 @@ isdir(outdir) && rm(outdir, recursive=true) 19.647239392277378, 1.3938810140985936, 1.8724965294853084, 0.0, 0.0016290067532561904], tspan = (0.0, 0.02)) + # 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_linearizedeuler_gaussian_source.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_linearizedeuler_gaussian_source.jl"), l2 = [0.006047938590548741, 0.0040953286019907035, 0.004222698522497298, 0.006269492499336128], linf = [0.06386175207349379, 0.0378926444850457, 0.041759728067967065, 0.06430136016259067]) + # 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 diff --git a/test/test_paper_self_gravitating_gas_dynamics.jl b/test/test_paper_self_gravitating_gas_dynamics.jl index 6a35543fe47..68aa2992601 100644 --- a/test/test_paper_self_gravitating_gas_dynamics.jl +++ b/test/test_paper_self_gravitating_gas_dynamics.jl @@ -17,6 +17,14 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "paper_self_gravitating_gas_dynam @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), l2 = [0.0001740977055972079, 0.0003369355182519592, 0.0003369355182518708, 0.0006099171220334989], linf = [0.001079347149189669, 0.0018836938381321389, 0.001883693838132583, 0.003971575376718217]) + # 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_convergence.jl with polydeg=4" begin @@ -24,6 +32,14 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "paper_self_gravitating_gas_dynam l2 = [1.7187201161597772e-5, 2.678065111772951e-5, 2.678065111783027e-5, 4.952504160091526e-5], linf = [0.0001501749544159381, 0.00016549482504535362, 0.00016549482504601976, 0.0004372960291432193], polydeg = 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 @@ -31,6 +47,14 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "paper_self_gravitating_gas_dynam @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_convergence.jl"), l2 = [0.003154024896093942, 0.012394432074951856, 0.02185973823794725], linf = [0.01731850928579215, 0.07843510773347553, 0.11242300176349201]) + # 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_hypdiff_convergence.jl with polydeg=4" begin @@ -38,6 +62,14 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "paper_self_gravitating_gas_dynam l2 = [0.0002511283012128458, 0.0008808243846610255, 0.0016313343228567005], linf = [0.0017290715087938668, 0.003129184465704738, 0.01000728849316701], polydeg = 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 @@ -46,6 +78,14 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "paper_self_gravitating_gas_dynam l2 = [0.00024871265138964204, 0.0003370077102132591, 0.0003370077102131964, 0.0007231525513793697], linf = [0.0015813032944647087, 0.0020494288423820173, 0.0020494288423824614, 0.004793821195083758], tspan = (0.0, 0.1)) + # 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_eulergravity_convergence.jl with polydeg=4" begin @@ -53,6 +93,14 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "paper_self_gravitating_gas_dynam l2 = [1.9537712148648045e-5, 2.7564396197947587e-5, 2.7564396197967635e-5, 5.688838772067586e-5], linf = [0.00012335710672761735, 0.00020086268350816283, 0.00020086268350727465, 0.0004962155455632278], tspan = (0.0, 0.1), polydeg = 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 @trixi_testset "elixir_eulergravity_convergence.jl with 1st order RK3S*" begin @@ -60,6 +108,14 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "paper_self_gravitating_gas_dynam l2 = [0.00024871265138959434, 0.000337007710281087, 0.0003370077102811394, 0.0007231525515231289], linf = [0.0015813032941613958, 0.002049428843978518, 0.0020494288439798503, 0.004793821198143977], tspan = (0.0, 0.1), timestep_gravity=Trixi.timestep_gravity_erk51_3Sstar!) + # 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_eulergravity_convergence.jl with 3rd order RK3S*" begin @@ -67,6 +123,14 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "paper_self_gravitating_gas_dynam l2 = [0.0002487126513894034, 0.00033700771023049785, 0.00033700771023048245, 0.0007231525514158737], linf = [0.0015813032943847727, 0.002049428842844314, 0.0020494288428452023, 0.004793821195971937], tspan = (0.0, 0.1), timestep_gravity=Trixi.timestep_gravity_erk53_3Sstar!) + # 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 @@ -77,6 +141,14 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "paper_self_gravitating_gas_dynam tspan = (0.0, 0.1), atol = 4.0e-6 # the background field is reatively large, so this corresponds to our usual atol ) + # 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_eulergravity_jeans_instability.jl with RK3S*" begin @@ -91,6 +163,14 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "paper_self_gravitating_gas_dynam resid_tol=1.0e-4, n_iterations_max=1000, timestep_gravity=timestep_gravity_erk52_3Sstar!)) + # 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 "Printing" begin @@ -108,6 +188,14 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "paper_self_gravitating_gas_dynam show(stdout, semi_euler.boundary_conditions) show(stdout, TrivialCallback()) show(stdout, equations_euler) + # 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 @@ -117,6 +205,14 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "paper_self_gravitating_gas_dynam linf = [2.3874843337593776, 4.07876384374792, 4.07876384374792, 16.23914384809855], tspan = (0.0, 0.05), coverage_override = (maxiters=2,)) + # 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_eulergravity_sedov_blast_wave.jl with ref-level=8 and no AMR" begin @@ -124,6 +220,14 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "paper_self_gravitating_gas_dynam l2 = [0.00289222135995042, 0.013724813590853825, 0.013724813590853832, 0.05822904710548214], linf = [0.26361780693997594, 1.3908873830688688, 1.3908873830688688, 4.066701303607613], tspan = (0.0, 0.005), initial_refinement_level=8, amr_callback=TrivialCallback()) + # 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 diff --git a/test/test_structured_2d.jl b/test/test_structured_2d.jl index 6d528abc7af..c3192f52b2c 100644 --- a/test/test_structured_2d.jl +++ b/test/test_structured_2d.jl @@ -19,6 +19,15 @@ isdir(outdir) && rm(outdir, recursive=true) # Expected errors are exactly the same as with TreeMesh! l2 = [8.311947673061856e-6], linf = [6.627000273229378e-5]) + # 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 @trixi_testset "elixir_advection_coupled.jl" begin @@ -31,6 +40,14 @@ isdir(outdir) && rm(outdir, recursive=true) errors = analysis_callback(sol) @test errors.l2 ≈ [7.816742843181738e-6, 7.816742843196112e-6] rtol=1.0e-4 @test errors.linf ≈ [6.314906965543265e-5, 6.314906965410039e-5] rtol=1.0e-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 @@ -38,6 +55,14 @@ isdir(outdir) && rm(outdir, recursive=true) @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), l2 = [4.220397559713772e-6], linf = [3.477948874874848e-5]) + # 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_extended.jl with polydeg=4" begin @@ -48,6 +73,14 @@ isdir(outdir) && rm(outdir, recursive=true) cells_per_dimension = (16, 23), polydeg = 4, cfl = 1.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 @testset "elixir_advection_rotated.jl" begin @@ -57,6 +90,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [8.311947673061856e-6], linf = [6.627000273229378e-5], alpha = 0.0) + # 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_rotated.jl with α = 0.1" begin @@ -65,6 +106,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [8.3122750550501e-6], linf = [6.626802581322089e-5], alpha = 0.1) + # 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_rotated.jl with α = 0.5 * pi" begin @@ -73,6 +122,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [8.311947673061856e-6], linf = [6.627000273229378e-5], alpha = 0.5 * pi) + # 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 @@ -81,30 +138,70 @@ isdir(outdir) && rm(outdir, recursive=true) # Expected errors are exactly the same as in elixir_advection_basic! l2 = [8.311947673061856e-6], linf = [6.627000273229378e-5]) + # 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_waving_flag.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_waving_flag.jl"), l2 = [0.00018553859900545866], linf = [0.0016167719118129753]) + # 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_free_stream.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_free_stream.jl"), l2 = [6.8925194184204476e-15], linf = [9.903189379656396e-14]) + # 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_nonperiodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_nonperiodic.jl"), l2 = [0.00025552740731641223], linf = [0.007252625722805939]) + # 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_restart.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), l2 = [4.219208035582454e-6], linf = [3.438434404412494e-5]) + # 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_restart.jl with waving flag mesh" begin @@ -114,6 +211,14 @@ isdir(outdir) && rm(outdir, recursive=true) rtol = 5.0e-5, # Higher tolerance to make tests pass in CI (in particular with macOS) elixir_file="elixir_advection_waving_flag.jl", restart_file="restart_000021.h5") + # 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_restart.jl with free stream mesh" begin @@ -122,6 +227,14 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [1.0857981180834031e-13], elixir_file="elixir_advection_free_stream.jl", restart_file="restart_000036.h5") + # 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_source_terms.jl" begin @@ -129,6 +242,14 @@ isdir(outdir) && rm(outdir, recursive=true) # Expected errors are exactly the same as with TreeMesh! l2 = [9.321181253186009e-7, 1.4181210743438511e-6, 1.4181210743487851e-6, 4.824553091276693e-6], linf = [9.577246529612893e-6, 1.1707525976012434e-5, 1.1707525976456523e-5, 4.8869615580926506e-5]) + # 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 @testset "elixir_euler_source_terms_rotated.jl" begin @@ -138,7 +259,15 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [9.321181253186009e-7, 1.4181210743438511e-6, 1.4181210743487851e-6, 4.824553091276693e-6], linf = [9.577246529612893e-6, 1.1707525976012434e-5, 1.1707525976456523e-5, 4.8869615580926506e-5], alpha = 0.0) - end + # 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_source_terms_rotated.jl with α = 0.1" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_rotated.jl"), @@ -146,7 +275,15 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [9.321188057029291e-7, 1.3195106906473365e-6, 1.510307360354032e-6, 4.82455408101712e-6], linf = [9.57723626271445e-6, 1.0480225511866337e-5, 1.2817828088262928e-5, 4.886962393513272e-5], alpha = 0.1) - end + # 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_source_terms_rotated.jl with α = 0.2 * pi" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_rotated.jl"), @@ -154,7 +291,15 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [9.32127973957391e-7, 8.477824799744325e-7, 1.8175286311402784e-6, 4.824562453521076e-6], linf = [9.576898420737834e-6, 5.057704352218195e-6, 1.635260719945464e-5, 4.886978754825577e-5], alpha = 0.2 * pi) - end + # 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_source_terms_rotated.jl with α = 0.5 * pi" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_rotated.jl"), @@ -162,19 +307,42 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [9.321181253186009e-7, 1.4181210743438511e-6, 1.4181210743487851e-6, 4.824553091276693e-6], linf = [9.577246529612893e-6, 1.1707525976012434e-5, 1.1707525976456523e-5, 4.8869615580926506e-5], alpha = 0.5 * pi) - end + # 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_source_terms_parallelogram.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_parallelogram.jl"), l2 = [1.1167802955144833e-5, 1.0805775514153104e-5, 1.953188337010932e-5, 5.5033856574857146e-5], linf = [8.297006495561199e-5, 8.663281475951301e-5, 0.00012264160606778596, 0.00041818802502024965]) + # 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_source_terms_waving_flag.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_waving_flag.jl"), l2 = [2.991891317562739e-5, 3.6063177168283174e-5, 2.7082941743640572e-5, 0.00011414695350996946], linf = [0.0002437454930492855, 0.0003438936171968887, 0.00024217622945688078, 0.001266380414757684]) + # 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.jl" begin @@ -182,6 +350,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [2.063350241405049e-15, 1.8571016296925367e-14, 3.1769447886391905e-14, 1.4104095258528071e-14], linf = [1.9539925233402755e-14, 2.9791447087035294e-13, 6.502853810985698e-13, 2.7000623958883807e-13], atol = 7.0e-13) + # 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.jl with FluxRotated(flux_lax_friedrichs)" begin @@ -190,12 +366,28 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [2.063350241405049e-15, 1.8571016296925367e-14, 3.1769447886391905e-14, 1.4104095258528071e-14], linf = [1.9539925233402755e-14, 2.9791447087035294e-13, 6.502853810985698e-13, 2.7000623958883807e-13], atol = 7.0e-13) + # 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_source_terms_nonperiodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonperiodic.jl"), l2 = [2.259440511901724e-6, 2.3188881559075347e-6, 2.3188881559568146e-6, 6.332786324137878e-6], linf = [1.4987382622067003e-5, 1.918201192063762e-5, 1.918201192019353e-5, 6.052671713430158e-5]) + # 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_ec.jl" begin @@ -203,6 +395,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.03774907669925568, 0.02845190575242045, 0.028262802829412605, 0.13785915638851698], linf = [0.3368296929764073, 0.27644083771519773, 0.27990039685141377, 1.1971436487402016], tspan = (0.0, 0.3)) + # 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 @@ -210,6 +410,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [3.69856202e-01, 2.35242180e-01, 2.41444928e-01, 1.28807120e+00], linf = [1.82786223e+00, 1.30452904e+00, 1.40347257e+00, 6.21791658e+00], tspan = (0.0, 0.3)) + # 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_rayleigh_taylor_instability.jl" begin @@ -218,30 +426,70 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [0.4799214336153155, 0.024595483032220266, 0.02059808120543466, 0.03190756362943725], cells_per_dimension = (8,8), tspan = (0.0, 0.3)) + # 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_eulerpolytropic_convergence.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulerpolytropic_convergence.jl"), l2 = [0.0016688820596537988, 0.0025921681885685425, 0.003280950351435014], linf = [0.010994679664394269, 0.01331197845637, 0.020080117011346488]) + # 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_eulerpolytropic_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulerpolytropic_ec.jl"), l2 = [0.03647890611450939, 0.025284915444045052, 0.025340697771609126], linf = [0.32516731565355583, 0.37509762516540046, 0.29812843284727336]) + # 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_eulerpolytropic_isothermal_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulerpolytropic_isothermal_wave.jl"), l2 = [0.004998778491726366, 0.004998916000294425, 9.259136963058664e-17], linf = [0.010001103673834888, 0.010051165098399503, 7.623942913643681e-16]) + # 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_eulerpolytropic_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulerpolytropic_wave.jl"), l2 = [0.23642682112204072, 0.20904264390331334, 8.174982691297391e-17], linf = [0.4848250368349989, 0.253350873815695, 4.984552457753618e-16]) + # 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_hypdiff_nonperiodic.jl" begin @@ -250,6 +498,14 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [1.0771947577311836, 1.9143913544309838, 2.149549109115789], tspan = (0.0, 0.1), coverage_override = (polydeg=3,)) # Prevent long compile time in CI + # 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)) < 15000 + end end @trixi_testset "elixir_hypdiff_harmonic_nonperiodic.jl" begin @@ -258,6 +514,14 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [0.35026352556630114, 0.8344372248051408, 0.8344372248051408], tspan = (0.0, 0.1), coverage_override = (polydeg=3,)) # Prevent long compile time in CI + # 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_mhd_ec.jl" begin @@ -269,6 +533,14 @@ isdir(outdir) && rm(outdir, recursive=true) 0.9757376320946505, 0.12123736788315098, 0.12837436699267113, 0.17793825293524734, 0.03460761690059514], tspan = (0.0, 0.3)) + # 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_mhd_alfven_wave.jl" begin @@ -280,6 +552,14 @@ isdir(outdir) && rm(outdir, recursive=true) 0.03817506476831778, 0.042847170999492534, 0.03761563456810613, 0.048184237474911844, 0.04114666955364693], tspan = (0.0, 1.0)) + # 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_source_terms.jl" begin @@ -287,6 +567,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.0017285599436729316, 0.025584610912606776, 0.028373834961180594, 6.274146767730866e-5], linf = [0.012972309788264802, 0.108283714215621, 0.15831585777928936, 0.00018196759554722775], tspan = (0.0, 0.05)) + # 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 @@ -294,6 +582,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.7920927046419308, 9.92129670988898e-15, 1.0118635033124588e-14, 0.7920927046419308], linf = [2.408429868800133, 5.5835419986809516e-14, 5.448874313931364e-14, 2.4084298688001335], tspan = (0.0, 0.25)) + # 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_wet_dry.jl" begin @@ -301,6 +597,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.019731646454942086, 1.0694532773278277e-14, 1.1969913383405568e-14, 0.0771517260037954], linf = [0.4999999999998892, 6.067153702623552e-14, 4.4849667259339357e-14, 1.9999999999999993], tspan = (0.0, 0.25)) + # 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_conical_island.jl" begin @@ -308,6 +612,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.04593154164306353, 0.1644534881916908, 0.16445348819169076, 0.0011537702354532122], linf = [0.21100717610846442, 0.9501592344310412, 0.950159234431041, 0.021790250683516296], tspan = (0.0, 0.025)) + # 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_parabolic_bowl.jl" begin @@ -315,6 +627,14 @@ isdir(outdir) && rm(outdir, recursive=true) l2 = [0.00015285369980313484, 1.9536806395943226e-5, 9.936906607758672e-5, 5.0686313334616055e-15], linf = [0.003316119030459211, 0.0005075409427972817, 0.001986721761060583, 4.701794509287538e-14], tspan = (0.0, 0.025), cells_per_dimension = (40, 40)) + # 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_mhd_ec_shockcapturing.jl" begin @@ -325,6 +645,14 @@ isdir(outdir) && rm(outdir, recursive=true) linf = [0.25144373906033013, 0.32881947152723745, 0.3053266801502693, 0.20989755319972866, 0.9927517314507455, 0.1105172121361323, 0.1257708104676617, 0.1628334844841588, 0.02624301627479052]) + # 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 diff --git a/test/test_tree_1d_hypdiff.jl b/test/test_tree_1d_hypdiff.jl index 560f77b2a13..19200b26892 100644 --- a/test/test_tree_1d_hypdiff.jl +++ b/test/test_tree_1d_hypdiff.jl @@ -14,6 +14,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [1.3655114954641076e-7, 1.0200345025539218e-6], linf = [7.173286515893551e-7, 4.507116363683394e-6], atol = 2.5e-13) + # 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_hypdiff_harmonic_nonperiodic.jl" begin @@ -21,6 +29,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") l2 = [3.0130941075207524e-12, 2.6240829677090014e-12], linf = [4.054534485931072e-12, 3.8826719617190975e-12], atol = 2.5e-13) + # 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)) < 10000 + end end end diff --git a/test/test_tree_2d_advection.jl b/test/test_tree_2d_advection.jl index 36cb1e882cc..365011eef53 100644 --- a/test/test_tree_2d_advection.jl +++ b/test/test_tree_2d_advection.jl @@ -15,6 +15,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") linf = [6.627000273229378e-5], # Let the small basic test run to the end coverage_override = (maxiters=10^5,)) + # 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_extended.jl with polydeg=1" begin @@ -22,6 +30,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [0.02134571266411136], linf = [0.04347734797775926], polydeg=1) + # 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_restart.jl" begin @@ -49,14 +65,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [0.0015188466707237375], linf = [0.008446655719187679]) - # 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 + # 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_amr.jl" begin @@ -66,6 +82,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") linf = [0.00045263895394385967], # Let this test run to the end to cover some AMR code coverage_override = (maxiters=10^5,)) + # 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_amr_nonperiodic.jl" begin @@ -74,6 +98,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [3.2207388565869075e-5], linf = [0.0007508059772436404], 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 end @trixi_testset "elixir_advection_amr_solution_independent.jl" begin @@ -81,6 +113,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [4.949660644033807e-5], linf = [0.0004867846262313763], 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 end @trixi_testset "elixir_advection_amr_visualization.jl" begin @@ -114,6 +154,15 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") # Let this test terminate by time instead of maxiters to cover some lines # in time_integration/methods_2N.jl coverage_override = (maxiters=10^5, tspan=(0.0, 0.1))) + # 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)) < 15000 + end + end end @trixi_testset "elixir_advection_timeintegration.jl with carpenter_kennedy_erk43" begin @@ -122,6 +171,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") linf = [0.0005437136621948904], ode_algorithm=Trixi.CarpenterKennedy2N43(), cfl = 1.0) + # 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)) < 15000 + end end @trixi_testset "elixir_advection_timeintegration.jl with carpenter_kennedy_erk43 with maxiters=1" begin @@ -131,6 +188,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") ode_algorithm=Trixi.CarpenterKennedy2N43(), cfl = 1.0, maxiters = 1) + # 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)) < 15000 + end end @trixi_testset "elixir_advection_timeintegration.jl with parsani_ketcheson_deconinck_erk94" begin @@ -138,6 +203,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [2.4976673477385313e-5], linf = [0.0005534166916640881], ode_algorithm=Trixi.ParsaniKetchesonDeconinck3Sstar94()) + # 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)) < 15000 + end end @trixi_testset "elixir_advection_timeintegration.jl with parsani_ketcheson_deconinck_erk32" begin @@ -146,6 +219,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") linf = [0.0005799465470165757], ode_algorithm=Trixi.ParsaniKetchesonDeconinck3Sstar32(), cfl = 1.0) + # 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)) < 15000 + end end @trixi_testset "elixir_advection_timeintegration.jl with parsani_ketcheson_deconinck_erk32 with maxiters=1" begin @@ -155,14 +236,29 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") ode_algorithm=Trixi.ParsaniKetchesonDeconinck3Sstar32(), cfl = 1.0, maxiters = 1) + # 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)) < 15000 + end end @trixi_testset "elixir_advection_callbacks.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_callbacks.jl"), l2 = [8.311947673061856e-6], linf = [6.627000273229378e-5]) + # 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 # Coverage test for all initial conditions @testset "Linear scalar advection: Tests for initial conditions" begin @@ -173,6 +269,14 @@ end linf = [0.0007140570281718439], maxiters = 1, initial_condition = Trixi.initial_condition_sin_sin) + # 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_extended.jl with initial_condition_constant" begin @@ -181,6 +285,14 @@ end linf = [1.3322676295501878e-15], maxiters = 1, initial_condition = initial_condition_constant) + # 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_extended.jl with initial_condition_linear_x_y" begin @@ -191,6 +303,14 @@ end initial_condition = Trixi.initial_condition_linear_x_y, boundary_conditions = Trixi.boundary_condition_linear_x_y, periodicity=false) + # 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_extended.jl with initial_condition_linear_x" begin @@ -201,6 +321,14 @@ end initial_condition = Trixi.initial_condition_linear_x, boundary_conditions = Trixi.boundary_condition_linear_x, periodicity=false) + # 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_extended.jl with initial_condition_linear_y" begin @@ -211,6 +339,14 @@ end initial_condition = Trixi.initial_condition_linear_y, boundary_conditions = Trixi.boundary_condition_linear_y, periodicity=false) + # 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 diff --git a/test/test_tree_2d_hypdiff.jl b/test/test_tree_2d_hypdiff.jl index eb8f8b297b6..30481fe910a 100644 --- a/test/test_tree_2d_hypdiff.jl +++ b/test/test_tree_2d_hypdiff.jl @@ -12,18 +12,42 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_lax_friedrichs.jl"), l2 = [0.00015687751817403066, 0.001025986772216324, 0.0010259867722164071], linf = [0.001198695637957381, 0.006423873515531753, 0.006423873515533529]) + # 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)) < 15000 + end end @trixi_testset "elixir_hypdiff_harmonic_nonperiodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_harmonic_nonperiodic.jl"), l2 = [8.618132355121019e-8, 5.619399844384306e-7, 5.619399844844044e-7], linf = [1.1248618588430072e-6, 8.622436487026874e-6, 8.622436487915053e-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 end @trixi_testset "elixir_hypdiff_nonperiodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_nonperiodic.jl"), l2 = [8.523077653954864e-6, 2.8779323653020624e-5, 5.454942769125663e-5], linf = [5.522740952468297e-5, 0.00014544895978971679, 0.00032396328684924924]) + # 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_hypdiff_godunov.jl" begin @@ -31,6 +55,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") l2 = [5.868147556427088e-6, 3.80517927324465e-5, 3.805179273249344e-5], linf = [3.701965498725812e-5, 0.0002122422943138247, 0.00021224229431116015], atol = 2.0e-12 #= required for CI on macOS =#) + # 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 diff --git a/test/test_tree_2d_kpp.jl b/test/test_tree_2d_kpp.jl index 16d240d4a9f..fb2a212ddf8 100644 --- a/test/test_tree_2d_kpp.jl +++ b/test/test_tree_2d_kpp.jl @@ -17,17 +17,16 @@ EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") atol = 1e-6, rtol = 1e-6, skip_coverage = true) - - #= Does fail in coverage run (since it is not executed) - # 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 + if @isdefined sol # Skipped in coverage run + # 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 end diff --git a/test/test_tree_3d_hypdiff.jl b/test/test_tree_3d_hypdiff.jl index 3db0ce93186..42231a9aaf6 100644 --- a/test/test_tree_3d_hypdiff.jl +++ b/test/test_tree_3d_hypdiff.jl @@ -13,6 +13,14 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") l2 = [0.001530331609036682, 0.011314177033289238, 0.011314177033289402, 0.011314177033289631], linf = [0.02263459033909354, 0.10139777904683545, 0.10139777904683545, 0.10139777904683545], initial_refinement_level=2) + # 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)) < 15000 + end end @trixi_testset "elixir_hypdiff_lax_friedrichs.jl with surface_flux=flux_godunov)" begin @@ -20,12 +28,28 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") l2 = [0.0015377731806850128, 0.01137685274151801, 0.011376852741518175, 0.011376852741518494], linf = [0.022715420630041172, 0.10183745338964201, 0.10183745338964201, 0.1018374533896429], initial_refinement_level=2, surface_flux=flux_godunov) + # 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)) < 15000 + end end @trixi_testset "elixir_hypdiff_nonperiodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_nonperiodic.jl"), l2 = [0.00022868320512754316, 0.0007974309948540525, 0.0015035143230654987, 0.0015035143230655293], linf = [0.0016405001653623241, 0.0029870057159104594, 0.009410031618285686, 0.009410031618287462]) + # 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)) < 15000 + end end end From 4d221416e96f41b4656cb22dbccb7b4460076c5b Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Wed, 25 Oct 2023 11:20:14 +0200 Subject: [PATCH 141/263] AMR for parabolic terms in 2D & 3D on TreeMeshes (#1629) * Clean branch * Un-Comment * un-comment * test coarsen * remove redundancy * Remove support for passive terms * expand resize * comments * format * Avoid code duplication * Update src/callbacks_step/amr_dg1d.jl Co-authored-by: Michael Schlottke-Lakemper * comment * comment & format * Try to increase coverage * Slightly more expressive names * Apply suggestions from code review * add specifier for 1d * Structs for resizing parabolic helpers * check if mortars are present * reuse `reinitialize_containers!` * resize calls for parabolic helpers * update analysis callbacks * Velocities for compr euler * Init container * correct copy-paste error * resize each dim * add dispatch * Add AMR for shear layer * USe only amr shear layer * first steps towards p4est parabolic amr * Add tests * remove plots * Format * remove redundant line * platform independent tests * No need for different flux_viscous comps after adding container_viscous to p4est * Laplace 3d * Longer times to allow converage to hit coarsen! * Increase testing of Laplace 3D * Add tests for velocities * remove comment * Add comments * Remove some specializations * Add comments * Use tuple for outer, fixed size datastruct for internal quantities * Format * Add comments * Update examples/tree_2d_dgsem/elixir_navierstokes_shearlayer_amr.jl Co-authored-by: Michael Schlottke-Lakemper * Update src/Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Move velocity into elixir * remove tests * Remove deprecated comments * Add news --------- Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> --- NEWS.md | 1 + ... => elixir_navierstokes_shearlayer_amr.jl} | 50 +++++++--- .../elixir_advection_diffusion_amr.jl | 93 +++++++++++++++++++ .../elixir_advection_diffusion_nonperiodic.jl | 91 ++++++++++++++++++ src/Trixi.jl | 2 +- src/callbacks_step/amr_dg1d.jl | 43 ++------- src/callbacks_step/amr_dg2d.jl | 46 +++++++++ src/callbacks_step/analysis_dg2d.jl | 2 +- src/callbacks_step/analysis_dg3d.jl | 2 +- src/equations/equations_parabolic.jl | 1 + src/equations/laplace_diffusion_2d.jl | 1 - src/equations/laplace_diffusion_3d.jl | 71 ++++++++++++++ src/solvers/dgsem_p4est/dg_2d_parabolic.jl | 14 ++- src/solvers/dgsem_p4est/dg_3d_parabolic.jl | 14 ++- .../dgsem_tree/container_viscous_1d.jl | 6 +- .../dgsem_tree/container_viscous_2d.jl | 69 ++++++++++++++ .../dgsem_tree/container_viscous_3d.jl | 75 +++++++++++++++ src/solvers/dgsem_tree/containers.jl | 8 +- src/solvers/dgsem_tree/containers_viscous.jl | 4 + src/solvers/dgsem_tree/dg.jl | 4 +- src/solvers/dgsem_tree/dg_1d_parabolic.jl | 8 +- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 28 +++--- src/solvers/dgsem_tree/dg_3d_parabolic.jl | 29 +++--- test/test_parabolic_2d.jl | 8 ++ test/test_parabolic_3d.jl | 14 +++ 25 files changed, 577 insertions(+), 107 deletions(-) rename examples/tree_2d_dgsem/{elixir_navierstokes_shear_layer.jl => elixir_navierstokes_shearlayer_amr.jl} (53%) create mode 100644 examples/tree_3d_dgsem/elixir_advection_diffusion_amr.jl create mode 100644 examples/tree_3d_dgsem/elixir_advection_diffusion_nonperiodic.jl create mode 100644 src/equations/laplace_diffusion_3d.jl create mode 100644 src/solvers/dgsem_tree/container_viscous_2d.jl create mode 100644 src/solvers/dgsem_tree/container_viscous_3d.jl create mode 100644 src/solvers/dgsem_tree/containers_viscous.jl diff --git a/NEWS.md b/NEWS.md index 0c78484a782..bc213fcea55 100644 --- a/NEWS.md +++ b/NEWS.md @@ -14,6 +14,7 @@ for human readability. - Wetting and drying feature and examples for 1D and 2D shallow water equations - Implementation of the polytropic Euler equations in 2D - Subcell positivity limiting support for conservative variables in 2D for `TreeMesh` +- AMR for hyperbolic-parabolic equations on 2D/3D `TreeMesh` #### Changed diff --git a/examples/tree_2d_dgsem/elixir_navierstokes_shear_layer.jl b/examples/tree_2d_dgsem/elixir_navierstokes_shearlayer_amr.jl similarity index 53% rename from examples/tree_2d_dgsem/elixir_navierstokes_shear_layer.jl rename to examples/tree_2d_dgsem/elixir_navierstokes_shearlayer_amr.jl index dd26fd8097b..06e8f06d3ca 100644 --- a/examples/tree_2d_dgsem/elixir_navierstokes_shear_layer.jl +++ b/examples/tree_2d_dgsem/elixir_navierstokes_shearlayer_amr.jl @@ -7,12 +7,20 @@ using Trixi # TODO: parabolic; unify names of these accessor functions prandtl_number() = 0.72 -mu() = 1.0/3.0 * 10^(-3) # equivalent to Re = 3000 +mu() = 1.0/3.0 * 10^(-5) # equivalent to Re = 30,000 equations = CompressibleEulerEquations2D(1.4) equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu=mu(), Prandtl=prandtl_number()) +""" +A compressible version of the double shear layer initial condition. Adapted from +Brown and Minion (1995). + +- David L. Brown and Michael L. Minion (1995) + Performance of Under-resolved Two-Dimensional Incompressible Flow Simulations. + [DOI: 10.1006/jcph.1995.1205](https://doi.org/10.1006/jcph.1995.1205) +""" function initial_condition_shear_layer(x, t, equations::CompressibleEulerEquations2D) # Shear layer parameters k = 80 @@ -22,8 +30,8 @@ function initial_condition_shear_layer(x, t, equations::CompressibleEulerEquatio Ms = 0.1 # maximum Mach number rho = 1.0 - v1 = x[2] <= 0.5 ? u0 * tanh(k*(x[2]*0.5 - 0.25)) : u0 * tanh(k*(0.75 -x[2]*0.5)) - v2 = u0 * delta * sin(2*pi*(x[1]*0.5 + 0.25)) + v1 = x[2] <= 0.5 ? u0 * tanh(k*(x[2] - 0.25)) : u0 * tanh(k*(0.75 -x[2])) + v2 = u0 * delta * sin(2*pi*(x[1]+ 0.25)) p = (u0 / Ms)^2 * rho / equations.gamma # scaling to get Ms return prim2cons(SVector(rho, v1, v2, p), equations) @@ -47,27 +55,43 @@ semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabol ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 2.0) +tspan = (0.0, 1.0) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -analysis_interval = 50 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=true, - extra_analysis_integrals=(energy_kinetic, - energy_internal, - enstrophy)) +analysis_interval = 2000 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) alive_callback = AliveCallback(analysis_interval=analysis_interval,) +# This uses velocity-based AMR +@inline function v1(u, equations::CompressibleEulerEquations2D) + rho, rho_v1, _, _ = u + return rho_v1 / rho +end +amr_indicator = IndicatorLöhner(semi, variable=v1) +amr_controller = ControllerThreeLevel(semi, amr_indicator, + base_level = 3, + med_level = 5, med_threshold=0.2, + max_level = 7, max_threshold=0.5) +amr_callback = AMRCallback(semi, amr_controller, + interval=50, + adapt_initial_condition=true, + adapt_initial_condition_only_refine=true) + +stepsize_callback = StepsizeCallback(cfl=1.3) + callbacks = CallbackSet(summary_callback, analysis_callback, - alive_callback) + alive_callback, + amr_callback, + stepsize_callback) ############################################################################### # run the simulation -time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) +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 \ No newline at end of file diff --git a/examples/tree_3d_dgsem/elixir_advection_diffusion_amr.jl b/examples/tree_3d_dgsem/elixir_advection_diffusion_amr.jl new file mode 100644 index 00000000000..0fab685b642 --- /dev/null +++ b/examples/tree_3d_dgsem/elixir_advection_diffusion_amr.jl @@ -0,0 +1,93 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear advection equation + +advection_velocity = (0.2, -0.7, 0.5) +equations = LinearScalarAdvectionEquation3D(advection_velocity) + +diffusivity() = 5.0e-4 +equations_parabolic = LaplaceDiffusion3D(diffusivity(), equations) + +solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) + +coordinates_min = (-1.0, -1.0, -1.0) +coordinates_max = ( 1.0, 1.0, 1.0) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + n_cells_max=80_000) + +# Define initial condition +function initial_condition_diffusive_convergence_test(x, t, equation::LinearScalarAdvectionEquation3D) + # Store translated coordinate for easy use of exact solution + x_trans = x - equation.advection_velocity * t + + nu = diffusivity() + c = 1.0 + A = 0.5 + L = 2 + f = 1/L + omega = 2 * pi * f + scalar = c + A * sin(omega * sum(x_trans)) * exp(-2 * nu * omega^2 * t) + return SVector(scalar) +end +initial_condition = initial_condition_diffusive_convergence_test + +# define periodic boundary conditions everywhere +boundary_conditions = boundary_condition_periodic +boundary_conditions_parabolic = boundary_condition_periodic + +# A semidiscretization collects data structures and functions for the spatial discretization +semi = SemidiscretizationHyperbolicParabolic(mesh, + (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions=(boundary_conditions, + boundary_conditions_parabolic)) + + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.2) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval, + extra_analysis_integrals=(entropy,)) + +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +save_solution = SaveSolutionCallback(interval=100, + save_initial_solution=true, + save_final_solution=true, + solution_variables=cons2prim) + +amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable=first), + base_level=3, + med_level=4, med_threshold=1.2, + max_level=5, max_threshold=1.45) +amr_callback = AMRCallback(semi, amr_controller, + interval=5, + adapt_initial_condition=true, + adapt_initial_condition_only_refine=true) + +stepsize_callback = StepsizeCallback(cfl=1.0) + +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); +summary_callback() # print the timer summary \ No newline at end of file diff --git a/examples/tree_3d_dgsem/elixir_advection_diffusion_nonperiodic.jl b/examples/tree_3d_dgsem/elixir_advection_diffusion_nonperiodic.jl new file mode 100644 index 00000000000..5dc6e6338a7 --- /dev/null +++ b/examples/tree_3d_dgsem/elixir_advection_diffusion_nonperiodic.jl @@ -0,0 +1,91 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear advection-diffusion equation + +diffusivity() = 5.0e-2 +advection_velocity = (1.0, 0.0, 0.0) +equations = LinearScalarAdvectionEquation3D(advection_velocity) +equations_parabolic = LaplaceDiffusion3D(diffusivity(), equations) + +# 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) + +coordinates_min = (-1.0, -0.5, -0.25) # minimum coordinates (min(x), min(y), min(z)) +coordinates_max = ( 0.0, 0.5, 0.25) # maximum coordinates (max(x), max(y), max(z)) + +# Create a uniformly refined mesh with periodic boundaries +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=3, + periodicity=false, + n_cells_max=30_000) # set maximum capacity of tree data structure + +# Example setup taken from +# - Truman Ellis, Jesse Chan, and Leszek Demkowicz (2016). +# Robust DPG methods for transient convection-diffusion. +# In: Building bridges: connections and challenges in modern approaches +# to numerical partial differential equations. +# [DOI](https://doi.org/10.1007/978-3-319-41640-3_6). +function initial_condition_eriksson_johnson(x, t, equations) + l = 4 + epsilon = diffusivity() # TODO: this requires epsilon < .6 due to sqrt + lambda_1 = (-1 + sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + lambda_2 = (-1 - sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + r1 = (1 + sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + s1 = (1 - sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + u = exp(-l * t) * (exp(lambda_1 * x[1]) - exp(lambda_2 * x[1])) + + cos(pi * x[2]) * (exp(s1 * x[1]) - exp(r1 * x[1])) / (exp(-s1) - exp(-r1)) + return SVector{1}(u) +end +initial_condition = initial_condition_eriksson_johnson + +boundary_conditions = (; x_neg = BoundaryConditionDirichlet(initial_condition), + y_neg = BoundaryConditionDirichlet(initial_condition), + z_neg = boundary_condition_do_nothing, + y_pos = BoundaryConditionDirichlet(initial_condition), + x_pos = boundary_condition_do_nothing, + z_pos = boundary_condition_do_nothing) + +boundary_conditions_parabolic = BoundaryConditionDirichlet(initial_condition) + +# A semidiscretization collects data structures and functions for the spatial discretization +semi = SemidiscretizationHyperbolicParabolic(mesh, + (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions=(boundary_conditions, + boundary_conditions_parabolic)) + + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span `tspan` +tspan = (0.0, 0.5) +ode = semidiscretize(semi, tspan); + +# 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_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) + +# The AliveCallback prints short status information in regular intervals +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +# Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) + + +############################################################################### +# run the simulation + +# OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks +time_int_tol = 1.0e-11 +sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, + ode_default_options()..., callback=callbacks) + +# Print the timer summary +summary_callback() diff --git a/src/Trixi.jl b/src/Trixi.jl index 457d9dc336d..5cb3cf0a9fe 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -153,7 +153,7 @@ export AcousticPerturbationEquations2D, LinearizedEulerEquations2D, PolytropicEulerEquations2D -export LaplaceDiffusion1D, LaplaceDiffusion2D, +export LaplaceDiffusion1D, LaplaceDiffusion2D, LaplaceDiffusion3D, CompressibleNavierStokesDiffusion1D, CompressibleNavierStokesDiffusion2D, CompressibleNavierStokesDiffusion3D diff --git a/src/callbacks_step/amr_dg1d.jl b/src/callbacks_step/amr_dg1d.jl index e721ccc61cb..b4cd6a00271 100644 --- a/src/callbacks_step/amr_dg1d.jl +++ b/src/callbacks_step/amr_dg1d.jl @@ -83,30 +83,13 @@ function refine!(u_ode::AbstractVector, adaptor, mesh::TreeMesh{1}, # actually transferring the solution to the refined cells refine!(u_ode, adaptor, mesh, equations, dg, cache, elements_to_refine) - # The remaining function only handles the necessary adaptation of the data structures - # for the parabolic part of the semidiscretization - - # Get new list of leaf cells - leaf_cell_ids = local_leaf_cells(mesh.tree) - - @unpack elements, viscous_container = cache_parabolic - resize!(elements, length(leaf_cell_ids)) - init_elements!(elements, leaf_cell_ids, mesh, dg.basis) - # Resize parabolic helper variables + @unpack viscous_container = cache_parabolic resize!(viscous_container, equations, dg, cache) - - # re-initialize interfaces container - @unpack interfaces = cache_parabolic - resize!(interfaces, count_required_interfaces(mesh, leaf_cell_ids)) - init_interfaces!(interfaces, elements, mesh) - - # re-initialize boundaries container - @unpack boundaries = cache_parabolic - resize!(boundaries, count_required_boundaries(mesh, leaf_cell_ids)) - init_boundaries!(boundaries, elements, mesh) + reinitialize_containers!(mesh, equations, dg, cache_parabolic) # Sanity check + @unpack interfaces = cache_parabolic if isperiodic(mesh.tree) @assert ninterfaces(interfaces)==1 * nelements(dg, cache_parabolic) ("For 1D and periodic domains, the number of interfaces must be the same as the number of elements") end @@ -246,27 +229,13 @@ function coarsen!(u_ode::AbstractVector, adaptor, mesh::TreeMesh{1}, # actually transferring the solution to the coarsened cells coarsen!(u_ode, adaptor, mesh, equations, dg, cache, elements_to_remove) - # Get new list of leaf cells - leaf_cell_ids = local_leaf_cells(mesh.tree) - - @unpack elements, viscous_container = cache_parabolic - resize!(elements, length(leaf_cell_ids)) - init_elements!(elements, leaf_cell_ids, mesh, dg.basis) - # Resize parabolic helper variables + @unpack viscous_container = cache_parabolic resize!(viscous_container, equations, dg, cache) - - # re-initialize interfaces container - @unpack interfaces = cache_parabolic - resize!(interfaces, count_required_interfaces(mesh, leaf_cell_ids)) - init_interfaces!(interfaces, elements, mesh) - - # re-initialize boundaries container - @unpack boundaries = cache_parabolic - resize!(boundaries, count_required_boundaries(mesh, leaf_cell_ids)) - init_boundaries!(boundaries, elements, mesh) + reinitialize_containers!(mesh, equations, dg, cache_parabolic) # Sanity check + @unpack interfaces = cache_parabolic if isperiodic(mesh.tree) @assert ninterfaces(interfaces)==1 * nelements(dg, cache_parabolic) ("For 1D and periodic domains, the number of interfaces must be the same as the number of elements") end diff --git a/src/callbacks_step/amr_dg2d.jl b/src/callbacks_step/amr_dg2d.jl index 1d37dfce034..6395a9f348f 100644 --- a/src/callbacks_step/amr_dg2d.jl +++ b/src/callbacks_step/amr_dg2d.jl @@ -136,6 +136,29 @@ function refine!(u_ode::AbstractVector, adaptor, mesh::Union{TreeMesh{2}, P4estM return nothing end +# AMR for hyperbolic-parabolic equations currently only supported on TreeMeshes +function refine!(u_ode::AbstractVector, adaptor, mesh::Union{TreeMesh{2}, TreeMesh{3}}, + equations, dg::DGSEM, cache, cache_parabolic, + elements_to_refine) + # Call `refine!` for the hyperbolic part, which does the heavy lifting of + # actually transferring the solution to the refined cells + refine!(u_ode, adaptor, mesh, equations, dg, cache, elements_to_refine) + + # Resize parabolic helper variables + @unpack viscous_container = cache_parabolic + resize!(viscous_container, equations, dg, cache) + reinitialize_containers!(mesh, equations, dg, cache_parabolic) + + # Sanity check + if mesh isa TreeMesh && isperiodic(mesh.tree) && nmortars(cache.mortars) == 0 && + !mpi_isparallel() + @assert ninterfaces(cache_parabolic.interfaces)==ndims(mesh) * + nelements(dg, cache_parabolic) ("For $(ndims(mesh))D and periodic domains and conforming elements, the number of interfaces must be $(ndims(mesh)) times the number of elements") + end + + return nothing +end + # TODO: Taal compare performance of different implementations # Refine solution data u for an element, using L2 projection (interpolation) function refine_element!(u::AbstractArray{<:Any, 4}, element_id, @@ -275,6 +298,29 @@ function coarsen!(u_ode::AbstractVector, adaptor, return nothing end +# AMR for hyperbolic-parabolic equations currently only supported on TreeMeshes +function coarsen!(u_ode::AbstractVector, adaptor, mesh::Union{TreeMesh{2}, TreeMesh{3}}, + equations, dg::DGSEM, cache, cache_parabolic, + elements_to_remove) + # Call `coarsen!` for the hyperbolic part, which does the heavy lifting of + # actually transferring the solution to the coarsened cells + coarsen!(u_ode, adaptor, mesh, equations, dg, cache, elements_to_remove) + + # Resize parabolic helper variables + @unpack viscous_container = cache_parabolic + resize!(viscous_container, equations, dg, cache) + reinitialize_containers!(mesh, equations, dg, cache_parabolic) + + # Sanity check + if mesh isa TreeMesh && isperiodic(mesh.tree) && nmortars(cache.mortars) == 0 && + !mpi_isparallel() + @assert ninterfaces(cache_parabolic.interfaces)==ndims(mesh) * + nelements(dg, cache_parabolic) ("For $(ndims(mesh))D and periodic domains and conforming elements, the number of interfaces must be $(ndims(mesh)) times the number of elements") + end + + return nothing +end + # TODO: Taal compare performance of different implementations # Coarsen solution data u for four elements, using L2 projection function coarsen_elements!(u::AbstractArray{<:Any, 4}, element_id, diff --git a/src/callbacks_step/analysis_dg2d.jl b/src/callbacks_step/analysis_dg2d.jl index aecabf0e4b7..a9e0cf87b0a 100644 --- a/src/callbacks_step/analysis_dg2d.jl +++ b/src/callbacks_step/analysis_dg2d.jl @@ -218,7 +218,7 @@ function integrate(func::Func, u, equations, equations_parabolic, dg::DGSEM, cache, cache_parabolic; normalize = true) where {Func} - gradients_x, gradients_y = cache_parabolic.gradients + gradients_x, gradients_y = cache_parabolic.viscous_container.gradients integrate_via_indices(u, mesh, equations, dg, cache; normalize = normalize) do u, i, j, element, equations, dg u_local = get_node_vars(u, equations, dg, i, j, element) diff --git a/src/callbacks_step/analysis_dg3d.jl b/src/callbacks_step/analysis_dg3d.jl index 3d9b38fd2a5..81d0795a159 100644 --- a/src/callbacks_step/analysis_dg3d.jl +++ b/src/callbacks_step/analysis_dg3d.jl @@ -232,7 +232,7 @@ function integrate(func::Func, u, equations, equations_parabolic, dg::DGSEM, cache, cache_parabolic; normalize = true) where {Func} - gradients_x, gradients_y, gradients_z = cache_parabolic.gradients + gradients_x, gradients_y, gradients_z = cache_parabolic.viscous_container.gradients integrate_via_indices(u, mesh, equations, dg, cache; normalize = normalize) do u, i, j, k, element, equations, dg u_local = get_node_vars(u, equations, dg, i, j, k, element) diff --git a/src/equations/equations_parabolic.jl b/src/equations/equations_parabolic.jl index 66214025044..47a76174cb1 100644 --- a/src/equations/equations_parabolic.jl +++ b/src/equations/equations_parabolic.jl @@ -7,6 +7,7 @@ abstract type AbstractLaplaceDiffusion{NDIMS, NVARS} <: AbstractEquationsParabolic{NDIMS, NVARS} end include("laplace_diffusion_1d.jl") include("laplace_diffusion_2d.jl") +include("laplace_diffusion_3d.jl") # Compressible Navier-Stokes equations abstract type AbstractCompressibleNavierStokesDiffusion{NDIMS, NVARS} <: diff --git a/src/equations/laplace_diffusion_2d.jl b/src/equations/laplace_diffusion_2d.jl index 3443e9c097b..b848633fbcb 100644 --- a/src/equations/laplace_diffusion_2d.jl +++ b/src/equations/laplace_diffusion_2d.jl @@ -18,7 +18,6 @@ function varnames(variable_mapping, equations_parabolic::LaplaceDiffusion2D) varnames(variable_mapping, equations_parabolic.equations_hyperbolic) end -# no orientation specified since the flux is vector-valued function flux(u, gradients, orientation::Integer, equations_parabolic::LaplaceDiffusion2D) dudx, dudy = gradients if orientation == 1 diff --git a/src/equations/laplace_diffusion_3d.jl b/src/equations/laplace_diffusion_3d.jl new file mode 100644 index 00000000000..457e742430b --- /dev/null +++ b/src/equations/laplace_diffusion_3d.jl @@ -0,0 +1,71 @@ +@doc raw""" + LaplaceDiffusion3D(diffusivity, equations) + +`LaplaceDiffusion3D` represents a scalar diffusion term ``\nabla \cdot (\kappa\nabla u))`` +with diffusivity ``\kappa`` applied to each solution component defined by `equations`. +""" +struct LaplaceDiffusion3D{E, N, T} <: AbstractLaplaceDiffusion{3, N} + diffusivity::T + equations_hyperbolic::E +end + +function LaplaceDiffusion3D(diffusivity, equations_hyperbolic) + LaplaceDiffusion3D{typeof(equations_hyperbolic), nvariables(equations_hyperbolic), + typeof(diffusivity)}(diffusivity, equations_hyperbolic) +end + +function varnames(variable_mapping, equations_parabolic::LaplaceDiffusion3D) + varnames(variable_mapping, equations_parabolic.equations_hyperbolic) +end + +function flux(u, gradients, orientation::Integer, equations_parabolic::LaplaceDiffusion3D) + dudx, dudy, dudz = gradients + if orientation == 1 + return SVector(equations_parabolic.diffusivity * dudx) + elseif orientation == 2 + return SVector(equations_parabolic.diffusivity * dudy) + else # if orientation == 3 + return SVector(equations_parabolic.diffusivity * dudz) + end +end + +# TODO: parabolic; should this remain in the equations file, be moved to solvers, or live in the elixir? +# The penalization depends on the solver, but also depends explicitly on physical parameters, +# and would probably need to be specialized for every different equation. +function penalty(u_outer, u_inner, inv_h, equations_parabolic::LaplaceDiffusion3D, + dg::ViscousFormulationLocalDG) + return dg.penalty_parameter * (u_outer - u_inner) * equations_parabolic.diffusivity +end + +# Dirichlet-type boundary condition for use with a parabolic solver in weak form +@inline function (boundary_condition::BoundaryConditionDirichlet)(flux_inner, u_inner, + normal::AbstractVector, + x, t, + operator_type::Gradient, + equations_parabolic::LaplaceDiffusion3D) + return boundary_condition.boundary_value_function(x, t, equations_parabolic) +end + +@inline function (boundary_condition::BoundaryConditionDirichlet)(flux_inner, u_inner, + normal::AbstractVector, + x, t, + operator_type::Divergence, + equations_parabolic::LaplaceDiffusion3D) + return flux_inner +end + +@inline function (boundary_condition::BoundaryConditionNeumann)(flux_inner, u_inner, + normal::AbstractVector, + x, t, + operator_type::Divergence, + equations_parabolic::LaplaceDiffusion3D) + return boundary_condition.boundary_normal_flux_function(x, t, equations_parabolic) +end + +@inline function (boundary_condition::BoundaryConditionNeumann)(flux_inner, u_inner, + normal::AbstractVector, + x, t, + operator_type::Gradient, + equations_parabolic::LaplaceDiffusion3D) + return flux_inner +end diff --git a/src/solvers/dgsem_p4est/dg_2d_parabolic.jl b/src/solvers/dgsem_p4est/dg_2d_parabolic.jl index a04523d2fb4..cf07645b949 100644 --- a/src/solvers/dgsem_p4est/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_p4est/dg_2d_parabolic.jl @@ -10,14 +10,11 @@ function create_cache_parabolic(mesh::P4estMesh{2}, equations_hyperbolic::Abstra interfaces = init_interfaces(mesh, equations_hyperbolic, dg.basis, elements) boundaries = init_boundaries(mesh, equations_hyperbolic, dg.basis, elements) - n_vars = nvariables(equations_hyperbolic) - n_elements = nelements(elements) - n_nodes = nnodes(dg.basis) # nodes in one direction - u_transformed = Array{uEltype}(undef, n_vars, n_nodes, n_nodes, n_elements) - gradients = ntuple(_ -> similar(u_transformed), ndims(mesh)) - flux_viscous = ntuple(_ -> similar(u_transformed), ndims(mesh)) + viscous_container = init_viscous_container_2d(nvariables(equations_hyperbolic), + nnodes(dg.basis), nelements(elements), + uEltype) - cache = (; elements, interfaces, boundaries, gradients, flux_viscous, u_transformed) + cache = (; elements, interfaces, boundaries, viscous_container) return cache end @@ -28,7 +25,8 @@ function rhs_parabolic!(du, u, t, mesh::P4estMesh{2}, equations_parabolic::AbstractEquationsParabolic, initial_condition, boundary_conditions_parabolic, source_terms, dg::DG, parabolic_scheme, cache, cache_parabolic) - (; u_transformed, gradients, flux_viscous) = cache_parabolic + @unpack viscous_container = cache_parabolic + @unpack u_transformed, gradients, flux_viscous = viscous_container # Convert conservative variables to a form more suitable for viscous flux calculations @trixi_timeit timer() "transform variables" begin diff --git a/src/solvers/dgsem_p4est/dg_3d_parabolic.jl b/src/solvers/dgsem_p4est/dg_3d_parabolic.jl index 2d26c1aff50..b06cdd42127 100644 --- a/src/solvers/dgsem_p4est/dg_3d_parabolic.jl +++ b/src/solvers/dgsem_p4est/dg_3d_parabolic.jl @@ -10,14 +10,11 @@ function create_cache_parabolic(mesh::P4estMesh{3}, equations_hyperbolic::Abstra interfaces = init_interfaces(mesh, equations_hyperbolic, dg.basis, elements) boundaries = init_boundaries(mesh, equations_hyperbolic, dg.basis, elements) - n_vars = nvariables(equations_hyperbolic) - n_elements = nelements(elements) - n_nodes = nnodes(dg.basis) # nodes in one direction - u_transformed = Array{uEltype}(undef, n_vars, n_nodes, n_nodes, n_nodes, n_elements) - gradients = ntuple(_ -> similar(u_transformed), ndims(mesh)) - flux_viscous = ntuple(_ -> similar(u_transformed), ndims(mesh)) + viscous_container = init_viscous_container_3d(nvariables(equations_hyperbolic), + nnodes(dg.basis), nelements(elements), + uEltype) - cache = (; elements, interfaces, boundaries, gradients, flux_viscous, u_transformed) + cache = (; elements, interfaces, boundaries, viscous_container) return cache end @@ -36,7 +33,8 @@ function rhs_parabolic!(du, u, t, mesh::P4estMesh{3}, equations_parabolic::AbstractEquationsParabolic, initial_condition, boundary_conditions_parabolic, source_terms, dg::DG, parabolic_scheme, cache, cache_parabolic) - @unpack u_transformed, gradients, flux_viscous = cache_parabolic + @unpack viscous_container = cache_parabolic + @unpack u_transformed, gradients, flux_viscous = viscous_container # Convert conservative variables to a form more suitable for viscous flux calculations @trixi_timeit timer() "transform variables" begin diff --git a/src/solvers/dgsem_tree/container_viscous_1d.jl b/src/solvers/dgsem_tree/container_viscous_1d.jl index a4919f75396..71c68dfc6df 100644 --- a/src/solvers/dgsem_tree/container_viscous_1d.jl +++ b/src/solvers/dgsem_tree/container_viscous_1d.jl @@ -19,9 +19,9 @@ mutable struct ViscousContainer1D{uEltype <: Real} end end -function init_viscous_container(n_vars::Integer, n_nodes::Integer, - n_elements::Integer, - ::Type{uEltype}) where {uEltype <: Real} +function init_viscous_container_1d(n_vars::Integer, n_nodes::Integer, + n_elements::Integer, + ::Type{uEltype}) where {uEltype <: Real} return ViscousContainer1D{uEltype}(n_vars, n_nodes, n_elements) end diff --git a/src/solvers/dgsem_tree/container_viscous_2d.jl b/src/solvers/dgsem_tree/container_viscous_2d.jl new file mode 100644 index 00000000000..bd7ff413af5 --- /dev/null +++ b/src/solvers/dgsem_tree/container_viscous_2d.jl @@ -0,0 +1,69 @@ +mutable struct ViscousContainer2D{uEltype <: Real} + u_transformed::Array{uEltype, 4} + # Using an outer fixed-size datastructure leads to nasty implementations, + # see https://github.com/trixi-framework/Trixi.jl/pull/1629#discussion_r1355293953. + # Also: This does not result in speed up compared to using tuples for the internal + # datastructures, see + # https://github.com/trixi-framework/Trixi.jl/pull/1629#discussion_r1363352188. + gradients::Vector{Array{uEltype, 4}} + flux_viscous::Vector{Array{uEltype, 4}} + + # internal `resize!`able storage + _u_transformed::Vector{uEltype} + # Use Tuple for outer, fixed-size datastructure + _gradients::Tuple{Vector{uEltype}, Vector{uEltype}} + _flux_viscous::Tuple{Vector{uEltype}, Vector{uEltype}} + + function ViscousContainer2D{uEltype}(n_vars::Integer, n_nodes::Integer, + n_elements::Integer) where {uEltype <: Real} + new(Array{uEltype, 4}(undef, n_vars, n_nodes, n_nodes, n_elements), + [Array{uEltype, 4}(undef, n_vars, n_nodes, n_nodes, n_elements) for _ in 1:2], + [Array{uEltype, 4}(undef, n_vars, n_nodes, n_nodes, n_elements) for _ in 1:2], + Vector{uEltype}(undef, n_vars * n_nodes^2 * n_elements), + (Vector{uEltype}(undef, n_vars * n_nodes^2 * n_elements), + Vector{uEltype}(undef, n_vars * n_nodes^2 * n_elements)), + (Vector{uEltype}(undef, n_vars * n_nodes^2 * n_elements), + Vector{uEltype}(undef, n_vars * n_nodes^2 * n_elements))) + end +end + +function init_viscous_container_2d(n_vars::Integer, n_nodes::Integer, + n_elements::Integer, + ::Type{uEltype}) where {uEltype <: Real} + return ViscousContainer2D{uEltype}(n_vars, n_nodes, n_elements) +end + +# Only one-dimensional `Array`s are `resize!`able in Julia. +# Hence, we use `Vector`s as internal storage and `resize!` +# them whenever needed. Then, we reuse the same memory by +# `unsafe_wrap`ping multi-dimensional `Array`s around the +# internal storage. +function Base.resize!(viscous_container::ViscousContainer2D, equations, dg, cache) + capacity = nvariables(equations) * nnodes(dg) * nnodes(dg) * nelements(dg, cache) + resize!(viscous_container._u_transformed, capacity) + for dim in 1:2 + resize!(viscous_container._gradients[dim], capacity) + resize!(viscous_container._flux_viscous[dim], capacity) + end + + viscous_container.u_transformed = unsafe_wrap(Array, + pointer(viscous_container._u_transformed), + (nvariables(equations), + nnodes(dg), nnodes(dg), + nelements(dg, cache))) + + for dim in 1:2 + viscous_container.gradients[dim] = unsafe_wrap(Array, + pointer(viscous_container._gradients[dim]), + (nvariables(equations), + nnodes(dg), nnodes(dg), + nelements(dg, cache))) + + viscous_container.flux_viscous[dim] = unsafe_wrap(Array, + pointer(viscous_container._flux_viscous[dim]), + (nvariables(equations), + nnodes(dg), nnodes(dg), + nelements(dg, cache))) + end + return nothing +end diff --git a/src/solvers/dgsem_tree/container_viscous_3d.jl b/src/solvers/dgsem_tree/container_viscous_3d.jl new file mode 100644 index 00000000000..64d283fe189 --- /dev/null +++ b/src/solvers/dgsem_tree/container_viscous_3d.jl @@ -0,0 +1,75 @@ +mutable struct ViscousContainer3D{uEltype <: Real} + u_transformed::Array{uEltype, 5} + # Using an outer fixed-size datastructure leads to nasty implementations, + # see https://github.com/trixi-framework/Trixi.jl/pull/1629#discussion_r1355293953. + # Also: This does not result in speed up compared to using tuples for the internal + # datastructures, see + # https://github.com/trixi-framework/Trixi.jl/pull/1629#discussion_r1363352188. + gradients::Vector{Array{uEltype, 5}} + flux_viscous::Vector{Array{uEltype, 5}} + + # internal `resize!`able storage + _u_transformed::Vector{uEltype} + # Use Tuple for outer, fixed-size datastructure + _gradients::Tuple{Vector{uEltype}, Vector{uEltype}, Vector{uEltype}} + _flux_viscous::Tuple{Vector{uEltype}, Vector{uEltype}, Vector{uEltype}} + + function ViscousContainer3D{uEltype}(n_vars::Integer, n_nodes::Integer, + n_elements::Integer) where {uEltype <: Real} + new(Array{uEltype, 5}(undef, n_vars, n_nodes, n_nodes, n_nodes, n_elements), + [Array{uEltype, 5}(undef, n_vars, n_nodes, n_nodes, n_nodes, n_elements) + for _ in 1:3], + [Array{uEltype, 5}(undef, n_vars, n_nodes, n_nodes, n_nodes, n_elements) + for _ in 1:3], + Vector{uEltype}(undef, n_vars * n_nodes^3 * n_elements), + (Vector{uEltype}(undef, n_vars * n_nodes^3 * n_elements), + Vector{uEltype}(undef, n_vars * n_nodes^3 * n_elements), + Vector{uEltype}(undef, n_vars * n_nodes^3 * n_elements)), + (Vector{uEltype}(undef, n_vars * n_nodes^3 * n_elements), + Vector{uEltype}(undef, n_vars * n_nodes^3 * n_elements), + Vector{uEltype}(undef, n_vars * n_nodes^3 * n_elements))) + end +end + +function init_viscous_container_3d(n_vars::Integer, n_nodes::Integer, + n_elements::Integer, + ::Type{uEltype}) where {uEltype <: Real} + return ViscousContainer3D{uEltype}(n_vars, n_nodes, n_elements) +end + +# Only one-dimensional `Array`s are `resize!`able in Julia. +# Hence, we use `Vector`s as internal storage and `resize!` +# them whenever needed. Then, we reuse the same memory by +# `unsafe_wrap`ping multi-dimensional `Array`s around the +# internal storage. +function Base.resize!(viscous_container::ViscousContainer3D, equations, dg, cache) + capacity = nvariables(equations) * nnodes(dg) * nnodes(dg) * nnodes(dg) * + nelements(dg, cache) + resize!(viscous_container._u_transformed, capacity) + for dim in 1:3 + resize!(viscous_container._gradients[dim], capacity) + resize!(viscous_container._flux_viscous[dim], capacity) + end + + viscous_container.u_transformed = unsafe_wrap(Array, + pointer(viscous_container._u_transformed), + (nvariables(equations), + nnodes(dg), nnodes(dg), nnodes(dg), + nelements(dg, cache))) + + for dim in 1:3 + viscous_container.gradients[dim] = unsafe_wrap(Array, + pointer(viscous_container._gradients[dim]), + (nvariables(equations), + nnodes(dg), nnodes(dg), nnodes(dg), + nelements(dg, cache))) + + viscous_container.flux_viscous[dim] = unsafe_wrap(Array, + pointer(viscous_container._flux_viscous[dim]), + (nvariables(equations), + nnodes(dg), nnodes(dg), + nnodes(dg), + nelements(dg, cache))) + end + return nothing +end diff --git a/src/solvers/dgsem_tree/containers.jl b/src/solvers/dgsem_tree/containers.jl index bba8b83b23a..3f05daf81d8 100644 --- a/src/solvers/dgsem_tree/containers.jl +++ b/src/solvers/dgsem_tree/containers.jl @@ -28,9 +28,11 @@ function reinitialize_containers!(mesh::TreeMesh, equations, dg::DGSEM, cache) init_boundaries!(boundaries, elements, mesh) # re-initialize mortars container - @unpack mortars = cache - resize!(mortars, count_required_mortars(mesh, leaf_cell_ids)) - init_mortars!(mortars, elements, mesh) + if hasproperty(cache, :mortars) # cache_parabolic does not carry mortars + @unpack mortars = cache + resize!(mortars, count_required_mortars(mesh, leaf_cell_ids)) + init_mortars!(mortars, elements, mesh) + end if mpi_isparallel() # re-initialize mpi_interfaces container diff --git a/src/solvers/dgsem_tree/containers_viscous.jl b/src/solvers/dgsem_tree/containers_viscous.jl new file mode 100644 index 00000000000..444f2cb7303 --- /dev/null +++ b/src/solvers/dgsem_tree/containers_viscous.jl @@ -0,0 +1,4 @@ +# Dimension-specific implementations +include("container_viscous_1d.jl") +include("container_viscous_2d.jl") +include("container_viscous_3d.jl") diff --git a/src/solvers/dgsem_tree/dg.jl b/src/solvers/dgsem_tree/dg.jl index ff37bad3b3a..ef9a42b4c1a 100644 --- a/src/solvers/dgsem_tree/dg.jl +++ b/src/solvers/dgsem_tree/dg.jl @@ -54,8 +54,8 @@ include("containers.jl") # Dimension-agnostic parallel setup include("dg_parallel.jl") -# Helper struct for parabolic AMR -include("container_viscous_1d.jl") +# Helper structs for parabolic AMR +include("containers_viscous.jl") # 1D DG implementation include("dg_1d.jl") diff --git a/src/solvers/dgsem_tree/dg_1d_parabolic.jl b/src/solvers/dgsem_tree/dg_1d_parabolic.jl index 97e31e0e22b..90007b05b3d 100644 --- a/src/solvers/dgsem_tree/dg_1d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_1d_parabolic.jl @@ -535,14 +535,14 @@ function create_cache_parabolic(mesh::TreeMesh{1}, elements = init_elements(leaf_cell_ids, mesh, equations_hyperbolic, dg.basis, RealT, uEltype) - viscous_container = init_viscous_container(nvariables(equations_hyperbolic), - nnodes(elements), nelements(elements), - uEltype) - interfaces = init_interfaces(leaf_cell_ids, mesh, elements) boundaries = init_boundaries(leaf_cell_ids, mesh, elements) + viscous_container = init_viscous_container_1d(nvariables(equations_hyperbolic), + nnodes(elements), nelements(elements), + uEltype) + cache = (; elements, interfaces, boundaries, viscous_container) return cache diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 1c32703c7c3..06abff5e85b 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -17,7 +17,8 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, initial_condition, boundary_conditions_parabolic, source_terms, dg::DG, parabolic_scheme, cache, cache_parabolic) - (; u_transformed, gradients, flux_viscous) = cache_parabolic + @unpack viscous_container = cache_parabolic + @unpack u_transformed, gradients, flux_viscous = viscous_container # Convert conservative variables to a form more suitable for viscous flux calculations @trixi_timeit timer() "transform variables" begin @@ -290,7 +291,8 @@ function prolong2boundaries!(cache_parabolic, flux_viscous, return nothing end -function calc_viscous_fluxes!(flux_viscous, gradients, u_transformed, +function calc_viscous_fluxes!(flux_viscous, + gradients, u_transformed, mesh::Union{TreeMesh{2}, P4estMesh{2}}, equations_parabolic::AbstractEquationsParabolic, dg::DG, cache, cache_parabolic) @@ -513,11 +515,16 @@ function calc_boundary_flux_by_direction_divergence!(surface_flux_values::Abstra return nothing end -function prolong2mortars!(cache, flux_viscous::Tuple{AbstractArray, AbstractArray}, +# `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 +# hyperbolic-parabolic systems. +function prolong2mortars!(cache, flux_viscous::Vector{Array{uEltype, 4}}, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, mortar_l2::LobattoLegendreMortarL2, surface_integral, - dg::DGSEM) + dg::DGSEM) where {uEltype <: Real} flux_viscous_x, flux_viscous_y = flux_viscous @threaded for mortar in eachmortar(dg, cache) large_element = cache.mortars.neighbor_ids[3, mortar] @@ -909,21 +916,18 @@ function create_cache_parabolic(mesh::TreeMesh{2}, elements = init_elements(leaf_cell_ids, mesh, equations_hyperbolic, dg.basis, RealT, uEltype) - n_vars = nvariables(equations_hyperbolic) - n_nodes = nnodes(elements) - n_elements = nelements(elements) - u_transformed = Array{uEltype}(undef, n_vars, n_nodes, n_nodes, n_elements) - gradients = ntuple(_ -> similar(u_transformed), ndims(mesh)) - flux_viscous = ntuple(_ -> similar(u_transformed), ndims(mesh)) - interfaces = init_interfaces(leaf_cell_ids, mesh, elements) boundaries = init_boundaries(leaf_cell_ids, mesh, elements) # mortars = init_mortars(leaf_cell_ids, mesh, elements, dg.mortar) + viscous_container = init_viscous_container_2d(nvariables(equations_hyperbolic), + nnodes(elements), nelements(elements), + uEltype) + # cache = (; elements, interfaces, boundaries, mortars) - cache = (; elements, interfaces, boundaries, gradients, flux_viscous, u_transformed) + cache = (; elements, interfaces, boundaries, viscous_container) # Add specialized parts of the cache required to compute the mortars etc. # cache = (;cache..., create_cache(mesh, equations_parabolic, dg.mortar, uEltype)...) diff --git a/src/solvers/dgsem_tree/dg_3d_parabolic.jl b/src/solvers/dgsem_tree/dg_3d_parabolic.jl index 37492dbcb91..2561c5fe5b0 100644 --- a/src/solvers/dgsem_tree/dg_3d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_3d_parabolic.jl @@ -17,7 +17,8 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{3}, equations_parabolic::AbstractEquationsParabolic, initial_condition, boundary_conditions_parabolic, source_terms, dg::DG, parabolic_scheme, cache, cache_parabolic) - @unpack u_transformed, gradients, flux_viscous = cache_parabolic + @unpack viscous_container = cache_parabolic + @unpack u_transformed, gradients, flux_viscous = viscous_container # Convert conservative variables to a form more suitable for viscous flux calculations @trixi_timeit timer() "transform variables" begin @@ -338,7 +339,8 @@ function prolong2boundaries!(cache_parabolic, flux_viscous, return nothing end -function calc_viscous_fluxes!(flux_viscous, gradients, u_transformed, +function calc_viscous_fluxes!(flux_viscous, + gradients, u_transformed, mesh::Union{TreeMesh{3}, P4estMesh{3}}, equations_parabolic::AbstractEquationsParabolic, dg::DG, cache, cache_parabolic) @@ -596,13 +598,17 @@ function calc_boundary_flux_by_direction_divergence!(surface_flux_values::Abstra return nothing 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 +# hyperbolic-parabolic systems. function prolong2mortars!(cache, - flux_viscous::Tuple{AbstractArray, AbstractArray, - AbstractArray}, + flux_viscous::Vector{Array{uEltype, 5}}, mesh::TreeMesh{3}, equations_parabolic::AbstractEquationsParabolic, mortar_l2::LobattoLegendreMortarL2, - surface_integral, dg::DGSEM) + surface_integral, dg::DGSEM) where {uEltype <: Real} # temporary buffer for projections @unpack fstar_tmp1_threaded = cache @@ -1099,21 +1105,18 @@ function create_cache_parabolic(mesh::TreeMesh{3}, elements = init_elements(leaf_cell_ids, mesh, equations_hyperbolic, dg.basis, RealT, uEltype) - n_vars = nvariables(equations_hyperbolic) - n_nodes = nnodes(elements) - n_elements = nelements(elements) - u_transformed = Array{uEltype}(undef, n_vars, n_nodes, n_nodes, n_nodes, n_elements) - gradients = ntuple(_ -> similar(u_transformed), ndims(mesh)) - flux_viscous = ntuple(_ -> similar(u_transformed), ndims(mesh)) - interfaces = init_interfaces(leaf_cell_ids, mesh, elements) boundaries = init_boundaries(leaf_cell_ids, mesh, elements) # mortars = init_mortars(leaf_cell_ids, mesh, elements, dg.mortar) + viscous_container = init_viscous_container_3d(nvariables(equations_hyperbolic), + nnodes(elements), nelements(elements), + uEltype) + # cache = (; elements, interfaces, boundaries, mortars) - cache = (; elements, interfaces, boundaries, gradients, flux_viscous, u_transformed) + cache = (; elements, interfaces, boundaries, viscous_container) # Add specialized parts of the cache required to compute the mortars etc. # cache = (;cache..., create_cache(mesh, equations_parabolic, dg.mortar, uEltype)...) diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 046494e1000..a57462ef7ea 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -377,6 +377,14 @@ isdir(outdir) && rm(outdir, recursive=true) end end + @trixi_testset "TreeMesh2D: elixir_navierstokes_shearlayer_amr.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navierstokes_shearlayer_amr.jl"), + l2 = [0.00526017743452336, 0.4130430692895672, 0.4310996183791349, 1.1544344171604635], + linf = [0.03492185879198495, 1.392635891671335, 1.357551616406459, 8.713760873018146], + tspan = (0.0, 0.7) + ) + end + @trixi_testset "P4estMesh2D: elixir_advection_diffusion_periodic.jl" begin @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_advection_diffusion_periodic.jl"), trees_per_dimension = (1, 1), initial_refinement_level = 2, tspan=(0.0, 0.5), diff --git a/test/test_parabolic_3d.jl b/test/test_parabolic_3d.jl index f74546d0146..276e37518ee 100644 --- a/test/test_parabolic_3d.jl +++ b/test/test_parabolic_3d.jl @@ -252,6 +252,20 @@ isdir(outdir) && rm(outdir, recursive=true) @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 end end + + @trixi_testset "TreeMesh3D: elixir_advection_diffusion_amr.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", "elixir_advection_diffusion_amr.jl"), + l2 = [0.000355780485397024], + linf = [0.0010810770271614256] + ) + end + + @trixi_testset "TreeMesh3D: elixir_advection_diffusion_nonperiodic.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", "elixir_advection_diffusion_nonperiodic.jl"), + l2 = [0.0009808996243280868], + linf = [0.01732621559135459] + ) + end end # Clean up afterwards: delete Trixi.jl output directory From 474410507181fa93cbe8201da4ade03311f09104 Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Wed, 25 Oct 2023 12:06:21 +0200 Subject: [PATCH 142/263] Set version to v0.5.47 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 48bb6b30182..59fc074d6d4 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.5.47-pre" +version = "0.5.47" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From dc0dc1d220e79d31465818acae235adf69ecddea Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Wed, 25 Oct 2023 12:19:06 +0200 Subject: [PATCH 143/263] Set development version v0.5.48-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 59fc074d6d4..f19f7fdecc3 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.5.47" +version = "0.5.48-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 3e9ee80bf1ede22946eacbcf115867a06e2f5a75 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 30 Oct 2023 11:24:48 +0100 Subject: [PATCH 144/263] format with new version of JuliaFormatter (#1696) --- .../semidiscretization_euler_acoustics.jl | 10 +++++----- .../semidiscretization_euler_gravity.jl | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/semidiscretization/semidiscretization_euler_acoustics.jl b/src/semidiscretization/semidiscretization_euler_acoustics.jl index 7608998c557..e49fe81177a 100644 --- a/src/semidiscretization/semidiscretization_euler_acoustics.jl +++ b/src/semidiscretization/semidiscretization_euler_acoustics.jl @@ -51,11 +51,11 @@ function SemidiscretizationEulerAcoustics(semi_acoustics::SemiAcoustics, semi_euler::SemiEuler; source_region = x -> true, weights = x -> 1.0) where - {Mesh, - SemiAcoustics <: - SemidiscretizationHyperbolic{Mesh, <:AbstractAcousticPerturbationEquations}, - SemiEuler <: - SemidiscretizationHyperbolic{Mesh, <:AbstractCompressibleEulerEquations}} + {Mesh, + SemiAcoustics <: + SemidiscretizationHyperbolic{Mesh, <:AbstractAcousticPerturbationEquations}, + SemiEuler <: + SemidiscretizationHyperbolic{Mesh, <:AbstractCompressibleEulerEquations}} cache = create_cache(SemidiscretizationEulerAcoustics, source_region, weights, mesh_equations_solver_cache(semi_acoustics)...) diff --git a/src/semidiscretization/semidiscretization_euler_gravity.jl b/src/semidiscretization/semidiscretization_euler_gravity.jl index 8fe9de1d2b2..a9a60a4ff04 100644 --- a/src/semidiscretization/semidiscretization_euler_gravity.jl +++ b/src/semidiscretization/semidiscretization_euler_gravity.jl @@ -117,11 +117,11 @@ Construct a semidiscretization of the compressible Euler equations with self-gra function SemidiscretizationEulerGravity(semi_euler::SemiEuler, semi_gravity::SemiGravity, parameters) where - {Mesh, - SemiEuler <: - SemidiscretizationHyperbolic{Mesh, <:AbstractCompressibleEulerEquations}, - SemiGravity <: - SemidiscretizationHyperbolic{Mesh, <:AbstractHyperbolicDiffusionEquations}} + {Mesh, + SemiEuler <: + SemidiscretizationHyperbolic{Mesh, <:AbstractCompressibleEulerEquations}, + SemiGravity <: + SemidiscretizationHyperbolic{Mesh, <:AbstractHyperbolicDiffusionEquations}} u_ode = compute_coefficients(zero(real(semi_gravity)), semi_gravity) du_ode = similar(u_ode) u_tmp1_ode = similar(u_ode) From 0f49e5bc86a26c2aa7c5e845bcc79090e22fc2b8 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 30 Oct 2023 11:57:53 +0100 Subject: [PATCH 145/263] format test directory (#1688) * format test * move D_SBP = ... outside of at-test_trixi_include * fix definition of SBP operators in tests (global) * do not indent all test files * fix typo * check formatting of test --- .github/workflows/FormatCheck.yml | 2 +- test/coverage/coverage.jl | 48 +- test/test_aqua.jl | 2 +- test/test_dgmulti_1d.jl | 214 ++- test/test_dgmulti_2d.jl | 917 +++++++---- test/test_dgmulti_3d.jl | 552 ++++--- test/test_mpi.jl | 45 +- test/test_mpi_p4est_2d.jl | 119 +- test/test_mpi_p4est_3d.jl | 218 ++- test/test_mpi_tree.jl | 510 +++--- test/test_p4est_2d.jl | 683 ++++---- test/test_p4est_3d.jl | 688 ++++---- ...est_paper_self_gravitating_gas_dynamics.jl | 527 +++--- test/test_parabolic_1d.jl | 327 ++-- test/test_parabolic_2d.jl | 952 ++++++----- test/test_parabolic_3d.jl | 627 ++++--- test/test_performance_specializations_2d.jl | 250 +-- test/test_performance_specializations_3d.jl | 250 +-- test/test_special_elixirs.jl | 454 +++--- test/test_structured_1d.jl | 209 +-- test/test_structured_2d.jl | 1443 ++++++++++------- test/test_structured_3d.jl | 523 +++--- test/test_t8code_2d.jl | 469 +++--- test/test_threaded.jl | 582 ++++--- test/test_tree_1d.jl | 444 ++--- test/test_tree_1d_advection.jl | 102 +- test/test_tree_1d_burgers.jl | 98 +- test/test_tree_1d_euler.jl | 600 ++++--- test/test_tree_1d_eulergravity.jl | 34 +- test/test_tree_1d_eulermulti.jl | 196 ++- test/test_tree_1d_fdsbp.jl | 275 ++-- test/test_tree_1d_hypdiff.jl | 54 +- test/test_tree_1d_mhd.jl | 404 +++-- test/test_tree_1d_mhdmulti.jl | 184 ++- test/test_tree_1d_shallowwater.jl | 575 ++++--- test/test_tree_1d_shallowwater_twolayer.jl | 144 +- test/test_tree_2d_acoustics.jl | 189 ++- test/test_tree_2d_advection.jl | 557 +++---- test/test_tree_2d_euler.jl | 1388 ++++++++++------ test/test_tree_2d_euleracoustics.jl | 46 +- test/test_tree_2d_eulermulti.jl | 283 ++-- test/test_tree_2d_fdsbp.jl | 205 ++- test/test_tree_2d_hypdiff.jl | 135 +- test/test_tree_2d_kpp.jl | 32 +- test/test_tree_2d_lbm.jl | 236 +-- test/test_tree_2d_linearizedeuler.jl | 69 +- test/test_tree_2d_mhd.jl | 423 +++-- test/test_tree_2d_mhdmulti.jl | 194 ++- test/test_tree_2d_part1.jl | 140 +- test/test_tree_2d_part2.jl | 30 +- test/test_tree_2d_part3.jl | 30 +- test/test_tree_2d_shallowwater.jl | 396 +++-- test/test_tree_2d_shallowwater_twolayer.jl | 160 +- test/test_tree_3d_advection.jl | 170 +- test/test_tree_3d_euler.jl | 649 +++++--- test/test_tree_3d_eulergravity.jl | 40 +- test/test_tree_3d_fdsbp.jl | 167 +- test/test_tree_3d_hypdiff.jl | 112 +- test/test_tree_3d_lbm.jl | 154 +- test/test_tree_3d_mhd.jl | 389 +++-- test/test_tree_3d_part1.jl | 11 +- test/test_tree_3d_part2.jl | 171 +- test/test_tree_3d_part3.jl | 50 +- test/test_trixi.jl | 344 ++-- test/test_unit.jl | 1356 ++++++++-------- test/test_unstructured_2d.jl | 939 ++++++----- test/test_visualization.jl | 367 +++-- 67 files changed, 13796 insertions(+), 9357 deletions(-) diff --git a/.github/workflows/FormatCheck.yml b/.github/workflows/FormatCheck.yml index ce46360b832..81d18f4105e 100644 --- a/.github/workflows/FormatCheck.yml +++ b/.github/workflows/FormatCheck.yml @@ -30,7 +30,7 @@ jobs: # format(".") run: | julia -e 'using Pkg; Pkg.add(PackageSpec(name = "JuliaFormatter"))' - julia -e 'using JuliaFormatter; format(["benchmark", "ext", "src", "utils"])' + julia -e 'using JuliaFormatter; format(["benchmark", "ext", "src", "test", "utils"])' - name: Format check run: | julia -e ' diff --git a/test/coverage/coverage.jl b/test/coverage/coverage.jl index fbe89acf702..5f1ae8af8fc 100644 --- a/test/coverage/coverage.jl +++ b/test/coverage/coverage.jl @@ -9,28 +9,28 @@ const lcov_info_file = "lcov.info" # Change path to root directory cd(joinpath(@__DIR__, "..", "..")) do - # Process coverage files - processed = process_folder("src") - - # Uncomment the following line once Codecov support is enabled - # Codecov.submit_local(processed) - - # Calculate coverage - covered_lines, total_lines = get_summary(processed) - percentage = covered_lines / total_lines * 100 - - # Print coverage in a format that can be easily parsed - println("($(percentage)%) covered") - - # Try to generate a coverage report - isdir(report_dir) || mkdir(report_dir) - tracefile = joinpath(report_dir, lcov_info_file) - Coverage.LCOV.writefile(tracefile, processed) - branch = strip(read(`git rev-parse --abbrev-ref HEAD`, String)) - commit = strip(read(`git rev-parse --short HEAD`, String)) - title = "commit $(commit) on branch $(branch)" - run(`genhtml -t $(title) -o $(report_dir) $(tracefile)`) - - # Clean up .cov files - clean_folder("src") + # Process coverage files + processed = process_folder("src") + + # Uncomment the following line once Codecov support is enabled + # Codecov.submit_local(processed) + + # Calculate coverage + covered_lines, total_lines = get_summary(processed) + percentage = covered_lines / total_lines * 100 + + # Print coverage in a format that can be easily parsed + println("($(percentage)%) covered") + + # Try to generate a coverage report + isdir(report_dir) || mkdir(report_dir) + tracefile = joinpath(report_dir, lcov_info_file) + Coverage.LCOV.writefile(tracefile, processed) + branch = strip(read(`git rev-parse --abbrev-ref HEAD`, String)) + commit = strip(read(`git rev-parse --short HEAD`, String)) + title = "commit $(commit) on branch $(branch)" + run(`genhtml -t $(title) -o $(report_dir) $(tracefile)`) + + # Clean up .cov files + clean_folder("src") end diff --git a/test/test_aqua.jl b/test/test_aqua.jl index f7ab4f545d0..9f57791406f 100644 --- a/test/test_aqua.jl +++ b/test/test_aqua.jl @@ -12,7 +12,7 @@ include("test_trixi.jl") # exceptions necessary for adding a new method `StartUpDG.estimate_h` # in src/solvers/dgmulti/sbp.jl piracy = (treat_as_own = [Trixi.StartUpDG.RefElemData, - Trixi.StartUpDG.MeshData],)) + Trixi.StartUpDG.MeshData],)) end end #module diff --git a/test/test_dgmulti_1d.jl b/test/test_dgmulti_1d.jl index 180838158ea..79ad64075b4 100644 --- a/test/test_dgmulti_1d.jl +++ b/test/test_dgmulti_1d.jl @@ -9,126 +9,162 @@ EXAMPLES_DIR = joinpath(examples_dir(), "dgmulti_1d") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) @testset "DGMulti 1D" begin +#! format: noindent - @trixi_testset "elixir_advection_gauss_sbp.jl " begin +@trixi_testset "elixir_advection_gauss_sbp.jl " begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_gauss_sbp.jl"), - cells_per_dimension = (8,), - l2 = [2.9953644500009865e-5], - linf = [4.467840577382365e-5] - ) - # 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 + cells_per_dimension=(8,), + l2=[2.9953644500009865e-5], + linf=[4.467840577382365e-5]) + # 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 - @trixi_testset "elixir_euler_flux_diff.jl " begin +@trixi_testset "elixir_euler_flux_diff.jl " begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_flux_diff.jl"), - cells_per_dimension = (16,), - # division by sqrt(2.0) corresponds to normalization by the square root of the size of the domain - l2 = [7.853842541289665e-7, 9.609905503440606e-7, 2.832322219966481e-6] ./ sqrt(2.0), - linf = [1.5003758788711963e-6, 1.802998748523521e-6, 4.83599270806323e-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 + cells_per_dimension=(16,), + # division by sqrt(2.0) corresponds to normalization by the square root of the size of the domain + l2=[ + 7.853842541289665e-7, + 9.609905503440606e-7, + 2.832322219966481e-6, + ] ./ sqrt(2.0), + linf=[ + 1.5003758788711963e-6, + 1.802998748523521e-6, + 4.83599270806323e-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 - end +end - @trixi_testset "elixir_euler_flux_diff.jl (convergence)" begin - mean_convergence = convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "elixir_euler_flux_diff.jl"), 3) - @test isapprox(mean_convergence[:l2], [4.1558759698638434, 3.977911306037128, 4.041421206468769], rtol=0.05) - # 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 +@trixi_testset "elixir_euler_flux_diff.jl (convergence)" begin + mean_convergence = convergence_test(@__MODULE__, + joinpath(EXAMPLES_DIR, + "elixir_euler_flux_diff.jl"), 3) + @test isapprox(mean_convergence[:l2], + [4.1558759698638434, 3.977911306037128, 4.041421206468769], + rtol = 0.05) + # 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 - @trixi_testset "elixir_euler_flux_diff.jl (SBP) " begin +@trixi_testset "elixir_euler_flux_diff.jl (SBP) " begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_flux_diff.jl"), - cells_per_dimension = (16,), - approximation_type = SBP(), - l2 = [6.437827414849647e-6, 2.1840558851820947e-6, 1.3245669629438228e-5], - linf = [2.0715843751295537e-5, 8.519520630301258e-6, 4.2642194098885255e-5] - ) - # 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 + cells_per_dimension=(16,), + approximation_type=SBP(), + l2=[ + 6.437827414849647e-6, + 2.1840558851820947e-6, + 1.3245669629438228e-5, + ], + linf=[ + 2.0715843751295537e-5, + 8.519520630301258e-6, + 4.2642194098885255e-5, + ]) + # 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 - @trixi_testset "elixir_euler_flux_diff.jl (FD SBP)" begin +@trixi_testset "elixir_euler_flux_diff.jl (FD SBP)" begin + global D = derivative_operator(SummationByPartsOperators.MattssonNordström2004(), + derivative_order = 1, + accuracy_order = 4, + xmin = 0.0, xmax = 1.0, + N = 16) @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_flux_diff.jl"), - cells_per_dimension = (4,), - approximation_type = derivative_operator( - SummationByPartsOperators.MattssonNordström2004(), - derivative_order=1, accuracy_order=4, - xmin=0.0, xmax=1.0, N=16), - l2 = [1.8684509287853788e-5, 1.0641411823379635e-5, 5.178010291876143e-5], - linf = [6.933493585936645e-5, 3.0277366229292113e-5, 0.0002220020568932668] - ) + cells_per_dimension=(4,), + approximation_type=D, + l2=[ + 1.8684509287853788e-5, + 1.0641411823379635e-5, + 5.178010291876143e-5, + ], + linf=[ + 6.933493585936645e-5, + 3.0277366229292113e-5, + 0.0002220020568932668, + ]) show(stdout, semi.solver.basis) show(stdout, MIME"text/plain"(), semi.solver.basis) - # 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 + # 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 - @trixi_testset "elixir_euler_fdsbp_periodic.jl" begin +@trixi_testset "elixir_euler_fdsbp_periodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_fdsbp_periodic.jl"), - l2 = [9.146929180585711e-7, 1.8997616878017292e-6, 3.991417702211889e-6], - linf = [1.7321089884614338e-6, 3.3252888855805907e-6, 6.5252787737613005e-6] - ) + l2=[ + 9.146929180585711e-7, + 1.8997616878017292e-6, + 3.991417702211889e-6, + ], + linf=[ + 1.7321089884614338e-6, + 3.3252888855805907e-6, + 6.5252787737613005e-6, + ]) show(stdout, semi.solver.basis) show(stdout, MIME"text/plain"(), semi.solver.basis) - # 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 + # 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 - @trixi_testset "DGMulti with periodic SBP unit test" begin +@trixi_testset "DGMulti with periodic SBP unit test" begin # see https://github.com/trixi-framework/Trixi.jl/pull/1013 - dg = DGMulti(element_type = Line(), - approximation_type = periodic_derivative_operator( - derivative_order=1, accuracy_order=4, xmin=-5.0, xmax=10.0, N=50)) + global D = periodic_derivative_operator(derivative_order = 1, + accuracy_order = 4, + xmin = -5.0, + xmax = 10.0, N = 50) + dg = DGMulti(element_type = Line(), approximation_type = D) mesh = DGMultiMesh(dg) @test mapreduce(isapprox, &, mesh.md.xyz, dg.basis.rst) # check to make sure nodes are rescaled to [-1, 1] @test minimum(dg.basis.rst[1]) ≈ -1 - @test maximum(dg.basis.rst[1]) ≈ 1 atol=0.35 - end + @test maximum(dg.basis.rst[1])≈1 atol=0.35 +end end # Clean up afterwards: delete Trixi.jl output directory -@test_nowarn isdir(outdir) && rm(outdir, recursive=true) +@test_nowarn isdir(outdir) && rm(outdir, recursive = true) end # module diff --git a/test/test_dgmulti_2d.jl b/test/test_dgmulti_2d.jl index 861e30045ce..8fd00df72ea 100644 --- a/test/test_dgmulti_2d.jl +++ b/test/test_dgmulti_2d.jl @@ -9,357 +9,680 @@ EXAMPLES_DIR = joinpath(examples_dir(), "dgmulti_2d") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) @testset "DGMulti 2D" begin +#! format: noindent - @trixi_testset "elixir_euler_weakform.jl" begin +@trixi_testset "elixir_euler_weakform.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weakform.jl"), - cells_per_dimension = (4, 4), - # division by 2.0 corresponds to normalization by the square root of the size of the domain - l2 = [0.0013536930300254945, 0.0014315603442106193, 0.001431560344211359, 0.0047393341007602625] ./ 2.0, - linf = [0.001514260921466004, 0.0020623991944839215, 0.002062399194485476, 0.004897700392503701] - ) - end - - @trixi_testset "elixir_euler_weakform.jl (SBP)" begin + cells_per_dimension=(4, 4), + # division by 2.0 corresponds to normalization by the square root of the size of the domain + l2=[ + 0.0013536930300254945, + 0.0014315603442106193, + 0.001431560344211359, + 0.0047393341007602625, + ] ./ 2.0, + linf=[ + 0.001514260921466004, + 0.0020623991944839215, + 0.002062399194485476, + 0.004897700392503701, + ]) +end + +@trixi_testset "elixir_euler_weakform.jl (SBP)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weakform.jl"), - cells_per_dimension = (4, 4), - approximation_type = SBP(), - # division by 2.0 corresponds to normalization by the square root of the size of the domain - l2 = [0.0074706882014934735, 0.005306220583603261, 0.005306220583613591, 0.014724842607716771] ./ 2.0, - linf = [0.021563604940952885, 0.01359397832530762, 0.013593978324845324, 0.03270995869587523] - ) - end - - @trixi_testset "elixir_euler_weakform.jl (Quadrilateral elements)" begin + cells_per_dimension=(4, 4), + approximation_type=SBP(), + # division by 2.0 corresponds to normalization by the square root of the size of the domain + l2=[ + 0.0074706882014934735, + 0.005306220583603261, + 0.005306220583613591, + 0.014724842607716771, + ] ./ 2.0, + linf=[ + 0.021563604940952885, + 0.01359397832530762, + 0.013593978324845324, + 0.03270995869587523, + ]) +end + +@trixi_testset "elixir_euler_weakform.jl (Quadrilateral elements)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weakform.jl"), - cells_per_dimension = (4, 4), - element_type = Quad(), - # division by 2.0 corresponds to normalization by the square root of the size of the domain - l2 = [0.00031892254415307093, 0.00033637562986771894, 0.0003363756298680649, 0.0011100259064243145] ./ 2.0, - linf = [0.001073298211445639, 0.0013568139808282087, 0.0013568139808290969, 0.0032249020004324613] - ) - end - - @trixi_testset "elixir_euler_weakform.jl (EC) " begin + cells_per_dimension=(4, 4), + element_type=Quad(), + # division by 2.0 corresponds to normalization by the square root of the size of the domain + l2=[ + 0.00031892254415307093, + 0.00033637562986771894, + 0.0003363756298680649, + 0.0011100259064243145, + ] ./ 2.0, + linf=[ + 0.001073298211445639, + 0.0013568139808282087, + 0.0013568139808290969, + 0.0032249020004324613, + ]) +end + +@trixi_testset "elixir_euler_weakform.jl (EC) " begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weakform.jl"), - cells_per_dimension = (4, 4), - volume_integral = VolumeIntegralFluxDifferencing(flux_ranocha), - surface_integral = SurfaceIntegralWeakForm(flux_ranocha), - # division by 2.0 corresponds to normalization by the square root of the size of the domain - l2 = [0.007801417730672109, 0.00708583561714128, 0.0070858356171393, 0.015217574294198809] ./ 2.0, - linf = [0.011572828457858897, 0.013965298735070686, 0.01396529873508534, 0.04227683691807904] - ) - end - - @trixi_testset "elixir_euler_weakform.jl (SBP, EC)" begin + cells_per_dimension=(4, 4), + volume_integral=VolumeIntegralFluxDifferencing(flux_ranocha), + surface_integral=SurfaceIntegralWeakForm(flux_ranocha), + # division by 2.0 corresponds to normalization by the square root of the size of the domain + l2=[ + 0.007801417730672109, + 0.00708583561714128, + 0.0070858356171393, + 0.015217574294198809, + ] ./ 2.0, + linf=[ + 0.011572828457858897, + 0.013965298735070686, + 0.01396529873508534, + 0.04227683691807904, + ]) +end + +@trixi_testset "elixir_euler_weakform.jl (SBP, EC)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weakform.jl"), - cells_per_dimension = (4, 4), - volume_integral = VolumeIntegralFluxDifferencing(flux_ranocha), - surface_integral = SurfaceIntegralWeakForm(flux_ranocha), - approximation_type = SBP(), - # division by 2.0 corresponds to normalization by the square root of the size of the domain - l2 = [0.01280067571168776, 0.010607599608273302, 0.010607599608239775, 0.026408338014056548] ./ 2.0, - linf = [0.037983023185674814, 0.05321027922533417, 0.05321027922608157, 0.13392025411844033] - ) - end - - @trixi_testset "elixir_euler_weakform.jl (Quadrilateral elements, SBP, EC)" begin + cells_per_dimension=(4, 4), + volume_integral=VolumeIntegralFluxDifferencing(flux_ranocha), + surface_integral=SurfaceIntegralWeakForm(flux_ranocha), + approximation_type=SBP(), + # division by 2.0 corresponds to normalization by the square root of the size of the domain + l2=[ + 0.01280067571168776, + 0.010607599608273302, + 0.010607599608239775, + 0.026408338014056548, + ] ./ 2.0, + linf=[ + 0.037983023185674814, + 0.05321027922533417, + 0.05321027922608157, + 0.13392025411844033, + ]) +end + +@trixi_testset "elixir_euler_weakform.jl (Quadrilateral elements, SBP, EC)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weakform.jl"), - cells_per_dimension = (4, 4), - element_type = Quad(), - volume_integral = VolumeIntegralFluxDifferencing(flux_ranocha), - surface_integral = SurfaceIntegralWeakForm(flux_ranocha), - approximation_type = SBP(), - # division by 2.0 corresponds to normalization by the square root of the size of the domain - l2 = [0.0029373718090697975, 0.0030629360605489465, 0.003062936060545615, 0.0068486089344859755] ./ 2.0, - linf = [0.01360165305316885, 0.01267402847925303, 0.012674028479251254, 0.02210545278615017] - ) - end - - @trixi_testset "elixir_euler_bilinear.jl (Bilinear quadrilateral elements, SBP, flux differencing)" begin + cells_per_dimension=(4, 4), + element_type=Quad(), + volume_integral=VolumeIntegralFluxDifferencing(flux_ranocha), + surface_integral=SurfaceIntegralWeakForm(flux_ranocha), + approximation_type=SBP(), + # division by 2.0 corresponds to normalization by the square root of the size of the domain + l2=[ + 0.0029373718090697975, + 0.0030629360605489465, + 0.003062936060545615, + 0.0068486089344859755, + ] ./ 2.0, + linf=[ + 0.01360165305316885, + 0.01267402847925303, + 0.012674028479251254, + 0.02210545278615017, + ]) +end + +@trixi_testset "elixir_euler_bilinear.jl (Bilinear quadrilateral elements, SBP, flux differencing)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_bilinear.jl"), - l2 = [1.0259435706215337e-5, 9.014090233720625e-6, 9.014090233223014e-6, 2.738953587401793e-5], - linf = [7.362609083649829e-5, 6.874188055272512e-5, 6.874188052830021e-5, 0.0001912435192696904] - ) - end + l2=[ + 1.0259435706215337e-5, + 9.014090233720625e-6, + 9.014090233223014e-6, + 2.738953587401793e-5, + ], + linf=[ + 7.362609083649829e-5, + 6.874188055272512e-5, + 6.874188052830021e-5, + 0.0001912435192696904, + ]) +end - @trixi_testset "elixir_euler_curved.jl (Quadrilateral elements, SBP, flux differencing)" begin +@trixi_testset "elixir_euler_curved.jl (Quadrilateral elements, SBP, flux differencing)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_curved.jl"), - l2 = [1.720476068165337e-5, 1.592168205710526e-5, 1.592168205812963e-5, 4.894094865697305e-5], - linf = [0.00010525416930584619, 0.00010003778091061122, 0.00010003778085621029, 0.00036426282101720275] - ) - end + l2=[ + 1.720476068165337e-5, + 1.592168205710526e-5, + 1.592168205812963e-5, + 4.894094865697305e-5, + ], + linf=[ + 0.00010525416930584619, + 0.00010003778091061122, + 0.00010003778085621029, + 0.00036426282101720275, + ]) +end - @trixi_testset "elixir_euler_curved.jl (Quadrilateral elements, GaussSBP, flux differencing)" begin +@trixi_testset "elixir_euler_curved.jl (Quadrilateral elements, GaussSBP, flux differencing)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_curved.jl"), - approximation_type = GaussSBP(), - l2 = [3.4666312079259457e-6, 3.4392774480368986e-6, 3.439277447953705e-6, 1.0965598424665836e-5], - linf = [1.1327280377004811e-5, 1.1343911926253725e-5, 1.1343911906935844e-5, 3.679582619220412e-5], - rtol = 2 * sqrt(eps()) - ) - end - - @trixi_testset "elixir_euler_curved.jl (Triangular elements, Polynomial, weak formulation)" begin + approximation_type=GaussSBP(), + l2=[ + 3.4666312079259457e-6, + 3.4392774480368986e-6, + 3.439277447953705e-6, + 1.0965598424665836e-5, + ], + linf=[ + 1.1327280377004811e-5, + 1.1343911926253725e-5, + 1.1343911906935844e-5, + 3.679582619220412e-5, + ], + rtol=2 * sqrt(eps())) +end + +@trixi_testset "elixir_euler_curved.jl (Triangular elements, Polynomial, weak formulation)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_curved.jl"), - element_type = Tri(), approximation_type = Polynomial(), volume_integral = VolumeIntegralWeakForm(), - l2 = [7.905498158659466e-6, 8.731690809663625e-6, 8.731690811576996e-6, 2.9113296018693953e-5], - linf = [3.298811230090237e-5, 4.032272476939269e-5, 4.032272526011127e-5, 0.00012013725458537294] - ) - end + element_type=Tri(), approximation_type=Polynomial(), + volume_integral=VolumeIntegralWeakForm(), + l2=[ + 7.905498158659466e-6, + 8.731690809663625e-6, + 8.731690811576996e-6, + 2.9113296018693953e-5, + ], + linf=[ + 3.298811230090237e-5, + 4.032272476939269e-5, + 4.032272526011127e-5, + 0.00012013725458537294, + ]) +end - @trixi_testset "elixir_euler_hohqmesh.jl (Quadrilateral elements, SBP, flux differencing)" begin +@trixi_testset "elixir_euler_hohqmesh.jl (Quadrilateral elements, SBP, flux differencing)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_hohqmesh.jl"), - l2 = [0.0008153911341517156, 0.0007768159701964676, 0.00047902606811690694, 0.0015551846076348535], - linf = [0.0029301131365355726, 0.0034427051471457304, 0.0028721569841545502, 0.011125365074589944] - ) - end + l2=[ + 0.0008153911341517156, + 0.0007768159701964676, + 0.00047902606811690694, + 0.0015551846076348535, + ], + linf=[ + 0.0029301131365355726, + 0.0034427051471457304, + 0.0028721569841545502, + 0.011125365074589944, + ]) +end - @trixi_testset "elixir_euler_weakform.jl (convergence)" begin - mean_convergence = convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "elixir_euler_weakform.jl"), 2) - @test isapprox(mean_convergence[:l2], [4.243843382379403, 4.128314378833922, 4.128314378397532, 4.081366752807379], rtol=0.05) - end +@trixi_testset "elixir_euler_weakform.jl (convergence)" begin + mean_convergence = convergence_test(@__MODULE__, + joinpath(EXAMPLES_DIR, + "elixir_euler_weakform.jl"), 2) + @test isapprox(mean_convergence[:l2], + [ + 4.243843382379403, + 4.128314378833922, + 4.128314378397532, + 4.081366752807379, + ], rtol = 0.05) +end - @trixi_testset "elixir_euler_weakform_periodic.jl" begin +@trixi_testset "elixir_euler_weakform_periodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weakform_periodic.jl"), - # division by 2.0 corresponds to normalization by the square root of the size of the domain - l2 = [0.0014986508075708323, 0.001528523420746786, 0.0015285234207473158, 0.004846505183839211] ./ 2.0, - linf = [0.0015062108658376872, 0.0019373508504645365, 0.0019373508504538783, 0.004742686826709086] - ) - end + # division by 2.0 corresponds to normalization by the square root of the size of the domain + l2=[ + 0.0014986508075708323, + 0.001528523420746786, + 0.0015285234207473158, + 0.004846505183839211, + ] ./ 2.0, + linf=[ + 0.0015062108658376872, + 0.0019373508504645365, + 0.0019373508504538783, + 0.004742686826709086, + ]) +end - @trixi_testset "elixir_euler_triangulate_pkg_mesh.jl" begin +@trixi_testset "elixir_euler_triangulate_pkg_mesh.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_triangulate_pkg_mesh.jl"), - l2 = [2.344080455438114e-6, 1.8610038753097983e-6, 2.4095165666095305e-6, 6.373308158814308e-6], - linf = [2.5099852761334418e-5, 2.2683684021362893e-5, 2.6180448559287584e-5, 5.5752932611508044e-5] - ) - end - - @trixi_testset "elixir_euler_kelvin_helmholtz_instability.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_kelvin_helmholtz_instability.jl"), - cells_per_dimension = (32, 32), tspan = (0.0, 0.2), - # division by 2.0 corresponds to normalization by the square root of the size of the domain - l2 = [0.11140378947116614, 0.06598161188703612, 0.10448953167839563, 0.16023209181809595] ./ 2.0, - linf = [0.24033843177853664, 0.1659992245272325, 0.1235468309508845, 0.26911424973147735] - ) - end - - @trixi_testset "elixir_euler_kelvin_helmholtz_instability.jl (Quadrilateral elements, GaussSBP)" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_kelvin_helmholtz_instability.jl"), - cells_per_dimension = (32, 32), element_type = Quad(), approximation_type=GaussSBP(), tspan = (0.0, 0.2), - # division by 2.0 corresponds to normalization by the square root of the size of the domain - l2 = [0.11141270656347146, 0.06598888014584121, 0.1044902203749932, 0.16023037364774995] ./ 2.0, - linf = [0.2414760062126462, 0.1662111846065654, 0.12344140473946856, 0.26978428189564774] - ) - end - - @trixi_testset "elixir_euler_rayleigh_taylor_instability.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_rayleigh_taylor_instability.jl"), - cells_per_dimension = (8, 8), tspan = (0.0, 0.2), - l2 = [0.0709665896982514, 0.005182828752164663, 0.013832655585206478, 0.03247013800580221], - linf = [0.4783963902824797, 0.022527207050681054, 0.040307056293369226, 0.0852365428206836] - ) - end - - @trixi_testset "elixir_euler_brown_minion_vortex.jl" begin + l2=[ + 2.344080455438114e-6, + 1.8610038753097983e-6, + 2.4095165666095305e-6, + 6.373308158814308e-6, + ], + linf=[ + 2.5099852761334418e-5, + 2.2683684021362893e-5, + 2.6180448559287584e-5, + 5.5752932611508044e-5, + ]) +end + +@trixi_testset "elixir_euler_kelvin_helmholtz_instability.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_kelvin_helmholtz_instability.jl"), + cells_per_dimension=(32, 32), tspan=(0.0, 0.2), + # division by 2.0 corresponds to normalization by the square root of the size of the domain + l2=[ + 0.11140378947116614, + 0.06598161188703612, + 0.10448953167839563, + 0.16023209181809595, + ] ./ 2.0, + linf=[ + 0.24033843177853664, + 0.1659992245272325, + 0.1235468309508845, + 0.26911424973147735, + ]) +end + +@trixi_testset "elixir_euler_kelvin_helmholtz_instability.jl (Quadrilateral elements, GaussSBP)" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_kelvin_helmholtz_instability.jl"), + cells_per_dimension=(32, 32), element_type=Quad(), + approximation_type=GaussSBP(), tspan=(0.0, 0.2), + # division by 2.0 corresponds to normalization by the square root of the size of the domain + l2=[ + 0.11141270656347146, + 0.06598888014584121, + 0.1044902203749932, + 0.16023037364774995, + ] ./ 2.0, + linf=[ + 0.2414760062126462, + 0.1662111846065654, + 0.12344140473946856, + 0.26978428189564774, + ]) +end + +@trixi_testset "elixir_euler_rayleigh_taylor_instability.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_rayleigh_taylor_instability.jl"), + cells_per_dimension=(8, 8), tspan=(0.0, 0.2), + l2=[ + 0.0709665896982514, + 0.005182828752164663, + 0.013832655585206478, + 0.03247013800580221, + ], + linf=[ + 0.4783963902824797, + 0.022527207050681054, + 0.040307056293369226, + 0.0852365428206836, + ]) +end + +@trixi_testset "elixir_euler_brown_minion_vortex.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_brown_minion_vortex.jl"), - cells_per_dimension = 4, tspan = (0.0, 0.1), - l2 = [0.006680001611078062, 0.02151676347585447, 0.010696524235364626, 0.15052841129694647], - linf = [0.01544756362800248, 0.09517304772476806, 0.021957154972646383, 0.33773439650806303] - ) - end + cells_per_dimension=4, tspan=(0.0, 0.1), + l2=[ + 0.006680001611078062, + 0.02151676347585447, + 0.010696524235364626, + 0.15052841129694647, + ], + linf=[ + 0.01544756362800248, + 0.09517304772476806, + 0.021957154972646383, + 0.33773439650806303, + ]) +end - @trixi_testset "elixir_euler_shockcapturing.jl" begin +@trixi_testset "elixir_euler_shockcapturing.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing.jl"), - cells_per_dimension = 4, tspan = (0.0, 0.1), - l2 = [0.05685148333985476, 0.04308122135907089, 0.043081221359070915, 0.21098131003847664], - linf = [0.2360672306096051, 0.16684417686971842, 0.1668441768697189, 0.8572572782118661] - ) - end + cells_per_dimension=4, tspan=(0.0, 0.1), + l2=[ + 0.05685148333985476, + 0.04308122135907089, + 0.043081221359070915, + 0.21098131003847664, + ], + linf=[ + 0.2360672306096051, + 0.16684417686971842, + 0.1668441768697189, + 0.8572572782118661, + ]) +end - @trixi_testset "elixir_euler_shockcapturing_curved.jl" begin +@trixi_testset "elixir_euler_shockcapturing_curved.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing_curved.jl"), - cells_per_dimension = 4, tspan = (0.0, 0.1), - l2 = [0.05565849298766252, 0.042322816017256494, 0.042322816017256466, 0.2064212098324083], - linf = [0.23633287875008924, 0.16930148707515683, 0.16930148707515688, 0.8587706761131937] - ) - end - + cells_per_dimension=4, tspan=(0.0, 0.1), + l2=[ + 0.05565849298766252, + 0.042322816017256494, + 0.042322816017256466, + 0.2064212098324083, + ], + linf=[ + 0.23633287875008924, + 0.16930148707515683, + 0.16930148707515688, + 0.8587706761131937, + ]) +end - @trixi_testset "elixir_euler_weakform.jl (FD SBP)" begin +@trixi_testset "elixir_euler_weakform.jl (FD SBP)" begin + global D = derivative_operator(SummationByPartsOperators.MattssonNordström2004(), + derivative_order = 1, + accuracy_order = 4, + xmin = 0.0, xmax = 1.0, + N = 12) @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weakform.jl"), - cells_per_dimension = (2, 2), - element_type = Quad(), - cfl = 1.0, - approximation_type = derivative_operator( - SummationByPartsOperators.MattssonNordström2004(), - derivative_order=1, accuracy_order=4, - xmin=0.0, xmax=1.0, N=12), - # division by 2.0 corresponds to normalization by the square root of the size of the domain - l2 = [0.0008966318978421226, 0.0011418826379110242, 0.001141882637910878, 0.0030918374335671393] ./ 2.0, - linf = [0.0015281525343109337, 0.00162430960401716, 0.0016243096040242655, 0.004447503691245913] - ) - end - - @trixi_testset "elixir_euler_weakform.jl (FD SBP, EC)" begin + cells_per_dimension=(2, 2), + element_type=Quad(), + cfl=1.0, + approximation_type=D, + # division by 2.0 corresponds to normalization by the square root of the size of the domain + l2=[ + 0.0008966318978421226, + 0.0011418826379110242, + 0.001141882637910878, + 0.0030918374335671393, + ] ./ 2.0, + linf=[ + 0.0015281525343109337, + 0.00162430960401716, + 0.0016243096040242655, + 0.004447503691245913, + ]) +end + +@trixi_testset "elixir_euler_weakform.jl (FD SBP, EC)" begin + global D = derivative_operator(SummationByPartsOperators.MattssonNordström2004(), + derivative_order = 1, + accuracy_order = 4, + xmin = 0.0, xmax = 1.0, + N = 12) @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weakform.jl"), - cells_per_dimension = (2, 2), - element_type = Quad(), - cfl = 1.0, - approximation_type = derivative_operator( - SummationByPartsOperators.MattssonNordström2004(), - derivative_order=1, accuracy_order=4, - xmin=0.0, xmax=1.0, N=12), - volume_integral = VolumeIntegralFluxDifferencing(flux_ranocha), - surface_integral = SurfaceIntegralWeakForm(flux_ranocha), - # division by 2.0 corresponds to normalization by the square root of the size of the domain - l2 = [0.0014018725496871129, 0.0015887007320868913, 0.001588700732086329, 0.003870926821031202] ./ 2.0, - linf = [0.0029541996523780867, 0.0034520465226108854, 0.003452046522624652, 0.007677153211004928] - ) - end - - @trixi_testset "elixir_euler_fdsbp_periodic.jl" begin + cells_per_dimension=(2, 2), + element_type=Quad(), + cfl=1.0, + approximation_type=D, + volume_integral=VolumeIntegralFluxDifferencing(flux_ranocha), + surface_integral=SurfaceIntegralWeakForm(flux_ranocha), + # division by 2.0 corresponds to normalization by the square root of the size of the domain + l2=[ + 0.0014018725496871129, + 0.0015887007320868913, + 0.001588700732086329, + 0.003870926821031202, + ] ./ 2.0, + linf=[ + 0.0029541996523780867, + 0.0034520465226108854, + 0.003452046522624652, + 0.007677153211004928, + ]) +end + +@trixi_testset "elixir_euler_fdsbp_periodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_fdsbp_periodic.jl"), - l2 = [1.3333320340010056e-6, 2.044834627970641e-6, 2.044834627855601e-6, 5.282189803559564e-6], - linf = [2.7000151718858945e-6, 3.988595028259212e-6, 3.9885950273710336e-6, 8.848583042286862e-6] - ) - end + l2=[ + 1.3333320340010056e-6, + 2.044834627970641e-6, + 2.044834627855601e-6, + 5.282189803559564e-6, + ], + linf=[ + 2.7000151718858945e-6, + 3.988595028259212e-6, + 3.9885950273710336e-6, + 8.848583042286862e-6, + ]) +end - @trixi_testset "elixir_euler_fdsbp_periodic.jl (arbitrary reference domain)" begin +@trixi_testset "elixir_euler_fdsbp_periodic.jl (arbitrary reference domain)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_fdsbp_periodic.jl"), - xmin=-200.0, xmax=100.0 #= parameters for reference interval =#, - l2 = [1.333332034149886e-6, 2.0448346280892024e-6, 2.0448346279766305e-6, 5.282189803510037e-6], - linf = [2.700015170553627e-6, 3.988595024262409e-6, 3.988595024928543e-6, 8.84858303740188e-6] - ) - end + xmin=-200.0, xmax=100.0, #= parameters for reference interval =# + l2=[ + 1.333332034149886e-6, + 2.0448346280892024e-6, + 2.0448346279766305e-6, + 5.282189803510037e-6, + ], + linf=[ + 2.700015170553627e-6, + 3.988595024262409e-6, + 3.988595024928543e-6, + 8.84858303740188e-6, + ]) +end - @trixi_testset "elixir_euler_fdsbp_periodic.jl (arbitrary reference and physical domains)" begin +@trixi_testset "elixir_euler_fdsbp_periodic.jl (arbitrary reference and physical domains)" begin + global D = periodic_derivative_operator(derivative_order = 1, + accuracy_order = 4, + xmin = -200.0, + xmax = 100.0, + N = 100) @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_fdsbp_periodic.jl"), - approximation_type = periodic_derivative_operator( - derivative_order=1, accuracy_order=4, xmin=-200.0, xmax=100.0, N=100), - coordinates_min=(-3.0, -4.0), coordinates_max=(0.0, -1.0), - l2 = [0.07318831033918516, 0.10039910610067465, 0.1003991061006748, 0.2642450566234564], - linf = [0.36081081739439735, 0.5244468027020845, 0.5244468027020814, 1.2210130256735705] - ) - end - - @trixi_testset "elixir_euler_fdsbp_periodic.jl (CGSEM)" begin + approximation_type=D, + coordinates_min=(-3.0, -4.0), coordinates_max=(0.0, -1.0), + l2=[ + 0.07318831033918516, + 0.10039910610067465, + 0.1003991061006748, + 0.2642450566234564, + ], + linf=[ + 0.36081081739439735, + 0.5244468027020845, + 0.5244468027020814, + 1.2210130256735705, + ]) +end + +@trixi_testset "elixir_euler_fdsbp_periodic.jl (CGSEM)" begin + D_local = SummationByPartsOperators.legendre_derivative_operator(xmin = 0.0, + xmax = 1.0, + N = 4) + mesh_local = SummationByPartsOperators.UniformPeriodicMesh1D(xmin = -1.0, + xmax = 1.0, + Nx = 10) + global D = SummationByPartsOperators.couple_continuously(D_local, mesh_local) @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_fdsbp_periodic.jl"), - approximation_type = SummationByPartsOperators.couple_continuously( - SummationByPartsOperators.legendre_derivative_operator(xmin=0.0, xmax=1.0, N=4), - SummationByPartsOperators.UniformPeriodicMesh1D(xmin=-1.0, xmax=1.0, Nx=10)), - l2 = [1.5440402410017893e-5, 1.4913189903083485e-5, 1.4913189902797073e-5, 2.6104615985156992e-5], - linf = [4.16334345412217e-5, 5.067812788173143e-5, 5.067812786885284e-5, 9.887976803746312e-5] - ) - end - - @trixi_testset "elixir_mhd_weak_blast_wave.jl (Quad)" begin + approximation_type=D, + l2=[ + 1.5440402410017893e-5, + 1.4913189903083485e-5, + 1.4913189902797073e-5, + 2.6104615985156992e-5, + ], + linf=[ + 4.16334345412217e-5, + 5.067812788173143e-5, + 5.067812786885284e-5, + 9.887976803746312e-5, + ]) +end + +@trixi_testset "elixir_mhd_weak_blast_wave.jl (Quad)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_weak_blast_wave.jl"), - cells_per_dimension = 4, - l2 = [0.03906769915509508, 0.04923079758984701, 0.049230797589847136, 0.02660348840973283, - 0.18054907061740028, 0.019195256934309846, 0.019195256934310016, 0.027856113419468087, - 0.0016567799774264065], - linf = [0.16447597822733662, 0.244157345789029, 0.24415734578903472, 0.11982440036793476, - 0.7450328339751362, 0.06357382685763713, 0.0635738268576378, 0.1058830287485999, - 0.005740591170062146] - ) - end - - @trixi_testset "elixir_mhd_weak_blast_wave.jl (Tri)" begin + cells_per_dimension=4, + l2=[0.03906769915509508, 0.04923079758984701, + 0.049230797589847136, 0.02660348840973283, + 0.18054907061740028, 0.019195256934309846, + 0.019195256934310016, 0.027856113419468087, + 0.0016567799774264065], + linf=[0.16447597822733662, 0.244157345789029, + 0.24415734578903472, 0.11982440036793476, + 0.7450328339751362, 0.06357382685763713, 0.0635738268576378, + 0.1058830287485999, + 0.005740591170062146]) +end + +@trixi_testset "elixir_mhd_weak_blast_wave.jl (Tri)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_weak_blast_wave.jl"), - cells_per_dimension = 4, element_type = Tri(), - l2 = [0.03372468091254386, 0.03971626483409167, 0.03971626483409208, 0.021427571421535722, - 0.15079331840847413, 0.015716300366650286, 0.015716300366652128, 0.022365252076279075, - 0.0009232971979900358], - linf = [0.16290247390873458, 0.2256891306641319, 0.2256891306641336, 0.09476017042552534, - 0.6906308908961734, 0.05349939593012487, 0.05349939593013042, 0.08830587480616725, - 0.0029551359803035027] - ) - end - - @trixi_testset "elixir_mhd_weak_blast_wave_SBP.jl (Quad)" begin + cells_per_dimension=4, element_type=Tri(), + l2=[0.03372468091254386, 0.03971626483409167, + 0.03971626483409208, 0.021427571421535722, + 0.15079331840847413, 0.015716300366650286, + 0.015716300366652128, 0.022365252076279075, + 0.0009232971979900358], + linf=[0.16290247390873458, 0.2256891306641319, + 0.2256891306641336, 0.09476017042552534, + 0.6906308908961734, 0.05349939593012487, + 0.05349939593013042, 0.08830587480616725, + 0.0029551359803035027]) +end + +@trixi_testset "elixir_mhd_weak_blast_wave_SBP.jl (Quad)" begin # These setups do not pass CI reliably, see # https://github.com/trixi-framework/Trixi.jl/pull/880 and # https://github.com/trixi-framework/Trixi.jl/issues/881 - @test_skip @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_weak_blast_wave_SBP.jl"), - cells_per_dimension = 4, - # division by 2.0 corresponds to normalization by the square root of the size of the domain - l2 = [0.15825983698241494, 0.19897219694837923, 0.19784182473275247, 0.10482833997417325, - 0.7310752391255246, 0.07374056714564853, 0.07371172293240634, 0.10782032253431281, - 0.004921676235111545] ./ 2.0, - linf = [0.1765644464978685, 0.2627803272865769, 0.26358136695848144, 0.12347681727447984, - 0.7733289736898254, 0.06695360844467957, 0.06650382120802623, 0.10885097000919097, - 0.007212567638078835] - ) - end - - @trixi_testset "elixir_mhd_weak_blast_wave_SBP.jl (Tri)" begin + @test_skip @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_mhd_weak_blast_wave_SBP.jl"), + cells_per_dimension=4, + # division by 2.0 corresponds to normalization by the square root of the size of the domain + l2=[0.15825983698241494, 0.19897219694837923, + 0.19784182473275247, 0.10482833997417325, + 0.7310752391255246, 0.07374056714564853, + 0.07371172293240634, 0.10782032253431281, + 0.004921676235111545] ./ 2.0, + linf=[0.1765644464978685, 0.2627803272865769, + 0.26358136695848144, 0.12347681727447984, + 0.7733289736898254, 0.06695360844467957, + 0.06650382120802623, 0.10885097000919097, + 0.007212567638078835]) +end + +@trixi_testset "elixir_mhd_weak_blast_wave_SBP.jl (Tri)" begin # These setups do not pass CI reliably, see # https://github.com/trixi-framework/Trixi.jl/pull/880 and # https://github.com/trixi-framework/Trixi.jl/issues/881 - @test_skip @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_weak_blast_wave_SBP.jl"), - cells_per_dimension = 4, element_type=Tri(), tspan = (0.0, 0.2), - # division by 2.0 corresponds to normalization by the square root of the size of the domain - l2 = [0.13825044764021147, 0.15472815448314997, 0.1549093274293255, 0.053103596213755405, - 0.7246162776815603, 0.07730777596615901, 0.07733438386480523, 0.109893463921706, - 0.00617678167062838] ./ 2.0, - linf = [0.22701306227317952, 0.2905255794821543, 0.2912409425436937, 0.08051361477962096, - 1.0842974228656006, 0.07866000368926784, 0.0786646354518149, 0.1614896380292925, - 0.010358210347485542] - ) - end - - @trixi_testset "elixir_mhd_reflective_wall.jl (Quad)" begin + @test_skip @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_mhd_weak_blast_wave_SBP.jl"), + cells_per_dimension=4, element_type=Tri(), + tspan=(0.0, 0.2), + # division by 2.0 corresponds to normalization by the square root of the size of the domain + l2=[0.13825044764021147, 0.15472815448314997, + 0.1549093274293255, 0.053103596213755405, + 0.7246162776815603, 0.07730777596615901, + 0.07733438386480523, 0.109893463921706, + 0.00617678167062838] ./ 2.0, + linf=[0.22701306227317952, 0.2905255794821543, + 0.2912409425436937, 0.08051361477962096, + 1.0842974228656006, 0.07866000368926784, + 0.0786646354518149, 0.1614896380292925, + 0.010358210347485542]) +end + +@trixi_testset "elixir_mhd_reflective_wall.jl (Quad)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_reflective_wall.jl"), - cells_per_dimension = 4, - l2 = [0.0036019536614619687, 0.001734097206958611, 0.008375221008997178, 0.0, 0.028596796602124414, 0.0018573693138866614, 0.0020807798141551166, 0.0, 5.301188920230166e-5], - linf = [0.01692601228199253, 0.009369662298436778, 0.04145169295835428, 0.0, 0.11569908670112738, 0.00984964453299233, 0.01141708032148614, 0.0, 0.0002992631411931389] - ) - end + cells_per_dimension=4, + l2=[ + 0.0036019536614619687, + 0.001734097206958611, + 0.008375221008997178, + 0.0, + 0.028596796602124414, + 0.0018573693138866614, + 0.0020807798141551166, + 0.0, + 5.301188920230166e-5, + ], + linf=[ + 0.01692601228199253, + 0.009369662298436778, + 0.04145169295835428, + 0.0, + 0.11569908670112738, + 0.00984964453299233, + 0.01141708032148614, + 0.0, + 0.0002992631411931389, + ]) +end - @trixi_testset "elixir_shallowwater_source_terms.jl (Quad, SBP)" begin +@trixi_testset "elixir_shallowwater_source_terms.jl (Quad, SBP)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), - cells_per_dimension = 8, element_type = Quad(), approximation_type = SBP(), - l2 = [0.0020316462913319046, 0.023669019044882247, 0.03446194752754684, 1.9333465252381796e-15], - linf = [0.010385010095182778, 0.08750628939565086, 0.12088392994348407, 9.325873406851315e-15] - ) - end + cells_per_dimension=8, element_type=Quad(), + approximation_type=SBP(), + l2=[ + 0.0020316462913319046, + 0.023669019044882247, + 0.03446194752754684, + 1.9333465252381796e-15, + ], + linf=[ + 0.010385010095182778, + 0.08750628939565086, + 0.12088392994348407, + 9.325873406851315e-15, + ]) +end - @trixi_testset "elixir_shallowwater_source_terms.jl (Tri, SBP)" begin +@trixi_testset "elixir_shallowwater_source_terms.jl (Tri, SBP)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), - cells_per_dimension = 8, element_type = Tri(), approximation_type = SBP(), - l2 = [0.004180680322490383, 0.07026192411558974, 0.11815151697006446, 2.329788936151192e-15], - linf = [0.02076003852980346, 0.29169601664914424, 0.5674183379872275, 1.1546319456101628e-14] - ) - end + cells_per_dimension=8, element_type=Tri(), + approximation_type=SBP(), + l2=[ + 0.004180680322490383, + 0.07026192411558974, + 0.11815151697006446, + 2.329788936151192e-15, + ], + linf=[ + 0.02076003852980346, + 0.29169601664914424, + 0.5674183379872275, + 1.1546319456101628e-14, + ]) +end - @trixi_testset "elixir_shallowwater_source_terms.jl (Tri, Polynomial)" begin +@trixi_testset "elixir_shallowwater_source_terms.jl (Tri, Polynomial)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), - cells_per_dimension = 8, element_type = Tri(), approximation_type = Polynomial(), - # The last l2, linf error are the L2 projection error in approximating `b`, so they are not - # zero for general non-collocated quadrature rules (e.g., for `element_type=Tri()`, `polydeg > 2`). - l2 = [0.0008309356912456799, 0.01522451288799231, 0.016033969387208476, 1.2820247308150876e-5], - linf = [0.001888045014140971, 0.05466838692127718, 0.06345885709961152, 3.3989933098554914e-5] - ) - end - - @trixi_testset "elixir_shallowwater_source_terms.jl (Quad, Polynomial)" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), - cells_per_dimension = 8, element_type = Quad(), approximation_type = Polynomial(), - # The last l2, linf error are the L2 projection error in approximating `b`. However, this is zero - # for `Quad()` elements with `Polynomial()` approximations because the quadrature rule defaults to - # a `(polydeg + 1)`-point Gauss quadrature rule in each coordinate (in general, StartUpDG.jl defaults - # to the quadrature rule with the fewest number of points which exactly integrates the mass matrix). - l2 = [7.460461950323111e-5, 0.003685589808444905, 0.0039101604749887785, 2.0636891126652983e-15], - linf = [0.000259995400729629, 0.0072236204211630906, 0.010364675200833062, 1.021405182655144e-14] - ) - end - + cells_per_dimension=8, element_type=Tri(), + approximation_type=Polynomial(), + # The last l2, linf error are the L2 projection error in approximating `b`, so they are not + # zero for general non-collocated quadrature rules (e.g., for `element_type=Tri()`, `polydeg > 2`). + l2=[ + 0.0008309356912456799, + 0.01522451288799231, + 0.016033969387208476, + 1.2820247308150876e-5, + ], + linf=[ + 0.001888045014140971, + 0.05466838692127718, + 0.06345885709961152, + 3.3989933098554914e-5, + ]) +end +@trixi_testset "elixir_shallowwater_source_terms.jl (Quad, Polynomial)" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), + cells_per_dimension=8, element_type=Quad(), + approximation_type=Polynomial(), + # The last l2, linf error are the L2 projection error in approximating `b`. However, this is zero + # for `Quad()` elements with `Polynomial()` approximations because the quadrature rule defaults to + # a `(polydeg + 1)`-point Gauss quadrature rule in each coordinate (in general, StartUpDG.jl defaults + # to the quadrature rule with the fewest number of points which exactly integrates the mass matrix). + l2=[ + 7.460461950323111e-5, + 0.003685589808444905, + 0.0039101604749887785, + 2.0636891126652983e-15, + ], + linf=[ + 0.000259995400729629, + 0.0072236204211630906, + 0.010364675200833062, + 1.021405182655144e-14, + ]) +end end # Clean up afterwards: delete Trixi.jl output directory -@test_nowarn isdir(outdir) && rm(outdir, recursive=true) +@test_nowarn isdir(outdir) && rm(outdir, recursive = true) end # module diff --git a/test/test_dgmulti_3d.jl b/test/test_dgmulti_3d.jl index d2556ae434b..3a1db255484 100644 --- a/test/test_dgmulti_3d.jl +++ b/test/test_dgmulti_3d.jl @@ -9,252 +9,402 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "dgmulti_3d") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) @testset "DGMulti 3D" begin - # 3d tet/hex tests - @trixi_testset "elixir_euler_weakform.jl" begin +#! format: noindent + +# 3d tet/hex tests +@trixi_testset "elixir_euler_weakform.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weakform.jl"), - # division by sqrt(8.0) corresponds to normalization by the square root of the size of the domain - l2 = [0.0010029534292051608, 0.0011682205957721673, 0.001072975385793516, 0.000997247778892257, 0.0039364354651358294] ./ sqrt(8), - linf = [0.003660737033303718, 0.005625620600749226, 0.0030566354814669516, 0.0041580358824311325, 0.019326660236036464] - ) - # 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 + # division by sqrt(8.0) corresponds to normalization by the square root of the size of the domain + l2=[ + 0.0010029534292051608, + 0.0011682205957721673, + 0.001072975385793516, + 0.000997247778892257, + 0.0039364354651358294, + ] ./ sqrt(8), + linf=[ + 0.003660737033303718, + 0.005625620600749226, + 0.0030566354814669516, + 0.0041580358824311325, + 0.019326660236036464, + ]) + # 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 - @trixi_testset "elixir_euler_weakform.jl (EC)" begin +@trixi_testset "elixir_euler_weakform.jl (EC)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weakform.jl"), - surface_integral = SurfaceIntegralWeakForm(flux_ranocha), - volume_integral = VolumeIntegralFluxDifferencing(flux_ranocha), - # division by sqrt(8.0) corresponds to normalization by the square root of the size of the domain - l2 = [0.014932088450136542, 0.017080219613061526, 0.016589517840793006, 0.015905000907070196, 0.03903416208587798] ./ sqrt(8), - linf = [0.06856547797256729, 0.08225664880340489, 0.06925055630951782, 0.06913016119820181, 0.19161418499621874] - ) - # 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 + surface_integral=SurfaceIntegralWeakForm(flux_ranocha), + volume_integral=VolumeIntegralFluxDifferencing(flux_ranocha), + # division by sqrt(8.0) corresponds to normalization by the square root of the size of the domain + l2=[ + 0.014932088450136542, + 0.017080219613061526, + 0.016589517840793006, + 0.015905000907070196, + 0.03903416208587798, + ] ./ sqrt(8), + linf=[ + 0.06856547797256729, + 0.08225664880340489, + 0.06925055630951782, + 0.06913016119820181, + 0.19161418499621874, + ]) + # 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 - @trixi_testset "elixir_euler_weakform.jl (Hexahedral elements)" begin +@trixi_testset "elixir_euler_weakform.jl (Hexahedral elements)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weakform.jl"), - element_type = Hex(), - # division by sqrt(8.0) corresponds to normalization by the square root of the size of the domain - l2 = [0.00030580190715769566, 0.00040146357607439464, 0.00040146357607564597, 0.000401463576075708, 0.0015749412434154315] ./ sqrt(8), - linf = [0.00036910287847780054, 0.00042659774184228283, 0.0004265977427213574, 0.00042659774250686233, 0.00143803344597071] - ) - # 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 + element_type=Hex(), + # division by sqrt(8.0) corresponds to normalization by the square root of the size of the domain + l2=[ + 0.00030580190715769566, + 0.00040146357607439464, + 0.00040146357607564597, + 0.000401463576075708, + 0.0015749412434154315, + ] ./ sqrt(8), + linf=[ + 0.00036910287847780054, + 0.00042659774184228283, + 0.0004265977427213574, + 0.00042659774250686233, + 0.00143803344597071, + ]) + # 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 - @trixi_testset "elixir_euler_curved.jl (Hex elements, SBP, flux differencing)" begin +@trixi_testset "elixir_euler_curved.jl (Hex elements, SBP, flux differencing)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_curved.jl"), - l2 = [0.018354883045936066, 0.024412704052042846, 0.024408520416087945, 0.01816314570880129, 0.039342805507972006], - linf = [0.14862225990775757, 0.28952368161864683, 0.2912054484817035, 0.1456603133854122, 0.3315354586775472] - ) - # 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 + l2=[ + 0.018354883045936066, + 0.024412704052042846, + 0.024408520416087945, + 0.01816314570880129, + 0.039342805507972006, + ], + linf=[ + 0.14862225990775757, + 0.28952368161864683, + 0.2912054484817035, + 0.1456603133854122, + 0.3315354586775472, + ]) + # 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 - @trixi_testset "elixir_euler_curved.jl (Hex elements, GaussSBP, flux differencing)" begin +@trixi_testset "elixir_euler_curved.jl (Hex elements, GaussSBP, flux differencing)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_curved.jl"), - approximation_type=GaussSBP(), - l2 = [0.002631131519508634, 0.0029144224044954105, 0.002913889110662827, 0.002615140832314194, 0.006881528610614373], - linf = [0.020996114874140215, 0.021314522450134543, 0.021288322783006297, 0.020273381695435244, 0.052598740390024545] - ) - # 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 + approximation_type=GaussSBP(), + l2=[ + 0.002631131519508634, + 0.0029144224044954105, + 0.002913889110662827, + 0.002615140832314194, + 0.006881528610614373, + ], + linf=[ + 0.020996114874140215, + 0.021314522450134543, + 0.021288322783006297, + 0.020273381695435244, + 0.052598740390024545, + ]) + # 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 - @trixi_testset "elixir_euler_weakform_periodic.jl" begin +@trixi_testset "elixir_euler_weakform_periodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weakform_periodic.jl"), - # division by sqrt(8.0) corresponds to normalization by the square root of the size of the domain - l2 = [0.0010317074322517949, 0.0012277090547035293, 0.0011273991123913515, 0.0010418496196130177, 0.004058878478404962] ./ sqrt(8), - linf = [0.003227752881827861, 0.005620317864620361, 0.0030514833972379307, 0.003987027618439498, 0.019282224709831652] - ) - # 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 + # division by sqrt(8.0) corresponds to normalization by the square root of the size of the domain + l2=[ + 0.0010317074322517949, + 0.0012277090547035293, + 0.0011273991123913515, + 0.0010418496196130177, + 0.004058878478404962, + ] ./ sqrt(8), + linf=[ + 0.003227752881827861, + 0.005620317864620361, + 0.0030514833972379307, + 0.003987027618439498, + 0.019282224709831652, + ]) + # 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 - @trixi_testset "elixir_euler_weakform_periodic.jl (Hexahedral elements)" begin +@trixi_testset "elixir_euler_weakform_periodic.jl (Hexahedral elements)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weakform_periodic.jl"), - element_type = Hex(), - # division by sqrt(8.0) corresponds to normalization by the square root of the size of the domain - l2 = [0.00034230612468547436, 0.00044397204714598747, 0.0004439720471461567, 0.0004439720471464591, 0.0016639410646990126] ./ sqrt(8), - linf = [0.0003674374460325147, 0.0004253921341716982, 0.0004253921340786615, 0.0004253921340831024, 0.0014333414071048267] - ) - # 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 + element_type=Hex(), + # division by sqrt(8.0) corresponds to normalization by the square root of the size of the domain + l2=[ + 0.00034230612468547436, + 0.00044397204714598747, + 0.0004439720471461567, + 0.0004439720471464591, + 0.0016639410646990126, + ] ./ sqrt(8), + linf=[ + 0.0003674374460325147, + 0.0004253921341716982, + 0.0004253921340786615, + 0.0004253921340831024, + 0.0014333414071048267, + ]) + # 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 - @trixi_testset "elixir_euler_weakform_periodic.jl (Hexahedral elements, SBP, EC)" begin +@trixi_testset "elixir_euler_weakform_periodic.jl (Hexahedral elements, SBP, EC)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weakform_periodic.jl"), - element_type = Hex(), - volume_integral = VolumeIntegralFluxDifferencing(flux_ranocha), - surface_integral = SurfaceIntegralWeakForm(flux_ranocha), - approximation_type = SBP(), - # division by sqrt(8.0) corresponds to normalization by the square root of the size of the domain - l2 = [0.001712443468716032, 0.002491315550718859, 0.0024913155507195303, 0.002491315550720031, 0.008585818982343299] ./ sqrt(8), - linf = [0.003810078279323559, 0.004998778644230928, 0.004998778643986235, 0.0049987786444081195, 0.016455044373650196] - ) - # 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 + element_type=Hex(), + volume_integral=VolumeIntegralFluxDifferencing(flux_ranocha), + surface_integral=SurfaceIntegralWeakForm(flux_ranocha), + approximation_type=SBP(), + # division by sqrt(8.0) corresponds to normalization by the square root of the size of the domain + l2=[ + 0.001712443468716032, + 0.002491315550718859, + 0.0024913155507195303, + 0.002491315550720031, + 0.008585818982343299, + ] ./ sqrt(8), + linf=[ + 0.003810078279323559, + 0.004998778644230928, + 0.004998778643986235, + 0.0049987786444081195, + 0.016455044373650196, + ]) + # 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 - @trixi_testset "elixir_euler_taylor_green_vortex.jl" begin +@trixi_testset "elixir_euler_taylor_green_vortex.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_taylor_green_vortex.jl"), - polydeg = 3, tspan = (0.0, 1.0), cells_per_dimension = (2, 2, 2), - l2 = [0.0003612827827560599, 0.06219350883951729, 0.062193508839503864, 0.08121963221634831, 0.07082703570808184], - linf = [0.0007893509649821162, 0.1481953939988877, 0.14819539399791176, 0.14847291108358926, 0.21313533492212855] - ) - # 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 + polydeg=3, tspan=(0.0, 1.0), cells_per_dimension=(2, 2, 2), + l2=[ + 0.0003612827827560599, + 0.06219350883951729, + 0.062193508839503864, + 0.08121963221634831, + 0.07082703570808184, + ], + linf=[ + 0.0007893509649821162, + 0.1481953939988877, + 0.14819539399791176, + 0.14847291108358926, + 0.21313533492212855, + ]) + # 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 - @trixi_testset "elixir_euler_taylor_green_vortex.jl (GaussSBP)" begin +@trixi_testset "elixir_euler_taylor_green_vortex.jl (GaussSBP)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_taylor_green_vortex.jl"), - polydeg = 3, approximation_type = GaussSBP(), tspan = (0.0, 1.0), cells_per_dimension = (2, 2, 2), - l2 = [0.00036128278275524326, 0.062193508839511434, 0.06219350883949677, 0.08121963221635205, 0.07082703570765223], - linf = [0.000789350964946367, 0.14819539399525805, 0.14819539399590542, 0.14847291107658706, 0.21313533492059378] - ) - # 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 + polydeg=3, approximation_type=GaussSBP(), tspan=(0.0, 1.0), + cells_per_dimension=(2, 2, 2), + l2=[ + 0.00036128278275524326, + 0.062193508839511434, + 0.06219350883949677, + 0.08121963221635205, + 0.07082703570765223, + ], + linf=[ + 0.000789350964946367, + 0.14819539399525805, + 0.14819539399590542, + 0.14847291107658706, + 0.21313533492059378, + ]) + # 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 - @trixi_testset "elixir_euler_weakform_periodic.jl (FD SBP)" begin +@trixi_testset "elixir_euler_weakform_periodic.jl (FD SBP)" begin + global D = derivative_operator(SummationByPartsOperators.MattssonNordström2004(), + derivative_order = 1, + accuracy_order = 2, + xmin = 0.0, xmax = 1.0, + N = 8) @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weakform_periodic.jl"), - element_type = Hex(), - cells_per_dimension = (2, 2, 2), - approximation_type = derivative_operator( - SummationByPartsOperators.MattssonNordström2004(), - derivative_order=1, accuracy_order=2, - xmin=0.0, xmax=1.0, N=8), - l2 = [0.0024092707138829925, 0.003318758964118284, 0.0033187589641182386, 0.003318758964118252, 0.012689348410504253], - linf = [0.006118565824207778, 0.008486456080185167, 0.008486456080180282, 0.008486456080185611, 0.035113544599208346] - ) - # 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 + element_type=Hex(), + cells_per_dimension=(2, 2, 2), + approximation_type=D, + l2=[ + 0.0024092707138829925, + 0.003318758964118284, + 0.0033187589641182386, + 0.003318758964118252, + 0.012689348410504253, + ], + linf=[ + 0.006118565824207778, + 0.008486456080185167, + 0.008486456080180282, + 0.008486456080185611, + 0.035113544599208346, + ]) + # 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 - @trixi_testset "elixir_euler_weakform_periodic.jl (FD SBP, EC)" begin +@trixi_testset "elixir_euler_weakform_periodic.jl (FD SBP, EC)" begin + global D = derivative_operator(SummationByPartsOperators.MattssonNordström2004(), + derivative_order = 1, + accuracy_order = 2, + xmin = 0.0, xmax = 1.0, + N = 8) @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_weakform_periodic.jl"), - element_type = Hex(), - cells_per_dimension = (2, 2, 2), - approximation_type = derivative_operator( - SummationByPartsOperators.MattssonNordström2004(), - derivative_order=1, accuracy_order=2, - xmin=0.0, xmax=1.0, N=8), - volume_integral = VolumeIntegralFluxDifferencing(flux_ranocha), - surface_integral = SurfaceIntegralWeakForm(flux_ranocha), - l2 = [0.0034543609010604407, 0.004944363692625066, 0.0049443636926250435, 0.004944363692625037, 0.01788695279620914], - linf = [0.013861851418853988, 0.02126572106620328, 0.021265721066209053, 0.021265721066210386, 0.0771455289446683] - ) - # 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 + element_type=Hex(), + cells_per_dimension=(2, 2, 2), + approximation_type=D, + volume_integral=VolumeIntegralFluxDifferencing(flux_ranocha), + surface_integral=SurfaceIntegralWeakForm(flux_ranocha), + l2=[ + 0.0034543609010604407, + 0.004944363692625066, + 0.0049443636926250435, + 0.004944363692625037, + 0.01788695279620914, + ], + linf=[ + 0.013861851418853988, + 0.02126572106620328, + 0.021265721066209053, + 0.021265721066210386, + 0.0771455289446683, + ]) + # 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 - @trixi_testset "elixir_euler_fdsbp_periodic.jl" begin +@trixi_testset "elixir_euler_fdsbp_periodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_fdsbp_periodic.jl"), - l2 = [7.561896970325353e-5, 6.884047859361093e-5, 6.884047859363204e-5, 6.884047859361148e-5, 0.000201107274617457], - linf = [0.0001337520020225913, 0.00011571467799287305, 0.0001157146779990903, 0.00011571467799376123, 0.0003446082308800058] - ) - # 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 + l2=[ + 7.561896970325353e-5, + 6.884047859361093e-5, + 6.884047859363204e-5, + 6.884047859361148e-5, + 0.000201107274617457, + ], + linf=[ + 0.0001337520020225913, + 0.00011571467799287305, + 0.0001157146779990903, + 0.00011571467799376123, + 0.0003446082308800058, + ]) + # 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 - @trixi_testset "elixir_advection_tensor_wedge.jl" begin +@trixi_testset "elixir_advection_tensor_wedge.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_tensor_wedge.jl"), - l2 = [2.30487910e-04] , - linf = [6.31795281e-04] ) - # 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 + l2=[2.30487910e-04], + linf=[6.31795281e-04]) + # 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 end # Clean up afterwards: delete Trixi.jl output directory -@test_nowarn isdir(outdir) && rm(outdir, recursive=true) +@test_nowarn isdir(outdir) && rm(outdir, recursive = true) end # module diff --git a/test/test_mpi.jl b/test/test_mpi.jl index 34febf7e268..ad1ba4e835d 100644 --- a/test/test_mpi.jl +++ b/test/test_mpi.jl @@ -7,7 +7,7 @@ include("test_trixi.jl") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) +Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive = true) # CI with MPI and some tests fails often on Windows. Thus, we check whether this # is the case here. We use GitHub Actions, so we can check whether we run CI @@ -16,33 +16,32 @@ Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) CI_ON_WINDOWS = (get(ENV, "GITHUB_ACTIONS", false) == "true") && Sys.iswindows() @testset "MPI" begin - # TreeMesh tests - include("test_mpi_tree.jl") - - # P4estMesh tests - include("test_mpi_p4est_2d.jl") - if !CI_ON_WINDOWS # see comment on `CI_ON_WINDOWS` above - include("test_mpi_p4est_3d.jl") - end + # TreeMesh tests + include("test_mpi_tree.jl") + + # P4estMesh tests + include("test_mpi_p4est_2d.jl") + if !CI_ON_WINDOWS # see comment on `CI_ON_WINDOWS` above + include("test_mpi_p4est_3d.jl") + end end # MPI - @trixi_testset "MPI supporting functionality" begin - using OrdinaryDiffEq - - t = 0.5 - let u = 1.0 - @test ode_norm(u, t) ≈ OrdinaryDiffEq.ODE_DEFAULT_NORM(u, t) - end - let u = [1.0, -2.0] - @test ode_norm(u, t) ≈ OrdinaryDiffEq.ODE_DEFAULT_NORM(u, t) - end - let u = [SVector(1.0, -2.0), SVector(0.5, -0.1)] - @test ode_norm(u, t) ≈ OrdinaryDiffEq.ODE_DEFAULT_NORM(u, t) - end + using OrdinaryDiffEq + + t = 0.5 + let u = 1.0 + @test ode_norm(u, t) ≈ OrdinaryDiffEq.ODE_DEFAULT_NORM(u, t) + end + let u = [1.0, -2.0] + @test ode_norm(u, t) ≈ OrdinaryDiffEq.ODE_DEFAULT_NORM(u, t) + end + let u = [SVector(1.0, -2.0), SVector(0.5, -0.1)] + @test ode_norm(u, t) ≈ OrdinaryDiffEq.ODE_DEFAULT_NORM(u, t) + end end # MPI supporting functionality # Clean up afterwards: delete Trixi.jl output directory -Trixi.mpi_isroot() && @test_nowarn rm(outdir, recursive=true) +Trixi.mpi_isroot() && @test_nowarn rm(outdir, recursive = true) end # module diff --git a/test/test_mpi_p4est_2d.jl b/test/test_mpi_p4est_2d.jl index 4023997eaf3..1edbce8f6c8 100644 --- a/test/test_mpi_p4est_2d.jl +++ b/test/test_mpi_p4est_2d.jl @@ -8,70 +8,87 @@ include("test_trixi.jl") const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_2d_dgsem") @testset "P4estMesh MPI 2D" begin +#! format: noindent # Run basic tests @testset "Examples 2D" begin - # Linear scalar advection - @trixi_testset "elixir_advection_basic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), - # Expected errors are exactly the same as with TreeMesh! - l2 = [8.311947673061856e-6], - linf = [6.627000273229378e-5]) + # Linear scalar advection + @trixi_testset "elixir_advection_basic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), + # Expected errors are exactly the same as with TreeMesh! + l2=[8.311947673061856e-6], + linf=[6.627000273229378e-5]) - @testset "error-based step size control" begin - Trixi.mpi_isroot() && println("-"^100) - Trixi.mpi_isroot() && println("elixir_advection_basic.jl with error-based step size control") + @testset "error-based step size control" begin + Trixi.mpi_isroot() && println("-"^100) + Trixi.mpi_isroot() && + println("elixir_advection_basic.jl with error-based step size control") - sol = solve(ode, RDPK3SpFSAL35(); abstol=1.0e-4, reltol=1.0e-4, - ode_default_options()..., callback=callbacks); summary_callback() - errors = analysis_callback(sol) - if Trixi.mpi_isroot() - @test errors.l2 ≈ [3.3022040342579066e-5] rtol=1.0e-4 - @test errors.linf ≈ [0.00011787417954578494] rtol=1.0e-4 - end + sol = solve(ode, RDPK3SpFSAL35(); abstol = 1.0e-4, reltol = 1.0e-4, + ode_default_options()..., callback = callbacks) + summary_callback() + errors = analysis_callback(sol) + if Trixi.mpi_isroot() + @test errors.l2≈[3.3022040342579066e-5] rtol=1.0e-4 + @test errors.linf≈[0.00011787417954578494] rtol=1.0e-4 + end + end end - end - @trixi_testset "elixir_advection_nonconforming_flag.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_nonconforming_flag.jl"), - l2 = [3.198940059144588e-5], - linf = [0.00030636069494005547]) - end + @trixi_testset "elixir_advection_nonconforming_flag.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_nonconforming_flag.jl"), + l2=[3.198940059144588e-5], + linf=[0.00030636069494005547]) + end - @trixi_testset "elixir_advection_unstructured_flag.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_unstructured_flag.jl"), - l2 = [0.0005379687442422346], - linf = [0.007438525029884735]) - end + @trixi_testset "elixir_advection_unstructured_flag.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_unstructured_flag.jl"), + l2=[0.0005379687442422346], + linf=[0.007438525029884735]) + end - @trixi_testset "elixir_advection_amr_solution_independent.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_solution_independent.jl"), - # Expected errors are exactly the same as with TreeMesh! - l2 = [4.949660644033807e-5], - linf = [0.0004867846262313763], - coverage_override = (maxiters=6,)) - end + @trixi_testset "elixir_advection_amr_solution_independent.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_amr_solution_independent.jl"), + # Expected errors are exactly the same as with TreeMesh! + l2=[4.949660644033807e-5], + linf=[0.0004867846262313763], + coverage_override=(maxiters = 6,)) + 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], - coverage_override = (maxiters=6,)) - 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], + coverage_override=(maxiters = 6,)) + end - @trixi_testset "elixir_advection_restart.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), - l2 = [4.507575525876275e-6], - linf = [6.21489667023134e-5]) - end + @trixi_testset "elixir_advection_restart.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), + l2=[4.507575525876275e-6], + linf=[6.21489667023134e-5]) + end - @trixi_testset "elixir_euler_source_terms_nonconforming_unstructured_flag.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), - l2 = [0.0034516244508588046, 0.0023420334036925493, 0.0024261923964557187, 0.004731710454271893], - linf = [0.04155789011775046, 0.024772109862748914, 0.03759938693042297, 0.08039824959535657]) - end + @trixi_testset "elixir_euler_source_terms_nonconforming_unstructured_flag.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), + l2=[ + 0.0034516244508588046, + 0.0023420334036925493, + 0.0024261923964557187, + 0.004731710454271893, + ], + linf=[ + 0.04155789011775046, + 0.024772109862748914, + 0.03759938693042297, + 0.08039824959535657, + ]) + end end - end # P4estMesh MPI end # module diff --git a/test/test_mpi_p4est_3d.jl b/test/test_mpi_p4est_3d.jl index f92feb1eed9..8082930b3b4 100644 --- a/test/test_mpi_p4est_3d.jl +++ b/test/test_mpi_p4est_3d.jl @@ -8,90 +8,150 @@ include("test_trixi.jl") const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_3d_dgsem") @testset "P4estMesh MPI 3D" begin +#! format: noindent # Run basic tests @testset "Examples 3D" begin - # Linear scalar advection - @trixi_testset "elixir_advection_basic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), - # Expected errors are exactly the same as with TreeMesh! - l2 = [0.00016263963870641478], - linf = [0.0014537194925779984]) - - @testset "error-based step size control" begin - Trixi.mpi_isroot() && println("-"^100) - Trixi.mpi_isroot() && println("elixir_advection_basic.jl with error-based step size control") - - sol = solve(ode, RDPK3SpFSAL35(); abstol=1.0e-4, reltol=1.0e-4, - ode_default_options()..., callback=callbacks); summary_callback() - errors = analysis_callback(sol) - if Trixi.mpi_isroot() - @test errors.l2 ≈ [0.00016800412839949264] rtol=1.0e-4 - @test errors.linf ≈ [0.0014548839020096516] rtol=1.0e-4 - end + # Linear scalar advection + @trixi_testset "elixir_advection_basic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), + # Expected errors are exactly the same as with TreeMesh! + l2=[0.00016263963870641478], + linf=[0.0014537194925779984]) + + @testset "error-based step size control" begin + Trixi.mpi_isroot() && println("-"^100) + Trixi.mpi_isroot() && + println("elixir_advection_basic.jl with error-based step size control") + + sol = solve(ode, RDPK3SpFSAL35(); abstol = 1.0e-4, reltol = 1.0e-4, + ode_default_options()..., callback = callbacks) + summary_callback() + errors = analysis_callback(sol) + if Trixi.mpi_isroot() + @test errors.l2≈[0.00016800412839949264] rtol=1.0e-4 + @test errors.linf≈[0.0014548839020096516] rtol=1.0e-4 + end + end + end + + @trixi_testset "elixir_advection_amr.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr.jl"), + # Expected errors are exactly the same as with TreeMesh! + l2=[9.773852895157622e-6], + linf=[0.0005853874124926162], + # override values are different from the serial tests to ensure each process holds at least + # one element, otherwise OrdinaryDiffEq fails during initialization + coverage_override=(maxiters = 6, + initial_refinement_level = 2, + base_level = 2, med_level = 3, + max_level = 4)) + 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], + tspan=(0.0, 1.0), + coverage_override=(maxiters = 6, + initial_refinement_level = 0, + base_level = 0, med_level = 1, + max_level = 2)) + end + + @trixi_testset "elixir_advection_restart.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), + l2=[0.002590388934758452], + linf=[0.01840757696885409]) + end + + @trixi_testset "elixir_advection_cubed_sphere.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_cubed_sphere.jl"), + l2=[0.002006918015656413], + linf=[0.027655117058380085]) end - end - - @trixi_testset "elixir_advection_amr.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr.jl"), - # Expected errors are exactly the same as with TreeMesh! - l2 = [9.773852895157622e-6], - linf = [0.0005853874124926162], - # override values are different from the serial tests to ensure each process holds at least - # one element, otherwise OrdinaryDiffEq fails during initialization - coverage_override = (maxiters=6, initial_refinement_level=2, base_level=2, med_level=3, max_level=4)) - 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], - tspan = (0.0, 1.0), - coverage_override = (maxiters=6, initial_refinement_level=0, base_level=0, med_level=1, max_level=2)) - end - - @trixi_testset "elixir_advection_restart.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), - l2 = [0.002590388934758452], - linf = [0.01840757696885409]) - end - - @trixi_testset "elixir_advection_cubed_sphere.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_cubed_sphere.jl"), - l2 = [0.002006918015656413], - linf = [0.027655117058380085]) - end - - # Compressible Euler - @trixi_testset "elixir_euler_source_terms_nonconforming_unstructured_curved.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonconforming_unstructured_curved.jl"), - l2 = [4.070355207909268e-5, 4.4993257426833716e-5, 5.10588457841744e-5, 5.102840924036687e-5, 0.00019986264001630542], - linf = [0.0016987332417202072, 0.003622956808262634, 0.002029576258317789, 0.0024206977281964193, 0.008526972236273522], - tspan = (0.0, 0.01)) - end - - @trixi_testset "elixir_euler_source_terms_nonperiodic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonperiodic.jl"), - l2 = [0.0015106060984283647, 0.0014733349038567685, 0.00147333490385685, 0.001473334903856929, 0.0028149479453087093], - linf = [0.008070806335238156, 0.009007245083113125, 0.009007245083121784, 0.009007245083102688, 0.01562861968368434], - tspan = (0.0, 1.0)) - end - - @trixi_testset "elixir_euler_ec.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.010380390326164493, 0.006192950051354618, 0.005970674274073704, 0.005965831290564327, 0.02628875593094754], - linf = [0.3326911600075694, 0.2824952141320467, 0.41401037398065543, 0.45574161423218573, 0.8099577682187109], - tspan = (0.0, 0.2), - coverage_override = (polydeg=3,)) # Prevent long compile time in CI - end - - @trixi_testset "elixir_euler_source_terms_nonperiodic_hohqmesh.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonperiodic_hohqmesh.jl"), - l2 = [0.0042023406458005464, 0.004122532789279737, 0.0042448149597303616, 0.0036361316700401765, 0.007389845952982495], - linf = [0.04530610539892499, 0.02765695110527666, 0.05670295599308606, 0.048396544302230504, 0.1154589758186293]) - end -end + # Compressible Euler + @trixi_testset "elixir_euler_source_terms_nonconforming_unstructured_curved.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonconforming_unstructured_curved.jl"), + l2=[ + 4.070355207909268e-5, + 4.4993257426833716e-5, + 5.10588457841744e-5, + 5.102840924036687e-5, + 0.00019986264001630542, + ], + linf=[ + 0.0016987332417202072, + 0.003622956808262634, + 0.002029576258317789, + 0.0024206977281964193, + 0.008526972236273522, + ], + tspan=(0.0, 0.01)) + end + + @trixi_testset "elixir_euler_source_terms_nonperiodic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonperiodic.jl"), + l2=[ + 0.0015106060984283647, + 0.0014733349038567685, + 0.00147333490385685, + 0.001473334903856929, + 0.0028149479453087093, + ], + linf=[ + 0.008070806335238156, + 0.009007245083113125, + 0.009007245083121784, + 0.009007245083102688, + 0.01562861968368434, + ], + tspan=(0.0, 1.0)) + end + + @trixi_testset "elixir_euler_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), + l2=[ + 0.010380390326164493, + 0.006192950051354618, + 0.005970674274073704, + 0.005965831290564327, + 0.02628875593094754, + ], + linf=[ + 0.3326911600075694, + 0.2824952141320467, + 0.41401037398065543, + 0.45574161423218573, + 0.8099577682187109, + ], + tspan=(0.0, 0.2), + coverage_override=(polydeg = 3,)) # Prevent long compile time in CI + end + + @trixi_testset "elixir_euler_source_terms_nonperiodic_hohqmesh.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonperiodic_hohqmesh.jl"), + l2=[ + 0.0042023406458005464, + 0.004122532789279737, + 0.0042448149597303616, + 0.0036361316700401765, + 0.007389845952982495, + ], + linf=[ + 0.04530610539892499, + 0.02765695110527666, + 0.05670295599308606, + 0.048396544302230504, + 0.1154589758186293, + ]) + end +end end # P4estMesh MPI end # module diff --git a/test/test_mpi_tree.jl b/test/test_mpi_tree.jl index 8f08a9d72e7..0831f6a1313 100644 --- a/test/test_mpi_tree.jl +++ b/test/test_mpi_tree.jl @@ -11,198 +11,334 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") CI_ON_WINDOWS = (get(ENV, "GITHUB_ACTIONS", false) == "true") && Sys.iswindows() @testset "TreeMesh MPI" begin +#! format: noindent # Run basic tests @testset "Examples 2D" begin - # Linear scalar advection - @trixi_testset "elixir_advection_basic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), - # Expected errors are exactly the same as in the serial test! - l2 = [8.311947673061856e-6], - linf = [6.627000273229378e-5]) - end - - @trixi_testset "elixir_advection_restart.jl" begin - using OrdinaryDiffEq: RDPK3SpFSAL49 - Trixi.mpi_isroot() && println("═"^100) - Trixi.mpi_isroot() && println(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl")) - trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - alg = RDPK3SpFSAL49(), tspan = (0.0, 10.0)) - l2_expected, linf_expected = analysis_callback(sol) - - Trixi.mpi_isroot() && println("═"^100) - Trixi.mpi_isroot() && println(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl")) - # Errors are exactly the same as in the elixir_advection_extended.jl - trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), - alg = RDPK3SpFSAL49()) - l2_actual, linf_actual = analysis_callback(sol) - - Trixi.mpi_isroot() && @test l2_actual == l2_expected - Trixi.mpi_isroot() && @test linf_actual == linf_expected - end - - @trixi_testset "elixir_advection_mortar.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_mortar.jl"), - # Expected errors are exactly the same as in the serial test! - l2 = [0.0015188466707237375], - linf = [0.008446655719187679]) - end - - @trixi_testset "elixir_advection_amr.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr.jl"), - # Expected errors are exactly the same as in the serial test! - l2 = [4.913300828257469e-5], - linf = [0.00045263895394385967], - coverage_override = (maxiters=6,)) - end - - @trixi_testset "elixir_advection_amr_nonperiodic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_nonperiodic.jl"), - # Expected errors are exactly the same as in the serial test! - l2 = [3.2207388565869075e-5], - linf = [0.0007508059772436404], - coverage_override = (maxiters=6,)) - end - - # Linear scalar advection with AMR - # These example files are only for testing purposes and have no practical use - @trixi_testset "elixir_advection_amr_refine_twice.jl" begin - # Here, we also test that SaveSolutionCallback prints multiple mesh files with AMR - # Start with a clean environment: remove Trixi.jl output directory if it exists - outdir = "out" - isdir(outdir) && rm(outdir, recursive=true) - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_refine_twice.jl"), - l2 = [0.00020547512522578292], - linf = [0.007831753383083506], - coverage_override = (maxiters=6,)) - meshfiles = filter(file -> endswith(file,".h5") && startswith(file,"mesh"), readdir(outdir)) - @test length(meshfiles) > 1 - end - - @trixi_testset "elixir_advection_amr_coarsen_twice.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_coarsen_twice.jl"), - l2 = [0.0014321062757891826], - linf = [0.0253454486893413], - coverage_override = (maxiters=6,)) - end - - # Hyperbolic diffusion - if !CI_ON_WINDOWS # see comment on `CI_ON_WINDOWS` in `test/test_mpi.jl` - @trixi_testset "elixir_hypdiff_lax_friedrichs.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_lax_friedrichs.jl"), - l2 = [0.00015687751816056159, 0.001025986772217084, 0.0010259867722169909], - linf = [0.0011986956416591976, 0.006423873516411049, 0.006423873516411049]) - end - end - - @trixi_testset "elixir_hypdiff_harmonic_nonperiodic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_harmonic_nonperiodic.jl"), - l2 = [8.61813235543625e-8, 5.619399844542781e-7, 5.6193998447443e-7], - linf = [1.124861862180196e-6, 8.622436471039663e-6, 8.622436470151484e-6]) - end - - @trixi_testset "elixir_hypdiff_nonperiodic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_nonperiodic.jl"), - l2 = [8.523077653955306e-6, 2.8779323653065056e-5, 5.4549427691297846e-5], - linf = [5.5227409524905013e-5, 0.0001454489597927185, 0.00032396328684569653]) - end - - if !CI_ON_WINDOWS # see comment on `CI_ON_WINDOWS` in `test/test_mpi.jl` - @trixi_testset "elixir_hypdiff_godunov.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_godunov.jl"), - l2 = [5.868147556427088e-6, 3.80517927324465e-5, 3.805179273249344e-5], - linf = [3.701965498725812e-5, 0.0002122422943138247, 0.00021224229431116015], - atol = 2.0e-12 #= required for CI on macOS =#) - end - end - - - # Compressible Euler - # Note: Some tests here have manually increased relative tolerances since reduction via MPI can - # slightly change the L2 error norms (different floating point truncation errors) - if !CI_ON_WINDOWS # see comment on `CI_ON_WINDOWS` in `test/test_mpi.jl` - @trixi_testset "elixir_euler_source_terms.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms.jl"), - l2 = [9.321181253186009e-7, 1.4181210743438511e-6, 1.4181210743487851e-6, 4.824553091276693e-6], - linf = [9.577246529612893e-6, 1.1707525976012434e-5, 1.1707525976456523e-5, 4.8869615580926506e-5], - rtol = 2000*sqrt(eps())) - end - end - - # This example file is only for testing purposes and has no practical use - if !CI_ON_WINDOWS # see comment on `CI_ON_WINDOWS` in `test/test_mpi.jl` - @trixi_testset "elixir_euler_source_terms_amr_refine_coarsen.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_amr_refine_coarsen.jl"), - l2 = [4.8226610349853444e-5, 4.117706709270575e-5, 4.1177067092959676e-5, 0.00012205252427437389], - linf = [0.0003543874851490436, 0.0002973166773747593, 0.0002973166773760916, 0.001154106793870291], - # Let this test run until the end to cover the time-dependent lines - # of the indicator and the MPI-specific AMR code. - coverage_override = (maxiters=10^5,)) - end - end - - if !CI_ON_WINDOWS # see comment on `CI_ON_WINDOWS` in `test/test_mpi.jl` - @trixi_testset "elixir_euler_source_terms_nonperiodic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonperiodic.jl"), - l2 = [2.259440511766445e-6, 2.318888155713922e-6, 2.3188881557894307e-6, 6.3327863238858925e-6], - linf = [1.498738264560373e-5, 1.9182011928187137e-5, 1.918201192685487e-5, 6.0526717141407005e-5], - rtol = 0.001) - end - end - - if !CI_ON_WINDOWS # see comment on `CI_ON_WINDOWS` in `test/test_mpi.jl` - @trixi_testset "elixir_euler_ec.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.061751715597716854, 0.05018223615408711, 0.05018989446443463, 0.225871559730513], - linf = [0.29347582879608825, 0.31081249232844693, 0.3107380389947736, 1.0540358049885143]) - - @testset "error-based step size control" begin - Trixi.mpi_isroot() && println("-"^100) - Trixi.mpi_isroot() && println("elixir_euler_ec.jl with error-based step size control") - - sol = solve(ode, RDPK3SpFSAL35(); abstol=1.0e-4, reltol=1.0e-4, - ode_default_options()..., callback=callbacks); summary_callback() - errors = analysis_callback(sol) - if Trixi.mpi_isroot() - @test errors.l2 ≈ [0.061653630426688116, 0.05006930431098764, 0.05007694316484242, 0.22550689872331683] rtol=1.0e-4 - @test errors.linf ≈ [0.28516937484583693, 0.2983633696512788, 0.297812036335975, 1.027368795517512] rtol=1.0e-4 + # Linear scalar advection + @trixi_testset "elixir_advection_basic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), + # Expected errors are exactly the same as in the serial test! + l2=[8.311947673061856e-6], + linf=[6.627000273229378e-5]) + end + + @trixi_testset "elixir_advection_restart.jl" begin + using OrdinaryDiffEq: RDPK3SpFSAL49 + Trixi.mpi_isroot() && println("═"^100) + Trixi.mpi_isroot() && + println(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl")) + trixi_include(@__MODULE__, + joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), + alg = RDPK3SpFSAL49(), tspan = (0.0, 10.0)) + l2_expected, linf_expected = analysis_callback(sol) + + Trixi.mpi_isroot() && println("═"^100) + Trixi.mpi_isroot() && + println(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl")) + # Errors are exactly the same as in the elixir_advection_extended.jl + trixi_include(@__MODULE__, + joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), + alg = RDPK3SpFSAL49()) + l2_actual, linf_actual = analysis_callback(sol) + + Trixi.mpi_isroot() && @test l2_actual == l2_expected + Trixi.mpi_isroot() && @test linf_actual == linf_expected + end + + @trixi_testset "elixir_advection_mortar.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_mortar.jl"), + # Expected errors are exactly the same as in the serial test! + l2=[0.0015188466707237375], + linf=[0.008446655719187679]) + end + + @trixi_testset "elixir_advection_amr.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr.jl"), + # Expected errors are exactly the same as in the serial test! + l2=[4.913300828257469e-5], + linf=[0.00045263895394385967], + coverage_override=(maxiters = 6,)) + end + + @trixi_testset "elixir_advection_amr_nonperiodic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_amr_nonperiodic.jl"), + # Expected errors are exactly the same as in the serial test! + l2=[3.2207388565869075e-5], + linf=[0.0007508059772436404], + coverage_override=(maxiters = 6,)) + end + + # Linear scalar advection with AMR + # These example files are only for testing purposes and have no practical use + @trixi_testset "elixir_advection_amr_refine_twice.jl" begin + # Here, we also test that SaveSolutionCallback prints multiple mesh files with AMR + # Start with a clean environment: remove Trixi.jl output directory if it exists + outdir = "out" + isdir(outdir) && rm(outdir, recursive = true) + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_amr_refine_twice.jl"), + l2=[0.00020547512522578292], + linf=[0.007831753383083506], + coverage_override=(maxiters = 6,)) + meshfiles = filter(file -> endswith(file, ".h5") && startswith(file, "mesh"), + readdir(outdir)) + @test length(meshfiles) > 1 + end + + @trixi_testset "elixir_advection_amr_coarsen_twice.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_amr_coarsen_twice.jl"), + l2=[0.0014321062757891826], + linf=[0.0253454486893413], + coverage_override=(maxiters = 6,)) + end + + # Hyperbolic diffusion + if !CI_ON_WINDOWS # see comment on `CI_ON_WINDOWS` in `test/test_mpi.jl` + @trixi_testset "elixir_hypdiff_lax_friedrichs.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_hypdiff_lax_friedrichs.jl"), + l2=[ + 0.00015687751816056159, + 0.001025986772217084, + 0.0010259867722169909, + ], + linf=[ + 0.0011986956416591976, + 0.006423873516411049, + 0.006423873516411049, + ]) end - end - end - end - - @trixi_testset "elixir_euler_vortex.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex.jl"), - l2 = [0.00013492249515826863, 0.006615696236378061, 0.006782108219800376, 0.016393831451740604], - linf = [0.0020782600954247776, 0.08150078921935999, 0.08663621974991986, 0.2829930622010579], - rtol = 0.001) - end - - @trixi_testset "elixir_euler_vortex_mortar.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex_mortar.jl"), - # Expected errors are exactly the same as in the serial test! - l2 = [0.0017208369388227673, 0.09628684992237334, 0.09620157717330868, 0.1758809552387432], - linf = [0.021869936355319086, 0.9956698009442038, 1.0002507727219028, 2.223249697515648]) - end - - @trixi_testset "elixir_euler_vortex_amr.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex_amr.jl"), - # Expected errors are exactly the same as in the serial test! - l2 = [5.051719943432265e-5, 0.0022574259317084747, 0.0021755998463189713, 0.004346492398617521], - linf = [0.0012880114865917447, 0.03857193149447702, 0.031090457959835893, 0.12125130332971423], - coverage_override = (maxiters=6,)) - end - - if !CI_ON_WINDOWS # see comment on `CI_ON_WINDOWS` in `test/test_mpi.jl` - @trixi_testset "elixir_euler_vortex_shockcapturing.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex_shockcapturing.jl"), - l2 = [0.0017158367642679273, 0.09619888722871434, 0.09616432767924141, 0.17553381166255197], - linf = [0.021853862449723982, 0.9878047229255944, 0.9880191167111795, 2.2154030488035588], - rtol = 0.001) - end - end -end + end + + @trixi_testset "elixir_hypdiff_harmonic_nonperiodic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_hypdiff_harmonic_nonperiodic.jl"), + l2=[ + 8.61813235543625e-8, + 5.619399844542781e-7, + 5.6193998447443e-7, + ], + linf=[ + 1.124861862180196e-6, + 8.622436471039663e-6, + 8.622436470151484e-6, + ]) + end + + @trixi_testset "elixir_hypdiff_nonperiodic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_nonperiodic.jl"), + l2=[ + 8.523077653955306e-6, + 2.8779323653065056e-5, + 5.4549427691297846e-5, + ], + linf=[ + 5.5227409524905013e-5, + 0.0001454489597927185, + 0.00032396328684569653, + ]) + end + + if !CI_ON_WINDOWS # see comment on `CI_ON_WINDOWS` in `test/test_mpi.jl` + @trixi_testset "elixir_hypdiff_godunov.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_godunov.jl"), + l2=[ + 5.868147556427088e-6, + 3.80517927324465e-5, + 3.805179273249344e-5, + ], + linf=[ + 3.701965498725812e-5, + 0.0002122422943138247, + 0.00021224229431116015, + ], + atol=2.0e-12) #= required for CI on macOS =# + end + end + + # Compressible Euler + # Note: Some tests here have manually increased relative tolerances since reduction via MPI can + # slightly change the L2 error norms (different floating point truncation errors) + if !CI_ON_WINDOWS # see comment on `CI_ON_WINDOWS` in `test/test_mpi.jl` + @trixi_testset "elixir_euler_source_terms.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms.jl"), + l2=[ + 9.321181253186009e-7, + 1.4181210743438511e-6, + 1.4181210743487851e-6, + 4.824553091276693e-6, + ], + linf=[ + 9.577246529612893e-6, + 1.1707525976012434e-5, + 1.1707525976456523e-5, + 4.8869615580926506e-5, + ], + rtol=2000 * sqrt(eps())) + end + end + + # This example file is only for testing purposes and has no practical use + if !CI_ON_WINDOWS # see comment on `CI_ON_WINDOWS` in `test/test_mpi.jl` + @trixi_testset "elixir_euler_source_terms_amr_refine_coarsen.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_amr_refine_coarsen.jl"), + l2=[ + 4.8226610349853444e-5, + 4.117706709270575e-5, + 4.1177067092959676e-5, + 0.00012205252427437389, + ], + linf=[ + 0.0003543874851490436, + 0.0002973166773747593, + 0.0002973166773760916, + 0.001154106793870291, + ], + # Let this test run until the end to cover the time-dependent lines + # of the indicator and the MPI-specific AMR code. + coverage_override=(maxiters = 10^5,)) + end + end + + if !CI_ON_WINDOWS # see comment on `CI_ON_WINDOWS` in `test/test_mpi.jl` + @trixi_testset "elixir_euler_source_terms_nonperiodic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonperiodic.jl"), + l2=[ + 2.259440511766445e-6, + 2.318888155713922e-6, + 2.3188881557894307e-6, + 6.3327863238858925e-6, + ], + linf=[ + 1.498738264560373e-5, + 1.9182011928187137e-5, + 1.918201192685487e-5, + 6.0526717141407005e-5, + ], + rtol=0.001) + end + end + + if !CI_ON_WINDOWS # see comment on `CI_ON_WINDOWS` in `test/test_mpi.jl` + @trixi_testset "elixir_euler_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), + l2=[ + 0.061751715597716854, + 0.05018223615408711, + 0.05018989446443463, + 0.225871559730513, + ], + linf=[ + 0.29347582879608825, + 0.31081249232844693, + 0.3107380389947736, + 1.0540358049885143, + ]) + + @testset "error-based step size control" begin + Trixi.mpi_isroot() && println("-"^100) + Trixi.mpi_isroot() && + println("elixir_euler_ec.jl with error-based step size control") + sol = solve(ode, RDPK3SpFSAL35(); abstol = 1.0e-4, reltol = 1.0e-4, + ode_default_options()..., callback = callbacks) + summary_callback() + errors = analysis_callback(sol) + if Trixi.mpi_isroot() + @test errors.l2≈[ + 0.061653630426688116, + 0.05006930431098764, + 0.05007694316484242, + 0.22550689872331683, + ] rtol=1.0e-4 + @test errors.linf≈[ + 0.28516937484583693, + 0.2983633696512788, + 0.297812036335975, + 1.027368795517512, + ] rtol=1.0e-4 + end + end + end + end + + @trixi_testset "elixir_euler_vortex.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex.jl"), + l2=[ + 0.00013492249515826863, + 0.006615696236378061, + 0.006782108219800376, + 0.016393831451740604, + ], + linf=[ + 0.0020782600954247776, + 0.08150078921935999, + 0.08663621974991986, + 0.2829930622010579, + ], + rtol=0.001) + end + + @trixi_testset "elixir_euler_vortex_mortar.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex_mortar.jl"), + # Expected errors are exactly the same as in the serial test! + l2=[ + 0.0017208369388227673, + 0.09628684992237334, + 0.09620157717330868, + 0.1758809552387432, + ], + linf=[ + 0.021869936355319086, + 0.9956698009442038, + 1.0002507727219028, + 2.223249697515648, + ]) + end + + @trixi_testset "elixir_euler_vortex_amr.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex_amr.jl"), + # Expected errors are exactly the same as in the serial test! + l2=[ + 5.051719943432265e-5, + 0.0022574259317084747, + 0.0021755998463189713, + 0.004346492398617521, + ], + linf=[ + 0.0012880114865917447, + 0.03857193149447702, + 0.031090457959835893, + 0.12125130332971423, + ], + coverage_override=(maxiters = 6,)) + end + + if !CI_ON_WINDOWS # see comment on `CI_ON_WINDOWS` in `test/test_mpi.jl` + @trixi_testset "elixir_euler_vortex_shockcapturing.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_vortex_shockcapturing.jl"), + l2=[ + 0.0017158367642679273, + 0.09619888722871434, + 0.09616432767924141, + 0.17553381166255197, + ], + linf=[ + 0.021853862449723982, + 0.9878047229255944, + 0.9880191167111795, + 2.2154030488035588, + ], + rtol=0.001) + end + end +end end # TreeMesh MPI end # module diff --git a/test/test_p4est_2d.jl b/test/test_p4est_2d.jl index 5baa090c8d7..cf7250b246b 100644 --- a/test/test_p4est_2d.jl +++ b/test/test_p4est_2d.jl @@ -9,326 +9,455 @@ EXAMPLES_DIR = joinpath(examples_dir(), "p4est_2d_dgsem") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) @testset "P4estMesh2D" begin - @trixi_testset "elixir_advection_basic.jl" begin +#! format: noindent + +@trixi_testset "elixir_advection_basic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), - # Expected errors are exactly the same as with TreeMesh! - l2 = [8.311947673061856e-6], - linf = [6.627000273229378e-5]) - # 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 + # Expected errors are exactly the same as with TreeMesh! + l2=[8.311947673061856e-6], + linf=[6.627000273229378e-5]) + # 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_nonconforming_flag.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_nonconforming_flag.jl"), - l2 = [3.198940059144588e-5], - linf = [0.00030636069494005547]) - # 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_nonconforming_flag.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_nonconforming_flag.jl"), + l2=[3.198940059144588e-5], + linf=[0.00030636069494005547]) + # 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_unstructured_flag.jl" begin +@trixi_testset "elixir_advection_unstructured_flag.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_unstructured_flag.jl"), - l2 = [0.0005379687442422346], - linf = [0.007438525029884735]) - # 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 + l2=[0.0005379687442422346], + linf=[0.007438525029884735]) + # 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_amr_solution_independent.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_solution_independent.jl"), - # Expected errors are exactly the same as with StructuredMesh! - l2 = [4.949660644033807e-5], - linf = [0.0004867846262313763], - 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 - end +@trixi_testset "elixir_advection_amr_solution_independent.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_amr_solution_independent.jl"), + # Expected errors are exactly the same as with StructuredMesh! + l2=[4.949660644033807e-5], + linf=[0.0004867846262313763], + 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 +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], - 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 - 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], + 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 +end - @trixi_testset "elixir_advection_restart.jl" begin +@trixi_testset "elixir_advection_restart.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), - l2 = [4.507575525876275e-6], - linf = [6.21489667023134e-5]) - # 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 + l2=[4.507575525876275e-6], + linf=[6.21489667023134e-5]) + # 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_source_terms_nonconforming_unstructured_flag.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), - l2 = [0.0034516244508588046, 0.0023420334036925493, 0.0024261923964557187, 0.004731710454271893], - linf = [0.04155789011775046, 0.024772109862748914, 0.03759938693042297, 0.08039824959535657]) - # 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 +@trixi_testset "elixir_euler_source_terms_nonconforming_unstructured_flag.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), + l2=[ + 0.0034516244508588046, + 0.0023420334036925493, + 0.0024261923964557187, + 0.004731710454271893, + ], + linf=[ + 0.04155789011775046, + 0.024772109862748914, + 0.03759938693042297, + 0.08039824959535657, + ]) + # 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 - @trixi_testset "elixir_euler_free_stream.jl" begin +@trixi_testset "elixir_euler_free_stream.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_free_stream.jl"), - l2 = [2.063350241405049e-15, 1.8571016296925367e-14, 3.1769447886391905e-14, 1.4104095258528071e-14], - linf = [1.9539925233402755e-14, 2e-12, 4.8e-12, 4e-12], - atol = 2.0e-12, # required to make CI tests pass on macOS - ) - # 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 + l2=[ + 2.063350241405049e-15, + 1.8571016296925367e-14, + 3.1769447886391905e-14, + 1.4104095258528071e-14, + ], + linf=[1.9539925233402755e-14, 2e-12, 4.8e-12, 4e-12], + atol=2.0e-12,) + # 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 - @trixi_testset "elixir_euler_shockcapturing_ec.jl" begin +@trixi_testset "elixir_euler_shockcapturing_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing_ec.jl"), - l2 = [9.53984675e-02, 1.05633455e-01, 1.05636158e-01, 3.50747237e-01], - linf = [2.94357464e-01, 4.07893014e-01, 3.97334516e-01, 1.08142520e+00], - tspan = (0.0, 1.0)) - # 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 + l2=[ + 9.53984675e-02, + 1.05633455e-01, + 1.05636158e-01, + 3.50747237e-01, + ], + linf=[ + 2.94357464e-01, + 4.07893014e-01, + 3.97334516e-01, + 1.08142520e+00, + ], + tspan=(0.0, 1.0)) + # 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 +@trixi_testset "elixir_euler_sedov.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov.jl"), - l2 = [3.76149952e-01, 2.46970327e-01, 2.46970327e-01, 1.28889042e+00], - linf = [1.22139001e+00, 1.17742626e+00, 1.17742626e+00, 6.20638482e+00], - tspan = (0.0, 0.3)) - # 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 + l2=[ + 3.76149952e-01, + 2.46970327e-01, + 2.46970327e-01, + 1.28889042e+00, + ], + linf=[ + 1.22139001e+00, + 1.17742626e+00, + 1.17742626e+00, + 6.20638482e+00, + ], + tspan=(0.0, 0.3)) + # 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_blast_wave_amr.jl" begin +@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], - linf = [2.76020890e+00, 2.32659890e+00, 2.32580837e+00, 2.15778188e+00], - tspan = (0.0, 0.3), - 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 - end + l2=[ + 6.32183914e-01, + 3.86914231e-01, + 3.86869171e-01, + 1.06575688e+00, + ], + linf=[ + 2.76020890e+00, + 2.32659890e+00, + 2.32580837e+00, + 2.15778188e+00, + ], + tspan=(0.0, 0.3), + 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 +end - @trixi_testset "elixir_euler_wall_bc_amr.jl" begin +@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], - linf = [0.3582779022370579, 0.32073537890751663, 0.221818049107692, 0.9209559420400415], - tspan = (0.0, 0.15)) - # 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 + l2=[ + 0.020291447969983396, + 0.017479614254319948, + 0.011387644425613437, + 0.0514420126021293, + ], + linf=[ + 0.3582779022370579, + 0.32073537890751663, + 0.221818049107692, + 0.9209559420400415, + ], + tspan=(0.0, 0.15)) + # 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_forward_step_amr.jl" begin +@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], - linf = [2.0585399781442852, 2.213428805506876, 3.862362410419163, 17.75187237459251], - tspan = (0.0, 0.0001), - rtol = 1.0e-7, - skip_coverage=true) - if @isdefined sol # Skipped in coverage run - # 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 + l2=[ + 0.004194875320833303, + 0.003785140699353966, + 0.0013696609105790351, + 0.03265268616046424, + ], + linf=[ + 2.0585399781442852, + 2.213428805506876, + 3.862362410419163, + 17.75187237459251, + ], + tspan=(0.0, 0.0001), + rtol=1.0e-7, + skip_coverage=true) + if @isdefined sol # Skipped in coverage run + # 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 + end +end - @trixi_testset "elixir_euler_double_mach_amr.jl" begin +@trixi_testset "elixir_euler_double_mach_amr.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_double_mach_amr.jl"), - l2 = [0.051359355290192046, 0.4266034859911273, 0.2438304855475594, 4.11487176105527], - linf = [6.902000373057003, 53.95714139820832, 24.241610279839758, 561.0630401858057], - tspan = (0.0, 0.0001), - skip_coverage=true) - if @isdefined sol # Skipped in coverage run - # 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 + l2=[ + 0.051359355290192046, + 0.4266034859911273, + 0.2438304855475594, + 4.11487176105527, + ], + linf=[ + 6.902000373057003, + 53.95714139820832, + 24.241610279839758, + 561.0630401858057, + ], + tspan=(0.0, 0.0001), + skip_coverage=true) + if @isdefined sol # Skipped in coverage run + # 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 + end +end - @trixi_testset "elixir_euler_supersonic_cylinder.jl" begin +@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], - linf = [3.653905721692421, 4.285035711361009, 6.8544353186357645, 31.748244912257533], - tspan = (0.0, 0.001), - skip_coverage=true) - if @isdefined sol # Skipped in coverage run - # 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 + l2=[ + 0.026798021911954406, + 0.05118546368109259, + 0.03206703583774831, + 0.19680026567208672, + ], + linf=[ + 3.653905721692421, + 4.285035711361009, + 6.8544353186357645, + 31.748244912257533, + ], + tspan=(0.0, 0.001), + skip_coverage=true) + if @isdefined sol # Skipped in coverage run + # 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 + end +end - @trixi_testset "elixir_eulergravity_convergence.jl" begin +@trixi_testset "elixir_eulergravity_convergence.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulergravity_convergence.jl"), - l2 = [0.00024871265138964204, 0.0003370077102132591, 0.0003370077102131964, 0.0007231525513793697], - linf = [0.0015813032944647087, 0.0020494288423820173, 0.0020494288423824614, 0.004793821195083758], - tspan = (0.0, 0.1)) - # 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 + l2=[ + 0.00024871265138964204, + 0.0003370077102132591, + 0.0003370077102131964, + 0.0007231525513793697, + ], + linf=[ + 0.0015813032944647087, + 0.0020494288423820173, + 0.0020494288423824614, + 0.004793821195083758, + ], + tspan=(0.0, 0.1)) + # 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_source_terms.jl" begin +@trixi_testset "elixir_shallowwater_source_terms.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), - l2 = [9.168126407325352e-5, 0.0009795410115453788, 0.002546408320320785, 3.941189812642317e-6], - linf = [0.0009903782521019089, 0.0059752684687262025, 0.010941106525454103, 1.2129488214718265e-5], - tspan = (0.0, 0.1)) - # 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 + l2=[ + 9.168126407325352e-5, + 0.0009795410115453788, + 0.002546408320320785, + 3.941189812642317e-6, + ], + linf=[ + 0.0009903782521019089, + 0.0059752684687262025, + 0.010941106525454103, + 1.2129488214718265e-5, + ], + tspan=(0.0, 0.1)) + # 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_mhd_alfven_wave.jl" begin +@trixi_testset "elixir_mhd_alfven_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), - l2 = [1.0513414461545583e-5, 1.0517900957166411e-6, 1.0517900957304043e-6, 1.511816606372376e-6, - 1.0443997728645063e-6, 7.879639064990798e-7, 7.879639065049896e-7, 1.0628631669056271e-6, - 4.3382328912336153e-7], - linf = [4.255466285174592e-5, 1.0029706745823264e-5, 1.0029706747467781e-5, 1.2122265939010224e-5, - 5.4791097160444835e-6, 5.18922042269665e-6, 5.189220422141538e-6, 9.552667261422676e-6, - 1.4237578427628152e-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 - end + l2=[1.0513414461545583e-5, 1.0517900957166411e-6, + 1.0517900957304043e-6, 1.511816606372376e-6, + 1.0443997728645063e-6, 7.879639064990798e-7, + 7.879639065049896e-7, 1.0628631669056271e-6, + 4.3382328912336153e-7], + linf=[4.255466285174592e-5, 1.0029706745823264e-5, + 1.0029706747467781e-5, 1.2122265939010224e-5, + 5.4791097160444835e-6, 5.18922042269665e-6, + 5.189220422141538e-6, 9.552667261422676e-6, + 1.4237578427628152e-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 +end - @trixi_testset "elixir_mhd_rotor.jl" begin +@trixi_testset "elixir_mhd_rotor.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_rotor.jl"), - l2 = [0.4552084651735862, 0.8918048264575757, 0.832471223081887, 0.0, - 0.9801264164951583, 0.10475690769435382, 0.1555132409149897, 0.0, - 2.0597079362763556e-5], - linf = [10.194181233788775, 18.25472397868819, 10.031307436191334, 0.0, - 19.647239392277378, 1.3938810140985936, 1.8724965294853084, 0.0, - 0.0016290067532561904], - tspan = (0.0, 0.02)) - # 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 + l2=[0.4552084651735862, 0.8918048264575757, 0.832471223081887, + 0.0, + 0.9801264164951583, 0.10475690769435382, 0.1555132409149897, + 0.0, + 2.0597079362763556e-5], + linf=[10.194181233788775, 18.25472397868819, 10.031307436191334, + 0.0, + 19.647239392277378, 1.3938810140985936, 1.8724965294853084, + 0.0, + 0.0016290067532561904], + tspan=(0.0, 0.02)) + # 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_linearizedeuler_gaussian_source.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_linearizedeuler_gaussian_source.jl"), - l2 = [0.006047938590548741, 0.0040953286019907035, 0.004222698522497298, 0.006269492499336128], - linf = [0.06386175207349379, 0.0378926444850457, 0.041759728067967065, 0.06430136016259067]) - # 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_linearizedeuler_gaussian_source.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_linearizedeuler_gaussian_source.jl"), + l2=[ + 0.006047938590548741, + 0.0040953286019907035, + 0.004222698522497298, + 0.006269492499336128, + ], + linf=[ + 0.06386175207349379, + 0.0378926444850457, + 0.041759728067967065, + 0.06430136016259067, + ]) + # 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 -@test_nowarn rm(outdir, recursive=true) +@test_nowarn rm(outdir, recursive = true) end # module diff --git a/test/test_p4est_3d.jl b/test/test_p4est_3d.jl index 370f864b5aa..63077deb436 100644 --- a/test/test_p4est_3d.jl +++ b/test/test_p4est_3d.jl @@ -9,311 +9,453 @@ EXAMPLES_DIR = joinpath(examples_dir(), "p4est_3d_dgsem") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) @testset "P4estMesh3D" begin - @trixi_testset "elixir_advection_basic.jl" begin +#! format: noindent + +@trixi_testset "elixir_advection_basic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), - # Expected errors are exactly the same as with TreeMesh! - l2 = [0.00016263963870641478], - linf = [0.0014537194925779984]) - # 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 + # Expected errors are exactly the same as with TreeMesh! + l2=[0.00016263963870641478], + linf=[0.0014537194925779984]) + # 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_unstructured_curved.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_unstructured_curved.jl"), - l2 = [0.0004750004258546538], - linf = [0.026527551737137167]) - # 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_unstructured_curved.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_unstructured_curved.jl"), + l2=[0.0004750004258546538], + linf=[0.026527551737137167]) + # 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_nonconforming.jl" begin +@trixi_testset "elixir_advection_nonconforming.jl" begin @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 - # (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 + l2=[0.00253595715323843], + linf=[0.016486952252155795]) + # 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_amr.jl" begin +@trixi_testset "elixir_advection_amr.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr.jl"), - # Expected errors are exactly the same as with TreeMesh! - l2 = [9.773852895157622e-6], - linf = [0.0005853874124926162], - 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 - # (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 + # Expected errors are exactly the same as with TreeMesh! + l2=[9.773852895157622e-6], + linf=[0.0005853874124926162], + 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 + # (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_amr_unstructured_curved.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_unstructured_curved.jl"), - l2 = [1.6236411810065552e-5], - linf = [0.0010554006923731395], - 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 - # (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_amr_unstructured_curved.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_amr_unstructured_curved.jl"), + l2=[1.6236411810065552e-5], + linf=[0.0010554006923731395], + 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 + # (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_cubed_sphere.jl" begin +@trixi_testset "elixir_advection_cubed_sphere.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_cubed_sphere.jl"), - l2 = [0.002006918015656413], - linf = [0.027655117058380085]) - # 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 + l2=[0.002006918015656413], + linf=[0.027655117058380085]) + # 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_restart.jl" begin +@trixi_testset "elixir_advection_restart.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), - l2 = [0.002590388934758452], - linf = [0.01840757696885409]) - # 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 + l2=[0.002590388934758452], + linf=[0.01840757696885409]) + # 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_source_terms_nonconforming_unstructured_curved.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonconforming_unstructured_curved.jl"), - l2 = [4.070355207909268e-5, 4.4993257426833716e-5, 5.10588457841744e-5, 5.102840924036687e-5, 0.00019986264001630542], - linf = [0.0016987332417202072, 0.003622956808262634, 0.002029576258317789, 0.0024206977281964193, 0.008526972236273522], - tspan = (0.0, 0.01)) - # 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_source_terms_nonconforming_unstructured_curved.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonconforming_unstructured_curved.jl"), + l2=[ + 4.070355207909268e-5, + 4.4993257426833716e-5, + 5.10588457841744e-5, + 5.102840924036687e-5, + 0.00019986264001630542, + ], + linf=[ + 0.0016987332417202072, + 0.003622956808262634, + 0.002029576258317789, + 0.0024206977281964193, + 0.008526972236273522, + ], + tspan=(0.0, 0.01)) + # 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_source_terms_nonperiodic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonperiodic.jl"), - l2 = [0.0015106060984283647, 0.0014733349038567685, 0.00147333490385685, 0.001473334903856929, 0.0028149479453087093], - linf = [0.008070806335238156, 0.009007245083113125, 0.009007245083121784, 0.009007245083102688, 0.01562861968368434], - tspan = (0.0, 1.0)) - # 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_source_terms_nonperiodic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonperiodic.jl"), + l2=[ + 0.0015106060984283647, + 0.0014733349038567685, + 0.00147333490385685, + 0.001473334903856929, + 0.0028149479453087093, + ], + linf=[ + 0.008070806335238156, + 0.009007245083113125, + 0.009007245083121784, + 0.009007245083102688, + 0.01562861968368434, + ], + tspan=(0.0, 1.0)) + # 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.jl" begin +@trixi_testset "elixir_euler_free_stream.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_free_stream.jl"), - l2 = [5.162664597942288e-15, 1.941857343642486e-14, 2.0232366394187278e-14, 2.3381518645408552e-14, 7.083114561232324e-14], - linf = [7.269740365245525e-13, 3.289868377720495e-12, 4.440087186807773e-12, 3.8686831516088205e-12, 9.412914891981927e-12], - tspan = (0.0, 0.03)) - # 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 + l2=[ + 5.162664597942288e-15, + 1.941857343642486e-14, + 2.0232366394187278e-14, + 2.3381518645408552e-14, + 7.083114561232324e-14, + ], + linf=[ + 7.269740365245525e-13, + 3.289868377720495e-12, + 4.440087186807773e-12, + 3.8686831516088205e-12, + 9.412914891981927e-12, + ], + tspan=(0.0, 0.03)) + # 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" begin +@trixi_testset "elixir_euler_free_stream_extruded.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_free_stream_extruded.jl"), - l2 = [8.444868392439035e-16, 4.889826056731442e-15, 2.2921260987087585e-15, 4.268460455702414e-15, 1.1356712092620279e-14], - linf = [7.749356711883593e-14, 2.8792246364872653e-13, 1.1121659149182506e-13, 3.3228975127030935e-13, 9.592326932761353e-13], - tspan=(0.0, 0.1)) - # 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 + l2=[ + 8.444868392439035e-16, + 4.889826056731442e-15, + 2.2921260987087585e-15, + 4.268460455702414e-15, + 1.1356712092620279e-14, + ], + linf=[ + 7.749356711883593e-14, + 2.8792246364872653e-13, + 1.1121659149182506e-13, + 3.3228975127030935e-13, + 9.592326932761353e-13, + ], + tspan=(0.0, 0.1)) + # 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_ec.jl" begin +@trixi_testset "elixir_euler_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.010380390326164493, 0.006192950051354618, 0.005970674274073704, 0.005965831290564327, 0.02628875593094754], - linf = [0.3326911600075694, 0.2824952141320467, 0.41401037398065543, 0.45574161423218573, 0.8099577682187109], - tspan = (0.0, 0.2), - coverage_override = (polydeg=3,)) # Prevent long compile time in CI - # 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 + l2=[ + 0.010380390326164493, + 0.006192950051354618, + 0.005970674274073704, + 0.005965831290564327, + 0.02628875593094754, + ], + linf=[ + 0.3326911600075694, + 0.2824952141320467, + 0.41401037398065543, + 0.45574161423218573, + 0.8099577682187109, + ], + tspan=(0.0, 0.2), + coverage_override=(polydeg = 3,)) # Prevent long compile time in CI + # 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 +@trixi_testset "elixir_euler_sedov.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov.jl"), - l2 = [7.82070951e-02, 4.33260474e-02, 4.33260474e-02, 4.33260474e-02, 3.75260911e-01], - linf = [7.45329845e-01, 3.21754792e-01, 3.21754792e-01, 3.21754792e-01, 4.76151527e+00], - tspan = (0.0, 0.3), - coverage_override = (polydeg=3,)) # Prevent long compile time in CI - # 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 + l2=[ + 7.82070951e-02, + 4.33260474e-02, + 4.33260474e-02, + 4.33260474e-02, + 3.75260911e-01, + ], + linf=[ + 7.45329845e-01, + 3.21754792e-01, + 3.21754792e-01, + 3.21754792e-01, + 4.76151527e+00, + ], + tspan=(0.0, 0.3), + coverage_override=(polydeg = 3,)) # Prevent long compile time in CI + # 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_source_terms_nonconforming_earth.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonconforming_earth.jl"), - l2 = [6.040180337738628e-6, 5.4254175153621895e-6, 5.677698851333843e-6, 5.8017136892469794e-6, 1.3637854615117974e-5], - linf = [0.00013996924184311865, 0.00013681539559939893, 0.00013681539539733834, 0.00013681539541021692, 0.00016833038543762058], - # Decrease tolerance of adaptive time stepping to get similar results across different systems - abstol=1.0e-11, reltol=1.0e-11, - coverage_override = (trees_per_cube_face=(1, 1), polydeg=3)) # Prevent long compile time in CI - # 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_source_terms_nonconforming_earth.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonconforming_earth.jl"), + l2=[ + 6.040180337738628e-6, + 5.4254175153621895e-6, + 5.677698851333843e-6, + 5.8017136892469794e-6, + 1.3637854615117974e-5, + ], + linf=[ + 0.00013996924184311865, + 0.00013681539559939893, + 0.00013681539539733834, + 0.00013681539541021692, + 0.00016833038543762058, + ], + # Decrease tolerance of adaptive time stepping to get similar results across different systems + abstol=1.0e-11, reltol=1.0e-11, + coverage_override=(trees_per_cube_face = (1, 1), polydeg = 3)) # Prevent long compile time in CI + # 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_circular_wind_nonconforming.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_circular_wind_nonconforming.jl"), - l2 = [1.573832094977477e-7, 3.863090659429634e-5, 3.867293305754584e-5, 3.686550296950078e-5, 0.05508968493733932], - linf = [2.2695202613887133e-6, 0.0005314968179916946, 0.0005314969614147458, 0.0005130280733059617, 0.7944959432352334], - tspan = (0.0, 2e2), - coverage_override = (trees_per_cube_face=(1, 1), polydeg=3)) # Prevent long compile time in CI - # 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_circular_wind_nonconforming.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_circular_wind_nonconforming.jl"), + l2=[ + 1.573832094977477e-7, + 3.863090659429634e-5, + 3.867293305754584e-5, + 3.686550296950078e-5, + 0.05508968493733932, + ], + linf=[ + 2.2695202613887133e-6, + 0.0005314968179916946, + 0.0005314969614147458, + 0.0005130280733059617, + 0.7944959432352334, + ], + tspan=(0.0, 2e2), + coverage_override=(trees_per_cube_face = (1, 1), polydeg = 3)) # Prevent long compile time in CI + # 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_baroclinic_instability.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_baroclinic_instability.jl"), - l2 = [6.725065410642336e-7, 0.00021710117340245454, 0.000438679759422352, 0.00020836356588024185, 0.07602006689579247], - linf = [1.9101671995258585e-5, 0.029803626911022396, 0.04847630924006063, 0.022001371349740104, 4.847761006938526], - tspan = (0.0, 1e2), - # Decrease tolerance of adaptive time stepping to get similar results across different systems - abstol=1.0e-9, reltol=1.0e-9, - coverage_override = (trees_per_cube_face=(1, 1), polydeg=3)) # Prevent long compile time in CI - # 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_baroclinic_instability.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_baroclinic_instability.jl"), + l2=[ + 6.725065410642336e-7, + 0.00021710117340245454, + 0.000438679759422352, + 0.00020836356588024185, + 0.07602006689579247, + ], + linf=[ + 1.9101671995258585e-5, + 0.029803626911022396, + 0.04847630924006063, + 0.022001371349740104, + 4.847761006938526, + ], + tspan=(0.0, 1e2), + # Decrease tolerance of adaptive time stepping to get similar results across different systems + abstol=1.0e-9, reltol=1.0e-9, + coverage_override=(trees_per_cube_face = (1, 1), polydeg = 3)) # Prevent long compile time in CI + # 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_source_terms_nonperiodic_hohqmesh.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonperiodic_hohqmesh.jl"), - l2 = [0.0042023406458005464, 0.004122532789279737, 0.0042448149597303616, 0.0036361316700401765, 0.007389845952982495], - linf = [0.04530610539892499, 0.02765695110527666, 0.05670295599308606, 0.048396544302230504, 0.1154589758186293]) - # 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_source_terms_nonperiodic_hohqmesh.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonperiodic_hohqmesh.jl"), + l2=[ + 0.0042023406458005464, + 0.004122532789279737, + 0.0042448149597303616, + 0.0036361316700401765, + 0.007389845952982495, + ], + linf=[ + 0.04530610539892499, + 0.02765695110527666, + 0.05670295599308606, + 0.048396544302230504, + 0.1154589758186293, + ]) + # 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_mhd_alfven_wave_nonconforming.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave_nonconforming.jl"), - l2 = [0.00019018725889431733, 0.0006523517707148006, 0.0002401595437705759, 0.0007796920661427565, - 0.0007095787460334334, 0.0006558819731628876, 0.0003565026134076906, 0.0007904654548841712, - 9.437300326448332e-7], - linf = [0.0012482306861187897, 0.006408776208178299, 0.0016845452099629663, 0.0068711236542984555, - 0.004626581522263695, 0.006614624811393632, 0.0030068344747734566, 0.008277825749754025, - 1.3475027166309006e-5], - tspan = (0.0, 0.25), - coverage_override = (trees_per_dimension=(1, 1, 1),)) - # 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_mhd_alfven_wave_nonconforming.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_mhd_alfven_wave_nonconforming.jl"), + l2=[0.00019018725889431733, 0.0006523517707148006, + 0.0002401595437705759, 0.0007796920661427565, + 0.0007095787460334334, 0.0006558819731628876, + 0.0003565026134076906, 0.0007904654548841712, + 9.437300326448332e-7], + linf=[0.0012482306861187897, 0.006408776208178299, + 0.0016845452099629663, 0.0068711236542984555, + 0.004626581522263695, 0.006614624811393632, + 0.0030068344747734566, 0.008277825749754025, + 1.3475027166309006e-5], + tspan=(0.0, 0.25), + coverage_override=(trees_per_dimension = (1, 1, 1),)) + # 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_mhd_shockcapturing_amr.jl" begin +@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], - tspan = (0.0, 0.04), - coverage_override = (maxiters=6, initial_refinement_level=1, base_level=1, max_level=2)) - # 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 + 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], + tspan=(0.0, 0.04), + coverage_override=(maxiters = 6, initial_refinement_level = 1, + base_level = 1, max_level = 2)) + # 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 -@test_nowarn rm(outdir, recursive=true) +@test_nowarn rm(outdir, recursive = true) end # module diff --git a/test/test_paper_self_gravitating_gas_dynamics.jl b/test/test_paper_self_gravitating_gas_dynamics.jl index 68aa2992601..10b4f93ad74 100644 --- a/test/test_paper_self_gravitating_gas_dynamics.jl +++ b/test/test_paper_self_gravitating_gas_dynamics.jl @@ -7,231 +7,352 @@ include("test_trixi.jl") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) const EXAMPLES_DIR = pkgdir(Trixi, "examples", "paper_self_gravitating_gas_dynamics") # Numerical examples from the Euler-gravity paper @testset "paper_self_gravitating_gas_dynamics" begin - @trixi_testset "elixir_euler_convergence.jl" begin +#! format: noindent + +@trixi_testset "elixir_euler_convergence.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), - l2 = [0.0001740977055972079, 0.0003369355182519592, 0.0003369355182518708, 0.0006099171220334989], - linf = [0.001079347149189669, 0.0018836938381321389, 0.001883693838132583, 0.003971575376718217]) - # 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_convergence.jl with polydeg=4" begin + l2=[ + 0.0001740977055972079, + 0.0003369355182519592, + 0.0003369355182518708, + 0.0006099171220334989, + ], + linf=[ + 0.001079347149189669, + 0.0018836938381321389, + 0.001883693838132583, + 0.003971575376718217, + ]) + # 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_convergence.jl with polydeg=4" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), - l2 = [1.7187201161597772e-5, 2.678065111772951e-5, 2.678065111783027e-5, 4.952504160091526e-5], - linf = [0.0001501749544159381, 0.00016549482504535362, 0.00016549482504601976, 0.0004372960291432193], - polydeg = 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 - - - @trixi_testset "elixir_hypdiff_convergence.jl" begin + l2=[ + 1.7187201161597772e-5, + 2.678065111772951e-5, + 2.678065111783027e-5, + 4.952504160091526e-5, + ], + linf=[ + 0.0001501749544159381, + 0.00016549482504535362, + 0.00016549482504601976, + 0.0004372960291432193, + ], + polydeg=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 + +@trixi_testset "elixir_hypdiff_convergence.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_convergence.jl"), - l2 = [0.003154024896093942, 0.012394432074951856, 0.02185973823794725], - linf = [0.01731850928579215, 0.07843510773347553, 0.11242300176349201]) - # 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_hypdiff_convergence.jl with polydeg=4" begin + l2=[ + 0.003154024896093942, + 0.012394432074951856, + 0.02185973823794725, + ], + linf=[ + 0.01731850928579215, + 0.07843510773347553, + 0.11242300176349201, + ]) + # 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_hypdiff_convergence.jl with polydeg=4" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_convergence.jl"), - l2 = [0.0002511283012128458, 0.0008808243846610255, 0.0016313343228567005], - linf = [0.0017290715087938668, 0.003129184465704738, 0.01000728849316701], - polydeg = 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 - - - @trixi_testset "elixir_eulergravity_convergence.jl" begin + l2=[ + 0.0002511283012128458, + 0.0008808243846610255, + 0.0016313343228567005, + ], + linf=[ + 0.0017290715087938668, + 0.003129184465704738, + 0.01000728849316701, + ], + polydeg=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 + +@trixi_testset "elixir_eulergravity_convergence.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulergravity_convergence.jl"), - l2 = [0.00024871265138964204, 0.0003370077102132591, 0.0003370077102131964, 0.0007231525513793697], - linf = [0.0015813032944647087, 0.0020494288423820173, 0.0020494288423824614, 0.004793821195083758], - tspan = (0.0, 0.1)) - # 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_eulergravity_convergence.jl with polydeg=4" begin + l2=[ + 0.00024871265138964204, + 0.0003370077102132591, + 0.0003370077102131964, + 0.0007231525513793697, + ], + linf=[ + 0.0015813032944647087, + 0.0020494288423820173, + 0.0020494288423824614, + 0.004793821195083758, + ], + tspan=(0.0, 0.1)) + # 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_eulergravity_convergence.jl with polydeg=4" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulergravity_convergence.jl"), - l2 = [1.9537712148648045e-5, 2.7564396197947587e-5, 2.7564396197967635e-5, 5.688838772067586e-5], - linf = [0.00012335710672761735, 0.00020086268350816283, 0.00020086268350727465, 0.0004962155455632278], - tspan = (0.0, 0.1), polydeg = 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 - - @trixi_testset "elixir_eulergravity_convergence.jl with 1st order RK3S*" begin + l2=[ + 1.9537712148648045e-5, + 2.7564396197947587e-5, + 2.7564396197967635e-5, + 5.688838772067586e-5, + ], + linf=[ + 0.00012335710672761735, + 0.00020086268350816283, + 0.00020086268350727465, + 0.0004962155455632278, + ], + tspan=(0.0, 0.1), polydeg=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 + +@trixi_testset "elixir_eulergravity_convergence.jl with 1st order RK3S*" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulergravity_convergence.jl"), - l2 = [0.00024871265138959434, 0.000337007710281087, 0.0003370077102811394, 0.0007231525515231289], - linf = [0.0015813032941613958, 0.002049428843978518, 0.0020494288439798503, 0.004793821198143977], - tspan = (0.0, 0.1), timestep_gravity=Trixi.timestep_gravity_erk51_3Sstar!) - # 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_eulergravity_convergence.jl with 3rd order RK3S*" begin + l2=[ + 0.00024871265138959434, + 0.000337007710281087, + 0.0003370077102811394, + 0.0007231525515231289, + ], + linf=[ + 0.0015813032941613958, + 0.002049428843978518, + 0.0020494288439798503, + 0.004793821198143977, + ], + tspan=(0.0, 0.1), + timestep_gravity=Trixi.timestep_gravity_erk51_3Sstar!) + # 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_eulergravity_convergence.jl with 3rd order RK3S*" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulergravity_convergence.jl"), - l2 = [0.0002487126513894034, 0.00033700771023049785, 0.00033700771023048245, 0.0007231525514158737], - linf = [0.0015813032943847727, 0.002049428842844314, 0.0020494288428452023, 0.004793821195971937], - tspan = (0.0, 0.1), timestep_gravity=Trixi.timestep_gravity_erk53_3Sstar!) - # 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_eulergravity_jeans_instability.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulergravity_jeans_instability.jl"), - l2 = [10733.63378538114, 13356.780607423452, 1.6722844879795038e-6, 26834.076821148774], - linf = [15194.296424901113, 18881.481685044182, 6.809726988008751e-6, 37972.99700513482], - tspan = (0.0, 0.1), - atol = 4.0e-6 # the background field is reatively large, so this corresponds to our usual atol - ) - # 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_eulergravity_jeans_instability.jl with RK3S*" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulergravity_jeans_instability.jl"), - l2 = [10734.598193238024, 13358.217234481384, 1.911011743371934e-6, 26836.487841241516], - linf = [15195.661004798487, 18883.512035906537, 7.867948710816926e-6, 37976.408478975296], - tspan = (0.0, 0.1), - atol = 4.0e-6, # the background field is reatively large, so this corresponds to our usual atol - parameters=ParametersEulerGravity(background_density=1.5e7, - gravitational_constant=6.674e-8, - cfl=2.4, - resid_tol=1.0e-4, - n_iterations_max=1000, - timestep_gravity=timestep_gravity_erk52_3Sstar!)) - # 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 "Printing" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulergravity_jeans_instability.jl"), - tspan = (0.0, 1.0e-5), - parameters=ParametersEulerGravity(background_density=1.5e7, - gravitational_constant=6.674e-8, - cfl=2.4, - resid_tol=1.0e-4, - n_iterations_max=1000, - timestep_gravity=timestep_gravity_erk52_3Sstar!)) + l2=[ + 0.0002487126513894034, + 0.00033700771023049785, + 0.00033700771023048245, + 0.0007231525514158737, + ], + linf=[ + 0.0015813032943847727, + 0.002049428842844314, + 0.0020494288428452023, + 0.004793821195971937, + ], + tspan=(0.0, 0.1), + timestep_gravity=Trixi.timestep_gravity_erk53_3Sstar!) + # 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_eulergravity_jeans_instability.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_eulergravity_jeans_instability.jl"), + l2=[ + 10733.63378538114, + 13356.780607423452, + 1.6722844879795038e-6, + 26834.076821148774, + ], + linf=[ + 15194.296424901113, + 18881.481685044182, + 6.809726988008751e-6, + 37972.99700513482, + ], + tspan=(0.0, 0.1), + atol=4.0e-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 +end + +@trixi_testset "elixir_eulergravity_jeans_instability.jl with RK3S*" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_eulergravity_jeans_instability.jl"), + l2=[ + 10734.598193238024, + 13358.217234481384, + 1.911011743371934e-6, + 26836.487841241516, + ], + linf=[ + 15195.661004798487, + 18883.512035906537, + 7.867948710816926e-6, + 37976.408478975296, + ], + tspan=(0.0, 0.1), + atol=4.0e-6, # the background field is reatively large, so this corresponds to our usual atol + parameters=ParametersEulerGravity(background_density = 1.5e7, + gravitational_constant = 6.674e-8, + cfl = 2.4, + resid_tol = 1.0e-4, + n_iterations_max = 1000, + timestep_gravity = timestep_gravity_erk52_3Sstar!)) + # 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 "Printing" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_eulergravity_jeans_instability.jl"), + tspan=(0.0, 1.0e-5), + parameters=ParametersEulerGravity(background_density = 1.5e7, + gravitational_constant = 6.674e-8, + cfl = 2.4, + resid_tol = 1.0e-4, + n_iterations_max = 1000, + timestep_gravity = timestep_gravity_erk52_3Sstar!)) show(stdout, parameters) show(stdout, semi) show(stdout, semi_euler.boundary_conditions) show(stdout, TrivialCallback()) show(stdout, equations_euler) - # 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 + # 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_eulergravity_sedov_blast_wave.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_eulergravity_sedov_blast_wave.jl"), + l2=[ + 0.046315994852653024, + 0.0650818006233669, + 0.06508180062336677, + 0.4896707211656037, + ], + linf=[ + 2.3874843337593776, + 4.07876384374792, + 4.07876384374792, + 16.23914384809855, + ], + tspan=(0.0, 0.05), + coverage_override=(maxiters = 2,)) + # 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_eulergravity_sedov_blast_wave.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulergravity_sedov_blast_wave.jl"), - l2 = [0.046315994852653024, 0.0650818006233669, 0.06508180062336677, 0.4896707211656037], - linf = [2.3874843337593776, 4.07876384374792, 4.07876384374792, 16.23914384809855], - tspan = (0.0, 0.05), - coverage_override = (maxiters=2,)) - # 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_eulergravity_sedov_blast_wave.jl with ref-level=8 and no AMR" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulergravity_sedov_blast_wave.jl"), - l2 = [0.00289222135995042, 0.013724813590853825, 0.013724813590853832, 0.05822904710548214], - linf = [0.26361780693997594, 1.3908873830688688, 1.3908873830688688, 4.066701303607613], - tspan = (0.0, 0.005), initial_refinement_level=8, amr_callback=TrivialCallback()) - # 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 + +@trixi_testset "elixir_eulergravity_sedov_blast_wave.jl with ref-level=8 and no AMR" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_eulergravity_sedov_blast_wave.jl"), + l2=[ + 0.00289222135995042, + 0.013724813590853825, + 0.013724813590853832, + 0.05822904710548214, + ], + linf=[ + 0.26361780693997594, + 1.3908873830688688, + 1.3908873830688688, + 4.066701303607613, + ], + tspan=(0.0, 0.005), initial_refinement_level=8, + amr_callback=TrivialCallback()) + # 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 -@test_nowarn rm(outdir, recursive=true) +@test_nowarn rm(outdir, recursive = true) end #module diff --git a/test/test_parabolic_1d.jl b/test/test_parabolic_1d.jl index d1f8b4d8057..c1cfec052fe 100644 --- a/test/test_parabolic_1d.jl +++ b/test/test_parabolic_1d.jl @@ -5,162 +5,217 @@ using Trixi include("test_trixi.jl") - # Start with a clean environment: remove Trixi output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) @testset "SemidiscretizationHyperbolicParabolic (1D)" begin - - @trixi_testset "TreeMesh1D: elixir_advection_diffusion.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", "elixir_advection_diffusion.jl"), - initial_refinement_level = 4, tspan=(0.0, 0.4), polydeg=3, - l2 = [8.389498188525518e-06], - linf = [2.847421658558336e-05] - ) - # 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 +#! format: noindent + +@trixi_testset "TreeMesh1D: elixir_advection_diffusion.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", + "elixir_advection_diffusion.jl"), + initial_refinement_level=4, tspan=(0.0, 0.4), polydeg=3, + l2=[8.389498188525518e-06], + linf=[2.847421658558336e-05]) + # 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 "TreeMesh1D: elixir_advection_diffusion.jl (AMR)" begin - @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", "elixir_advection_diffusion.jl"), - tspan=(0.0, 0.0), initial_refinement_level = 5) - tspan=(0.0, 1.0) - ode = semidiscretize(semi, tspan) - amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable=first), - base_level=4, - med_level=5, med_threshold=0.1, - max_level=6, max_threshold=0.6) - amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true) +end - # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver - callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, amr_callback) - sol = solve(ode, KenCarp4(autodiff=false), abstol=time_abs_tol, reltol=time_int_tol, - save_everystep=false, callback=callbacks) - l2_error, linf_error = analysis_callback(sol) - @test l2_error ≈ [6.4878111416468355e-6] - @test linf_error ≈ [3.258075790424364e-5] - # 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 "TreeMesh1D: elixir_advection_diffusion.jl (AMR)" begin + @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", + "elixir_advection_diffusion.jl"), + tspan=(0.0, 0.0), initial_refinement_level=5) + tspan = (0.0, 1.0) + ode = semidiscretize(semi, tspan) + amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first), + base_level = 4, + med_level = 5, med_threshold = 0.1, + max_level = 6, max_threshold = 0.6) + amr_callback = AMRCallback(semi, amr_controller, + interval = 5, + adapt_initial_condition = true) + + # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver + callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, + amr_callback) + sol = solve(ode, KenCarp4(autodiff = false), abstol = time_abs_tol, + reltol = time_int_tol, + save_everystep = false, callback = callbacks) + l2_error, linf_error = analysis_callback(sol) + @test l2_error ≈ [6.4878111416468355e-6] + @test linf_error ≈ [3.258075790424364e-5] + # 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 "TreeMesh1D: elixir_navierstokes_convergence_periodic.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", "elixir_navierstokes_convergence_periodic.jl"), - l2 = [0.0001133835907077494, 6.226282245610444e-5, 0.0002820171699999139], - linf = [0.0006255102377159538, 0.00036195501456059986, 0.0016147729485886941] - ) - # 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 +@trixi_testset "TreeMesh1D: elixir_navierstokes_convergence_periodic.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", + "elixir_navierstokes_convergence_periodic.jl"), + l2=[ + 0.0001133835907077494, + 6.226282245610444e-5, + 0.0002820171699999139, + ], + linf=[ + 0.0006255102377159538, + 0.00036195501456059986, + 0.0016147729485886941, + ]) + # 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 - @trixi_testset "TreeMesh1D: elixir_navierstokes_convergence_periodic.jl: GradientVariablesEntropy" begin - @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", "elixir_navierstokes_convergence_periodic.jl"), - equations_parabolic = CompressibleNavierStokesDiffusion1D(equations, mu=mu(), - Prandtl=prandtl_number(), - gradient_variables = GradientVariablesEntropy()), - l2 = [0.00011310615871043463, 6.216495207074201e-5, 0.00028195843110817814], - linf = [0.0006240837363233886, 0.0003616694320713876, 0.0016147339542413874] - ) - # 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 +@trixi_testset "TreeMesh1D: elixir_navierstokes_convergence_periodic.jl: GradientVariablesEntropy" begin + @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", + "elixir_navierstokes_convergence_periodic.jl"), + equations_parabolic=CompressibleNavierStokesDiffusion1D(equations, + mu = mu(), + Prandtl = prandtl_number(), + gradient_variables = GradientVariablesEntropy()), + l2=[ + 0.00011310615871043463, + 6.216495207074201e-5, + 0.00028195843110817814, + ], + linf=[ + 0.0006240837363233886, + 0.0003616694320713876, + 0.0016147339542413874, + ]) + # 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 - @trixi_testset "TreeMesh1D: elixir_navierstokes_convergence_walls.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", "elixir_navierstokes_convergence_walls.jl"), - l2 = [0.00047023310868269237, 0.00032181736027057234, 0.0014966266486095025], - linf = [0.002996375101363302, 0.002863904256059634, 0.012691132946258676] - ) - # 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 +@trixi_testset "TreeMesh1D: elixir_navierstokes_convergence_walls.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", + "elixir_navierstokes_convergence_walls.jl"), + l2=[ + 0.00047023310868269237, + 0.00032181736027057234, + 0.0014966266486095025, + ], + linf=[ + 0.002996375101363302, + 0.002863904256059634, + 0.012691132946258676, + ]) + # 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 - @trixi_testset "TreeMesh1D: elixir_navierstokes_convergence_walls.jl: GradientVariablesEntropy" begin - @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", "elixir_navierstokes_convergence_walls.jl"), - equations_parabolic = CompressibleNavierStokesDiffusion1D(equations, mu=mu(), - Prandtl=prandtl_number(), - gradient_variables = GradientVariablesEntropy()), - l2 = [0.0004608500483647771, 0.00032431091222851285, 0.0015159733360626845], - linf = [0.002754803146635787, 0.0028567714697580906, 0.012941794048176192] - ) - # 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 +@trixi_testset "TreeMesh1D: elixir_navierstokes_convergence_walls.jl: GradientVariablesEntropy" begin + @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", + "elixir_navierstokes_convergence_walls.jl"), + equations_parabolic=CompressibleNavierStokesDiffusion1D(equations, + mu = mu(), + Prandtl = prandtl_number(), + gradient_variables = GradientVariablesEntropy()), + l2=[ + 0.0004608500483647771, + 0.00032431091222851285, + 0.0015159733360626845, + ], + linf=[ + 0.002754803146635787, + 0.0028567714697580906, + 0.012941794048176192, + ]) + # 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 - @trixi_testset "TreeMesh1D: elixir_navierstokes_convergence_walls_amr.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", "elixir_navierstokes_convergence_walls_amr.jl"), - equations_parabolic = CompressibleNavierStokesDiffusion1D(equations, mu=mu(), - Prandtl=prandtl_number()), - l2 = [2.5278824700860636e-5, 2.5540078777006958e-5, 0.00012118655083858043], - linf = [0.0001466387075579334, 0.00019422427462629705, 0.0009556446847707178] - ) - # 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 +@trixi_testset "TreeMesh1D: elixir_navierstokes_convergence_walls_amr.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", + "elixir_navierstokes_convergence_walls_amr.jl"), + equations_parabolic=CompressibleNavierStokesDiffusion1D(equations, + mu = mu(), + Prandtl = prandtl_number()), + l2=[ + 2.5278824700860636e-5, + 2.5540078777006958e-5, + 0.00012118655083858043, + ], + linf=[ + 0.0001466387075579334, + 0.00019422427462629705, + 0.0009556446847707178, + ]) + # 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 - @trixi_testset "TreeMesh1D: elixir_navierstokes_convergence_walls_amr.jl: GradientVariablesEntropy" begin - @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", "elixir_navierstokes_convergence_walls_amr.jl"), - equations_parabolic = CompressibleNavierStokesDiffusion1D(equations, mu=mu(), - Prandtl=prandtl_number(), - gradient_variables = GradientVariablesEntropy()), - l2 = [2.459359632523962e-5, 2.3928390718460263e-5, 0.00011252414117082376], - linf = [0.0001185052018830568, 0.00018987717854305393, 0.0009597503607920999] - ) - # 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 +@trixi_testset "TreeMesh1D: elixir_navierstokes_convergence_walls_amr.jl: GradientVariablesEntropy" begin + @test_trixi_include(joinpath(examples_dir(), "tree_1d_dgsem", + "elixir_navierstokes_convergence_walls_amr.jl"), + equations_parabolic=CompressibleNavierStokesDiffusion1D(equations, + mu = mu(), + Prandtl = prandtl_number(), + gradient_variables = GradientVariablesEntropy()), + l2=[ + 2.459359632523962e-5, + 2.3928390718460263e-5, + 0.00011252414117082376, + ], + linf=[ + 0.0001185052018830568, + 0.00018987717854305393, + 0.0009597503607920999, + ]) + # 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 end # Clean up afterwards: delete Trixi output directory -@test_nowarn isdir(outdir) && rm(outdir, recursive=true) +@test_nowarn isdir(outdir) && rm(outdir, recursive = true) end # module diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index a57462ef7ea..22a5a8b4e31 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -5,19 +5,18 @@ using Trixi include("test_trixi.jl") - # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) @testset "SemidiscretizationHyperbolicParabolic (2D)" begin +#! format: noindent - @trixi_testset "DGMulti 2D rhs_parabolic!" begin - +@trixi_testset "DGMulti 2D rhs_parabolic!" begin dg = DGMulti(polydeg = 2, element_type = Quad(), approximation_type = Polynomial(), surface_integral = SurfaceIntegralWeakForm(flux_central), volume_integral = VolumeIntegralWeakForm()) - mesh = DGMultiMesh(dg, cells_per_dimension=(2, 2)) + mesh = DGMultiMesh(dg, cells_per_dimension = (2, 2)) # test with polynomial initial condition x^2 * y # test if we recover the exact second derivative @@ -26,7 +25,8 @@ isdir(outdir) && rm(outdir, recursive=true) equations = LinearScalarAdvectionEquation2D(1.0, 1.0) equations_parabolic = LaplaceDiffusion2D(1.0, equations) - semi = SemidiscretizationHyperbolicParabolic(mesh, equations, equations_parabolic, initial_condition, dg) + semi = SemidiscretizationHyperbolicParabolic(mesh, equations, equations_parabolic, + initial_condition, dg) @test_nowarn_mod show(stdout, semi) @test_nowarn_mod show(stdout, MIME"text/plain"(), semi) @test_nowarn_mod show(stdout, boundary_condition_do_nothing) @@ -46,8 +46,8 @@ isdir(outdir) && rm(outdir, recursive=true) @unpack cache, cache_parabolic, equations_parabolic = semi @unpack gradients = cache_parabolic for dim in eachindex(gradients) - fill!(gradients[dim], zero(eltype(gradients[dim]))) - end + fill!(gradients[dim], zero(eltype(gradients[dim]))) + end t = 0.0 # pass in `boundary_condition_periodic` to skip boundary flux/integral evaluation @@ -55,7 +55,7 @@ isdir(outdir) && rm(outdir, recursive=true) boundary_condition_periodic, dg, cache, cache_parabolic) @unpack x, y, xq, yq = mesh.md @test getindex.(gradients[1], 1) ≈ 2 * xq .* yq - @test getindex.(gradients[2], 1) ≈ xq.^2 + @test getindex.(gradients[2], 1) ≈ xq .^ 2 u_flux = similar.(gradients) Trixi.calc_viscous_fluxes!(u_flux, ode.u0, gradients, mesh, equations_parabolic, @@ -64,425 +64,579 @@ isdir(outdir) && rm(outdir, recursive=true) @test u_flux[2] ≈ gradients[2] du = similar(ode.u0) - Trixi.calc_divergence!(du, ode.u0, t, u_flux, mesh, equations_parabolic, boundary_condition_periodic, + Trixi.calc_divergence!(du, ode.u0, t, u_flux, mesh, equations_parabolic, + boundary_condition_periodic, dg, semi.solver_parabolic, cache, cache_parabolic) @test getindex.(du, 1) ≈ 2 * y - end - - @trixi_testset "DGMulti: elixir_advection_diffusion.jl" begin - @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_advection_diffusion.jl"), - cells_per_dimension = (4, 4), tspan=(0.0, 0.1), - l2 = [0.2485803335154642], - linf = [1.079606969242132] - ) - # 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 + +@trixi_testset "DGMulti: elixir_advection_diffusion.jl" begin + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", + "elixir_advection_diffusion.jl"), + cells_per_dimension=(4, 4), tspan=(0.0, 0.1), + l2=[0.2485803335154642], + linf=[1.079606969242132]) + # 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 "DGMulti: elixir_advection_diffusion_periodic.jl" begin - @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_advection_diffusion_periodic.jl"), - cells_per_dimension = (4, 4), tspan=(0.0, 0.1), - l2 = [0.03180371984888462], - linf = [0.2136821621370909] - ) - # 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 + +@trixi_testset "DGMulti: elixir_advection_diffusion_periodic.jl" begin + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", + "elixir_advection_diffusion_periodic.jl"), + cells_per_dimension=(4, 4), tspan=(0.0, 0.1), + l2=[0.03180371984888462], + linf=[0.2136821621370909]) + # 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 "DGMulti: elixir_advection_diffusion_nonperiodic.jl" begin - @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_advection_diffusion_nonperiodic.jl"), - cells_per_dimension = (4, 4), tspan=(0.0, 0.1), - l2 = [0.002123168335604323], - linf = [0.00963640423513712] - ) - # 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 + +@trixi_testset "DGMulti: elixir_advection_diffusion_nonperiodic.jl" begin + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", + "elixir_advection_diffusion_nonperiodic.jl"), + cells_per_dimension=(4, 4), tspan=(0.0, 0.1), + l2=[0.002123168335604323], + linf=[0.00963640423513712]) + # 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 "DGMulti: elixir_navierstokes_convergence.jl" begin - @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_navierstokes_convergence.jl"), - cells_per_dimension = (4, 4), tspan=(0.0, 0.1), - l2 = [0.0015355076812510957, 0.0033843168272696756, 0.0036531858107443434, 0.009948436427519214], - linf = [0.005522560467190019, 0.013425258500730508, 0.013962115643482154, 0.027483102120502423] - ) - # 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 + +@trixi_testset "DGMulti: elixir_navierstokes_convergence.jl" begin + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", + "elixir_navierstokes_convergence.jl"), + cells_per_dimension=(4, 4), tspan=(0.0, 0.1), + l2=[ + 0.0015355076812510957, + 0.0033843168272696756, + 0.0036531858107443434, + 0.009948436427519214, + ], + linf=[ + 0.005522560467190019, + 0.013425258500730508, + 0.013962115643482154, + 0.027483102120502423, + ]) + # 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 "DGMulti: elixir_navierstokes_convergence_curved.jl" begin - @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_navierstokes_convergence_curved.jl"), - cells_per_dimension = (4, 4), tspan=(0.0, 0.1), - l2 = [0.004255101916146187, 0.011118488923215765, 0.011281831283462686, 0.03573656447388509], - linf = [0.015071710669706473, 0.04103132025858458, 0.03990424085750277, 0.1309401718598764], - ) - # 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 + +@trixi_testset "DGMulti: elixir_navierstokes_convergence_curved.jl" begin + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", + "elixir_navierstokes_convergence_curved.jl"), + cells_per_dimension=(4, 4), tspan=(0.0, 0.1), + l2=[ + 0.004255101916146187, + 0.011118488923215765, + 0.011281831283462686, + 0.03573656447388509, + ], + linf=[ + 0.015071710669706473, + 0.04103132025858458, + 0.03990424085750277, + 0.1309401718598764, + ],) + # 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 "DGMulti: elixir_navierstokes_lid_driven_cavity.jl" begin - @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_navierstokes_lid_driven_cavity.jl"), - cells_per_dimension = (4, 4), tspan=(0.0, 0.5), - l2 = [0.00022156125227115747, 0.028318325921401, 0.009509168701070296, 0.028267900513550506], - linf = [0.001562278941298234, 0.14886653390744856, 0.0716323565533752, 0.19472785105241996] - ) - # 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 + +@trixi_testset "DGMulti: elixir_navierstokes_lid_driven_cavity.jl" begin + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", + "elixir_navierstokes_lid_driven_cavity.jl"), + cells_per_dimension=(4, 4), tspan=(0.0, 0.5), + l2=[ + 0.00022156125227115747, + 0.028318325921401, + 0.009509168701070296, + 0.028267900513550506, + ], + linf=[ + 0.001562278941298234, + 0.14886653390744856, + 0.0716323565533752, + 0.19472785105241996, + ]) + # 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 "TreeMesh2D: elixir_advection_diffusion.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_diffusion.jl"), - initial_refinement_level = 2, tspan=(0.0, 0.4), polydeg=5, - l2 = [4.0915532997994255e-6], - linf = [2.3040850347877395e-5] - ) - # 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 + +@trixi_testset "TreeMesh2D: elixir_advection_diffusion.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_advection_diffusion.jl"), + initial_refinement_level=2, tspan=(0.0, 0.4), polydeg=5, + l2=[4.0915532997994255e-6], + linf=[2.3040850347877395e-5]) + # 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 "TreeMesh2D: elixir_advection_diffusion.jl (Refined mesh)" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_diffusion.jl"), - tspan=(0.0, 0.0)) - LLID = Trixi.local_leaf_cells(mesh.tree) - num_leafs = length(LLID) - @assert num_leafs % 8 == 0 - Trixi.refine!(mesh.tree, LLID[1:Int(num_leafs/8)]) - tspan=(0.0, 1.5) - semi = SemidiscretizationHyperbolicParabolic(mesh, - (equations, equations_parabolic), - initial_condition, solver; - boundary_conditions=(boundary_conditions, +end + +@trixi_testset "TreeMesh2D: elixir_advection_diffusion.jl (Refined mesh)" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_advection_diffusion.jl"), + tspan=(0.0, 0.0)) + LLID = Trixi.local_leaf_cells(mesh.tree) + num_leafs = length(LLID) + @assert num_leafs % 8 == 0 + Trixi.refine!(mesh.tree, LLID[1:Int(num_leafs / 8)]) + tspan = (0.0, 1.5) + semi = SemidiscretizationHyperbolicParabolic(mesh, + (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions = (boundary_conditions, boundary_conditions_parabolic)) - ode = semidiscretize(semi, tspan) - analysis_callback = AnalysisCallback(semi, interval=analysis_interval) - callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) - sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) - l2_error, linf_error = analysis_callback(sol) - @test l2_error ≈ [1.67452550744728e-6] - @test linf_error ≈ [7.905059166368744e-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) + ode = semidiscretize(semi, tspan) + analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) + sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) + l2_error, linf_error = analysis_callback(sol) + @test l2_error ≈ [1.67452550744728e-6] + @test linf_error ≈ [7.905059166368744e-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)) < 100 @test (@allocated Trixi.rhs_parabolic!(du_ode, u_ode, semi, t)) < 100 end - end - - @trixi_testset "TreeMesh2D: elixir_advection_diffusion_nonperiodic.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_diffusion_nonperiodic.jl"), - initial_refinement_level = 2, tspan=(0.0, 0.1), - l2 = [0.007646800618485118], - linf = [0.10067621050468958] - ) - # 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 + +@trixi_testset "TreeMesh2D: elixir_advection_diffusion_nonperiodic.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_advection_diffusion_nonperiodic.jl"), + initial_refinement_level=2, tspan=(0.0, 0.1), + l2=[0.007646800618485118], + linf=[0.10067621050468958]) + # 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 "TreeMesh2D: elixir_navierstokes_convergence.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navierstokes_convergence.jl"), - initial_refinement_level = 2, tspan=(0.0, 0.1), - analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(energy_kinetic, - energy_internal, - enstrophy)), - l2 = [0.002111672530658797, 0.0034322351490857846, 0.0038742528195910416, 0.012469246082568561], - linf = [0.012006418939223495, 0.035520871209746126, 0.024512747492231427, 0.11191122588756564] - ) - # 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 + +@trixi_testset "TreeMesh2D: elixir_navierstokes_convergence.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_navierstokes_convergence.jl"), + initial_refinement_level=2, tspan=(0.0, 0.1), + analysis_callback=AnalysisCallback(semi, + interval = analysis_interval, + extra_analysis_integrals = (energy_kinetic, + energy_internal, + enstrophy)), + l2=[ + 0.002111672530658797, + 0.0034322351490857846, + 0.0038742528195910416, + 0.012469246082568561, + ], + linf=[ + 0.012006418939223495, + 0.035520871209746126, + 0.024512747492231427, + 0.11191122588756564, + ]) + # 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 "TreeMesh2D: elixir_navierstokes_convergence.jl (isothermal walls)" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navierstokes_convergence.jl"), - initial_refinement_level = 2, tspan=(0.0, 0.1), - heat_bc_top_bottom=Isothermal((x, t, equations) -> Trixi.temperature(initial_condition_navier_stokes_convergence_test(x, t, equations), equations)), - l2 = [0.002103629650383915, 0.003435843933396454, 0.00386735987813341, 0.012670355349235728], - linf = [0.012006261793147788, 0.03550212518982032, 0.025107947319661185, 0.11647078036571124] - ) - # 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 + +@trixi_testset "TreeMesh2D: elixir_navierstokes_convergence.jl (isothermal walls)" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_navierstokes_convergence.jl"), + initial_refinement_level=2, tspan=(0.0, 0.1), + heat_bc_top_bottom=Isothermal((x, t, equations) -> Trixi.temperature(initial_condition_navier_stokes_convergence_test(x, + t, + equations), + equations)), + l2=[ + 0.002103629650383915, + 0.003435843933396454, + 0.00386735987813341, + 0.012670355349235728, + ], + linf=[ + 0.012006261793147788, + 0.03550212518982032, + 0.025107947319661185, + 0.11647078036571124, + ]) + # 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 "TreeMesh2D: elixir_navierstokes_convergence.jl (Entropy gradient variables)" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navierstokes_convergence.jl"), - initial_refinement_level=2, tspan=(0.0, 0.1), gradient_variables=GradientVariablesEntropy(), - l2 = [0.0021403742517389513, 0.0034258287094908572, 0.0038915122886898517, 0.012506862343013842], - linf = [0.012244412004628336, 0.03507559186162224, 0.024580892345558894, 0.11425600758350107] - ) - # 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 + +@trixi_testset "TreeMesh2D: elixir_navierstokes_convergence.jl (Entropy gradient variables)" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_navierstokes_convergence.jl"), + initial_refinement_level=2, tspan=(0.0, 0.1), + gradient_variables=GradientVariablesEntropy(), + l2=[ + 0.0021403742517389513, + 0.0034258287094908572, + 0.0038915122886898517, + 0.012506862343013842, + ], + linf=[ + 0.012244412004628336, + 0.03507559186162224, + 0.024580892345558894, + 0.11425600758350107, + ]) + # 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 "TreeMesh2D: elixir_navierstokes_convergence.jl (Entropy gradient variables, isothermal walls)" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navierstokes_convergence.jl"), - initial_refinement_level=2, tspan=(0.0, 0.1), gradient_variables=GradientVariablesEntropy(), - heat_bc_top_bottom=Isothermal((x, t, equations) -> Trixi.temperature(initial_condition_navier_stokes_convergence_test(x, t, equations), equations)), - l2 = [0.0021349737347844907, 0.0034301388278203033, 0.0038928324474291572, 0.012693611436230873], - linf = [0.01224423627586213, 0.035054066314102905, 0.025099598504931965, 0.11795616324751634] - ) - # 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 + +@trixi_testset "TreeMesh2D: elixir_navierstokes_convergence.jl (Entropy gradient variables, isothermal walls)" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_navierstokes_convergence.jl"), + initial_refinement_level=2, tspan=(0.0, 0.1), + gradient_variables=GradientVariablesEntropy(), + heat_bc_top_bottom=Isothermal((x, t, equations) -> Trixi.temperature(initial_condition_navier_stokes_convergence_test(x, + t, + equations), + equations)), + l2=[ + 0.0021349737347844907, + 0.0034301388278203033, + 0.0038928324474291572, + 0.012693611436230873, + ], + linf=[ + 0.01224423627586213, + 0.035054066314102905, + 0.025099598504931965, + 0.11795616324751634, + ]) + # 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 "TreeMesh2D: elixir_navierstokes_convergence.jl (flux differencing)" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navierstokes_convergence.jl"), - initial_refinement_level = 2, tspan=(0.0, 0.1), - volume_integral=VolumeIntegralFluxDifferencing(flux_central), - l2 = [0.0021116725306633594, 0.0034322351490827557, 0.0038742528196093542, 0.012469246082526909], - linf = [0.012006418939291663, 0.035520871209594115, 0.024512747491801577, 0.11191122588591007] - ) - # 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 + +@trixi_testset "TreeMesh2D: elixir_navierstokes_convergence.jl (flux differencing)" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_navierstokes_convergence.jl"), + initial_refinement_level=2, tspan=(0.0, 0.1), + volume_integral=VolumeIntegralFluxDifferencing(flux_central), + l2=[ + 0.0021116725306633594, + 0.0034322351490827557, + 0.0038742528196093542, + 0.012469246082526909, + ], + linf=[ + 0.012006418939291663, + 0.035520871209594115, + 0.024512747491801577, + 0.11191122588591007, + ]) + # 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 "TreeMesh2D: elixir_navierstokes_convergence.jl (Refined mesh)" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navierstokes_convergence.jl"), - tspan=(0.0, 0.0), initial_refinement_level=3) - LLID = Trixi.local_leaf_cells(mesh.tree) - num_leafs = length(LLID) - @assert num_leafs % 4 == 0 - Trixi.refine!(mesh.tree, LLID[1:Int(num_leafs/4)]) - tspan=(0.0, 0.5) - semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; - boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), - source_terms=source_terms_navier_stokes_convergence_test) - ode = semidiscretize(semi, tspan) - analysis_callback = AnalysisCallback(semi, interval=analysis_interval) - callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) - sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, - ode_default_options()..., callback=callbacks) - l2_error, linf_error = analysis_callback(sol) - @test l2_error ≈ [0.00024296959173852447; 0.0002093263158670915; 0.0005390572390977262; 0.00026753561392341537] - @test linf_error ≈ [0.0016210102053424436; 0.002593287648655501; 0.002953907343823712; 0.002077119120180271] - # 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 "TreeMesh2D: elixir_navierstokes_lid_driven_cavity.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navierstokes_lid_driven_cavity.jl"), - initial_refinement_level = 2, tspan=(0.0, 0.5), - l2 = [0.00015144571529699053, 0.018766076072331623, 0.007065070765652574, 0.0208399005734258], - linf = [0.0014523369373669048, 0.12366779944955864, 0.05532450997115432, 0.16099927805328207] - ) - # 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 + +@trixi_testset "TreeMesh2D: elixir_navierstokes_convergence.jl (Refined mesh)" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_navierstokes_convergence.jl"), + tspan=(0.0, 0.0), initial_refinement_level=3) + LLID = Trixi.local_leaf_cells(mesh.tree) + num_leafs = length(LLID) + @assert num_leafs % 4 == 0 + Trixi.refine!(mesh.tree, LLID[1:Int(num_leafs / 4)]) + tspan = (0.0, 0.5) + semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic), + source_terms = source_terms_navier_stokes_convergence_test) + ode = semidiscretize(semi, tspan) + analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) + sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + dt = 1e-5, + ode_default_options()..., callback = callbacks) + l2_error, linf_error = analysis_callback(sol) + @test l2_error ≈ + [0.00024296959173852447; 0.0002093263158670915; 0.0005390572390977262; + 0.00026753561392341537] + @test linf_error ≈ + [0.0016210102053424436; 0.002593287648655501; 0.002953907343823712; + 0.002077119120180271] + # 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 "TreeMesh2D: elixir_navierstokes_taylor_green_vortex.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navierstokes_taylor_green_vortex.jl"), - l2 = [0.0009279657228109691, 0.012454661988687185, 0.012454661988689886, 0.030487112728612178], - linf = [0.002435582543096171, 0.024824039368199546, 0.024824039368212758, 0.06731583711777489] - ) - # 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 + +@trixi_testset "TreeMesh2D: elixir_navierstokes_lid_driven_cavity.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_navierstokes_lid_driven_cavity.jl"), + initial_refinement_level=2, tspan=(0.0, 0.5), + l2=[ + 0.00015144571529699053, + 0.018766076072331623, + 0.007065070765652574, + 0.0208399005734258, + ], + linf=[ + 0.0014523369373669048, + 0.12366779944955864, + 0.05532450997115432, + 0.16099927805328207, + ]) + # 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 "TreeMesh2D: elixir_navierstokes_shearlayer_amr.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_navierstokes_shearlayer_amr.jl"), + l2=[ + 0.00526017743452336, + 0.4130430692895672, + 0.4310996183791349, + 1.1544344171604635, + ], + linf=[ + 0.03492185879198495, + 1.392635891671335, + 1.357551616406459, + 8.713760873018146, + ], + tspan=(0.0, 0.7)) +end + +@trixi_testset "P4estMesh2D: elixir_advection_diffusion_periodic.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", + "elixir_advection_diffusion_periodic.jl"), + trees_per_dimension=(1, 1), initial_refinement_level=2, + tspan=(0.0, 0.5), + l2=[0.0023754695605828443], + linf=[0.008154128363741964]) + # 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 "TreeMesh2D: elixir_navierstokes_shearlayer_amr.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navierstokes_shearlayer_amr.jl"), - l2 = [0.00526017743452336, 0.4130430692895672, 0.4310996183791349, 1.1544344171604635], - linf = [0.03492185879198495, 1.392635891671335, 1.357551616406459, 8.713760873018146], - tspan = (0.0, 0.7) - ) - end - - @trixi_testset "P4estMesh2D: elixir_advection_diffusion_periodic.jl" begin - @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_advection_diffusion_periodic.jl"), - trees_per_dimension = (1, 1), initial_refinement_level = 2, tspan=(0.0, 0.5), - l2 = [0.0023754695605828443], - linf = [0.008154128363741964] - ) - # 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 + +@trixi_testset "P4estMesh2D: elixir_advection_diffusion_periodic.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", + "elixir_advection_diffusion_periodic.jl"), + trees_per_dimension=(1, 1), initial_refinement_level=2, + tspan=(0.0, 0.5), + l2=[0.0023754695605828443], + linf=[0.008154128363741964]) + # 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 "P4estMesh2D: elixir_advection_diffusion_periodic_curved.jl" begin - @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_advection_diffusion_periodic_curved.jl"), - trees_per_dimension = (1, 1), initial_refinement_level = 2, tspan=(0.0, 0.5), - l2 = [0.006708147442490916], - linf = [0.04807038397976693] - ) - # 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 + +@trixi_testset "P4estMesh2D: elixir_advection_diffusion_periodic_curved.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", + "elixir_advection_diffusion_periodic_curved.jl"), + trees_per_dimension=(1, 1), initial_refinement_level=2, + tspan=(0.0, 0.5), + l2=[0.006708147442490916], + linf=[0.04807038397976693]) + # 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 "P4estMesh2D: elixir_advection_diffusion_nonperiodic_curved.jl" begin - @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_advection_diffusion_nonperiodic_curved.jl"), - trees_per_dimension = (1, 1), initial_refinement_level = 2, tspan=(0.0, 0.5), - l2 = [0.00919917034843865], - linf = [0.14186297438393505] - ) - # 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 + +@trixi_testset "P4estMesh2D: elixir_advection_diffusion_nonperiodic_curved.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", + "elixir_advection_diffusion_nonperiodic_curved.jl"), + trees_per_dimension=(1, 1), initial_refinement_level=2, + tspan=(0.0, 0.5), + l2=[0.00919917034843865], + linf=[0.14186297438393505]) + # 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 "P4estMesh2D: elixir_navierstokes_convergence.jl" begin - @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_navierstokes_convergence.jl"), - initial_refinement_level = 1, tspan=(0.0, 0.2), - l2 = [0.0003811978985836709, 0.0005874314969169538, 0.0009142898787923481, 0.0011613918899727263], - linf = [0.0021633623982135752, 0.009484348274135372, 0.004231572066492217, 0.011661660275365193] - ) - # 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 + +@trixi_testset "P4estMesh2D: elixir_navierstokes_convergence.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", + "elixir_navierstokes_convergence.jl"), + initial_refinement_level=1, tspan=(0.0, 0.2), + l2=[ + 0.0003811978985836709, + 0.0005874314969169538, + 0.0009142898787923481, + 0.0011613918899727263, + ], + linf=[ + 0.0021633623982135752, + 0.009484348274135372, + 0.004231572066492217, + 0.011661660275365193, + ]) + # 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 "P4estMesh2D: elixir_navierstokes_convergence_nonperiodic.jl" begin - @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_navierstokes_convergence_nonperiodic.jl"), - initial_refinement_level = 1, tspan=(0.0, 0.2), - l2 = [0.00040364962558511795, 0.0005869762481506936, 0.00091488537427274, 0.0011984191566376762], - linf = [0.0024993634941723464, 0.009487866203944725, 0.004505829506628117, 0.011634902776245681] - ) - # 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 + +@trixi_testset "P4estMesh2D: elixir_navierstokes_convergence_nonperiodic.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", + "elixir_navierstokes_convergence_nonperiodic.jl"), + initial_refinement_level=1, tspan=(0.0, 0.2), + l2=[ + 0.00040364962558511795, + 0.0005869762481506936, + 0.00091488537427274, + 0.0011984191566376762, + ], + linf=[ + 0.0024993634941723464, + 0.009487866203944725, + 0.004505829506628117, + 0.011634902776245681, + ]) + # 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 "P4estMesh2D: elixir_navierstokes_lid_driven_cavity.jl" begin - @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_navierstokes_lid_driven_cavity.jl"), - initial_refinement_level = 2, tspan=(0.0, 0.5), - l2 = [0.00028716166408816073, 0.08101204560401647, 0.02099595625377768, 0.05008149754143295], - linf = [0.014804500261322406, 0.9513271652357098, 0.7223919625994717, 1.4846907331004786] - ) - # 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 + +@trixi_testset "P4estMesh2D: elixir_navierstokes_lid_driven_cavity.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", + "elixir_navierstokes_lid_driven_cavity.jl"), + initial_refinement_level=2, tspan=(0.0, 0.5), + l2=[ + 0.00028716166408816073, + 0.08101204560401647, + 0.02099595625377768, + 0.05008149754143295, + ], + linf=[ + 0.014804500261322406, + 0.9513271652357098, + 0.7223919625994717, + 1.4846907331004786, + ]) + # 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 end # Clean up afterwards: delete Trixi.jl output directory -@test_nowarn isdir(outdir) && rm(outdir, recursive=true) +@test_nowarn isdir(outdir) && rm(outdir, recursive = true) end # module diff --git a/test/test_parabolic_3d.jl b/test/test_parabolic_3d.jl index 276e37518ee..d6c720cf0d9 100644 --- a/test/test_parabolic_3d.jl +++ b/test/test_parabolic_3d.jl @@ -7,268 +7,439 @@ include("test_trixi.jl") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) @testset "SemidiscretizationHyperbolicParabolic (3D)" begin +#! format: noindent - @trixi_testset "DGMulti: elixir_navierstokes_convergence.jl" begin - @test_trixi_include(joinpath(examples_dir(), "dgmulti_3d", "elixir_navierstokes_convergence.jl"), - cells_per_dimension = (4, 4, 4), tspan=(0.0, 0.1), - l2 = [0.0005532847115849239, 0.000659263490965341, 0.0007776436127362806, 0.0006592634909662951, 0.0038073628897809185], - linf = [0.0017039861523615585, 0.002628561703560073, 0.003531057425112172, 0.0026285617036090336, 0.015587829540351095] - ) - # 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 +@trixi_testset "DGMulti: elixir_navierstokes_convergence.jl" begin + @test_trixi_include(joinpath(examples_dir(), "dgmulti_3d", + "elixir_navierstokes_convergence.jl"), + cells_per_dimension=(4, 4, 4), tspan=(0.0, 0.1), + l2=[ + 0.0005532847115849239, + 0.000659263490965341, + 0.0007776436127362806, + 0.0006592634909662951, + 0.0038073628897809185, + ], + linf=[ + 0.0017039861523615585, + 0.002628561703560073, + 0.003531057425112172, + 0.0026285617036090336, + 0.015587829540351095, + ]) + # 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 - @trixi_testset "DGMulti: elixir_navierstokes_convergence_curved.jl" begin - @test_trixi_include(joinpath(examples_dir(), "dgmulti_3d", "elixir_navierstokes_convergence_curved.jl"), - cells_per_dimension = (4, 4, 4), tspan=(0.0, 0.1), - l2 = [0.0014027227251207474, 0.0021322235533273513, 0.0027873741447455194, 0.0024587473070627423, 0.00997836818019202], - linf = [0.006341750402837576, 0.010306014252246865, 0.01520740250924979, 0.010968264045485565, 0.047454389831591115] - ) - # 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 +@trixi_testset "DGMulti: elixir_navierstokes_convergence_curved.jl" begin + @test_trixi_include(joinpath(examples_dir(), "dgmulti_3d", + "elixir_navierstokes_convergence_curved.jl"), + cells_per_dimension=(4, 4, 4), tspan=(0.0, 0.1), + l2=[ + 0.0014027227251207474, + 0.0021322235533273513, + 0.0027873741447455194, + 0.0024587473070627423, + 0.00997836818019202, + ], + linf=[ + 0.006341750402837576, + 0.010306014252246865, + 0.01520740250924979, + 0.010968264045485565, + 0.047454389831591115, + ]) + # 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 - @trixi_testset "DGMulti: elixir_navierstokes_taylor_green_vortex.jl" begin - @test_trixi_include(joinpath(examples_dir(), "dgmulti_3d", "elixir_navierstokes_taylor_green_vortex.jl"), - cells_per_dimension = (4, 4, 4), tspan=(0.0, 0.25), - l2 = [0.0001825713444029892, 0.015589736382772248, 0.015589736382771884, 0.021943924667273653, 0.01927370280244222], - linf = [0.0006268463584697681, 0.03218881662749007, 0.03218881662697948, 0.053872495395614256, 0.05183822000984151] - ) - # 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 +@trixi_testset "DGMulti: elixir_navierstokes_taylor_green_vortex.jl" begin + @test_trixi_include(joinpath(examples_dir(), "dgmulti_3d", + "elixir_navierstokes_taylor_green_vortex.jl"), + cells_per_dimension=(4, 4, 4), tspan=(0.0, 0.25), + l2=[ + 0.0001825713444029892, + 0.015589736382772248, + 0.015589736382771884, + 0.021943924667273653, + 0.01927370280244222, + ], + linf=[ + 0.0006268463584697681, + 0.03218881662749007, + 0.03218881662697948, + 0.053872495395614256, + 0.05183822000984151, + ]) + # 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 - @trixi_testset "TreeMesh3D: elixir_navierstokes_convergence.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", "elixir_navierstokes_convergence.jl"), - initial_refinement_level = 2, tspan=(0.0, 0.1), - l2 = [0.0019582188528512257, 0.002653449504302844, 0.002898264205184629, 0.002653449504302853, 0.009511572365085706], - linf = [0.013680656759085918, 0.0356910450154318, 0.023526343547736236, 0.035691045015431855, 0.11482570604041165] - ) - # 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 +@trixi_testset "TreeMesh3D: elixir_navierstokes_convergence.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", + "elixir_navierstokes_convergence.jl"), + initial_refinement_level=2, tspan=(0.0, 0.1), + l2=[ + 0.0019582188528512257, + 0.002653449504302844, + 0.002898264205184629, + 0.002653449504302853, + 0.009511572365085706, + ], + linf=[ + 0.013680656759085918, + 0.0356910450154318, + 0.023526343547736236, + 0.035691045015431855, + 0.11482570604041165, + ]) + # 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 - @trixi_testset "TreeMesh3D: elixir_navierstokes_convergence.jl (isothermal walls)" begin - @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", "elixir_navierstokes_convergence.jl"), - initial_refinement_level = 2, tspan=(0.0, 0.1), - heat_bc_top_bottom=Isothermal((x, t, equations) -> Trixi.temperature(initial_condition_navier_stokes_convergence_test(x, t, equations), equations)), - l2 = [0.00195468651965362, 0.0026554367897028506, 0.002892730402724066, 0.002655436789702817, 0.009596351796609566], - linf = [0.013680508110645473, 0.035673446359424356, 0.024024936779729028, 0.03567344635942474, 0.11839497110809383] - ) - # 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 +@trixi_testset "TreeMesh3D: elixir_navierstokes_convergence.jl (isothermal walls)" begin + @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", + "elixir_navierstokes_convergence.jl"), + initial_refinement_level=2, tspan=(0.0, 0.1), + heat_bc_top_bottom=Isothermal((x, t, equations) -> Trixi.temperature(initial_condition_navier_stokes_convergence_test(x, + t, + equations), + equations)), + l2=[ + 0.00195468651965362, + 0.0026554367897028506, + 0.002892730402724066, + 0.002655436789702817, + 0.009596351796609566, + ], + linf=[ + 0.013680508110645473, + 0.035673446359424356, + 0.024024936779729028, + 0.03567344635942474, + 0.11839497110809383, + ]) + # 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 - @trixi_testset "TreeMesh3D: elixir_navierstokes_convergence.jl (Entropy gradient variables)" begin - @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", "elixir_navierstokes_convergence.jl"), - initial_refinement_level=2, tspan=(0.0, 0.1), gradient_variables=GradientVariablesEntropy(), - l2 = [0.0019770444875099307, 0.0026524750946399327, 0.00290860030832445, 0.0026524750946399396, 0.009509568981439294], - linf = [0.01387936112914212, 0.03526260609304053, 0.023554197097368997, 0.035262606093040896, 0.11719963716509518] - ) - # 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 +@trixi_testset "TreeMesh3D: elixir_navierstokes_convergence.jl (Entropy gradient variables)" begin + @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", + "elixir_navierstokes_convergence.jl"), + initial_refinement_level=2, tspan=(0.0, 0.1), + gradient_variables=GradientVariablesEntropy(), + l2=[ + 0.0019770444875099307, + 0.0026524750946399327, + 0.00290860030832445, + 0.0026524750946399396, + 0.009509568981439294, + ], + linf=[ + 0.01387936112914212, + 0.03526260609304053, + 0.023554197097368997, + 0.035262606093040896, + 0.11719963716509518, + ]) + # 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 - @trixi_testset "TreeMesh3D: elixir_navierstokes_convergence.jl (Entropy gradient variables, isothermal walls)" begin - @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", "elixir_navierstokes_convergence.jl"), - initial_refinement_level=2, tspan=(0.0, 0.1), gradient_variables=GradientVariablesEntropy(), - heat_bc_top_bottom=Isothermal((x, t, equations) -> Trixi.temperature(initial_condition_navier_stokes_convergence_test(x, t, equations), equations)), - l2 = [0.001974631423398113, 0.002654768259143932, 0.002907031063651286, 0.002654768259143901, 0.009587792882971452], - linf = [0.01387919380137137, 0.035244084526358944, 0.02398614622061363, 0.03524408452635828, 0.12005056512506407] - ) - # 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 +@trixi_testset "TreeMesh3D: elixir_navierstokes_convergence.jl (Entropy gradient variables, isothermal walls)" begin + @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", + "elixir_navierstokes_convergence.jl"), + initial_refinement_level=2, tspan=(0.0, 0.1), + gradient_variables=GradientVariablesEntropy(), + heat_bc_top_bottom=Isothermal((x, t, equations) -> Trixi.temperature(initial_condition_navier_stokes_convergence_test(x, + t, + equations), + equations)), + l2=[ + 0.001974631423398113, + 0.002654768259143932, + 0.002907031063651286, + 0.002654768259143901, + 0.009587792882971452, + ], + linf=[ + 0.01387919380137137, + 0.035244084526358944, + 0.02398614622061363, + 0.03524408452635828, + 0.12005056512506407, + ]) + # 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 - @trixi_testset "TreeMesh3D: elixir_navierstokes_convergence.jl (flux differencing)" begin - @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", "elixir_navierstokes_convergence.jl"), - initial_refinement_level = 2, tspan=(0.0, 0.1), - volume_integral=VolumeIntegralFluxDifferencing(flux_central), - l2 = [0.0019582188528180213, 0.002653449504301736, 0.0028982642051960006, 0.0026534495043017384, 0.009511572364811033], - linf = [0.013680656758949583, 0.035691045015224444, 0.02352634354676752, 0.035691045015223424, 0.11482570603751441] - ) - # 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 +@trixi_testset "TreeMesh3D: elixir_navierstokes_convergence.jl (flux differencing)" begin + @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", + "elixir_navierstokes_convergence.jl"), + initial_refinement_level=2, tspan=(0.0, 0.1), + volume_integral=VolumeIntegralFluxDifferencing(flux_central), + l2=[ + 0.0019582188528180213, + 0.002653449504301736, + 0.0028982642051960006, + 0.0026534495043017384, + 0.009511572364811033, + ], + linf=[ + 0.013680656758949583, + 0.035691045015224444, + 0.02352634354676752, + 0.035691045015223424, + 0.11482570603751441, + ]) + # 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 - @trixi_testset "TreeMesh3D: elixir_navierstokes_convergence.jl (Refined mesh)" begin - @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", "elixir_navierstokes_convergence.jl"), - tspan=(0.0, 0.0)) - LLID = Trixi.local_leaf_cells(mesh.tree) - num_leafs = length(LLID) - @assert num_leafs % 16 == 0 - Trixi.refine!(mesh.tree, LLID[1:Int(num_leafs/16)]) - tspan=(0.0, 0.25) - semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; - boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), - source_terms=source_terms_navier_stokes_convergence_test) - ode = semidiscretize(semi, tspan) - analysis_callback = AnalysisCallback(semi, interval=analysis_interval) - callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) - sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, - ode_default_options()..., callback=callbacks) - l2_error, linf_error = analysis_callback(sol) - @test l2_error ≈ [0.0003109336253407314, 0.0006473493036803503, 0.0007705277238213672, 0.0006280517917198335, 0.000903927789884075] - @test linf_error ≈ [0.0023694155365339142, 0.010634932622402863, 0.006772070862236412, 0.010640551561726901, 0.019256819038719897] - # 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 "TreeMesh3D: elixir_navierstokes_convergence.jl (Refined mesh)" begin + @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", + "elixir_navierstokes_convergence.jl"), + tspan=(0.0, 0.0)) + LLID = Trixi.local_leaf_cells(mesh.tree) + num_leafs = length(LLID) + @assert num_leafs % 16 == 0 + Trixi.refine!(mesh.tree, LLID[1:Int(num_leafs / 16)]) + tspan = (0.0, 0.25) + semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic), + source_terms = source_terms_navier_stokes_convergence_test) + ode = semidiscretize(semi, tspan) + analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) + sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + dt = 1e-5, + ode_default_options()..., callback = callbacks) + l2_error, linf_error = analysis_callback(sol) + @test l2_error ≈ [ + 0.0003109336253407314, + 0.0006473493036803503, + 0.0007705277238213672, + 0.0006280517917198335, + 0.000903927789884075, + ] + @test linf_error ≈ [ + 0.0023694155365339142, + 0.010634932622402863, + 0.006772070862236412, + 0.010640551561726901, + 0.019256819038719897, + ] + # 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 "TreeMesh3D: elixir_navierstokes_taylor_green_vortex.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", "elixir_navierstokes_taylor_green_vortex.jl"), - initial_refinement_level = 2, tspan=(0.0, 0.25), - l2 = [0.00024173250389635442, 0.015684268393762454, 0.01568426839376248, 0.021991909545192333, 0.02825413672911425], - linf = [0.0008410587892853094, 0.04740176181772552, 0.04740176181772507, 0.07483494924031157, 0.150181591534448] - ) - # 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 +@trixi_testset "TreeMesh3D: elixir_navierstokes_taylor_green_vortex.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", + "elixir_navierstokes_taylor_green_vortex.jl"), + initial_refinement_level=2, tspan=(0.0, 0.25), + l2=[ + 0.00024173250389635442, + 0.015684268393762454, + 0.01568426839376248, + 0.021991909545192333, + 0.02825413672911425, + ], + linf=[ + 0.0008410587892853094, + 0.04740176181772552, + 0.04740176181772507, + 0.07483494924031157, + 0.150181591534448, + ]) + # 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 - @trixi_testset "TreeMesh3D: elixir_navierstokes_taylor_green_vortex.jl (Refined mesh)" begin - @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", "elixir_navierstokes_taylor_green_vortex.jl"), - tspan=(0.0, 0.0)) - LLID = Trixi.local_leaf_cells(mesh.tree) - num_leafs = length(LLID) - @assert num_leafs % 32 == 0 - Trixi.refine!(mesh.tree, LLID[1:Int(num_leafs/32)]) - tspan=(0.0, 0.1) - semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), - initial_condition, solver) - ode = semidiscretize(semi, tspan) - analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=true, - extra_analysis_integrals=(energy_kinetic, +@trixi_testset "TreeMesh3D: elixir_navierstokes_taylor_green_vortex.jl (Refined mesh)" begin + @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", + "elixir_navierstokes_taylor_green_vortex.jl"), + tspan=(0.0, 0.0)) + LLID = Trixi.local_leaf_cells(mesh.tree) + num_leafs = length(LLID) + @assert num_leafs % 32 == 0 + Trixi.refine!(mesh.tree, LLID[1:Int(num_leafs / 32)]) + tspan = (0.0, 0.1) + semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver) + ode = semidiscretize(semi, tspan) + analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_integrals = (energy_kinetic, energy_internal, enstrophy)) - callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) - # Use CarpenterKennedy2N54 since `RDPK3SpFSAL49` gives slightly different results on different machines - sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=5e-3, - save_everystep=false, callback=callbacks); - l2_error, linf_error = analysis_callback(sol) - @test l2_error ≈ [7.314319856736271e-5, 0.006266480163542894, 0.006266489911815533, 0.008829222305770226, 0.0032859166842329228] - @test linf_error ≈ [0.0002943968186086554, 0.013876261980614757, 0.013883619864959451, 0.025201279960491936, 0.018679364985388247] - # 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) + callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) + # Use CarpenterKennedy2N54 since `RDPK3SpFSAL49` gives slightly different results on different machines + sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 5e-3, + save_everystep = false, callback = callbacks) + l2_error, linf_error = analysis_callback(sol) + @test l2_error ≈ [ + 7.314319856736271e-5, + 0.006266480163542894, + 0.006266489911815533, + 0.008829222305770226, + 0.0032859166842329228, + ] + @test linf_error ≈ [ + 0.0002943968186086554, + 0.013876261980614757, + 0.013883619864959451, + 0.025201279960491936, + 0.018679364985388247, + ] + # 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)) < 100 @test (@allocated Trixi.rhs_parabolic!(du_ode, u_ode, semi, t)) < 100 end - end +end - @trixi_testset "P4estMesh3D: elixir_navierstokes_convergence.jl" begin - @test_trixi_include(joinpath(examples_dir(), "p4est_3d_dgsem", "elixir_navierstokes_convergence.jl"), - initial_refinement_level = 2, tspan=(0.0, 0.1), - l2 = [0.00026599105554982194, 0.000461877794472316, 0.0005424899076052261, 0.0004618777944723191, 0.0015846392581126832], - linf = [0.0025241668929956163, 0.006308461681816373, 0.004334939663169113, 0.006308461681804009, 0.03176343480493493] - ) - # 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 +@trixi_testset "P4estMesh3D: elixir_navierstokes_convergence.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_3d_dgsem", + "elixir_navierstokes_convergence.jl"), + initial_refinement_level=2, tspan=(0.0, 0.1), + l2=[ + 0.00026599105554982194, + 0.000461877794472316, + 0.0005424899076052261, + 0.0004618777944723191, + 0.0015846392581126832, + ], + linf=[ + 0.0025241668929956163, + 0.006308461681816373, + 0.004334939663169113, + 0.006308461681804009, + 0.03176343480493493, + ]) + # 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 - @trixi_testset "P4estMesh3D: elixir_navierstokes_taylor_green_vortex.jl" begin - @test_trixi_include(joinpath(examples_dir(), "p4est_3d_dgsem", "elixir_navierstokes_taylor_green_vortex.jl"), - initial_refinement_level = 2, tspan=(0.0, 0.25), - l2 = [0.0001547509861140407, 0.015637861347119624, 0.015637861347119687, 0.022024699158522523, 0.009711013505930812], - linf = [0.0006696415247340326, 0.03442565722527785, 0.03442565722577423, 0.06295407168705314, 0.032857472756916195] - ) - # 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 +@trixi_testset "P4estMesh3D: elixir_navierstokes_taylor_green_vortex.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_3d_dgsem", + "elixir_navierstokes_taylor_green_vortex.jl"), + initial_refinement_level=2, tspan=(0.0, 0.25), + l2=[ + 0.0001547509861140407, + 0.015637861347119624, + 0.015637861347119687, + 0.022024699158522523, + 0.009711013505930812, + ], + linf=[ + 0.0006696415247340326, + 0.03442565722527785, + 0.03442565722577423, + 0.06295407168705314, + 0.032857472756916195, + ]) + # 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 - @trixi_testset "TreeMesh3D: elixir_advection_diffusion_amr.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", "elixir_advection_diffusion_amr.jl"), - l2 = [0.000355780485397024], - linf = [0.0010810770271614256] - ) - end +@trixi_testset "TreeMesh3D: elixir_advection_diffusion_amr.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", + "elixir_advection_diffusion_amr.jl"), + l2=[0.000355780485397024], + linf=[0.0010810770271614256]) +end - @trixi_testset "TreeMesh3D: elixir_advection_diffusion_nonperiodic.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", "elixir_advection_diffusion_nonperiodic.jl"), - l2 = [0.0009808996243280868], - linf = [0.01732621559135459] - ) - end +@trixi_testset "TreeMesh3D: elixir_advection_diffusion_nonperiodic.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_3d_dgsem", + "elixir_advection_diffusion_nonperiodic.jl"), + l2=[0.0009808996243280868], + linf=[0.01732621559135459]) +end end # Clean up afterwards: delete Trixi.jl output directory -@test_nowarn isdir(outdir) && rm(outdir, recursive=true) +@test_nowarn isdir(outdir) && rm(outdir, recursive = true) -end # module \ No newline at end of file +end # module diff --git a/test/test_performance_specializations_2d.jl b/test/test_performance_specializations_2d.jl index eaf2a66e84f..4fd39c78f64 100644 --- a/test/test_performance_specializations_2d.jl +++ b/test/test_performance_specializations_2d.jl @@ -7,169 +7,171 @@ include("test_trixi.jl") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) - +isdir(outdir) && rm(outdir, recursive = true) @testset "Performance specializations 2D" begin - @timed_testset "TreeMesh2D, flux_shima_etal_turbo" begin +#! format: noindent + +@timed_testset "TreeMesh2D, flux_shima_etal_turbo" begin trixi_include(@__MODULE__, - joinpath(examples_dir(), "tree_2d_dgsem", "elixir_euler_ec.jl"), - initial_refinement_level=0, tspan=(0.0, 0.0), polydeg=3, - volume_flux=flux_shima_etal_turbo, surface_flux=flux_shima_etal_turbo) + joinpath(examples_dir(), "tree_2d_dgsem", "elixir_euler_ec.jl"), + initial_refinement_level = 0, tspan = (0.0, 0.0), polydeg = 3, + volume_flux = flux_shima_etal_turbo, + surface_flux = flux_shima_etal_turbo) u_ode = copy(sol.u[end]) du_ode = zero(u_ode) # Preserve original memory since it will be `unsafe_wrap`ped and might # thus otherwise be garbage collected GC.@preserve u_ode du_ode begin - u = Trixi.wrap_array(u_ode, semi) - du = Trixi.wrap_array(du_ode, semi) - nonconservative_terms = Trixi.have_nonconservative_terms(semi.equations) - - # Call the optimized default version - du .= 0 - Trixi.flux_differencing_kernel!( - du, u, 1, semi.mesh, - nonconservative_terms, semi.equations, - semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) - du_specialized = du[:, :, :, 1] - - # Call the plain version - note the argument type `Function` of - # `semi.solver.volume_integral.volume_flux` - du .= 0 - invoke(Trixi.flux_differencing_kernel!, - Tuple{typeof(du), typeof(u), Integer, typeof(semi.mesh), - typeof(nonconservative_terms), typeof(semi.equations), - Function, typeof(semi.solver), typeof(semi.cache), Bool}, - du, u, 1, semi.mesh, - nonconservative_terms, semi.equations, - semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) - du_baseline = du[:, :, :, 1] - - @test du_specialized ≈ du_baseline + u = Trixi.wrap_array(u_ode, semi) + du = Trixi.wrap_array(du_ode, semi) + nonconservative_terms = Trixi.have_nonconservative_terms(semi.equations) + + # Call the optimized default version + du .= 0 + Trixi.flux_differencing_kernel!(du, u, 1, semi.mesh, + nonconservative_terms, semi.equations, + semi.solver.volume_integral.volume_flux, + semi.solver, semi.cache, true) + du_specialized = du[:, :, :, 1] + + # Call the plain version - note the argument type `Function` of + # `semi.solver.volume_integral.volume_flux` + du .= 0 + invoke(Trixi.flux_differencing_kernel!, + Tuple{typeof(du), typeof(u), Integer, typeof(semi.mesh), + typeof(nonconservative_terms), typeof(semi.equations), + Function, typeof(semi.solver), typeof(semi.cache), Bool}, + du, u, 1, semi.mesh, + nonconservative_terms, semi.equations, + semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) + du_baseline = du[:, :, :, 1] + + @test du_specialized ≈ du_baseline end - end +end - @timed_testset "TreeMesh2D, flux_ranocha_turbo" begin +@timed_testset "TreeMesh2D, flux_ranocha_turbo" begin trixi_include(@__MODULE__, - joinpath(examples_dir(), "tree_2d_dgsem", "elixir_euler_ec.jl"), - initial_refinement_level=0, tspan=(0.0, 0.0), polydeg=3, - volume_flux=flux_ranocha_turbo, surface_flux=flux_ranocha_turbo) + joinpath(examples_dir(), "tree_2d_dgsem", "elixir_euler_ec.jl"), + initial_refinement_level = 0, tspan = (0.0, 0.0), polydeg = 3, + volume_flux = flux_ranocha_turbo, surface_flux = flux_ranocha_turbo) u_ode = copy(sol.u[end]) du_ode = zero(u_ode) # Preserve original memory since it will be `unsafe_wrap`ped and might # thus otherwise be garbage collected GC.@preserve u_ode du_ode begin - u = Trixi.wrap_array(u_ode, semi) - du = Trixi.wrap_array(du_ode, semi) - nonconservative_terms = Trixi.have_nonconservative_terms(semi.equations) - - # Call the optimized default version - du .= 0 - Trixi.flux_differencing_kernel!( - du, u, 1, semi.mesh, - nonconservative_terms, semi.equations, - semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) - du_specialized = du[:, :, :, 1] - - # Call the plain version - note the argument type `Function` of - # `semi.solver.volume_integral.volume_flux` - du .= 0 - invoke(Trixi.flux_differencing_kernel!, - Tuple{typeof(du), typeof(u), Integer, typeof(semi.mesh), - typeof(nonconservative_terms), typeof(semi.equations), - Function, typeof(semi.solver), typeof(semi.cache), Bool}, - du, u, 1, semi.mesh, - nonconservative_terms, semi.equations, - semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) - du_baseline = du[:, :, :, 1] - - @test du_specialized ≈ du_baseline + u = Trixi.wrap_array(u_ode, semi) + du = Trixi.wrap_array(du_ode, semi) + nonconservative_terms = Trixi.have_nonconservative_terms(semi.equations) + + # Call the optimized default version + du .= 0 + Trixi.flux_differencing_kernel!(du, u, 1, semi.mesh, + nonconservative_terms, semi.equations, + semi.solver.volume_integral.volume_flux, + semi.solver, semi.cache, true) + du_specialized = du[:, :, :, 1] + + # Call the plain version - note the argument type `Function` of + # `semi.solver.volume_integral.volume_flux` + du .= 0 + invoke(Trixi.flux_differencing_kernel!, + Tuple{typeof(du), typeof(u), Integer, typeof(semi.mesh), + typeof(nonconservative_terms), typeof(semi.equations), + Function, typeof(semi.solver), typeof(semi.cache), Bool}, + du, u, 1, semi.mesh, + nonconservative_terms, semi.equations, + semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) + du_baseline = du[:, :, :, 1] + + @test du_specialized ≈ du_baseline end - end +end - @timed_testset "StructuredMesh2D, flux_shima_etal_turbo" begin +@timed_testset "StructuredMesh2D, flux_shima_etal_turbo" begin trixi_include(@__MODULE__, - joinpath(examples_dir(), "structured_2d_dgsem", "elixir_euler_ec.jl"), - cells_per_dimension=(1, 1), tspan=(0.0, 0.0), polydeg=3, - volume_flux=flux_shima_etal_turbo, surface_flux=flux_shima_etal_turbo) + joinpath(examples_dir(), "structured_2d_dgsem", "elixir_euler_ec.jl"), + cells_per_dimension = (1, 1), tspan = (0.0, 0.0), polydeg = 3, + volume_flux = flux_shima_etal_turbo, + surface_flux = flux_shima_etal_turbo) u_ode = copy(sol.u[end]) du_ode = zero(u_ode) # Preserve original memory since it will be `unsafe_wrap`ped and might # thus otherwise be garbage collected GC.@preserve u_ode du_ode begin - u = Trixi.wrap_array(u_ode, semi) - du = Trixi.wrap_array(du_ode, semi) - nonconservative_terms = Trixi.have_nonconservative_terms(semi.equations) - - # Call the optimized default version - du .= 0 - Trixi.flux_differencing_kernel!( - du, u, 1, semi.mesh, - nonconservative_terms, semi.equations, - semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) - du_specialized = du[:, :, :, 1] - - # Call the plain version - note the argument type `Function` of - # `semi.solver.volume_integral.volume_flux` - du .= 0 - invoke(Trixi.flux_differencing_kernel!, - Tuple{typeof(du), typeof(u), Integer, typeof(semi.mesh), - typeof(nonconservative_terms), typeof(semi.equations), - Function, typeof(semi.solver), typeof(semi.cache), Bool}, - du, u, 1, semi.mesh, - nonconservative_terms, semi.equations, - semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) - du_baseline = du[:, :, :, 1] - - @test du_specialized ≈ du_baseline + u = Trixi.wrap_array(u_ode, semi) + du = Trixi.wrap_array(du_ode, semi) + nonconservative_terms = Trixi.have_nonconservative_terms(semi.equations) + + # Call the optimized default version + du .= 0 + Trixi.flux_differencing_kernel!(du, u, 1, semi.mesh, + nonconservative_terms, semi.equations, + semi.solver.volume_integral.volume_flux, + semi.solver, semi.cache, true) + du_specialized = du[:, :, :, 1] + + # Call the plain version - note the argument type `Function` of + # `semi.solver.volume_integral.volume_flux` + du .= 0 + invoke(Trixi.flux_differencing_kernel!, + Tuple{typeof(du), typeof(u), Integer, typeof(semi.mesh), + typeof(nonconservative_terms), typeof(semi.equations), + Function, typeof(semi.solver), typeof(semi.cache), Bool}, + du, u, 1, semi.mesh, + nonconservative_terms, semi.equations, + semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) + du_baseline = du[:, :, :, 1] + + @test du_specialized ≈ du_baseline end - end +end - @timed_testset "StructuredMesh2D, flux_ranocha_turbo" begin +@timed_testset "StructuredMesh2D, flux_ranocha_turbo" begin trixi_include(@__MODULE__, - joinpath(examples_dir(), "structured_2d_dgsem", "elixir_euler_ec.jl"), - cells_per_dimension=(1, 1), tspan=(0.0, 0.0), polydeg=3, - volume_flux=flux_ranocha_turbo, surface_flux=flux_ranocha_turbo) + joinpath(examples_dir(), "structured_2d_dgsem", "elixir_euler_ec.jl"), + cells_per_dimension = (1, 1), tspan = (0.0, 0.0), polydeg = 3, + volume_flux = flux_ranocha_turbo, surface_flux = flux_ranocha_turbo) u_ode = copy(sol.u[end]) du_ode = zero(u_ode) # Preserve original memory since it will be `unsafe_wrap`ped and might # thus otherwise be garbage collected GC.@preserve u_ode du_ode begin - u = Trixi.wrap_array(u_ode, semi) - du = Trixi.wrap_array(du_ode, semi) - nonconservative_terms = Trixi.have_nonconservative_terms(semi.equations) - - # Call the optimized default version - du .= 0 - Trixi.flux_differencing_kernel!( - du, u, 1, semi.mesh, - nonconservative_terms, semi.equations, - semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) - du_specialized = du[:, :, :, 1] - - # Call the plain version - note the argument type `Function` of - # `semi.solver.volume_integral.volume_flux` - du .= 0 - invoke(Trixi.flux_differencing_kernel!, - Tuple{typeof(du), typeof(u), Integer, typeof(semi.mesh), - typeof(nonconservative_terms), typeof(semi.equations), - Function, typeof(semi.solver), typeof(semi.cache), Bool}, - du, u, 1, semi.mesh, - nonconservative_terms, semi.equations, - semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) - du_baseline = du[:, :, :, 1] - - @test du_specialized ≈ du_baseline + u = Trixi.wrap_array(u_ode, semi) + du = Trixi.wrap_array(du_ode, semi) + nonconservative_terms = Trixi.have_nonconservative_terms(semi.equations) + + # Call the optimized default version + du .= 0 + Trixi.flux_differencing_kernel!(du, u, 1, semi.mesh, + nonconservative_terms, semi.equations, + semi.solver.volume_integral.volume_flux, + semi.solver, semi.cache, true) + du_specialized = du[:, :, :, 1] + + # Call the plain version - note the argument type `Function` of + # `semi.solver.volume_integral.volume_flux` + du .= 0 + invoke(Trixi.flux_differencing_kernel!, + Tuple{typeof(du), typeof(u), Integer, typeof(semi.mesh), + typeof(nonconservative_terms), typeof(semi.equations), + Function, typeof(semi.solver), typeof(semi.cache), Bool}, + du, u, 1, semi.mesh, + nonconservative_terms, semi.equations, + semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) + du_baseline = du[:, :, :, 1] + + @test du_specialized ≈ du_baseline end - end end - +end # Clean up afterwards: delete Trixi.jl output directory -@test_nowarn rm(outdir, recursive=true) +@test_nowarn rm(outdir, recursive = true) end #module diff --git a/test/test_performance_specializations_3d.jl b/test/test_performance_specializations_3d.jl index f767930996a..929fc7e3621 100644 --- a/test/test_performance_specializations_3d.jl +++ b/test/test_performance_specializations_3d.jl @@ -7,169 +7,171 @@ include("test_trixi.jl") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) - +isdir(outdir) && rm(outdir, recursive = true) @testset "Performance specializations 3D" begin - @timed_testset "TreeMesh3D, flux_shima_etal_turbo" begin +#! format: noindent + +@timed_testset "TreeMesh3D, flux_shima_etal_turbo" begin trixi_include(@__MODULE__, - joinpath(examples_dir(), "tree_3d_dgsem", "elixir_euler_ec.jl"), - initial_refinement_level=0, tspan=(0.0, 0.0), polydeg=3, - volume_flux=flux_shima_etal_turbo, surface_flux=flux_shima_etal_turbo) + joinpath(examples_dir(), "tree_3d_dgsem", "elixir_euler_ec.jl"), + initial_refinement_level = 0, tspan = (0.0, 0.0), polydeg = 3, + volume_flux = flux_shima_etal_turbo, + surface_flux = flux_shima_etal_turbo) u_ode = copy(sol.u[end]) du_ode = zero(u_ode) # Preserve original memory since it will be `unsafe_wrap`ped and might # thus otherwise be garbage collected GC.@preserve u_ode du_ode begin - u = Trixi.wrap_array(u_ode, semi) - du = Trixi.wrap_array(du_ode, semi) - nonconservative_terms = Trixi.have_nonconservative_terms(semi.equations) - - # Call the optimized default version - du .= 0 - Trixi.flux_differencing_kernel!( - du, u, 1, semi.mesh, - nonconservative_terms, semi.equations, - semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) - du_specialized = du[:, :, :, :, 1] - - # Call the plain version - note the argument type `Function` of - # `semi.solver.volume_integral.volume_flux` - du .= 0 - invoke(Trixi.flux_differencing_kernel!, - Tuple{typeof(du), typeof(u), Integer, typeof(semi.mesh), - typeof(nonconservative_terms), typeof(semi.equations), - Function, typeof(semi.solver), typeof(semi.cache), Bool}, - du, u, 1, semi.mesh, - nonconservative_terms, semi.equations, - semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) - du_baseline = du[:, :, :, :, 1] - - @test du_specialized ≈ du_baseline + u = Trixi.wrap_array(u_ode, semi) + du = Trixi.wrap_array(du_ode, semi) + nonconservative_terms = Trixi.have_nonconservative_terms(semi.equations) + + # Call the optimized default version + du .= 0 + Trixi.flux_differencing_kernel!(du, u, 1, semi.mesh, + nonconservative_terms, semi.equations, + semi.solver.volume_integral.volume_flux, + semi.solver, semi.cache, true) + du_specialized = du[:, :, :, :, 1] + + # Call the plain version - note the argument type `Function` of + # `semi.solver.volume_integral.volume_flux` + du .= 0 + invoke(Trixi.flux_differencing_kernel!, + Tuple{typeof(du), typeof(u), Integer, typeof(semi.mesh), + typeof(nonconservative_terms), typeof(semi.equations), + Function, typeof(semi.solver), typeof(semi.cache), Bool}, + du, u, 1, semi.mesh, + nonconservative_terms, semi.equations, + semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) + du_baseline = du[:, :, :, :, 1] + + @test du_specialized ≈ du_baseline end - end +end - @timed_testset "TreeMesh3D, flux_ranocha_turbo" begin +@timed_testset "TreeMesh3D, flux_ranocha_turbo" begin trixi_include(@__MODULE__, - joinpath(examples_dir(), "tree_3d_dgsem", "elixir_euler_ec.jl"), - initial_refinement_level=0, tspan=(0.0, 0.0), polydeg=3, - volume_flux=flux_ranocha_turbo, surface_flux=flux_ranocha_turbo) + joinpath(examples_dir(), "tree_3d_dgsem", "elixir_euler_ec.jl"), + initial_refinement_level = 0, tspan = (0.0, 0.0), polydeg = 3, + volume_flux = flux_ranocha_turbo, surface_flux = flux_ranocha_turbo) u_ode = copy(sol.u[end]) du_ode = zero(u_ode) # Preserve original memory since it will be `unsafe_wrap`ped and might # thus otherwise be garbage collected GC.@preserve u_ode du_ode begin - u = Trixi.wrap_array(u_ode, semi) - du = Trixi.wrap_array(du_ode, semi) - nonconservative_terms = Trixi.have_nonconservative_terms(semi.equations) - - # Call the optimized default version - du .= 0 - Trixi.flux_differencing_kernel!( - du, u, 1, semi.mesh, - nonconservative_terms, semi.equations, - semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) - du_specialized = du[:, :, :, :, 1] - - # Call the plain version - note the argument type `Function` of - # `semi.solver.volume_integral.volume_flux` - du .= 0 - invoke(Trixi.flux_differencing_kernel!, - Tuple{typeof(du), typeof(u), Integer, typeof(semi.mesh), - typeof(nonconservative_terms), typeof(semi.equations), - Function, typeof(semi.solver), typeof(semi.cache), Bool}, - du, u, 1, semi.mesh, - nonconservative_terms, semi.equations, - semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) - du_baseline = du[:, :, :, :, 1] - - @test du_specialized ≈ du_baseline + u = Trixi.wrap_array(u_ode, semi) + du = Trixi.wrap_array(du_ode, semi) + nonconservative_terms = Trixi.have_nonconservative_terms(semi.equations) + + # Call the optimized default version + du .= 0 + Trixi.flux_differencing_kernel!(du, u, 1, semi.mesh, + nonconservative_terms, semi.equations, + semi.solver.volume_integral.volume_flux, + semi.solver, semi.cache, true) + du_specialized = du[:, :, :, :, 1] + + # Call the plain version - note the argument type `Function` of + # `semi.solver.volume_integral.volume_flux` + du .= 0 + invoke(Trixi.flux_differencing_kernel!, + Tuple{typeof(du), typeof(u), Integer, typeof(semi.mesh), + typeof(nonconservative_terms), typeof(semi.equations), + Function, typeof(semi.solver), typeof(semi.cache), Bool}, + du, u, 1, semi.mesh, + nonconservative_terms, semi.equations, + semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) + du_baseline = du[:, :, :, :, 1] + + @test du_specialized ≈ du_baseline end - end +end - @timed_testset "StructuredMesh3D, flux_shima_etal_turbo" begin +@timed_testset "StructuredMesh3D, flux_shima_etal_turbo" begin trixi_include(@__MODULE__, - joinpath(examples_dir(), "structured_3d_dgsem", "elixir_euler_ec.jl"), - cells_per_dimension=(1, 1, 1), tspan=(0.0, 0.0), polydeg=3, - volume_flux=flux_shima_etal_turbo, surface_flux=flux_shima_etal_turbo) + joinpath(examples_dir(), "structured_3d_dgsem", "elixir_euler_ec.jl"), + cells_per_dimension = (1, 1, 1), tspan = (0.0, 0.0), polydeg = 3, + volume_flux = flux_shima_etal_turbo, + surface_flux = flux_shima_etal_turbo) u_ode = copy(sol.u[end]) du_ode = zero(u_ode) # Preserve original memory since it will be `unsafe_wrap`ped and might # thus otherwise be garbage collected GC.@preserve u_ode du_ode begin - u = Trixi.wrap_array(u_ode, semi) - du = Trixi.wrap_array(du_ode, semi) - nonconservative_terms = Trixi.have_nonconservative_terms(semi.equations) - - # Call the optimized default version - du .= 0 - Trixi.flux_differencing_kernel!( - du, u, 1, semi.mesh, - nonconservative_terms, semi.equations, - semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) - du_specialized = du[:, :, :, :, 1] - - # Call the plain version - note the argument type `Function` of - # `semi.solver.volume_integral.volume_flux` - du .= 0 - invoke(Trixi.flux_differencing_kernel!, - Tuple{typeof(du), typeof(u), Integer, typeof(semi.mesh), - typeof(nonconservative_terms), typeof(semi.equations), - Function, typeof(semi.solver), typeof(semi.cache), Bool}, - du, u, 1, semi.mesh, - nonconservative_terms, semi.equations, - semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) - du_baseline = du[:, :, :, :, 1] - - @test du_specialized ≈ du_baseline + u = Trixi.wrap_array(u_ode, semi) + du = Trixi.wrap_array(du_ode, semi) + nonconservative_terms = Trixi.have_nonconservative_terms(semi.equations) + + # Call the optimized default version + du .= 0 + Trixi.flux_differencing_kernel!(du, u, 1, semi.mesh, + nonconservative_terms, semi.equations, + semi.solver.volume_integral.volume_flux, + semi.solver, semi.cache, true) + du_specialized = du[:, :, :, :, 1] + + # Call the plain version - note the argument type `Function` of + # `semi.solver.volume_integral.volume_flux` + du .= 0 + invoke(Trixi.flux_differencing_kernel!, + Tuple{typeof(du), typeof(u), Integer, typeof(semi.mesh), + typeof(nonconservative_terms), typeof(semi.equations), + Function, typeof(semi.solver), typeof(semi.cache), Bool}, + du, u, 1, semi.mesh, + nonconservative_terms, semi.equations, + semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) + du_baseline = du[:, :, :, :, 1] + + @test du_specialized ≈ du_baseline end - end +end - @timed_testset "StructuredMesh3D, flux_ranocha_turbo" begin +@timed_testset "StructuredMesh3D, flux_ranocha_turbo" begin trixi_include(@__MODULE__, - joinpath(examples_dir(), "structured_3d_dgsem", "elixir_euler_ec.jl"), - cells_per_dimension=(1, 1, 1), tspan=(0.0, 0.0), polydeg=3, - volume_flux=flux_ranocha_turbo, surface_flux=flux_ranocha_turbo) + joinpath(examples_dir(), "structured_3d_dgsem", "elixir_euler_ec.jl"), + cells_per_dimension = (1, 1, 1), tspan = (0.0, 0.0), polydeg = 3, + volume_flux = flux_ranocha_turbo, surface_flux = flux_ranocha_turbo) u_ode = copy(sol.u[end]) du_ode = zero(u_ode) # Preserve original memory since it will be `unsafe_wrap`ped and might # thus otherwise be garbage collected GC.@preserve u_ode du_ode begin - u = Trixi.wrap_array(u_ode, semi) - du = Trixi.wrap_array(du_ode, semi) - nonconservative_terms = Trixi.have_nonconservative_terms(semi.equations) - - # Call the optimized default version - du .= 0 - Trixi.flux_differencing_kernel!( - du, u, 1, semi.mesh, - nonconservative_terms, semi.equations, - semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) - du_specialized = du[:, :, :, :, 1] - - # Call the plain version - note the argument type `Function` of - # `semi.solver.volume_integral.volume_flux` - du .= 0 - invoke(Trixi.flux_differencing_kernel!, - Tuple{typeof(du), typeof(u), Integer, typeof(semi.mesh), - typeof(nonconservative_terms), typeof(semi.equations), - Function, typeof(semi.solver), typeof(semi.cache), Bool}, - du, u, 1, semi.mesh, - nonconservative_terms, semi.equations, - semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) - du_baseline = du[:, :, :, :, 1] - - @test du_specialized ≈ du_baseline + u = Trixi.wrap_array(u_ode, semi) + du = Trixi.wrap_array(du_ode, semi) + nonconservative_terms = Trixi.have_nonconservative_terms(semi.equations) + + # Call the optimized default version + du .= 0 + Trixi.flux_differencing_kernel!(du, u, 1, semi.mesh, + nonconservative_terms, semi.equations, + semi.solver.volume_integral.volume_flux, + semi.solver, semi.cache, true) + du_specialized = du[:, :, :, :, 1] + + # Call the plain version - note the argument type `Function` of + # `semi.solver.volume_integral.volume_flux` + du .= 0 + invoke(Trixi.flux_differencing_kernel!, + Tuple{typeof(du), typeof(u), Integer, typeof(semi.mesh), + typeof(nonconservative_terms), typeof(semi.equations), + Function, typeof(semi.solver), typeof(semi.cache), Bool}, + du, u, 1, semi.mesh, + nonconservative_terms, semi.equations, + semi.solver.volume_integral.volume_flux, semi.solver, semi.cache, true) + du_baseline = du[:, :, :, :, 1] + + @test du_specialized ≈ du_baseline end - end end - +end # Clean up afterwards: delete Trixi.jl output directory -@test_nowarn rm(outdir, recursive=true) +@test_nowarn rm(outdir, recursive = true) end #module diff --git a/test/test_special_elixirs.jl b/test/test_special_elixirs.jl index c05dfbdfca1..4f42414ccbf 100644 --- a/test/test_special_elixirs.jl +++ b/test/test_special_elixirs.jl @@ -10,7 +10,7 @@ include("test_trixi.jl") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) const EXAMPLES_DIR = pkgdir(Trixi, "examples") @@ -18,66 +18,116 @@ cmd = string(Base.julia_cmd()) coverage = occursin("--code-coverage", cmd) && !occursin("--code-coverage=none", cmd) @testset "Special elixirs" begin - @testset "Convergence test" begin +#! format: noindent + +@testset "Convergence test" begin if !coverage - @timed_testset "tree_2d_dgsem" begin - mean_convergence = convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_2d_dgsem", "elixir_advection_extended.jl"), 3, initial_refinement_level=2) - @test isapprox(mean_convergence[:l2], [4.0], rtol=0.05) - end - - @timed_testset "structured_2d_dgsem" begin - mean_convergence = convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "structured_2d_dgsem", "elixir_advection_extended.jl"), 3, cells_per_dimension=(5, 9)) - @test isapprox(mean_convergence[:l2], [4.0], rtol=0.05) - end - - @timed_testset "structured_2d_dgsem coupled" begin - mean_convergence = convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "structured_2d_dgsem", "elixir_advection_coupled.jl"), 3) - @test isapprox(mean_convergence[1][:l2], [4.0], rtol=0.05) - @test isapprox(mean_convergence[2][:l2], [4.0], rtol=0.05) - end - - @timed_testset "p4est_2d_dgsem" begin - # Run convergence test on unrefined mesh - no_refine = @cfunction((p4est, which_tree, quadrant) -> Cint(0), Cint, (Ptr{Trixi.p4est_t}, Ptr{Trixi.p4est_topidx_t}, Ptr{Trixi.p4est_quadrant_t})) - mean_convergence = convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "p4est_2d_dgsem", "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), 2, refine_fn_c=no_refine) - @test isapprox(mean_convergence[:linf], [3.2, 3.2, 4.0, 3.7], rtol=0.05) - end - - @timed_testset "structured_3d_dgsem" begin - mean_convergence = convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "structured_3d_dgsem", "elixir_advection_basic.jl"), 2, cells_per_dimension=(7, 4, 5)) - @test isapprox(mean_convergence[:l2], [4.0], rtol=0.05) - end - - @timed_testset "p4est_3d_dgsem" begin - mean_convergence = convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "p4est_3d_dgsem", "elixir_advection_unstructured_curved.jl"), 2, initial_refinement_level=0) - @test isapprox(mean_convergence[:l2], [2.7], rtol=0.05) - end - - @timed_testset "paper_self_gravitating_gas_dynamics" begin - mean_convergence = convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "paper_self_gravitating_gas_dynamics", "elixir_eulergravity_convergence.jl"), 2, tspan=(0.0, 0.25), initial_refinement_level=1) - @test isapprox(mean_convergence[:l2], 4 * ones(4), atol=0.4) - end + @timed_testset "tree_2d_dgsem" begin + mean_convergence = convergence_test(@__MODULE__, + joinpath(EXAMPLES_DIR, "tree_2d_dgsem", + "elixir_advection_extended.jl"), + 3, initial_refinement_level = 2) + @test isapprox(mean_convergence[:l2], [4.0], rtol = 0.05) + end + + @timed_testset "structured_2d_dgsem" begin + mean_convergence = convergence_test(@__MODULE__, + joinpath(EXAMPLES_DIR, + "structured_2d_dgsem", + "elixir_advection_extended.jl"), + 3, cells_per_dimension = (5, 9)) + @test isapprox(mean_convergence[:l2], [4.0], rtol = 0.05) + end + + @timed_testset "structured_2d_dgsem coupled" begin + mean_convergence = convergence_test(@__MODULE__, + joinpath(EXAMPLES_DIR, + "structured_2d_dgsem", + "elixir_advection_coupled.jl"), + 3) + @test isapprox(mean_convergence[1][:l2], [4.0], rtol = 0.05) + @test isapprox(mean_convergence[2][:l2], [4.0], rtol = 0.05) + end + + @timed_testset "p4est_2d_dgsem" begin + # Run convergence test on unrefined mesh + no_refine = @cfunction((p4est, which_tree, quadrant)->Cint(0), Cint, + (Ptr{Trixi.p4est_t}, Ptr{Trixi.p4est_topidx_t}, + Ptr{Trixi.p4est_quadrant_t})) + mean_convergence = convergence_test(@__MODULE__, + joinpath(EXAMPLES_DIR, "p4est_2d_dgsem", + "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), + 2, refine_fn_c = no_refine) + @test isapprox(mean_convergence[:linf], [3.2, 3.2, 4.0, 3.7], rtol = 0.05) + end + + @timed_testset "structured_3d_dgsem" begin + mean_convergence = convergence_test(@__MODULE__, + joinpath(EXAMPLES_DIR, + "structured_3d_dgsem", + "elixir_advection_basic.jl"), + 2, cells_per_dimension = (7, 4, 5)) + @test isapprox(mean_convergence[:l2], [4.0], rtol = 0.05) + end + + @timed_testset "p4est_3d_dgsem" begin + mean_convergence = convergence_test(@__MODULE__, + joinpath(EXAMPLES_DIR, "p4est_3d_dgsem", + "elixir_advection_unstructured_curved.jl"), + 2, initial_refinement_level = 0) + @test isapprox(mean_convergence[:l2], [2.7], rtol = 0.05) + end + + @timed_testset "paper_self_gravitating_gas_dynamics" begin + mean_convergence = convergence_test(@__MODULE__, + joinpath(EXAMPLES_DIR, + "paper_self_gravitating_gas_dynamics", + "elixir_eulergravity_convergence.jl"), + 2, tspan = (0.0, 0.25), + initial_refinement_level = 1) + @test isapprox(mean_convergence[:l2], 4 * ones(4), atol = 0.4) + end else - # Without coverage, just run simple convergence tests to cover - # the convergence test logic - @test_nowarn_mod convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_2d_dgsem", "elixir_advection_basic.jl"), 2, tspan=(0.0, 0.01)) - @test_nowarn_mod convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_2d_dgsem", "elixir_advection_extended.jl"), 2, initial_refinement_level=0, tspan=(0.0, 0.1)) - @test_nowarn_mod convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "structured_2d_dgsem", "elixir_advection_basic.jl"), 2, tspan=(0.0, 0.01)) - @test_nowarn_mod convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "structured_2d_dgsem", "elixir_advection_coupled.jl"), 2, tspan=(0.0, 0.01)) - @test_nowarn_mod convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "structured_2d_dgsem", "elixir_advection_extended.jl"), 2, cells_per_dimension=(1, 1), tspan=(0.0, 0.1)) + # Without coverage, just run simple convergence tests to cover + # the convergence test logic + @test_nowarn_mod convergence_test(@__MODULE__, + joinpath(EXAMPLES_DIR, "tree_2d_dgsem", + "elixir_advection_basic.jl"), 2, + tspan = (0.0, 0.01)) + @test_nowarn_mod convergence_test(@__MODULE__, + joinpath(EXAMPLES_DIR, "tree_2d_dgsem", + "elixir_advection_extended.jl"), 2, + initial_refinement_level = 0, + tspan = (0.0, 0.1)) + @test_nowarn_mod convergence_test(@__MODULE__, + joinpath(EXAMPLES_DIR, "structured_2d_dgsem", + "elixir_advection_basic.jl"), 2, + tspan = (0.0, 0.01)) + @test_nowarn_mod convergence_test(@__MODULE__, + joinpath(EXAMPLES_DIR, "structured_2d_dgsem", + "elixir_advection_coupled.jl"), 2, + tspan = (0.0, 0.01)) + @test_nowarn_mod convergence_test(@__MODULE__, + joinpath(EXAMPLES_DIR, "structured_2d_dgsem", + "elixir_advection_extended.jl"), 2, + cells_per_dimension = (1, 1), + tspan = (0.0, 0.1)) end - end - +end - @timed_testset "Test linear structure (2D)" begin - trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_2d_dgsem", "elixir_advection_extended.jl"), - tspan=(0.0, 0.0), initial_refinement_level=2) +@timed_testset "Test linear structure (2D)" begin + trixi_include(@__MODULE__, + joinpath(EXAMPLES_DIR, "tree_2d_dgsem", + "elixir_advection_extended.jl"), + tspan = (0.0, 0.0), initial_refinement_level = 2) A, b = linear_structure(semi) λ = eigvals(Matrix(A)) @test maximum(real, λ) < 10 * sqrt(eps(real(semi))) - trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_2d_dgsem", "elixir_hypdiff_lax_friedrichs.jl"), - tspan=(0.0, 0.0), initial_refinement_level=2) + trixi_include(@__MODULE__, + joinpath(EXAMPLES_DIR, "tree_2d_dgsem", + "elixir_hypdiff_lax_friedrichs.jl"), + tspan = (0.0, 0.0), initial_refinement_level = 2) A, b = linear_structure(semi) λ = eigvals(Matrix(A)) @test maximum(real, λ) < 10 * sqrt(eps(real(semi))) @@ -87,122 +137,141 @@ coverage = occursin("--code-coverage", cmd) && !occursin("--code-coverage=none", Ax = A * x @. b = 2 * b + x @test A * x ≈ Ax - end - +end - @testset "Test Jacobian of DG (2D)" begin +@testset "Test Jacobian of DG (2D)" begin @timed_testset "Linear advection" begin - trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_2d_dgsem", "elixir_advection_extended.jl"), - tspan=(0.0, 0.0), initial_refinement_level=2) - A, _ = linear_structure(semi) - - J = jacobian_ad_forward(semi) - @test Matrix(A) ≈ J - λ = eigvals(J) - @test maximum(real, λ) < 10 * sqrt(eps(real(semi))) - - J = jacobian_fd(semi) - @test Matrix(A) ≈ J - λ = eigvals(J) - @test maximum(real, λ) < 10 * sqrt(eps(real(semi))) + trixi_include(@__MODULE__, + joinpath(EXAMPLES_DIR, "tree_2d_dgsem", + "elixir_advection_extended.jl"), + tspan = (0.0, 0.0), initial_refinement_level = 2) + A, _ = linear_structure(semi) + + J = jacobian_ad_forward(semi) + @test Matrix(A) ≈ J + λ = eigvals(J) + @test maximum(real, λ) < 10 * sqrt(eps(real(semi))) + + J = jacobian_fd(semi) + @test Matrix(A) ≈ J + λ = eigvals(J) + @test maximum(real, λ) < 10 * sqrt(eps(real(semi))) end @timed_testset "Linear advection-diffusion" begin - trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_2d_dgsem", "elixir_advection_diffusion.jl"), - tspan=(0.0, 0.0), initial_refinement_level=2) + trixi_include(@__MODULE__, + joinpath(EXAMPLES_DIR, "tree_2d_dgsem", + "elixir_advection_diffusion.jl"), + tspan = (0.0, 0.0), initial_refinement_level = 2) - J = jacobian_ad_forward(semi) - λ = eigvals(J) - @test maximum(real, λ) < 10 * sqrt(eps(real(semi))) + J = jacobian_ad_forward(semi) + λ = eigvals(J) + @test maximum(real, λ) < 10 * sqrt(eps(real(semi))) end @timed_testset "Compressible Euler equations" begin - trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_2d_dgsem", "elixir_euler_density_wave.jl"), - tspan=(0.0, 0.0), initial_refinement_level=1) + trixi_include(@__MODULE__, + joinpath(EXAMPLES_DIR, "tree_2d_dgsem", + "elixir_euler_density_wave.jl"), + tspan = (0.0, 0.0), initial_refinement_level = 1) - J = jacobian_ad_forward(semi) - λ = eigvals(J) - @test maximum(real, λ) < 7.0e-7 - - J = jacobian_fd(semi) - λ = eigvals(J) - @test maximum(real, λ) < 7.0e-3 + J = jacobian_ad_forward(semi) + λ = eigvals(J) + @test maximum(real, λ) < 7.0e-7 - # This does not work yet because of the indicators... - @test_skip begin - trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_2d_dgsem", "elixir_euler_shockcapturing.jl"), - tspan=(0.0, 0.0), initial_refinement_level=1) - jacobian_ad_forward(semi) - end + J = jacobian_fd(semi) + λ = eigvals(J) + @test maximum(real, λ) < 7.0e-3 + + # This does not work yet because of the indicators... + @test_skip begin + trixi_include(@__MODULE__, + joinpath(EXAMPLES_DIR, "tree_2d_dgsem", + "elixir_euler_shockcapturing.jl"), + tspan = (0.0, 0.0), initial_refinement_level = 1) + jacobian_ad_forward(semi) + end - @timed_testset "DGMulti (weak form)" begin - gamma = 1.4 - equations = CompressibleEulerEquations2D(gamma) - initial_condition = initial_condition_density_wave + @timed_testset "DGMulti (weak form)" begin + gamma = 1.4 + equations = CompressibleEulerEquations2D(gamma) + initial_condition = initial_condition_density_wave - solver = DGMulti(polydeg = 5, element_type = Quad(), approximation_type = SBP(), - surface_integral = SurfaceIntegralWeakForm(flux_central), - volume_integral = VolumeIntegralWeakForm()) + solver = DGMulti(polydeg = 5, element_type = Quad(), + approximation_type = SBP(), + surface_integral = SurfaceIntegralWeakForm(flux_central), + volume_integral = VolumeIntegralWeakForm()) - # DGMultiMesh is on [-1, 1]^ndims by default - mesh = DGMultiMesh(solver, cells_per_dimension=(2, 2), periodicity=(true, true)) + # DGMultiMesh is on [-1, 1]^ndims by default + mesh = DGMultiMesh(solver, cells_per_dimension = (2, 2), + periodicity = (true, true)) - semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, + solver) - J = jacobian_ad_forward(semi) - λ = eigvals(J) - @test maximum(real, λ) < 7.0e-7 - end + J = jacobian_ad_forward(semi) + λ = eigvals(J) + @test maximum(real, λ) < 7.0e-7 + end - @timed_testset "DGMulti (SBP, flux differencing)" begin - gamma = 1.4 - equations = CompressibleEulerEquations2D(gamma) - initial_condition = initial_condition_density_wave + @timed_testset "DGMulti (SBP, flux differencing)" begin + gamma = 1.4 + equations = CompressibleEulerEquations2D(gamma) + initial_condition = initial_condition_density_wave - solver = DGMulti(polydeg = 5, element_type = Quad(), approximation_type = SBP(), - surface_integral = SurfaceIntegralWeakForm(flux_central), - volume_integral = VolumeIntegralFluxDifferencing(flux_central)) + solver = DGMulti(polydeg = 5, element_type = Quad(), + approximation_type = SBP(), + surface_integral = SurfaceIntegralWeakForm(flux_central), + volume_integral = VolumeIntegralFluxDifferencing(flux_central)) - # DGMultiMesh is on [-1, 1]^ndims by default - mesh = DGMultiMesh(solver, cells_per_dimension=(2, 2), periodicity=(true, true)) + # DGMultiMesh is on [-1, 1]^ndims by default + mesh = DGMultiMesh(solver, cells_per_dimension = (2, 2), + periodicity = (true, true)) - semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, + solver) - J = jacobian_ad_forward(semi) - λ = eigvals(J) - @test maximum(real, λ) < 7.0e-7 - end + J = jacobian_ad_forward(semi) + λ = eigvals(J) + @test maximum(real, λ) < 7.0e-7 + end end @timed_testset "Navier-Stokes" begin - trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_2d_dgsem", "elixir_navierstokes_taylor_green_vortex.jl"), - tspan=(0.0, 0.0), initial_refinement_level=2) + trixi_include(@__MODULE__, + joinpath(EXAMPLES_DIR, "tree_2d_dgsem", + "elixir_navierstokes_taylor_green_vortex.jl"), + tspan = (0.0, 0.0), initial_refinement_level = 2) - J = jacobian_ad_forward(semi) - λ = eigvals(J) - @test maximum(real, λ) < 0.2 + J = jacobian_ad_forward(semi) + λ = eigvals(J) + @test maximum(real, λ) < 0.2 end @timed_testset "MHD" begin - trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_2d_dgsem", "elixir_mhd_alfven_wave.jl"), - tspan=(0.0, 0.0), initial_refinement_level=0) - @test_nowarn jacobian_ad_forward(semi) + trixi_include(@__MODULE__, + joinpath(EXAMPLES_DIR, "tree_2d_dgsem", + "elixir_mhd_alfven_wave.jl"), + tspan = (0.0, 0.0), initial_refinement_level = 0) + @test_nowarn jacobian_ad_forward(semi) end - end - +end - @timed_testset "Test linear structure (3D)" begin - trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_3d_dgsem", "elixir_advection_extended.jl"), - tspan=(0.0, 0.0), initial_refinement_level=1) +@timed_testset "Test linear structure (3D)" begin + trixi_include(@__MODULE__, + joinpath(EXAMPLES_DIR, "tree_3d_dgsem", + "elixir_advection_extended.jl"), + tspan = (0.0, 0.0), initial_refinement_level = 1) A, b = linear_structure(semi) λ = eigvals(Matrix(A)) @test maximum(real, λ) < 10 * sqrt(eps(real(semi))) - end - +end - @timed_testset "Test Jacobian of DG (3D)" begin - trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_3d_dgsem", "elixir_advection_extended.jl"), - tspan=(0.0, 0.0), initial_refinement_level=1) +@timed_testset "Test Jacobian of DG (3D)" begin + trixi_include(@__MODULE__, + joinpath(EXAMPLES_DIR, "tree_3d_dgsem", + "elixir_advection_extended.jl"), + tspan = (0.0, 0.0), initial_refinement_level = 1) A, _ = linear_structure(semi) J = jacobian_ad_forward(semi) @@ -210,76 +279,77 @@ coverage = occursin("--code-coverage", cmd) && !occursin("--code-coverage=none", J = jacobian_fd(semi) @test Matrix(A) ≈ J - end - +end - @testset "AD using ForwardDiff" begin +@testset "AD using ForwardDiff" begin @timed_testset "Euler equations 1D" begin - function entropy_at_final_time(k) # k is the wave number of the initial condition - equations = CompressibleEulerEquations1D(1.4) - mesh = TreeMesh((-1.0,), (1.0,), initial_refinement_level=3, n_cells_max=10^4) - solver = DGSEM(3, flux_hll, VolumeIntegralFluxDifferencing(flux_ranocha)) - initial_condition = (x, t, equations) -> begin - rho = 2 + sinpi(k * sum(x)) - v1 = 0.1 - p = 10.0 - return prim2cons(SVector(rho, v1, p), equations) + function entropy_at_final_time(k) # k is the wave number of the initial condition + equations = CompressibleEulerEquations1D(1.4) + mesh = TreeMesh((-1.0,), (1.0,), initial_refinement_level = 3, + n_cells_max = 10^4) + solver = DGSEM(3, flux_hll, VolumeIntegralFluxDifferencing(flux_ranocha)) + initial_condition = (x, t, equations) -> begin + rho = 2 + sinpi(k * sum(x)) + v1 = 0.1 + p = 10.0 + return prim2cons(SVector(rho, v1, p), equations) + end + semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, + solver, + uEltype = typeof(k)) + ode = semidiscretize(semi, (0.0, 1.0)) + summary_callback = SummaryCallback() + analysis_interval = 100 + analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + alive_callback = AliveCallback(analysis_interval = analysis_interval) + callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback) + sol = solve(ode, SSPRK43(), callback = callbacks) + Trixi.integrate(entropy, sol.u[end], semi) end - semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - uEltype=typeof(k)) - ode = semidiscretize(semi, (0.0, 1.0)) - summary_callback = SummaryCallback() - analysis_interval = 100 - analysis_callback = AnalysisCallback(semi, interval=analysis_interval) - alive_callback = AliveCallback(analysis_interval=analysis_interval) - callbacks = CallbackSet( - summary_callback, - analysis_callback, - alive_callback - ) - sol = solve(ode, SSPRK43(), callback=callbacks) - Trixi.integrate(entropy, sol.u[end], semi) - end - ForwardDiff.derivative(entropy_at_final_time, 1.0) ≈ -0.4524664696235628 + ForwardDiff.derivative(entropy_at_final_time, 1.0) ≈ -0.4524664696235628 end @timed_testset "Linear advection 2D" begin - function energy_at_final_time(k) # k is the wave number of the initial condition - equations = LinearScalarAdvectionEquation2D(0.2, -0.7) - mesh = TreeMesh((-1.0, -1.0), (1.0, 1.0), initial_refinement_level=3, n_cells_max=10^4) - solver = DGSEM(3, flux_lax_friedrichs) - initial_condition = (x, t, equation) -> begin - x_trans = Trixi.x_trans_periodic_2d(x - equation.advection_velocity * t) - return SVector(sinpi(k * sum(x_trans))) + function energy_at_final_time(k) # k is the wave number of the initial condition + equations = LinearScalarAdvectionEquation2D(0.2, -0.7) + mesh = TreeMesh((-1.0, -1.0), (1.0, 1.0), initial_refinement_level = 3, + n_cells_max = 10^4) + solver = DGSEM(3, flux_lax_friedrichs) + initial_condition = (x, t, equation) -> begin + x_trans = Trixi.x_trans_periodic_2d(x - equation.advection_velocity * t) + return SVector(sinpi(k * sum(x_trans))) + end + semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, + solver, + uEltype = typeof(k)) + ode = semidiscretize(semi, (0.0, 1.0)) + 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.6) + callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + stepsize_callback) + sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + save_everystep = false, adaptive = false, dt = 1.0, + callback = callbacks) + Trixi.integrate(energy_total, sol.u[end], semi) end - semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - uEltype=typeof(k)) - ode = semidiscretize(semi, (0.0, 1.0)) - 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.6) - callbacks = CallbackSet( - summary_callback, - analysis_callback, - alive_callback, - stepsize_callback - ) - sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), save_everystep=false, adaptive=false, dt=1.0, callback=callbacks) - Trixi.integrate(energy_total, sol.u[end], semi) - end - ForwardDiff.derivative(energy_at_final_time, 1.0) ≈ 1.4388628342896945e-5 + ForwardDiff.derivative(energy_at_final_time, 1.0) ≈ 1.4388628342896945e-5 end @timed_testset "elixir_euler_ad.jl" begin - @test_trixi_include(joinpath(examples_dir(), "special_elixirs", "elixir_euler_ad.jl")) + @test_trixi_include(joinpath(examples_dir(), "special_elixirs", + "elixir_euler_ad.jl")) end - end end - +end # Clean up afterwards: delete Trixi.jl output directory -@test_nowarn rm(outdir, recursive=true) +@test_nowarn rm(outdir, recursive = true) end #module diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index 85b26192fb5..f0eecfa9acd 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -9,115 +9,138 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "structured_1d_dgsem") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) @testset "StructuredMesh1D" begin - @trixi_testset "elixir_advection_basic.jl" begin +#! format: noindent + +@trixi_testset "elixir_advection_basic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), - # Expected errors are exactly the same as with TreeMesh! - l2 = [6.0388296447998465e-6], - linf = [3.217887726258972e-5]) - # 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 + # Expected errors are exactly the same as with TreeMesh! + l2=[6.0388296447998465e-6], + linf=[3.217887726258972e-5]) + # 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_nonperiodic.jl" begin +@trixi_testset "elixir_advection_nonperiodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_nonperiodic.jl"), - l2 = [5.641921365468918e-5], - linf = [0.00021049780975179733]) - # 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 + l2=[5.641921365468918e-5], + linf=[0.00021049780975179733]) + # 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_shockcapturing.jl" begin +@trixi_testset "elixir_advection_shockcapturing.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_shockcapturing.jl"), - l2 = [0.08015029105233593], - linf = [0.610709468736576], - atol = 1.0e-5) - # 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 + l2=[0.08015029105233593], + linf=[0.610709468736576], + atol=1.0e-5) + # 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 +@trixi_testset "elixir_euler_sedov.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov.jl"), - l2 = [3.67478226e-01, 3.49491179e-01, 8.08910759e-01], - linf = [1.58971947e+00, 1.59812384e+00, 1.94732969e+00], - tspan = (0.0, 0.3)) - # 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 + l2=[3.67478226e-01, 3.49491179e-01, 8.08910759e-01], + linf=[1.58971947e+00, 1.59812384e+00, 1.94732969e+00], + tspan=(0.0, 0.3)) + # 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_hll_davis.jl" begin +@trixi_testset "elixir_euler_sedov_hll_davis.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov.jl"), - l2 = [1.278661029299215, 0.0663853410742763, 0.9585741943783386], - linf = [3.1661064228547255, 0.16256363944708607, 2.667676158812806], - tspan = (0.0, 12.5), - surface_flux = FluxHLL(min_max_speed_davis)) - # 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 + l2=[1.278661029299215, 0.0663853410742763, 0.9585741943783386], + linf=[ + 3.1661064228547255, + 0.16256363944708607, + 2.667676158812806, + ], + tspan=(0.0, 12.5), + surface_flux=FluxHLL(min_max_speed_davis)) + # 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_source_terms.jl" begin +@trixi_testset "elixir_euler_source_terms.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms.jl"), - # Expected errors are exactly the same as with TreeMesh! - l2 = [2.2527950196212703e-8, 1.8187357193835156e-8, 7.705669939973104e-8], - linf = [1.6205433861493646e-7, 1.465427772462391e-7, 5.372255111879554e-7]) - # 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 + # Expected errors are exactly the same as with TreeMesh! + l2=[ + 2.2527950196212703e-8, + 1.8187357193835156e-8, + 7.705669939973104e-8, + ], + linf=[ + 1.6205433861493646e-7, + 1.465427772462391e-7, + 5.372255111879554e-7, + ]) + # 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_source_terms_nonperiodic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonperiodic.jl"), - l2 = [3.8099996914101204e-6, 1.6745575717106341e-6, 7.732189531480852e-6], - linf = [1.2971473393186272e-5, 9.270328934274374e-6, 3.092514399671842e-5]) - # 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_source_terms_nonperiodic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonperiodic.jl"), + l2=[ + 3.8099996914101204e-6, + 1.6745575717106341e-6, + 7.732189531480852e-6, + ], + linf=[ + 1.2971473393186272e-5, + 9.270328934274374e-6, + 3.092514399671842e-5, + ]) + # 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 -@test_nowarn rm(outdir, recursive=true) +@test_nowarn rm(outdir, recursive = true) end # module diff --git a/test/test_structured_2d.jl b/test/test_structured_2d.jl index c3192f52b2c..dd2248e10b2 100644 --- a/test/test_structured_2d.jl +++ b/test/test_structured_2d.jl @@ -11,652 +11,897 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "structured_2d_dgsem") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) @testset "StructuredMesh2D" begin - @trixi_testset "elixir_advection_basic.jl" begin +#! format: noindent + +@trixi_testset "elixir_advection_basic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), - # Expected errors are exactly the same as with TreeMesh! - l2 = [8.311947673061856e-6], - linf = [6.627000273229378e-5]) - # 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 - - @trixi_testset "elixir_advection_coupled.jl" begin + # Expected errors are exactly the same as with TreeMesh! + l2=[8.311947673061856e-6], + linf=[6.627000273229378e-5]) + # 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 = [7.816742843181738e-6, 7.816742843196112e-6], - linf = [6.314906965543265e-5, 6.314906965410039e-5], - coverage_override = (maxiters=10^5,)) + l2=[7.816742843181738e-6, 7.816742843196112e-6], + linf=[6.314906965543265e-5, 6.314906965410039e-5], + coverage_override=(maxiters = 10^5,)) @testset "analysis_callback(sol) for AnalysisCallbackCoupled" begin - errors = analysis_callback(sol) - @test errors.l2 ≈ [7.816742843181738e-6, 7.816742843196112e-6] rtol=1.0e-4 - @test errors.linf ≈ [6.314906965543265e-5, 6.314906965410039e-5] rtol=1.0e-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 - - @trixi_testset "elixir_advection_extended.jl" begin + errors = analysis_callback(sol) + @test errors.l2≈[7.816742843181738e-6, 7.816742843196112e-6] rtol=1.0e-4 + @test errors.linf≈[6.314906965543265e-5, 6.314906965410039e-5] rtol=1.0e-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 + +@trixi_testset "elixir_advection_extended.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2 = [4.220397559713772e-6], - linf = [3.477948874874848e-5]) - # 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_extended.jl with polydeg=4" begin + l2=[4.220397559713772e-6], + linf=[3.477948874874848e-5]) + # 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_extended.jl with polydeg=4" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2 = [5.32996976442737e-7], - linf = [4.1344662966569246e-6], - atol = 1e-12, # required to make CI tests pass on macOS - cells_per_dimension = (16, 23), - polydeg = 4, - cfl = 1.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 - - @testset "elixir_advection_rotated.jl" begin + l2=[5.32996976442737e-7], + linf=[4.1344662966569246e-6], + atol=1e-12, # required to make CI tests pass on macOS + cells_per_dimension=(16, 23), + polydeg=4, + cfl=1.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 + +@testset "elixir_advection_rotated.jl" begin @trixi_testset "elixir_advection_rotated.jl with α = 0.0" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_rotated.jl"), - # Expected errors are exactly the same as in elixir_advection_basic! - l2 = [8.311947673061856e-6], - linf = [6.627000273229378e-5], - alpha = 0.0) - # 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 + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_rotated.jl"), + # Expected errors are exactly the same as in elixir_advection_basic! + l2=[8.311947673061856e-6], + linf=[6.627000273229378e-5], + alpha=0.0) + # 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_rotated.jl with α = 0.1" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_rotated.jl"), - # Expected errors differ only slightly from elixir_advection_basic! - l2 = [8.3122750550501e-6], - linf = [6.626802581322089e-5], - alpha = 0.1) - # 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 + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_rotated.jl"), + # Expected errors differ only slightly from elixir_advection_basic! + l2=[8.3122750550501e-6], + linf=[6.626802581322089e-5], + alpha=0.1) + # 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_rotated.jl with α = 0.5 * pi" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_rotated.jl"), - # Expected errors are exactly the same as in elixir_advection_basic! - l2 = [8.311947673061856e-6], - linf = [6.627000273229378e-5], - alpha = 0.5 * pi) - # 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 - - @trixi_testset "elixir_advection_parallelogram.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_rotated.jl"), + # Expected errors are exactly the same as in elixir_advection_basic! + l2=[8.311947673061856e-6], + linf=[6.627000273229378e-5], + alpha=0.5 * pi) + # 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 + +@trixi_testset "elixir_advection_parallelogram.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_parallelogram.jl"), - # Expected errors are exactly the same as in elixir_advection_basic! - l2 = [8.311947673061856e-6], - linf = [6.627000273229378e-5]) - # 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_waving_flag.jl" begin + # Expected errors are exactly the same as in elixir_advection_basic! + l2=[8.311947673061856e-6], + linf=[6.627000273229378e-5]) + # 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_waving_flag.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_waving_flag.jl"), - l2 = [0.00018553859900545866], - linf = [0.0016167719118129753]) - # 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_free_stream.jl" begin + l2=[0.00018553859900545866], + linf=[0.0016167719118129753]) + # 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_free_stream.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_free_stream.jl"), - l2 = [6.8925194184204476e-15], - linf = [9.903189379656396e-14]) - # 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_nonperiodic.jl" begin + l2=[6.8925194184204476e-15], + linf=[9.903189379656396e-14]) + # 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_nonperiodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_nonperiodic.jl"), - l2 = [0.00025552740731641223], - linf = [0.007252625722805939]) - # 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_restart.jl" begin + l2=[0.00025552740731641223], + linf=[0.007252625722805939]) + # 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_restart.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), - l2 = [4.219208035582454e-6], - linf = [3.438434404412494e-5]) - # 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_restart.jl with waving flag mesh" begin + l2=[4.219208035582454e-6], + linf=[3.438434404412494e-5]) + # 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_restart.jl with waving flag mesh" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), - l2 = [0.00016265538265929818], - linf = [0.0015194252169410394], - rtol = 5.0e-5, # Higher tolerance to make tests pass in CI (in particular with macOS) - elixir_file="elixir_advection_waving_flag.jl", - restart_file="restart_000021.h5") - # 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_restart.jl with free stream mesh" begin + l2=[0.00016265538265929818], + linf=[0.0015194252169410394], + rtol=5.0e-5, # Higher tolerance to make tests pass in CI (in particular with macOS) + elixir_file="elixir_advection_waving_flag.jl", + restart_file="restart_000021.h5") + # 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_restart.jl with free stream mesh" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), - l2 = [7.841217436552029e-15], - linf = [1.0857981180834031e-13], - elixir_file="elixir_advection_free_stream.jl", - restart_file="restart_000036.h5") - # 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_source_terms.jl" begin + l2=[7.841217436552029e-15], + linf=[1.0857981180834031e-13], + elixir_file="elixir_advection_free_stream.jl", + restart_file="restart_000036.h5") + # 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_source_terms.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms.jl"), - # Expected errors are exactly the same as with TreeMesh! - l2 = [9.321181253186009e-7, 1.4181210743438511e-6, 1.4181210743487851e-6, 4.824553091276693e-6], - linf = [9.577246529612893e-6, 1.1707525976012434e-5, 1.1707525976456523e-5, 4.8869615580926506e-5]) - # 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 - - @testset "elixir_euler_source_terms_rotated.jl" begin + # Expected errors are exactly the same as with TreeMesh! + l2=[ + 9.321181253186009e-7, + 1.4181210743438511e-6, + 1.4181210743487851e-6, + 4.824553091276693e-6, + ], + linf=[ + 9.577246529612893e-6, + 1.1707525976012434e-5, + 1.1707525976456523e-5, + 4.8869615580926506e-5, + ]) + # 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 + +@testset "elixir_euler_source_terms_rotated.jl" begin @trixi_testset "elixir_euler_source_terms_rotated.jl with α = 0.0" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_rotated.jl"), - # Expected errors are exactly the same as in elixir_euler_source_terms! - l2 = [9.321181253186009e-7, 1.4181210743438511e-6, 1.4181210743487851e-6, 4.824553091276693e-6], - linf = [9.577246529612893e-6, 1.1707525976012434e-5, 1.1707525976456523e-5, 4.8869615580926506e-5], - alpha = 0.0) - # 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 + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_rotated.jl"), + # Expected errors are exactly the same as in elixir_euler_source_terms! + l2=[ + 9.321181253186009e-7, + 1.4181210743438511e-6, + 1.4181210743487851e-6, + 4.824553091276693e-6, + ], + linf=[ + 9.577246529612893e-6, + 1.1707525976012434e-5, + 1.1707525976456523e-5, + 4.8869615580926506e-5, + ], + alpha=0.0) + # 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_source_terms_rotated.jl with α = 0.1" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_rotated.jl"), - # Expected errors differ only slightly from elixir_euler_source_terms! - l2 = [9.321188057029291e-7, 1.3195106906473365e-6, 1.510307360354032e-6, 4.82455408101712e-6], - linf = [9.57723626271445e-6, 1.0480225511866337e-5, 1.2817828088262928e-5, 4.886962393513272e-5], - alpha = 0.1) - # 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 + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_rotated.jl"), + # Expected errors differ only slightly from elixir_euler_source_terms! + l2=[ + 9.321188057029291e-7, + 1.3195106906473365e-6, + 1.510307360354032e-6, + 4.82455408101712e-6, + ], + linf=[ + 9.57723626271445e-6, + 1.0480225511866337e-5, + 1.2817828088262928e-5, + 4.886962393513272e-5, + ], + alpha=0.1) + # 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_source_terms_rotated.jl with α = 0.2 * pi" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_rotated.jl"), - # Expected errors differ only slightly from elixir_euler_source_terms! - l2 = [9.32127973957391e-7, 8.477824799744325e-7, 1.8175286311402784e-6, 4.824562453521076e-6], - linf = [9.576898420737834e-6, 5.057704352218195e-6, 1.635260719945464e-5, 4.886978754825577e-5], - alpha = 0.2 * pi) - # 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 + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_rotated.jl"), + # Expected errors differ only slightly from elixir_euler_source_terms! + l2=[ + 9.32127973957391e-7, + 8.477824799744325e-7, + 1.8175286311402784e-6, + 4.824562453521076e-6, + ], + linf=[ + 9.576898420737834e-6, + 5.057704352218195e-6, + 1.635260719945464e-5, + 4.886978754825577e-5, + ], + alpha=0.2 * pi) + # 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_source_terms_rotated.jl with α = 0.5 * pi" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_rotated.jl"), - # Expected errors are exactly the same as in elixir_euler_source_terms! - l2 = [9.321181253186009e-7, 1.4181210743438511e-6, 1.4181210743487851e-6, 4.824553091276693e-6], - linf = [9.577246529612893e-6, 1.1707525976012434e-5, 1.1707525976456523e-5, 4.8869615580926506e-5], - alpha = 0.5 * pi) - # 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_source_terms_parallelogram.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_parallelogram.jl"), - l2 = [1.1167802955144833e-5, 1.0805775514153104e-5, 1.953188337010932e-5, 5.5033856574857146e-5], - linf = [8.297006495561199e-5, 8.663281475951301e-5, 0.00012264160606778596, 0.00041818802502024965]) - # 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_source_terms_waving_flag.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_waving_flag.jl"), - l2 = [2.991891317562739e-5, 3.6063177168283174e-5, 2.7082941743640572e-5, 0.00011414695350996946], - linf = [0.0002437454930492855, 0.0003438936171968887, 0.00024217622945688078, 0.001266380414757684]) - # 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.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_rotated.jl"), + # Expected errors are exactly the same as in elixir_euler_source_terms! + l2=[ + 9.321181253186009e-7, + 1.4181210743438511e-6, + 1.4181210743487851e-6, + 4.824553091276693e-6, + ], + linf=[ + 9.577246529612893e-6, + 1.1707525976012434e-5, + 1.1707525976456523e-5, + 4.8869615580926506e-5, + ], + alpha=0.5 * pi) + # 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 + +@trixi_testset "elixir_euler_source_terms_parallelogram.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_parallelogram.jl"), + l2=[ + 1.1167802955144833e-5, + 1.0805775514153104e-5, + 1.953188337010932e-5, + 5.5033856574857146e-5, + ], + linf=[ + 8.297006495561199e-5, + 8.663281475951301e-5, + 0.00012264160606778596, + 0.00041818802502024965, + ]) + # 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_source_terms_waving_flag.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_waving_flag.jl"), + l2=[ + 2.991891317562739e-5, + 3.6063177168283174e-5, + 2.7082941743640572e-5, + 0.00011414695350996946, + ], + linf=[ + 0.0002437454930492855, + 0.0003438936171968887, + 0.00024217622945688078, + 0.001266380414757684, + ]) + # 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.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_free_stream.jl"), - l2 = [2.063350241405049e-15, 1.8571016296925367e-14, 3.1769447886391905e-14, 1.4104095258528071e-14], - linf = [1.9539925233402755e-14, 2.9791447087035294e-13, 6.502853810985698e-13, 2.7000623958883807e-13], - atol = 7.0e-13) - # 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.jl with FluxRotated(flux_lax_friedrichs)" begin + l2=[ + 2.063350241405049e-15, + 1.8571016296925367e-14, + 3.1769447886391905e-14, + 1.4104095258528071e-14, + ], + linf=[ + 1.9539925233402755e-14, + 2.9791447087035294e-13, + 6.502853810985698e-13, + 2.7000623958883807e-13, + ], + atol=7.0e-13) + # 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.jl with FluxRotated(flux_lax_friedrichs)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_free_stream.jl"), - surface_flux=FluxRotated(flux_lax_friedrichs), - l2 = [2.063350241405049e-15, 1.8571016296925367e-14, 3.1769447886391905e-14, 1.4104095258528071e-14], - linf = [1.9539925233402755e-14, 2.9791447087035294e-13, 6.502853810985698e-13, 2.7000623958883807e-13], - atol = 7.0e-13) - # 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_source_terms_nonperiodic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonperiodic.jl"), - l2 = [2.259440511901724e-6, 2.3188881559075347e-6, 2.3188881559568146e-6, 6.332786324137878e-6], - linf = [1.4987382622067003e-5, 1.918201192063762e-5, 1.918201192019353e-5, 6.052671713430158e-5]) - # 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_ec.jl" begin + surface_flux=FluxRotated(flux_lax_friedrichs), + l2=[ + 2.063350241405049e-15, + 1.8571016296925367e-14, + 3.1769447886391905e-14, + 1.4104095258528071e-14, + ], + linf=[ + 1.9539925233402755e-14, + 2.9791447087035294e-13, + 6.502853810985698e-13, + 2.7000623958883807e-13, + ], + atol=7.0e-13) + # 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_source_terms_nonperiodic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonperiodic.jl"), + l2=[ + 2.259440511901724e-6, + 2.3188881559075347e-6, + 2.3188881559568146e-6, + 6.332786324137878e-6, + ], + linf=[ + 1.4987382622067003e-5, + 1.918201192063762e-5, + 1.918201192019353e-5, + 6.052671713430158e-5, + ]) + # 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_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.03774907669925568, 0.02845190575242045, 0.028262802829412605, 0.13785915638851698], - linf = [0.3368296929764073, 0.27644083771519773, 0.27990039685141377, 1.1971436487402016], - tspan = (0.0, 0.3)) - # 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 + l2=[ + 0.03774907669925568, + 0.02845190575242045, + 0.028262802829412605, + 0.13785915638851698, + ], + linf=[ + 0.3368296929764073, + 0.27644083771519773, + 0.27990039685141377, + 1.1971436487402016, + ], + tspan=(0.0, 0.3)) + # 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 = [3.69856202e-01, 2.35242180e-01, 2.41444928e-01, 1.28807120e+00], - linf = [1.82786223e+00, 1.30452904e+00, 1.40347257e+00, 6.21791658e+00], - tspan = (0.0, 0.3)) - # 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_rayleigh_taylor_instability.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_rayleigh_taylor_instability.jl"), - l2 = [0.06365630381017849, 0.007166887387738937, 0.002878708825497772, 0.010247678114070121], - linf = [0.4799214336153155, 0.024595483032220266, 0.02059808120543466, 0.03190756362943725], - cells_per_dimension = (8,8), - tspan = (0.0, 0.3)) - # 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_eulerpolytropic_convergence.jl" begin + l2=[ + 3.69856202e-01, + 2.35242180e-01, + 2.41444928e-01, + 1.28807120e+00, + ], + linf=[ + 1.82786223e+00, + 1.30452904e+00, + 1.40347257e+00, + 6.21791658e+00, + ], + tspan=(0.0, 0.3)) + # 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_rayleigh_taylor_instability.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_rayleigh_taylor_instability.jl"), + l2=[ + 0.06365630381017849, + 0.007166887387738937, + 0.002878708825497772, + 0.010247678114070121, + ], + linf=[ + 0.4799214336153155, + 0.024595483032220266, + 0.02059808120543466, + 0.03190756362943725, + ], + cells_per_dimension=(8, 8), + tspan=(0.0, 0.3)) + # 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_eulerpolytropic_convergence.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulerpolytropic_convergence.jl"), - l2 = [0.0016688820596537988, 0.0025921681885685425, 0.003280950351435014], - linf = [0.010994679664394269, 0.01331197845637, 0.020080117011346488]) - # 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_eulerpolytropic_ec.jl" begin + l2=[ + 0.0016688820596537988, + 0.0025921681885685425, + 0.003280950351435014, + ], + linf=[ + 0.010994679664394269, + 0.01331197845637, + 0.020080117011346488, + ]) + # 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_eulerpolytropic_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulerpolytropic_ec.jl"), - l2 = [0.03647890611450939, 0.025284915444045052, 0.025340697771609126], - linf = [0.32516731565355583, 0.37509762516540046, 0.29812843284727336]) - # 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_eulerpolytropic_isothermal_wave.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulerpolytropic_isothermal_wave.jl"), - l2 = [0.004998778491726366, 0.004998916000294425, 9.259136963058664e-17], - linf = [0.010001103673834888, 0.010051165098399503, 7.623942913643681e-16]) - # 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_eulerpolytropic_wave.jl" begin + l2=[ + 0.03647890611450939, + 0.025284915444045052, + 0.025340697771609126, + ], + linf=[ + 0.32516731565355583, + 0.37509762516540046, + 0.29812843284727336, + ]) + # 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_eulerpolytropic_isothermal_wave.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_eulerpolytropic_isothermal_wave.jl"), + l2=[ + 0.004998778491726366, + 0.004998916000294425, + 9.259136963058664e-17, + ], + linf=[ + 0.010001103673834888, + 0.010051165098399503, + 7.623942913643681e-16, + ]) + # 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_eulerpolytropic_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulerpolytropic_wave.jl"), - l2 = [0.23642682112204072, 0.20904264390331334, 8.174982691297391e-17], - linf = [0.4848250368349989, 0.253350873815695, 4.984552457753618e-16]) - # 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_hypdiff_nonperiodic.jl" begin + l2=[ + 0.23642682112204072, + 0.20904264390331334, + 8.174982691297391e-17, + ], + linf=[ + 0.4848250368349989, + 0.253350873815695, + 4.984552457753618e-16, + ]) + # 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_hypdiff_nonperiodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_nonperiodic.jl"), - l2 = [0.8799744480157664, 0.8535008397034816, 0.7851383019164209], - linf = [1.0771947577311836, 1.9143913544309838, 2.149549109115789], - tspan = (0.0, 0.1), - coverage_override = (polydeg=3,)) # Prevent long compile time in CI - # 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)) < 15000 - end - end - - @trixi_testset "elixir_hypdiff_harmonic_nonperiodic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_harmonic_nonperiodic.jl"), - l2 = [0.19357947606509474, 0.47041398037626814, 0.4704139803762686], - linf = [0.35026352556630114, 0.8344372248051408, 0.8344372248051408], - tspan = (0.0, 0.1), - coverage_override = (polydeg=3,)) # Prevent long compile time in CI - # 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_mhd_ec.jl" begin + l2=[0.8799744480157664, 0.8535008397034816, 0.7851383019164209], + linf=[1.0771947577311836, 1.9143913544309838, 2.149549109115789], + tspan=(0.0, 0.1), + coverage_override=(polydeg = 3,)) # Prevent long compile time in CI + # 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)) < 15000 + end +end + +@trixi_testset "elixir_hypdiff_harmonic_nonperiodic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_hypdiff_harmonic_nonperiodic.jl"), + l2=[ + 0.19357947606509474, + 0.47041398037626814, + 0.4704139803762686, + ], + linf=[ + 0.35026352556630114, + 0.8344372248051408, + 0.8344372248051408, + ], + tspan=(0.0, 0.1), + coverage_override=(polydeg = 3,)) # Prevent long compile time in CI + # 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_mhd_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ec.jl"), - l2 = [0.04937480811868297, 0.06117033019988596, 0.060998028674664716, 0.03155145889799417, - 0.2319175391388658, 0.02476283192966346, 0.024483244374818587, 0.035439957899127385, - 0.0016022148194667542], - linf = [0.24749024430983746, 0.2990608279625713, 0.3966937932860247, 0.22265033744519683, - 0.9757376320946505, 0.12123736788315098, 0.12837436699267113, 0.17793825293524734, - 0.03460761690059514], - tspan = (0.0, 0.3)) - # 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_mhd_alfven_wave.jl" begin + l2=[0.04937480811868297, 0.06117033019988596, + 0.060998028674664716, 0.03155145889799417, + 0.2319175391388658, 0.02476283192966346, + 0.024483244374818587, 0.035439957899127385, + 0.0016022148194667542], + linf=[0.24749024430983746, 0.2990608279625713, + 0.3966937932860247, 0.22265033744519683, + 0.9757376320946505, 0.12123736788315098, + 0.12837436699267113, 0.17793825293524734, + 0.03460761690059514], + tspan=(0.0, 0.3)) + # 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_mhd_alfven_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), - l2 = [0.02890769490562535, 0.0062599448721613205, 0.005650300017676721, 0.007334415940022972, - 0.00490446035599909, 0.007202284100220619, 0.007003258686714405, 0.006734267830082687, - 0.004253003868791559], - linf = [0.17517380432288565, 0.06197353710696667, 0.038494840938641646, 0.05293345499813148, - 0.03817506476831778, 0.042847170999492534, 0.03761563456810613, 0.048184237474911844, - 0.04114666955364693], - tspan = (0.0, 1.0)) - # 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_source_terms.jl" begin + l2=[0.02890769490562535, 0.0062599448721613205, + 0.005650300017676721, 0.007334415940022972, + 0.00490446035599909, 0.007202284100220619, + 0.007003258686714405, 0.006734267830082687, + 0.004253003868791559], + linf=[0.17517380432288565, 0.06197353710696667, + 0.038494840938641646, 0.05293345499813148, + 0.03817506476831778, 0.042847170999492534, + 0.03761563456810613, 0.048184237474911844, + 0.04114666955364693], + tspan=(0.0, 1.0)) + # 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_source_terms.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), - l2 = [0.0017285599436729316, 0.025584610912606776, 0.028373834961180594, 6.274146767730866e-5], - linf = [0.012972309788264802, 0.108283714215621, 0.15831585777928936, 0.00018196759554722775], - tspan = (0.0, 0.05)) - # 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 + l2=[ + 0.0017285599436729316, + 0.025584610912606776, + 0.028373834961180594, + 6.274146767730866e-5, + ], + linf=[ + 0.012972309788264802, + 0.108283714215621, + 0.15831585777928936, + 0.00018196759554722775, + ], + tspan=(0.0, 0.05)) + # 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 = [0.7920927046419308, 9.92129670988898e-15, 1.0118635033124588e-14, 0.7920927046419308], - linf = [2.408429868800133, 5.5835419986809516e-14, 5.448874313931364e-14, 2.4084298688001335], - tspan = (0.0, 0.25)) - # 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_wet_dry.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced_wet_dry.jl"), - l2 = [0.019731646454942086, 1.0694532773278277e-14, 1.1969913383405568e-14, 0.0771517260037954], - linf = [0.4999999999998892, 6.067153702623552e-14, 4.4849667259339357e-14, 1.9999999999999993], - tspan = (0.0, 0.25)) - # 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_conical_island.jl" begin + l2=[ + 0.7920927046419308, + 9.92129670988898e-15, + 1.0118635033124588e-14, + 0.7920927046419308, + ], + linf=[ + 2.408429868800133, + 5.5835419986809516e-14, + 5.448874313931364e-14, + 2.4084298688001335, + ], + tspan=(0.0, 0.25)) + # 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_wet_dry.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_well_balanced_wet_dry.jl"), + l2=[ + 0.019731646454942086, + 1.0694532773278277e-14, + 1.1969913383405568e-14, + 0.0771517260037954, + ], + linf=[ + 0.4999999999998892, + 6.067153702623552e-14, + 4.4849667259339357e-14, + 1.9999999999999993, + ], + tspan=(0.0, 0.25)) + # 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_conical_island.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_conical_island.jl"), - l2 = [0.04593154164306353, 0.1644534881916908, 0.16445348819169076, 0.0011537702354532122], - linf = [0.21100717610846442, 0.9501592344310412, 0.950159234431041, 0.021790250683516296], - tspan = (0.0, 0.025)) - # 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_parabolic_bowl.jl" begin + l2=[ + 0.04593154164306353, + 0.1644534881916908, + 0.16445348819169076, + 0.0011537702354532122, + ], + linf=[ + 0.21100717610846442, + 0.9501592344310412, + 0.950159234431041, + 0.021790250683516296, + ], + tspan=(0.0, 0.025)) + # 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_parabolic_bowl.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_parabolic_bowl.jl"), - l2 = [0.00015285369980313484, 1.9536806395943226e-5, 9.936906607758672e-5, 5.0686313334616055e-15], - linf = [0.003316119030459211, 0.0005075409427972817, 0.001986721761060583, 4.701794509287538e-14], - tspan = (0.0, 0.025), cells_per_dimension = (40, 40)) - # 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_mhd_ec_shockcapturing.jl" begin + l2=[ + 0.00015285369980313484, + 1.9536806395943226e-5, + 9.936906607758672e-5, + 5.0686313334616055e-15, + ], + linf=[ + 0.003316119030459211, + 0.0005075409427972817, + 0.001986721761060583, + 4.701794509287538e-14, + ], + tspan=(0.0, 0.025), cells_per_dimension=(40, 40)) + # 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_mhd_ec_shockcapturing.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ec_shockcapturing.jl"), - l2 = [0.0364192725149364, 0.0426667193422069, 0.04261673001449095, 0.025884071405646924, - 0.16181626564020496, 0.017346518770783536, 0.017291573200291104, 0.026856206495339655, - 0.0007443858043598808], - linf = [0.25144373906033013, 0.32881947152723745, 0.3053266801502693, 0.20989755319972866, - 0.9927517314507455, 0.1105172121361323, 0.1257708104676617, 0.1628334844841588, - 0.02624301627479052]) - # 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 + l2=[0.0364192725149364, 0.0426667193422069, 0.04261673001449095, + 0.025884071405646924, + 0.16181626564020496, 0.017346518770783536, + 0.017291573200291104, 0.026856206495339655, + 0.0007443858043598808], + linf=[0.25144373906033013, 0.32881947152723745, + 0.3053266801502693, 0.20989755319972866, + 0.9927517314507455, 0.1105172121361323, 0.1257708104676617, + 0.1628334844841588, + 0.02624301627479052]) + # 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 -@test_nowarn rm(outdir, recursive=true) +@test_nowarn rm(outdir, recursive = true) end # module diff --git a/test/test_structured_3d.jl b/test/test_structured_3d.jl index 07910e1119b..0213e1a9813 100644 --- a/test/test_structured_3d.jl +++ b/test/test_structured_3d.jl @@ -9,240 +9,331 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "structured_3d_dgsem") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) @testset "Structured mesh" begin - @trixi_testset "elixir_advection_basic.jl" begin +#! format: noindent + +@trixi_testset "elixir_advection_basic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), - # Expected errors are exactly the same as with TreeMesh! - l2 = [0.00016263963870641478], - linf = [0.0014537194925779984]) - # 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_free_stream.jl" begin + # Expected errors are exactly the same as with TreeMesh! + l2=[0.00016263963870641478], + linf=[0.0014537194925779984]) + # 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_free_stream.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_free_stream.jl"), - l2 = [1.2908196366970896e-14], - linf = [1.0262901639634947e-12], - atol = 8e-13, # required to make tests pass on Windows - ) - # 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_nonperiodic_curved.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_nonperiodic_curved.jl"), - l2 = [0.0004483892474201268], - linf = [0.009201820593762955]) - # 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_restart.jl" begin + l2=[1.2908196366970896e-14], + linf=[1.0262901639634947e-12], + atol=8e-13,) + # 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_nonperiodic_curved.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_nonperiodic_curved.jl"), + l2=[0.0004483892474201268], + linf=[0.009201820593762955]) + # 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_restart.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), - l2 = [0.0025903889347585777], - linf = [0.018407576968841655]) - # 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_source_terms.jl" begin + l2=[0.0025903889347585777], + linf=[0.018407576968841655]) + # 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_source_terms.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms.jl"), - # Expected errors are exactly the same as with TreeMesh! - l2 = [0.010385936842224346, 0.009776048833895767, 0.00977604883389591, 0.009776048833895733, 0.01506687097416608], - linf = [0.03285848350791731, 0.0321792316408982, 0.032179231640894645, 0.032179231640895534, 0.0655408023333299]) - # 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.jl" begin + # Expected errors are exactly the same as with TreeMesh! + l2=[ + 0.010385936842224346, + 0.009776048833895767, + 0.00977604883389591, + 0.009776048833895733, + 0.01506687097416608, + ], + linf=[ + 0.03285848350791731, + 0.0321792316408982, + 0.032179231640894645, + 0.032179231640895534, + 0.0655408023333299, + ]) + # 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.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_free_stream.jl"), - l2 = [2.8815700334367128e-15, 9.361915278236651e-15, 9.95614203619935e-15, 1.6809941842374106e-14, 1.4815037041566735e-14], - linf = [4.1300296516055823e-14, 2.0444756998472258e-13, 1.0133560657266116e-13, 2.0627943797535409e-13, 2.8954616482224083e-13]) - # 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.jl with FluxRotated(flux_lax_friedrichs)" begin + l2=[ + 2.8815700334367128e-15, + 9.361915278236651e-15, + 9.95614203619935e-15, + 1.6809941842374106e-14, + 1.4815037041566735e-14, + ], + linf=[ + 4.1300296516055823e-14, + 2.0444756998472258e-13, + 1.0133560657266116e-13, + 2.0627943797535409e-13, + 2.8954616482224083e-13, + ]) + # 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.jl with FluxRotated(flux_lax_friedrichs)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_free_stream.jl"), - surface_flux=FluxRotated(flux_lax_friedrichs), - l2 = [2.8815700334367128e-15, 9.361915278236651e-15, 9.95614203619935e-15, 1.6809941842374106e-14, 1.4815037041566735e-14], - linf = [4.1300296516055823e-14, 2.0444756998472258e-13, 1.0133560657266116e-13, 2.0627943797535409e-13, 2.8954616482224083e-13]) - # 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_source_terms_nonperiodic_curved.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonperiodic_curved.jl"), - l2 = [0.0032940531178824463, 0.003275679548217804, 0.0030020672748714084, 0.00324007343451744, 0.005721986362580164], - linf = [0.03156756290660656, 0.033597629023726316, 0.02095783702361409, 0.03353574465232212, 0.05873635745032857]) - # 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 + surface_flux=FluxRotated(flux_lax_friedrichs), + l2=[ + 2.8815700334367128e-15, + 9.361915278236651e-15, + 9.95614203619935e-15, + 1.6809941842374106e-14, + 1.4815037041566735e-14, + ], + linf=[ + 4.1300296516055823e-14, + 2.0444756998472258e-13, + 1.0133560657266116e-13, + 2.0627943797535409e-13, + 2.8954616482224083e-13, + ]) + # 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_source_terms_nonperiodic_curved.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonperiodic_curved.jl"), + l2=[ + 0.0032940531178824463, + 0.003275679548217804, + 0.0030020672748714084, + 0.00324007343451744, + 0.005721986362580164, + ], + linf=[ + 0.03156756290660656, + 0.033597629023726316, + 0.02095783702361409, + 0.03353574465232212, + 0.05873635745032857, + ]) + # 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 - @trixi_testset "elixir_euler_ec.jl" begin +@trixi_testset "elixir_euler_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.011367083018614027, 0.007022020327490176, 0.006759580335962235, 0.006820337637760632, 0.02912659127566544], - linf = [0.2761764220925329, 0.20286331858055706, 0.18763944865434593, 0.19313636558790004, 0.707563913727584], - tspan = (0.0, 0.25), - coverage_override = (polydeg=3,)) # Prevent long compile time in CI - # 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 + l2=[ + 0.011367083018614027, + 0.007022020327490176, + 0.006759580335962235, + 0.006820337637760632, + 0.02912659127566544, + ], + linf=[ + 0.2761764220925329, + 0.20286331858055706, + 0.18763944865434593, + 0.19313636558790004, + 0.707563913727584, + ], + tspan=(0.0, 0.25), + coverage_override=(polydeg = 3,)) # Prevent long compile time in CI + # 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 = [5.30310390e-02, 2.53167260e-02, 2.64276438e-02, 2.52195992e-02, 3.56830295e-01], - linf = [6.16356950e-01, 2.50600049e-01, 2.74796377e-01, 2.46448217e-01, 4.77888479e+00], - tspan = (0.0, 0.3)) - # 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_mhd_ec.jl" begin + l2=[ + 5.30310390e-02, + 2.53167260e-02, + 2.64276438e-02, + 2.52195992e-02, + 3.56830295e-01, + ], + linf=[ + 6.16356950e-01, + 2.50600049e-01, + 2.74796377e-01, + 2.46448217e-01, + 4.77888479e+00, + ], + tspan=(0.0, 0.3)) + # 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_mhd_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ec.jl"), - l2 = [0.009082353036644902, 0.007128360240528109, 0.006970330025996491, 0.006898850266874514, - 0.03302008823756457, 0.003203389099143526, 0.003077498677885352, 0.0030740006760477624, - 4.192129696970217e-5], - linf = [0.2883946030582689, 0.25956437344015054, 0.2614364943543665, 0.24617277938134657, - 1.1370443512475847, 0.1278041831463388, 0.13347391885068594, 0.1457563463643099, - 0.0021174246048172563], - tspan = (0.0, 0.25)) - # 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_mhd_alfven_wave.jl" begin + l2=[0.009082353036644902, 0.007128360240528109, + 0.006970330025996491, 0.006898850266874514, + 0.03302008823756457, 0.003203389099143526, + 0.003077498677885352, 0.0030740006760477624, + 4.192129696970217e-5], + linf=[0.2883946030582689, 0.25956437344015054, + 0.2614364943543665, 0.24617277938134657, + 1.1370443512475847, 0.1278041831463388, 0.13347391885068594, + 0.1457563463643099, + 0.0021174246048172563], + tspan=(0.0, 0.25)) + # 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_mhd_alfven_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), - l2 = [0.003015476175153681, 0.00145499403283373, 0.0009125744757935803, 0.0017703080480578979, - 0.0013046447673965966, 0.0014564863387645508, 0.0013332311430907598, 0.001647832598455728, - 0.0013647609788548722], - linf = [0.027510637768610846, 0.02797062834945721, 0.01274249949295704, 0.038940694415543736, - 0.02200825678588325, 0.03167600959583505, 0.021420957993862344, 0.03386589835999665, - 0.01888303191983353], - # Use same polydeg as everything else to prevent long compile times in CI - coverage_override = (polydeg=3,)) - # 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_mhd_alfven_wave.jl with flux_lax_friedrichs" begin + l2=[0.003015476175153681, 0.00145499403283373, + 0.0009125744757935803, 0.0017703080480578979, + 0.0013046447673965966, 0.0014564863387645508, + 0.0013332311430907598, 0.001647832598455728, + 0.0013647609788548722], + linf=[0.027510637768610846, 0.02797062834945721, + 0.01274249949295704, 0.038940694415543736, + 0.02200825678588325, 0.03167600959583505, + 0.021420957993862344, 0.03386589835999665, + 0.01888303191983353], + # Use same polydeg as everything else to prevent long compile times in CI + coverage_override=(polydeg = 3,)) + # 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_mhd_alfven_wave.jl with flux_lax_friedrichs" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), - l2 = [0.003047854479955232, 0.0014572199588782184, 0.0009093737183251411, 0.0017937548694553895, - 0.0013010437110755424, 0.0014545607744895874, 0.001328514015121245, 0.001671342529206066, - 0.0013653963058149186], - linf = [0.027719103797310463, 0.027570111789910784, 0.012561901006903103, 0.03903568568480584, - 0.021311996934554767, 0.03154849824135775, 0.020996033645485412, 0.03403185137382961, - 0.019488952445771597], - surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell), - # Use same polydeg as everything else to prevent long compile times in CI - coverage_override = (polydeg=3,)) - # 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_mhd_ec_shockcapturing.jl" begin + l2=[0.003047854479955232, 0.0014572199588782184, + 0.0009093737183251411, 0.0017937548694553895, + 0.0013010437110755424, 0.0014545607744895874, + 0.001328514015121245, 0.001671342529206066, + 0.0013653963058149186], + linf=[0.027719103797310463, 0.027570111789910784, + 0.012561901006903103, 0.03903568568480584, + 0.021311996934554767, 0.03154849824135775, + 0.020996033645485412, 0.03403185137382961, + 0.019488952445771597], + surface_flux=(flux_lax_friedrichs, flux_nonconservative_powell), + # Use same polydeg as everything else to prevent long compile times in CI + coverage_override=(polydeg = 3,)) + # 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_mhd_ec_shockcapturing.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ec_shockcapturing.jl"), - l2 = [0.009352631220872144, 0.008058649103542618, 0.008027041293333663, 0.008071417851552725, - 0.034909149665869485, 0.00393019428600812, 0.0039219074393817, 0.003906321245184237, - 4.197255300781248e-5], - linf = [0.30749098250807516, 0.2679008863509767, 0.271243087484388, 0.26545396569129537, - 0.9620950892188596, 0.18163281157498123, 0.15995708312378454, 0.17918221526906408, - 0.015138346608166353], - tspan = (0.0, 0.25), - # Use same polydeg as everything else to prevent long compile times in CI - coverage_override = (polydeg=3,)) - # 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 + l2=[0.009352631220872144, 0.008058649103542618, + 0.008027041293333663, 0.008071417851552725, + 0.034909149665869485, 0.00393019428600812, + 0.0039219074393817, 0.003906321245184237, + 4.197255300781248e-5], + linf=[0.30749098250807516, 0.2679008863509767, + 0.271243087484388, 0.26545396569129537, + 0.9620950892188596, 0.18163281157498123, + 0.15995708312378454, 0.17918221526906408, + 0.015138346608166353], + tspan=(0.0, 0.25), + # Use same polydeg as everything else to prevent long compile times in CI + coverage_override=(polydeg = 3,)) + # 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 -@test_nowarn rm(outdir, recursive=true) +@test_nowarn rm(outdir, recursive = true) end # module diff --git a/test/test_t8code_2d.jl b/test/test_t8code_2d.jl index 660d7bc0a1d..b3e19471323 100644 --- a/test/test_t8code_2d.jl +++ b/test/test_t8code_2d.jl @@ -13,263 +13,264 @@ isdir(outdir) && rm(outdir, recursive = true) mkdir(outdir) @testset "T8codeMesh2D" begin +#! format: noindent - @trixi_testset "test save_mesh_file" begin - @test_throws Exception begin +@trixi_testset "test save_mesh_file" begin + @test_throws Exception begin # Save mesh file support will be added in the future. The following # lines of code are here for satisfying code coverage. # Create dummy mesh. mesh = T8codeMesh((1, 1), polydeg = 1, - mapping = Trixi.coordinates2mapping((-1.0, -1.0), ( 1.0, 1.0)), + mapping = Trixi.coordinates2mapping((-1.0, -1.0), (1.0, 1.0)), initial_refinement_level = 1) # This call throws an error. Trixi.save_mesh_file(mesh, "dummy") - end end +end - @trixi_testset "elixir_advection_basic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), - # Expected errors are exactly the same as with TreeMesh! - l2=[8.311947673061856e-6], - linf=[6.627000273229378e-5]) - # 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_basic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), + # Expected errors are exactly the same as with TreeMesh! + l2=[8.311947673061856e-6], + linf=[6.627000273229378e-5]) + # 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_nonconforming_flag.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_advection_nonconforming_flag.jl"), - l2=[3.198940059144588e-5], - linf=[0.00030636069494005547]) - # 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_nonconforming_flag.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_nonconforming_flag.jl"), + l2=[3.198940059144588e-5], + linf=[0.00030636069494005547]) + # 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_unstructured_flag.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_unstructured_flag.jl"), - l2=[0.0005379687442422346], - linf=[0.007438525029884735]) - # 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_unstructured_flag.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_unstructured_flag.jl"), + l2=[0.0005379687442422346], + linf=[0.007438525029884735]) + # 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_amr_unstructured_flag.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_advection_amr_unstructured_flag.jl"), - l2=[0.001993165013217687], - linf=[0.032891018571625796], - 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 - 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], + 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 +end - @trixi_testset "elixir_advection_amr_solution_independent.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_advection_amr_solution_independent.jl"), - # Expected errors are exactly the same as with StructuredMesh! - l2=[4.949660644033807e-5], - linf=[0.0004867846262313763], - 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 - end +@trixi_testset "elixir_advection_amr_solution_independent.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_amr_solution_independent.jl"), + # Expected errors are exactly the same as with StructuredMesh! + l2=[4.949660644033807e-5], + linf=[0.0004867846262313763], + 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 +end - @trixi_testset "elixir_euler_source_terms_nonconforming_unstructured_flag.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), - l2=[ - 0.0034516244508588046, - 0.0023420334036925493, - 0.0024261923964557187, - 0.004731710454271893, - ], - linf=[ - 0.04155789011775046, - 0.024772109862748914, - 0.03759938693042297, - 0.08039824959535657, - ]) - # 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_source_terms_nonconforming_unstructured_flag.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), + l2=[ + 0.0034516244508588046, + 0.0023420334036925493, + 0.0024261923964557187, + 0.004731710454271893, + ], + linf=[ + 0.04155789011775046, + 0.024772109862748914, + 0.03759938693042297, + 0.08039824959535657, + ]) + # 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.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_free_stream.jl"), - l2=[ - 2.063350241405049e-15, - 1.8571016296925367e-14, - 3.1769447886391905e-14, - 1.4104095258528071e-14, - ], - linf=[1.9539925233402755e-14, 2e-12, 4.8e-12, 4e-12], - atol=2.0e-12,) - # 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.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_free_stream.jl"), + l2=[ + 2.063350241405049e-15, + 1.8571016296925367e-14, + 3.1769447886391905e-14, + 1.4104095258528071e-14, + ], + linf=[1.9539925233402755e-14, 2e-12, 4.8e-12, 4e-12], + atol=2.0e-12,) + # 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_shockcapturing_ec.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing_ec.jl"), - l2=[ - 9.53984675e-02, - 1.05633455e-01, - 1.05636158e-01, - 3.50747237e-01, - ], - linf=[ - 2.94357464e-01, - 4.07893014e-01, - 3.97334516e-01, - 1.08142520e+00, - ], - tspan=(0.0, 1.0)) - # 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_shockcapturing_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing_ec.jl"), + l2=[ + 9.53984675e-02, + 1.05633455e-01, + 1.05636158e-01, + 3.50747237e-01, + ], + linf=[ + 2.94357464e-01, + 4.07893014e-01, + 3.97334516e-01, + 1.08142520e+00, + ], + tspan=(0.0, 1.0)) + # 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=[ - 3.76149952e-01, - 2.46970327e-01, - 2.46970327e-01, - 1.28889042e+00, - ], - linf=[ - 1.22139001e+00, - 1.17742626e+00, - 1.17742626e+00, - 6.20638482e+00, - ], - tspan=(0.0, 0.3)) - # 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=[ + 3.76149952e-01, + 2.46970327e-01, + 2.46970327e-01, + 1.28889042e+00, + ], + linf=[ + 1.22139001e+00, + 1.17742626e+00, + 1.17742626e+00, + 6.20638482e+00, + ], + tspan=(0.0, 0.3)) + # 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_source_terms.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), - l2=[ - 9.168126407325352e-5, - 0.0009795410115453788, - 0.002546408320320785, - 3.941189812642317e-6, - ], - linf=[ - 0.0009903782521019089, - 0.0059752684687262025, - 0.010941106525454103, - 1.2129488214718265e-5, - ], - tspan=(0.0, 0.1)) - # 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_source_terms.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), + l2=[ + 9.168126407325352e-5, + 0.0009795410115453788, + 0.002546408320320785, + 3.941189812642317e-6, + ], + linf=[ + 0.0009903782521019089, + 0.0059752684687262025, + 0.010941106525454103, + 1.2129488214718265e-5, + ], + tspan=(0.0, 0.1)) + # 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_mhd_alfven_wave.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), - l2=[1.0513414461545583e-5, 1.0517900957166411e-6, - 1.0517900957304043e-6, 1.511816606372376e-6, - 1.0443997728645063e-6, 7.879639064990798e-7, - 7.879639065049896e-7, 1.0628631669056271e-6, - 4.3382328912336153e-7], - linf=[4.255466285174592e-5, 1.0029706745823264e-5, - 1.0029706747467781e-5, 1.2122265939010224e-5, - 5.4791097160444835e-6, 5.18922042269665e-6, - 5.189220422141538e-6, 9.552667261422676e-6, - 1.4237578427628152e-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 - end +@trixi_testset "elixir_mhd_alfven_wave.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), + l2=[1.0513414461545583e-5, 1.0517900957166411e-6, + 1.0517900957304043e-6, 1.511816606372376e-6, + 1.0443997728645063e-6, 7.879639064990798e-7, + 7.879639065049896e-7, 1.0628631669056271e-6, + 4.3382328912336153e-7], + linf=[4.255466285174592e-5, 1.0029706745823264e-5, + 1.0029706747467781e-5, 1.2122265939010224e-5, + 5.4791097160444835e-6, 5.18922042269665e-6, + 5.189220422141538e-6, 9.552667261422676e-6, + 1.4237578427628152e-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 +end - @trixi_testset "elixir_mhd_rotor.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_rotor.jl"), - l2=[0.44211360369891683, 0.8805178316216257, 0.8262710688468049, - 0.0, - 0.9616090460973586, 0.10386643568745411, - 0.15403457366543802, 0.0, - 2.8399715649715473e-5], - linf=[10.04369305341599, 17.995640564998403, 9.576041548174265, - 0.0, - 19.429658884314534, 1.3821395681242314, 1.818559351543182, - 0.0, - 0.002261930217575465], - tspan=(0.0, 0.02)) - # 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_mhd_rotor.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_rotor.jl"), + l2=[0.44211360369891683, 0.8805178316216257, 0.8262710688468049, + 0.0, + 0.9616090460973586, 0.10386643568745411, + 0.15403457366543802, 0.0, + 2.8399715649715473e-5], + linf=[10.04369305341599, 17.995640564998403, 9.576041548174265, + 0.0, + 19.429658884314534, 1.3821395681242314, 1.818559351543182, + 0.0, + 0.002261930217575465], + tspan=(0.0, 0.02)) + # 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 diff --git a/test/test_threaded.jl b/test/test_threaded.jl index b13b5d0f5fc..478c90b476a 100644 --- a/test/test_threaded.jl +++ b/test/test_threaded.jl @@ -7,334 +7,466 @@ include("test_trixi.jl") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive=true) +Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive = true) @testset "Threaded tests" begin - @testset "TreeMesh" begin +#! format: noindent + +@testset "TreeMesh" begin @trixi_testset "elixir_advection_restart.jl" begin - elixir = joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_extended.jl") - Trixi.mpi_isroot() && println("═"^100) - Trixi.mpi_isroot() && println(elixir) - trixi_include(@__MODULE__, elixir, tspan = (0.0, 10.0)) - l2_expected, linf_expected = analysis_callback(sol) - - elixir = joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_restart.jl") - Trixi.mpi_isroot() && println("═"^100) - Trixi.mpi_isroot() && println(elixir) - # Errors are exactly the same as in the elixir_advection_extended.jl - trixi_include(@__MODULE__, elixir) - l2_actual, linf_actual = analysis_callback(sol) - - Trixi.mpi_isroot() && @test l2_actual == l2_expected - Trixi.mpi_isroot() && @test linf_actual == linf_expected - - # 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)) < 5000 - end + elixir = joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_advection_extended.jl") + Trixi.mpi_isroot() && println("═"^100) + Trixi.mpi_isroot() && println(elixir) + trixi_include(@__MODULE__, elixir, tspan = (0.0, 10.0)) + l2_expected, linf_expected = analysis_callback(sol) + + elixir = joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_advection_restart.jl") + Trixi.mpi_isroot() && println("═"^100) + Trixi.mpi_isroot() && println(elixir) + # Errors are exactly the same as in the elixir_advection_extended.jl + trixi_include(@__MODULE__, elixir) + l2_actual, linf_actual = analysis_callback(sol) + + Trixi.mpi_isroot() && @test l2_actual == l2_expected + Trixi.mpi_isroot() && @test linf_actual == linf_expected + + # 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)) < 5000 + end end @trixi_testset "elixir_advection_restart.jl with threaded time integration" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_restart.jl"), - alg = CarpenterKennedy2N54(williamson_condition = false, thread = OrdinaryDiffEq.True()), - # Expected errors are exactly the same as in the serial test! - l2 = [8.005068880114254e-6], - linf = [6.39093577996519e-5]) + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_advection_restart.jl"), + alg=CarpenterKennedy2N54(williamson_condition = false, + thread = OrdinaryDiffEq.True()), + # Expected errors are exactly the same as in the serial test! + l2=[8.005068880114254e-6], + linf=[6.39093577996519e-5]) end @trixi_testset "elixir_advection_amr_refine_twice.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_amr_refine_twice.jl"), - l2 = [0.00020547512522578292], - linf = [0.007831753383083506]) + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_advection_amr_refine_twice.jl"), + l2=[0.00020547512522578292], + linf=[0.007831753383083506]) # 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)) < 5000 + t = sol.t[end] + u_ode = sol.u[end] + du_ode = similar(u_ode) + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 5000 end end @trixi_testset "elixir_advection_amr_coarsen_twice.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_amr_coarsen_twice.jl"), - l2 = [0.0014321062757891826], - linf = [0.0253454486893413]) + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_advection_amr_coarsen_twice.jl"), + l2=[0.0014321062757891826], + linf=[0.0253454486893413]) # 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)) < 5000 + t = sol.t[end] + u_ode = sol.u[end] + du_ode = similar(u_ode) + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 5000 end end @trixi_testset "elixir_euler_source_terms_nonperiodic.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_euler_source_terms_nonperiodic.jl"), - l2 = [2.259440511766445e-6, 2.318888155713922e-6, 2.3188881557894307e-6, 6.3327863238858925e-6], - linf = [1.498738264560373e-5, 1.9182011928187137e-5, 1.918201192685487e-5, 6.0526717141407005e-5], - rtol = 0.001) + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_euler_source_terms_nonperiodic.jl"), + l2=[ + 2.259440511766445e-6, + 2.318888155713922e-6, + 2.3188881557894307e-6, + 6.3327863238858925e-6, + ], + linf=[ + 1.498738264560373e-5, + 1.9182011928187137e-5, + 1.918201192685487e-5, + 6.0526717141407005e-5, + ], + rtol=0.001) # 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)) < 5000 + t = sol.t[end] + u_ode = sol.u[end] + du_ode = similar(u_ode) + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 5000 end end @trixi_testset "elixir_euler_ec.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_euler_ec.jl"), - l2 = [0.061751715597716854, 0.05018223615408711, 0.05018989446443463, 0.225871559730513], - linf = [0.29347582879608825, 0.31081249232844693, 0.3107380389947736, 1.0540358049885143]) + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_euler_ec.jl"), + l2=[ + 0.061751715597716854, + 0.05018223615408711, + 0.05018989446443463, + 0.225871559730513, + ], + linf=[ + 0.29347582879608825, + 0.31081249232844693, + 0.3107380389947736, + 1.0540358049885143, + ]) # 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)) < 5000 + t = sol.t[end] + u_ode = sol.u[end] + du_ode = similar(u_ode) + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 5000 end end @trixi_testset "elixir_advection_diffusion.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_diffusion.jl"), - initial_refinement_level = 2, tspan = (0.0, 0.4), polydeg = 5, - alg = RDPK3SpFSAL49(thread = OrdinaryDiffEq.True()), - l2 = [4.0915532997994255e-6], - linf = [2.3040850347877395e-5] - ) - - # 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)) < 5000 - end + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_advection_diffusion.jl"), + initial_refinement_level=2, tspan=(0.0, 0.4), polydeg=5, + alg=RDPK3SpFSAL49(thread = OrdinaryDiffEq.True()), + l2=[4.0915532997994255e-6], + linf=[2.3040850347877395e-5]) + + # 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)) < 5000 + end end @trixi_testset "FDSBP, elixir_advection_extended.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_fdsbp", "elixir_advection_extended.jl"), - l2 = [2.898644263922225e-6], - linf = [8.491517930142578e-6], - rtol = 1.0e-7) # These results change a little bit and depend on the CI system - - # 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)) < 5000 - end + @test_trixi_include(joinpath(examples_dir(), "tree_2d_fdsbp", + "elixir_advection_extended.jl"), + l2=[2.898644263922225e-6], + linf=[8.491517930142578e-6], + rtol=1.0e-7) # These results change a little bit and depend on the CI system + + # 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)) < 5000 + end end @trixi_testset "FDSBP, elixir_euler_convergence.jl" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_fdsbp", "elixir_euler_convergence.jl"), - l2 = [1.7088389997042244e-6, 1.7437997855125774e-6, 1.7437997855350776e-6, 5.457223460127621e-6], - linf = [9.796504903736292e-6, 9.614745892783105e-6, 9.614745892783105e-6, 4.026107182575345e-5], - tspan = (0.0, 0.1)) - - # 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)) < 5000 - end - end - end + @test_trixi_include(joinpath(examples_dir(), "tree_2d_fdsbp", + "elixir_euler_convergence.jl"), + l2=[ + 1.7088389997042244e-6, + 1.7437997855125774e-6, + 1.7437997855350776e-6, + 5.457223460127621e-6, + ], + linf=[ + 9.796504903736292e-6, + 9.614745892783105e-6, + 9.614745892783105e-6, + 4.026107182575345e-5, + ], + tspan=(0.0, 0.1)) + # 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)) < 5000 + end + end +end - @testset "StructuredMesh" begin +@testset "StructuredMesh" begin @trixi_testset "elixir_advection_restart.jl with waving flag mesh" begin - @test_trixi_include(joinpath(examples_dir(), "structured_2d_dgsem", "elixir_advection_restart.jl"), - l2 = [0.00016265538265929818], - linf = [0.0015194252169410394], - rtol = 5.0e-5, # Higher tolerance to make tests pass in CI (in particular with macOS) - elixir_file="elixir_advection_waving_flag.jl", - restart_file="restart_000021.h5") + @test_trixi_include(joinpath(examples_dir(), "structured_2d_dgsem", + "elixir_advection_restart.jl"), + l2=[0.00016265538265929818], + linf=[0.0015194252169410394], + rtol=5.0e-5, # Higher tolerance to make tests pass in CI (in particular with macOS) + elixir_file="elixir_advection_waving_flag.jl", + restart_file="restart_000021.h5") # 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)) < 5000 + t = sol.t[end] + u_ode = sol.u[end] + du_ode = similar(u_ode) + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 5000 end end @trixi_testset "elixir_mhd_ec.jl" begin - @test_trixi_include(joinpath(examples_dir(), "structured_2d_dgsem", "elixir_mhd_ec.jl"), - l2 = [0.04937480811868297, 0.06117033019988596, 0.060998028674664716, 0.03155145889799417, - 0.2319175391388658, 0.02476283192966346, 0.024483244374818587, 0.035439957899127385, - 0.0016022148194667542], - linf = [0.24749024430983746, 0.2990608279625713, 0.3966937932860247, 0.22265033744519683, - 0.9757376320946505, 0.12123736788315098, 0.12837436699267113, 0.17793825293524734, - 0.03460761690059514], - tspan = (0.0, 0.3)) + @test_trixi_include(joinpath(examples_dir(), "structured_2d_dgsem", + "elixir_mhd_ec.jl"), + l2=[0.04937480811868297, 0.06117033019988596, + 0.060998028674664716, 0.03155145889799417, + 0.2319175391388658, 0.02476283192966346, + 0.024483244374818587, 0.035439957899127385, + 0.0016022148194667542], + linf=[0.24749024430983746, 0.2990608279625713, + 0.3966937932860247, 0.22265033744519683, + 0.9757376320946505, 0.12123736788315098, + 0.12837436699267113, 0.17793825293524734, + 0.03460761690059514], + tspan=(0.0, 0.3)) # 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)) < 5000 + t = sol.t[end] + u_ode = sol.u[end] + du_ode = similar(u_ode) + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 5000 end end - end - +end - @testset "UnstructuredMesh" begin +@testset "UnstructuredMesh" begin @trixi_testset "elixir_acoustics_gauss_wall.jl" begin - @test_trixi_include(joinpath(examples_dir(), "unstructured_2d_dgsem", "elixir_acoustics_gauss_wall.jl"), - l2 = [0.029330394861252995, 0.029345079728907965, 0.03803795043486467, 0.0, - 7.175152371650832e-16, 1.4350304743301665e-15, 1.4350304743301665e-15], - linf = [0.36236334472179443, 0.3690785638275256, 0.8475748723784078, 0.0, - 8.881784197001252e-16, 1.7763568394002505e-15, 1.7763568394002505e-15], - tspan = (0.0, 5.0)) + @test_trixi_include(joinpath(examples_dir(), "unstructured_2d_dgsem", + "elixir_acoustics_gauss_wall.jl"), + l2=[0.029330394861252995, 0.029345079728907965, + 0.03803795043486467, 0.0, + 7.175152371650832e-16, 1.4350304743301665e-15, + 1.4350304743301665e-15], + linf=[0.36236334472179443, 0.3690785638275256, + 0.8475748723784078, 0.0, + 8.881784197001252e-16, 1.7763568394002505e-15, + 1.7763568394002505e-15], + tspan=(0.0, 5.0)) # 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)) < 5000 + t = sol.t[end] + u_ode = sol.u[end] + du_ode = similar(u_ode) + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 5000 end end - end - +end - @testset "P4estMesh" begin +@testset "P4estMesh" begin @trixi_testset "elixir_euler_source_terms_nonconforming_unstructured_flag.jl" begin - @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), - l2 = [0.0034516244508588046, 0.0023420334036925493, 0.0024261923964557187, 0.004731710454271893], - linf = [0.04155789011775046, 0.024772109862748914, 0.03759938693042297, 0.08039824959535657]) + @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", + "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), + l2=[ + 0.0034516244508588046, + 0.0023420334036925493, + 0.0024261923964557187, + 0.004731710454271893, + ], + linf=[ + 0.04155789011775046, + 0.024772109862748914, + 0.03759938693042297, + 0.08039824959535657, + ]) # 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)) < 5000 + t = sol.t[end] + u_ode = sol.u[end] + du_ode = similar(u_ode) + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 5000 end end @trixi_testset "elixir_eulergravity_convergence.jl" begin - @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_eulergravity_convergence.jl"), - l2 = [0.00024871265138964204, 0.0003370077102132591, 0.0003370077102131964, 0.0007231525513793697], - linf = [0.0015813032944647087, 0.0020494288423820173, 0.0020494288423824614, 0.004793821195083758], - tspan = (0.0, 0.1)) + @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", + "elixir_eulergravity_convergence.jl"), + l2=[ + 0.00024871265138964204, + 0.0003370077102132591, + 0.0003370077102131964, + 0.0007231525513793697, + ], + linf=[ + 0.0015813032944647087, + 0.0020494288423820173, + 0.0020494288423824614, + 0.004793821195083758, + ], + tspan=(0.0, 0.1)) end - end - +end - @testset "T8codeMesh" begin +@testset "T8codeMesh" begin @trixi_testset "elixir_euler_source_terms_nonconforming_unstructured_flag.jl" begin - @test_trixi_include(joinpath(examples_dir(), "t8code_2d_dgsem", "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), - l2 = [0.0034516244508588046, 0.0023420334036925493, 0.0024261923964557187, 0.004731710454271893], - linf = [0.04155789011775046, 0.024772109862748914, 0.03759938693042297, 0.08039824959535657]) + @test_trixi_include(joinpath(examples_dir(), "t8code_2d_dgsem", + "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), + l2=[ + 0.0034516244508588046, + 0.0023420334036925493, + 0.0024261923964557187, + 0.004731710454271893, + ], + linf=[ + 0.04155789011775046, + 0.024772109862748914, + 0.03759938693042297, + 0.08039824959535657, + ]) end @trixi_testset "elixir_eulergravity_convergence.jl" begin - @test_trixi_include(joinpath(examples_dir(), "t8code_2d_dgsem", "elixir_eulergravity_convergence.jl"), - l2 = [0.00024871265138964204, 0.0003370077102132591, 0.0003370077102131964, 0.0007231525513793697], - linf = [0.0015813032944647087, 0.0020494288423820173, 0.0020494288423824614, 0.004793821195083758], - tspan = (0.0, 0.1)) + @test_trixi_include(joinpath(examples_dir(), "t8code_2d_dgsem", + "elixir_eulergravity_convergence.jl"), + l2=[ + 0.00024871265138964204, + 0.0003370077102132591, + 0.0003370077102131964, + 0.0007231525513793697, + ], + linf=[ + 0.0015813032944647087, + 0.0020494288423820173, + 0.0020494288423824614, + 0.004793821195083758, + ], + tspan=(0.0, 0.1)) end - end - +end - @testset "DGMulti" begin +@testset "DGMulti" begin @trixi_testset "elixir_euler_weakform.jl (SBP, EC)" begin - @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_euler_weakform.jl"), - cells_per_dimension = (4, 4), - volume_integral = VolumeIntegralFluxDifferencing(flux_ranocha), - surface_integral = SurfaceIntegralWeakForm(flux_ranocha), - approximation_type = SBP(), - l2 = [0.006400337855843578, 0.005303799804137764, 0.005303799804119745, 0.013204169007030144], - linf = [0.03798302318566282, 0.05321027922532284, 0.05321027922605448, 0.13392025411839015], - ) - - # 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)) < 5000 - end + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", + "elixir_euler_weakform.jl"), + cells_per_dimension=(4, 4), + volume_integral=VolumeIntegralFluxDifferencing(flux_ranocha), + surface_integral=SurfaceIntegralWeakForm(flux_ranocha), + approximation_type=SBP(), + l2=[ + 0.006400337855843578, + 0.005303799804137764, + 0.005303799804119745, + 0.013204169007030144, + ], + linf=[ + 0.03798302318566282, + 0.05321027922532284, + 0.05321027922605448, + 0.13392025411839015, + ],) + + # 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)) < 5000 + end end @trixi_testset "elixir_euler_curved.jl with threaded time integration" begin - @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_euler_curved.jl"), - alg = RDPK3SpFSAL49(thread = OrdinaryDiffEq.True()), - l2 = [1.720476068165337e-5, 1.592168205710526e-5, 1.592168205812963e-5, 4.894094865697305e-5], - linf = [0.00010525416930584619, 0.00010003778091061122, 0.00010003778085621029, 0.00036426282101720275] - ) - - # 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)) < 5000 - end + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", + "elixir_euler_curved.jl"), + alg=RDPK3SpFSAL49(thread = OrdinaryDiffEq.True()), + l2=[ + 1.720476068165337e-5, + 1.592168205710526e-5, + 1.592168205812963e-5, + 4.894094865697305e-5, + ], + linf=[ + 0.00010525416930584619, + 0.00010003778091061122, + 0.00010003778085621029, + 0.00036426282101720275, + ]) + + # 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)) < 5000 + end end @trixi_testset "elixir_euler_triangulate_pkg_mesh.jl" begin - @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_euler_triangulate_pkg_mesh.jl"), - l2 = [2.344080455438114e-6, 1.8610038753097983e-6, 2.4095165666095305e-6, 6.373308158814308e-6], - linf = [2.5099852761334418e-5, 2.2683684021362893e-5, 2.6180448559287584e-5, 5.5752932611508044e-5] - ) - - # 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)) < 5000 - end + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", + "elixir_euler_triangulate_pkg_mesh.jl"), + l2=[ + 2.344080455438114e-6, + 1.8610038753097983e-6, + 2.4095165666095305e-6, + 6.373308158814308e-6, + ], + linf=[ + 2.5099852761334418e-5, + 2.2683684021362893e-5, + 2.6180448559287584e-5, + 5.5752932611508044e-5, + ]) + + # 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)) < 5000 + end end @trixi_testset "elixir_euler_fdsbp_periodic.jl" begin - @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_euler_fdsbp_periodic.jl"), - l2 = [1.3333320340010056e-6, 2.044834627970641e-6, 2.044834627855601e-6, 5.282189803559564e-6], - linf = [2.7000151718858945e-6, 3.988595028259212e-6, 3.9885950273710336e-6, 8.848583042286862e-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)) < 5000 - end + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", + "elixir_euler_fdsbp_periodic.jl"), + l2=[ + 1.3333320340010056e-6, + 2.044834627970641e-6, + 2.044834627855601e-6, + 5.282189803559564e-6, + ], + linf=[ + 2.7000151718858945e-6, + 3.988595028259212e-6, + 3.9885950273710336e-6, + 8.848583042286862e-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)) < 5000 + end end - end +end end # Clean up afterwards: delete Trixi.jl output directory -Trixi.mpi_isroot() && isdir(outdir) && @test_nowarn rm(outdir, recursive=true) +Trixi.mpi_isroot() && isdir(outdir) && @test_nowarn rm(outdir, recursive = true) end # module diff --git a/test/test_tree_1d.jl b/test/test_tree_1d.jl index 7737a93a15a..4654f6313f7 100644 --- a/test/test_tree_1d.jl +++ b/test/test_tree_1d.jl @@ -9,275 +9,289 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) @testset "TreeMesh1D" begin +#! format: noindent # Run basic tests @testset "Examples 1D" begin - # Linear scalar advection - include("test_tree_1d_advection.jl") + # Linear scalar advection + include("test_tree_1d_advection.jl") - # Burgers - include("test_tree_1d_burgers.jl") + # Burgers + include("test_tree_1d_burgers.jl") - # Hyperbolic diffusion - include("test_tree_1d_hypdiff.jl") + # Hyperbolic diffusion + include("test_tree_1d_hypdiff.jl") - # Compressible Euler - include("test_tree_1d_euler.jl") + # Compressible Euler + include("test_tree_1d_euler.jl") - # Compressible Euler Multicomponent - include("test_tree_1d_eulermulti.jl") + # Compressible Euler Multicomponent + include("test_tree_1d_eulermulti.jl") - # MHD - include("test_tree_1d_mhd.jl") + # MHD + include("test_tree_1d_mhd.jl") - # MHD Multicomponent - include("test_tree_1d_mhdmulti.jl") + # MHD Multicomponent + include("test_tree_1d_mhdmulti.jl") - # Compressible Euler with self-gravity - include("test_tree_1d_eulergravity.jl") + # Compressible Euler with self-gravity + include("test_tree_1d_eulergravity.jl") - # Shallow water - include("test_tree_1d_shallowwater.jl") - # Two-layer Shallow Water - include("test_tree_1d_shallowwater_twolayer.jl") + # Shallow water + include("test_tree_1d_shallowwater.jl") + # Two-layer Shallow Water + include("test_tree_1d_shallowwater_twolayer.jl") - # FDSBP methods on the TreeMesh - include("test_tree_1d_fdsbp.jl") + # FDSBP methods on the TreeMesh + include("test_tree_1d_fdsbp.jl") end # Coverage test for all initial conditions @testset "Tests for initial conditions" begin - # Linear scalar advection - @trixi_testset "elixir_advection_extended.jl with initial_condition_sin" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2 = [0.00017373554109980247], - linf = [0.0006021275678165239], - maxiters = 1, - initial_condition = Trixi.initial_condition_sin) - end - - @trixi_testset "elixir_advection_extended.jl with initial_condition_constant" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2 = [2.441369287653687e-16], - linf = [4.440892098500626e-16], - maxiters = 1, - initial_condition = initial_condition_constant) - end - - @trixi_testset "elixir_advection_extended.jl with initial_condition_linear_x" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2 = [1.9882464973192864e-16], - linf = [1.4432899320127035e-15], - maxiters = 1, - initial_condition = Trixi.initial_condition_linear_x, - boundary_conditions = Trixi.boundary_condition_linear_x, - periodicity=false) - end - - @trixi_testset "elixir_advection_extended.jl with initial_condition_convergence_test" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2 = [6.1803596620800215e-6], - linf = [2.4858560899509996e-5], - maxiters = 1, - initial_condition = initial_condition_convergence_test, - boundary_conditions = BoundaryConditionDirichlet(initial_condition_convergence_test), - periodicity=false) - end -end + # Linear scalar advection + @trixi_testset "elixir_advection_extended.jl with initial_condition_sin" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), + l2=[0.00017373554109980247], + linf=[0.0006021275678165239], + maxiters=1, + initial_condition=Trixi.initial_condition_sin) + end + + @trixi_testset "elixir_advection_extended.jl with initial_condition_constant" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), + l2=[2.441369287653687e-16], + linf=[4.440892098500626e-16], + maxiters=1, + initial_condition=initial_condition_constant) + end + + @trixi_testset "elixir_advection_extended.jl with initial_condition_linear_x" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), + l2=[1.9882464973192864e-16], + linf=[1.4432899320127035e-15], + maxiters=1, + initial_condition=Trixi.initial_condition_linear_x, + boundary_conditions=Trixi.boundary_condition_linear_x, + periodicity=false) + end + @trixi_testset "elixir_advection_extended.jl with initial_condition_convergence_test" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), + l2=[6.1803596620800215e-6], + linf=[2.4858560899509996e-5], + maxiters=1, + initial_condition=initial_condition_convergence_test, + boundary_conditions=BoundaryConditionDirichlet(initial_condition_convergence_test), + periodicity=false) + end +end @testset "Displaying components 1D" begin - @test_nowarn include(joinpath(EXAMPLES_DIR, "elixir_advection_amr.jl")) - - # test both short and long printing formats - @test_nowarn show(mesh); println() - @test_nowarn println(mesh) - @test_nowarn display(mesh) - - @test_nowarn show(equations); println() - @test_nowarn println(equations) - @test_nowarn display(equations) - - @test_nowarn show(solver); println() - @test_nowarn println(solver) - @test_nowarn display(solver) - - @test_nowarn show(solver.basis); println() - @test_nowarn println(solver.basis) - @test_nowarn display(solver.basis) - - @test_nowarn show(solver.mortar); println() - @test_nowarn println(solver.mortar) - @test_nowarn display(solver.mortar) - - @test_nowarn show(solver.volume_integral); println() - @test_nowarn println(solver.volume_integral) - @test_nowarn display(solver.volume_integral) - - @test_nowarn show(semi); println() - @test_nowarn println(semi) - @test_nowarn display(semi) - - @test_nowarn show(summary_callback); println() - @test_nowarn println(summary_callback) - @test_nowarn display(summary_callback) - - @test_nowarn show(amr_controller); println() - @test_nowarn println(amr_controller) - @test_nowarn display(amr_controller) - - @test_nowarn show(amr_callback); println() - @test_nowarn println(amr_callback) - @test_nowarn display(amr_callback) - - @test_nowarn show(stepsize_callback); println() - @test_nowarn println(stepsize_callback) - @test_nowarn display(stepsize_callback) - - @test_nowarn show(save_solution); println() - @test_nowarn println(save_solution) - @test_nowarn display(save_solution) - - @test_nowarn show(analysis_callback); println() - @test_nowarn println(analysis_callback) - @test_nowarn display(analysis_callback) - - @test_nowarn show(alive_callback); println() - @test_nowarn println(alive_callback) - @test_nowarn display(alive_callback) - - @test_nowarn println(callbacks) - - # Check whether all output is suppressed if the summary, analysis and alive - # callbacks are set to the TrivialCallback(). Modelled using `@test_nowarn` - # as basis. - let fname = tempname() - try - open(fname, "w") do f - redirect_stderr(f) do - trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - summary_callback=TrivialCallback(), - analysis_callback=TrivialCallback(), - alive_callback=TrivialCallback()) + @test_nowarn include(joinpath(EXAMPLES_DIR, "elixir_advection_amr.jl")) + + # test both short and long printing formats + @test_nowarn show(mesh) + println() + @test_nowarn println(mesh) + @test_nowarn display(mesh) + + @test_nowarn show(equations) + println() + @test_nowarn println(equations) + @test_nowarn display(equations) + + @test_nowarn show(solver) + println() + @test_nowarn println(solver) + @test_nowarn display(solver) + + @test_nowarn show(solver.basis) + println() + @test_nowarn println(solver.basis) + @test_nowarn display(solver.basis) + + @test_nowarn show(solver.mortar) + println() + @test_nowarn println(solver.mortar) + @test_nowarn display(solver.mortar) + + @test_nowarn show(solver.volume_integral) + println() + @test_nowarn println(solver.volume_integral) + @test_nowarn display(solver.volume_integral) + + @test_nowarn show(semi) + println() + @test_nowarn println(semi) + @test_nowarn display(semi) + + @test_nowarn show(summary_callback) + println() + @test_nowarn println(summary_callback) + @test_nowarn display(summary_callback) + + @test_nowarn show(amr_controller) + println() + @test_nowarn println(amr_controller) + @test_nowarn display(amr_controller) + + @test_nowarn show(amr_callback) + println() + @test_nowarn println(amr_callback) + @test_nowarn display(amr_callback) + + @test_nowarn show(stepsize_callback) + println() + @test_nowarn println(stepsize_callback) + @test_nowarn display(stepsize_callback) + + @test_nowarn show(save_solution) + println() + @test_nowarn println(save_solution) + @test_nowarn display(save_solution) + + @test_nowarn show(analysis_callback) + println() + @test_nowarn println(analysis_callback) + @test_nowarn display(analysis_callback) + + @test_nowarn show(alive_callback) + println() + @test_nowarn println(alive_callback) + @test_nowarn display(alive_callback) + + @test_nowarn println(callbacks) + + # Check whether all output is suppressed if the summary, analysis and alive + # callbacks are set to the TrivialCallback(). Modelled using `@test_nowarn` + # as basis. + let fname = tempname() + try + open(fname, "w") do f + redirect_stderr(f) do + trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_extended.jl"), + summary_callback = TrivialCallback(), + analysis_callback = TrivialCallback(), + alive_callback = TrivialCallback()) + end + end + output = read(fname, String) + output = replace(output, + "[ Info: You just called `trixi_include`. Julia may now compile the code, please be patient.\n" => "") + @test isempty(output) + finally + rm(fname, force = true) end - end - output = read(fname, String) - output = replace(output, "[ Info: You just called `trixi_include`. Julia may now compile the code, please be patient.\n" => "") - @test isempty(output) - finally - rm(fname, force=true) end - end end - @testset "Additional tests in 1D" begin - @testset "compressible Euler" begin - eqn = CompressibleEulerEquations1D(1.4) + @testset "compressible Euler" begin + eqn = CompressibleEulerEquations1D(1.4) - @test isapprox(Trixi.entropy_thermodynamic([1.0, 2.0, 20.0], eqn), 1.9740810260220094) - @test isapprox(Trixi.entropy_math([1.0, 2.0, 20.0], eqn), -4.935202565055024) - @test isapprox(Trixi.entropy([1.0, 2.0, 20.0], eqn), -4.935202565055024) + @test isapprox(Trixi.entropy_thermodynamic([1.0, 2.0, 20.0], eqn), + 1.9740810260220094) + @test isapprox(Trixi.entropy_math([1.0, 2.0, 20.0], eqn), -4.935202565055024) + @test isapprox(Trixi.entropy([1.0, 2.0, 20.0], eqn), -4.935202565055024) - @test isapprox(energy_total([1.0, 2.0, 20.0], eqn), 20.0) - @test isapprox(energy_kinetic([1.0, 2.0, 20.0], eqn), 2.0) - @test isapprox(energy_internal([1.0, 2.0, 20.0], eqn), 18.0) - end + @test isapprox(energy_total([1.0, 2.0, 20.0], eqn), 20.0) + @test isapprox(energy_kinetic([1.0, 2.0, 20.0], eqn), 2.0) + @test isapprox(energy_internal([1.0, 2.0, 20.0], eqn), 18.0) + end end @trixi_testset "Nonconservative terms in 1D (linear advection)" begin - # Same setup as docs/src/adding_new_equations/nonconservative_advection.md + # Same setup as docs/src/adding_new_equations/nonconservative_advection.md - # Define new physics - using Trixi - using Trixi: AbstractEquations, get_node_vars - - # Since there is no native support for variable coefficients, we use two - # variables: one for the basic unknown `u` and another one for the coefficient `a` - struct NonconservativeLinearAdvectionEquation <: AbstractEquations{1 #= spatial dimension =#, - 2 #= two variables (u,a) =#} - end - - Trixi.varnames(::typeof(cons2cons), ::NonconservativeLinearAdvectionEquation) = ("scalar", "advection_velocity") - - Trixi.default_analysis_integrals(::NonconservativeLinearAdvectionEquation) = () + # Define new physics + using Trixi + using Trixi: AbstractEquations, get_node_vars + # Since there is no native support for variable coefficients, we use two + # variables: one for the basic unknown `u` and another one for the coefficient `a` + struct NonconservativeLinearAdvectionEquation <: AbstractEquations{1, #= spatial dimension =# + 2} #= two variables (u,a) =# + end - # The conservative part of the flux is zero - Trixi.flux(u, orientation, equation::NonconservativeLinearAdvectionEquation) = zero(u) + Trixi.varnames(::typeof(cons2cons), ::NonconservativeLinearAdvectionEquation) = ("scalar", + "advection_velocity") - # Calculate maximum wave speed for local Lax-Friedrichs-type dissipation - function Trixi.max_abs_speed_naive(u_ll, u_rr, orientation::Integer, ::NonconservativeLinearAdvectionEquation) - _, advection_velocity_ll = u_ll - _, advection_velocity_rr = u_rr + Trixi.default_analysis_integrals(::NonconservativeLinearAdvectionEquation) = () - return max(abs(advection_velocity_ll), abs(advection_velocity_rr)) - end + # The conservative part of the flux is zero + Trixi.flux(u, orientation, equation::NonconservativeLinearAdvectionEquation) = zero(u) + # Calculate maximum wave speed for local Lax-Friedrichs-type dissipation + function Trixi.max_abs_speed_naive(u_ll, u_rr, orientation::Integer, + ::NonconservativeLinearAdvectionEquation) + _, advection_velocity_ll = u_ll + _, advection_velocity_rr = u_rr - # We use nonconservative terms - Trixi.have_nonconservative_terms(::NonconservativeLinearAdvectionEquation) = Trixi.True() + return max(abs(advection_velocity_ll), abs(advection_velocity_rr)) + end - function flux_nonconservative(u_mine, u_other, orientation, - equations::NonconservativeLinearAdvectionEquation) - _, advection_velocity = u_mine - scalar, _ = u_other + # We use nonconservative terms + Trixi.have_nonconservative_terms(::NonconservativeLinearAdvectionEquation) = Trixi.True() - return SVector(advection_velocity * scalar, zero(scalar)) - end + function flux_nonconservative(u_mine, u_other, orientation, + equations::NonconservativeLinearAdvectionEquation) + _, advection_velocity = u_mine + scalar, _ = u_other + return SVector(advection_velocity * scalar, zero(scalar)) + end - # Create a simulation setup - using Trixi - using OrdinaryDiffEq + # Create a simulation setup + using Trixi + using OrdinaryDiffEq - equation = NonconservativeLinearAdvectionEquation() + equation = NonconservativeLinearAdvectionEquation() - # You can derive the exact solution for this setup using the method of - # characteristics - function initial_condition_sine(x, t, equation::NonconservativeLinearAdvectionEquation) - x0 = -2 * atan(sqrt(3) * tan(sqrt(3) / 2 * t - atan(tan(x[1] / 2) / sqrt(3)))) - scalar = sin(x0) - advection_velocity = 2 + cos(x[1]) - SVector(scalar, advection_velocity) - end + # You can derive the exact solution for this setup using the method of + # characteristics + function initial_condition_sine(x, t, + equation::NonconservativeLinearAdvectionEquation) + x0 = -2 * atan(sqrt(3) * tan(sqrt(3) / 2 * t - atan(tan(x[1] / 2) / sqrt(3)))) + scalar = sin(x0) + advection_velocity = 2 + cos(x[1]) + SVector(scalar, advection_velocity) + end - # Create a uniform mesh in 1D in the interval [-π, π] with periodic boundaries - mesh = TreeMesh(-Float64(π), Float64(π), # min/max coordinates - initial_refinement_level=4, n_cells_max=10^4) + # Create a uniform mesh in 1D in the interval [-π, π] with periodic boundaries + mesh = TreeMesh(-Float64(π), Float64(π), # min/max coordinates + initial_refinement_level = 4, n_cells_max = 10^4) - # Create a DGSEM solver with polynomials of degree `polydeg` - volume_flux = (flux_central, flux_nonconservative) - surface_flux = (flux_lax_friedrichs, flux_nonconservative) - solver = DGSEM(polydeg=3, surface_flux=surface_flux, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) + # Create a DGSEM solver with polynomials of degree `polydeg` + volume_flux = (flux_central, flux_nonconservative) + surface_flux = (flux_lax_friedrichs, flux_nonconservative) + solver = DGSEM(polydeg = 3, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) - # Setup the spatial semidiscretization containing all ingredients - semi = SemidiscretizationHyperbolic(mesh, equation, initial_condition_sine, solver) + # Setup the spatial semidiscretization containing all ingredients + semi = SemidiscretizationHyperbolic(mesh, equation, initial_condition_sine, solver) - # Create an ODE problem with given time span - tspan = (0.0, 1.0) - ode = semidiscretize(semi, tspan); + # Create an ODE problem with given time span + tspan = (0.0, 1.0) + ode = semidiscretize(semi, tspan) - summary_callback = SummaryCallback() - analysis_callback = AnalysisCallback(semi, interval=50) - callbacks = CallbackSet(summary_callback, analysis_callback); + summary_callback = SummaryCallback() + analysis_callback = AnalysisCallback(semi, interval = 50) + callbacks = CallbackSet(summary_callback, analysis_callback) - # OrdinaryDiffEq's `solve` method evolves the solution in time and executes - # the passed callbacks - sol = solve(ode, Tsit5(), abstol=1.0e-6, reltol=1.0e-6, - save_everystep=false, callback=callbacks); + # OrdinaryDiffEq's `solve` method evolves the solution in time and executes + # the passed callbacks + sol = solve(ode, Tsit5(), abstol = 1.0e-6, reltol = 1.0e-6, + save_everystep = false, callback = callbacks) - @test analysis_callback(sol).l2 ≈ [0.00029609575838969394, 5.5681704039507985e-6] + @test analysis_callback(sol).l2 ≈ [0.00029609575838969394, 5.5681704039507985e-6] end - # Clean up afterwards: delete Trixi.jl output directory -@test_nowarn rm(outdir, recursive=true) - +@test_nowarn rm(outdir, recursive = true) end # TreeMesh1D end # module diff --git a/test/test_tree_1d_advection.jl b/test/test_tree_1d_advection.jl index 681fea4a8ae..7cfd78e0ade 100644 --- a/test/test_tree_1d_advection.jl +++ b/test/test_tree_1d_advection.jl @@ -8,63 +8,65 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @testset "Linear scalar advection" begin - @trixi_testset "elixir_advection_basic.jl" begin +#! format: noindent + +@trixi_testset "elixir_advection_basic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), - l2 = [6.0388296447998465e-6], - linf = [3.217887726258972e-5]) - # 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 + l2=[6.0388296447998465e-6], + linf=[3.217887726258972e-5]) + # 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_amr.jl" begin +@trixi_testset "elixir_advection_amr.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr.jl"), - l2 = [0.3540206249507417], - linf = [0.9999896603382347], - 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 - end + l2=[0.3540206249507417], + linf=[0.9999896603382347], + 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 +end - @trixi_testset "elixir_advection_amr_nonperiodic.jl" begin +@trixi_testset "elixir_advection_amr_nonperiodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_nonperiodic.jl"), - l2 = [4.283508859843524e-6], - linf = [3.235356127918171e-5], - 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 - end + l2=[4.283508859843524e-6], + linf=[3.235356127918171e-5], + 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 +end - @trixi_testset "elixir_advection_finite_volume.jl" begin +@trixi_testset "elixir_advection_finite_volume.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_finite_volume.jl"), - l2 = [0.011662300515980219], - linf = [0.01647256923710194]) - # 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 + l2=[0.011662300515980219], + linf=[0.01647256923710194]) + # 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 end # module diff --git a/test/test_tree_1d_burgers.jl b/test/test_tree_1d_burgers.jl index eb4ece05b7e..56e1ee749f7 100644 --- a/test/test_tree_1d_burgers.jl +++ b/test/test_tree_1d_burgers.jl @@ -8,61 +8,63 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @testset "Inviscid Burgers" begin - @trixi_testset "elixir_burgers_basic.jl" begin +#! format: noindent + +@trixi_testset "elixir_burgers_basic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_basic.jl"), - l2 = [2.967470209082194e-5], - linf = [0.00016152468882624227]) - # 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 + l2=[2.967470209082194e-5], + linf=[0.00016152468882624227]) + # 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_burgers_linear_stability.jl" begin +@trixi_testset "elixir_burgers_linear_stability.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_linear_stability.jl"), - l2 = [0.5660569881106876], - linf = [1.9352238038313998]) - # 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 + l2=[0.5660569881106876], + linf=[1.9352238038313998]) + # 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_burgers_shock.jl" begin +@trixi_testset "elixir_burgers_shock.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_shock.jl"), - l2 = [0.4422505602587537], - linf = [1.0000000000000009]) - # 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 + l2=[0.4422505602587537], + linf=[1.0000000000000009]) + # 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_burgers_rarefaction.jl" begin +@trixi_testset "elixir_burgers_rarefaction.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_rarefaction.jl"), - l2 = [0.4038224690923722], - linf = [1.0049201454652736]) - # 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 + l2=[0.4038224690923722], + linf=[1.0049201454652736]) + # 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 end # module diff --git a/test/test_tree_1d_euler.jl b/test/test_tree_1d_euler.jl index 92a917d0622..f01124509cb 100644 --- a/test/test_tree_1d_euler.jl +++ b/test/test_tree_1d_euler.jl @@ -8,281 +8,395 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @testset "Compressible Euler" begin - @trixi_testset "elixir_euler_source_terms.jl" begin +#! format: noindent + +@trixi_testset "elixir_euler_source_terms.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms.jl"), - l2 = [2.2527950196212703e-8, 1.8187357193835156e-8, 7.705669939973104e-8], - linf = [1.6205433861493646e-7, 1.465427772462391e-7, 5.372255111879554e-7]) - # 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 + l2=[ + 2.2527950196212703e-8, + 1.8187357193835156e-8, + 7.705669939973104e-8, + ], + linf=[ + 1.6205433861493646e-7, + 1.465427772462391e-7, + 5.372255111879554e-7, + ]) + # 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_convergence_pure_fv.jl" begin +@trixi_testset "elixir_euler_convergence_pure_fv.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence_pure_fv.jl"), - l2 = [0.019355699748523896, 0.022326984561234497, 0.02523665947241734], - linf = [0.02895961127645519, 0.03293442484199227, 0.04246098278632804]) - # 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 + l2=[ + 0.019355699748523896, + 0.022326984561234497, + 0.02523665947241734, + ], + linf=[ + 0.02895961127645519, + 0.03293442484199227, + 0.04246098278632804, + ]) + # 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_density_wave.jl" begin +@trixi_testset "elixir_euler_density_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_density_wave.jl"), - l2 = [0.0011482554820217855, 0.00011482554830323462, 5.741277429325267e-6], - linf = [0.004090978306812376, 0.0004090978313582294, 2.045489210189544e-5]) - # 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 + l2=[ + 0.0011482554820217855, + 0.00011482554830323462, + 5.741277429325267e-6, + ], + linf=[ + 0.004090978306812376, + 0.0004090978313582294, + 2.045489210189544e-5, + ]) + # 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_density_wave.jl with initial_condition_constant" begin +@trixi_testset "elixir_euler_density_wave.jl with initial_condition_constant" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_density_wave.jl"), - l2 = [7.71293052584723e-16, 1.9712947511091717e-14, 7.50672833504266e-15], - linf = [3.774758283725532e-15, 6.733502644351574e-14, 2.4868995751603507e-14], - initial_condition = initial_condition_constant) - # 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 + l2=[ + 7.71293052584723e-16, + 1.9712947511091717e-14, + 7.50672833504266e-15, + ], + linf=[ + 3.774758283725532e-15, + 6.733502644351574e-14, + 2.4868995751603507e-14, + ], + initial_condition=initial_condition_constant) + # 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_source_terms_nonperiodic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonperiodic.jl"), - l2 = [3.8099996914101204e-6, 1.6745575717106341e-6, 7.732189531480852e-6], - linf = [1.2971473393186272e-5, 9.270328934274374e-6, 3.092514399671842e-5]) - # 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_source_terms_nonperiodic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonperiodic.jl"), + l2=[ + 3.8099996914101204e-6, + 1.6745575717106341e-6, + 7.732189531480852e-6, + ], + linf=[ + 1.2971473393186272e-5, + 9.270328934274374e-6, + 3.092514399671842e-5, + ]) + # 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_ec.jl" begin +@trixi_testset "elixir_euler_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.11821957357197649, 0.15330089521538678, 0.4417674632047301], - linf = [0.24280567569982958, 0.29130548795961936, 0.8847009003152442]) - # 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 + l2=[ + 0.11821957357197649, + 0.15330089521538678, + 0.4417674632047301, + ], + linf=[ + 0.24280567569982958, + 0.29130548795961936, + 0.8847009003152442, + ]) + # 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_ec.jl with flux_kennedy_gruber" begin +@trixi_testset "elixir_euler_ec.jl with flux_kennedy_gruber" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.07803455838661963, 0.10032577312032283, 0.29228156303827935], - linf = [0.2549869853794955, 0.3376472164661263, 0.9650477546553962], - maxiters = 10, - surface_flux = flux_kennedy_gruber, - volume_flux = flux_kennedy_gruber) - # 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 + l2=[ + 0.07803455838661963, + 0.10032577312032283, + 0.29228156303827935, + ], + linf=[ + 0.2549869853794955, + 0.3376472164661263, + 0.9650477546553962, + ], + maxiters=10, + surface_flux=flux_kennedy_gruber, + volume_flux=flux_kennedy_gruber) + # 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_ec.jl with flux_shima_etal" begin +@trixi_testset "elixir_euler_ec.jl with flux_shima_etal" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.07800654460172655, 0.10030365573277883, 0.2921481199111959], - linf = [0.25408579350400395, 0.3388657679031271, 0.9776486386921928], - maxiters = 10, - surface_flux = flux_shima_etal, - volume_flux = flux_shima_etal) - # 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 + l2=[ + 0.07800654460172655, + 0.10030365573277883, + 0.2921481199111959, + ], + linf=[ + 0.25408579350400395, + 0.3388657679031271, + 0.9776486386921928, + ], + maxiters=10, + surface_flux=flux_shima_etal, + volume_flux=flux_shima_etal) + # 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_ec.jl with flux_chandrashekar" begin +@trixi_testset "elixir_euler_ec.jl with flux_chandrashekar" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.07801923089205756, 0.10039557434912669, 0.2922210399923278], - linf = [0.2576521982607225, 0.3409717926625057, 0.9772961936567048], - maxiters = 10, - surface_flux = flux_chandrashekar, - volume_flux = flux_chandrashekar) - # 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 + l2=[ + 0.07801923089205756, + 0.10039557434912669, + 0.2922210399923278, + ], + linf=[ + 0.2576521982607225, + 0.3409717926625057, + 0.9772961936567048, + ], + maxiters=10, + surface_flux=flux_chandrashekar, + volume_flux=flux_chandrashekar) + # 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_ec.jl with flux_hll" begin +@trixi_testset "elixir_euler_ec.jl with flux_hll" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.07852272782240548, 0.10209790867523805, 0.293873048809011], - linf = [0.19244768908604093, 0.2515941686151897, 0.7258000837553769], - maxiters = 10, - surface_flux = flux_hll, - volume_flux = flux_ranocha) - # 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 + l2=[0.07852272782240548, 0.10209790867523805, 0.293873048809011], + linf=[ + 0.19244768908604093, + 0.2515941686151897, + 0.7258000837553769, + ], + maxiters=10, + surface_flux=flux_hll, + volume_flux=flux_ranocha) + # 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_shockcapturing.jl" begin +@trixi_testset "elixir_euler_shockcapturing.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing.jl"), - l2 = [0.11606096465319675, 0.15028768943458806, 0.4328230323046703], - linf = [0.18031710091067965, 0.2351582421501841, 0.6776805692092567]) - # 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 + l2=[ + 0.11606096465319675, + 0.15028768943458806, + 0.4328230323046703, + ], + linf=[ + 0.18031710091067965, + 0.2351582421501841, + 0.6776805692092567, + ]) + # 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_blast_wave.jl" begin +@trixi_testset "elixir_euler_sedov_blast_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov_blast_wave.jl"), - l2 = [1.250005061244617, 0.06878411345533507, 0.9264328311018613], - linf = [2.9766770877037168, 0.16838100902295852, 2.6655773445485798], - 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 - end + l2=[1.250005061244617, 0.06878411345533507, 0.9264328311018613], + linf=[ + 2.9766770877037168, + 0.16838100902295852, + 2.6655773445485798, + ], + 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 +end - @trixi_testset "elixir_euler_sedov_blast_wave_pure_fv.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov_blast_wave_pure_fv.jl"), - l2 = [1.0735456065491455, 0.07131078703089379, 0.9205739468590453], - linf = [3.4296365168219216, 0.17635583964559245, 2.6574584326179505], - # Let this test run longer to cover some lines in flux_hllc - coverage_override = (maxiters=10^5, tspan=(0.0, 0.1))) - # 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_blast_wave_pure_fv.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_sedov_blast_wave_pure_fv.jl"), + l2=[1.0735456065491455, 0.07131078703089379, 0.9205739468590453], + linf=[ + 3.4296365168219216, + 0.17635583964559245, + 2.6574584326179505, + ], + # Let this test run longer to cover some lines in flux_hllc + coverage_override=(maxiters = 10^5, tspan = (0.0, 0.1))) + # 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_blast_wave.jl with pressure" begin +@trixi_testset "elixir_euler_sedov_blast_wave.jl with pressure" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov_blast_wave.jl"), - l2 = [1.297525985166995, 0.07964929522694145, 0.9269991156246368], - linf = [3.1773015255764427, 0.21331831536493773, 2.6650170188241047], - shock_indicator_variable = pressure, - cfl = 0.2, - 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 - end + l2=[1.297525985166995, 0.07964929522694145, 0.9269991156246368], + linf=[ + 3.1773015255764427, + 0.21331831536493773, + 2.6650170188241047, + ], + shock_indicator_variable=pressure, + cfl=0.2, + 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 +end - @trixi_testset "elixir_euler_sedov_blast_wave.jl with density" begin +@trixi_testset "elixir_euler_sedov_blast_wave.jl with density" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov_blast_wave.jl"), - l2 = [1.2798798835860528, 0.07103461242058921, 0.9273792517187003], - linf = [3.1087017048015824, 0.17734706962928956, 2.666689753470263], - shock_indicator_variable = density, - cfl = 0.2, - 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 - end + l2=[1.2798798835860528, 0.07103461242058921, 0.9273792517187003], + linf=[ + 3.1087017048015824, + 0.17734706962928956, + 2.666689753470263, + ], + shock_indicator_variable=density, + cfl=0.2, + 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 +end - @trixi_testset "elixir_euler_positivity.jl" begin +@trixi_testset "elixir_euler_positivity.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_positivity.jl"), - l2 = [1.6493820253458906, 0.19793887460986834, 0.9783506076125921], - linf = [4.71751203912051, 0.5272411022735763, 2.7426163947635844], - coverage_override = (maxiters=3,)) - # 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 + l2=[1.6493820253458906, 0.19793887460986834, 0.9783506076125921], + linf=[4.71751203912051, 0.5272411022735763, 2.7426163947635844], + coverage_override=(maxiters = 3,)) + # 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_blast_wave.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blast_wave.jl"), - l2 = [0.21934822867340323, 0.28131919126002686, 0.554361702716662], - linf = [1.5180897390290355, 1.3967085956620369, 2.0663825294019595], - maxiters = 30) - # 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_blast_wave.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blast_wave.jl"), + l2=[0.21934822867340323, 0.28131919126002686, 0.554361702716662], + linf=[ + 1.5180897390290355, + 1.3967085956620369, + 2.0663825294019595, + ], + maxiters=30) + # 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_blast_wave_neuralnetwork_perssonperaire.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl"), - l2 = [0.21814833203212694, 0.2818328665444332, 0.5528379124720818], - linf = [1.5548653877320868, 1.4474018998129738, 2.071919577393772], - maxiters = 30) - end +@trixi_testset "elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl"), + l2=[0.21814833203212694, 0.2818328665444332, 0.5528379124720818], + linf=[1.5548653877320868, 1.4474018998129738, 2.071919577393772], + maxiters=30) +end - @trixi_testset "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl"), - l2 = [0.22054468879127423, 0.2828269190680846, 0.5542369885642424], - linf = [1.5623359741479623, 1.4290121654488288, 2.1040405133123072], - maxiters = 30) - end +@trixi_testset "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl"), + l2=[0.22054468879127423, 0.2828269190680846, 0.5542369885642424], + linf=[ + 1.5623359741479623, + 1.4290121654488288, + 2.1040405133123072, + ], + maxiters=30) +end end end # module diff --git a/test/test_tree_1d_eulergravity.jl b/test/test_tree_1d_eulergravity.jl index 7738d847d31..9ab5b287d0b 100644 --- a/test/test_tree_1d_eulergravity.jl +++ b/test/test_tree_1d_eulergravity.jl @@ -8,19 +8,29 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @testset "Compressible Euler with self-gravity" begin - @trixi_testset "elixir_eulergravity_convergence.jl" begin +#! format: noindent + +@trixi_testset "elixir_eulergravity_convergence.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulergravity_convergence.jl"), - l2 = [0.0002170799126638106, 0.0002913792848717502, 0.0006112320856262327], - linf = [0.0004977401033188222, 0.0013594223337776157, 0.002041891084400227]) - # 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 + l2=[ + 0.0002170799126638106, + 0.0002913792848717502, + 0.0006112320856262327, + ], + linf=[ + 0.0004977401033188222, + 0.0013594223337776157, + 0.002041891084400227, + ]) + # 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 end # module diff --git a/test/test_tree_1d_eulermulti.jl b/test/test_tree_1d_eulermulti.jl index 7e0d69cea1c..bd86de928e3 100644 --- a/test/test_tree_1d_eulermulti.jl +++ b/test/test_tree_1d_eulermulti.jl @@ -8,100 +8,130 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @testset "Compressible Euler Multicomponent" begin +#! format: noindent - @trixi_testset "elixir_eulermulti_ec.jl" begin +@trixi_testset "elixir_eulermulti_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_ec.jl"), - l2 = [0.15330089521538684, 0.4417674632047301, 0.016888510510282385, 0.03377702102056477, - 0.06755404204112954], - linf = [0.29130548795961864, 0.8847009003152357, 0.034686525099975274, 0.06937305019995055, - 0.1387461003999011]) - # 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 + l2=[0.15330089521538684, 0.4417674632047301, + 0.016888510510282385, 0.03377702102056477, + 0.06755404204112954], + linf=[0.29130548795961864, 0.8847009003152357, + 0.034686525099975274, 0.06937305019995055, + 0.1387461003999011]) + # 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_eulermulti_es.jl" begin +@trixi_testset "elixir_eulermulti_es.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_es.jl"), - l2 = [0.1522380497572071, 0.43830846465313206, 0.03907262116499431, 0.07814524232998862], - linf = [0.24939193075537294, 0.7139395740052739, 0.06324208768391237, 0.12648417536782475]) - # 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 + l2=[ + 0.1522380497572071, + 0.43830846465313206, + 0.03907262116499431, + 0.07814524232998862, + ], + linf=[ + 0.24939193075537294, + 0.7139395740052739, + 0.06324208768391237, + 0.12648417536782475, + ]) + # 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_eulermulti_convergence_ec.jl" begin +@trixi_testset "elixir_eulermulti_convergence_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_ec.jl"), - l2 = [8.575236038539227e-5, 0.00016387804318585358, 1.9412699303977585e-5, 3.882539860795517e-5], - linf = [0.00030593277277124464, 0.0006244803933350696, 7.253121435135679e-5, 0.00014506242870271358]) - # 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 + l2=[ + 8.575236038539227e-5, + 0.00016387804318585358, + 1.9412699303977585e-5, + 3.882539860795517e-5, + ], + linf=[ + 0.00030593277277124464, + 0.0006244803933350696, + 7.253121435135679e-5, + 0.00014506242870271358, + ]) + # 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_eulermulti_convergence_es.jl" begin +@trixi_testset "elixir_eulermulti_convergence_es.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_es.jl"), - l2 = [1.8983933794407234e-5, 6.207744299844731e-5, 1.5466205761868047e-6, 3.0932411523736094e-6, - 6.186482304747219e-6, 1.2372964609494437e-5], - linf = [0.00012014372605895218, 0.0003313207215800418, 6.50836791016296e-6, 1.301673582032592e-5, - 2.603347164065184e-5, 5.206694328130368e-5]) - # 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 + l2=[1.8983933794407234e-5, 6.207744299844731e-5, + 1.5466205761868047e-6, 3.0932411523736094e-6, + 6.186482304747219e-6, 1.2372964609494437e-5], + linf=[0.00012014372605895218, 0.0003313207215800418, + 6.50836791016296e-6, 1.301673582032592e-5, + 2.603347164065184e-5, 5.206694328130368e-5]) + # 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_eulermulti_convergence_es.jl with flux_chandrashekar" begin +@trixi_testset "elixir_eulermulti_convergence_es.jl with flux_chandrashekar" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_es.jl"), - l2 = [1.888450477353845e-5, 5.4910600482795386e-5, 9.426737161533622e-7, 1.8853474323067245e-6, - 3.770694864613449e-6, 7.541389729226898e-6], - linf = [0.00011622351152063004, 0.0003079221967086099, 3.2177423254231563e-6, 6.435484650846313e-6, - 1.2870969301692625e-5, 2.574193860338525e-5], - volume_flux = flux_chandrashekar) - # 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 + l2=[1.888450477353845e-5, 5.4910600482795386e-5, + 9.426737161533622e-7, 1.8853474323067245e-6, + 3.770694864613449e-6, 7.541389729226898e-6], + linf=[0.00011622351152063004, 0.0003079221967086099, + 3.2177423254231563e-6, 6.435484650846313e-6, + 1.2870969301692625e-5, 2.574193860338525e-5], + volume_flux=flux_chandrashekar) + # 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_eulermulti_two_interacting_blast_waves.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_two_interacting_blast_waves.jl"), - l2 = [1.288867611915533, 82.71335258388848, 0.00350680272313187, 0.013698784353152794, - 0.019179518517518084], - linf = [29.6413044707026, 1322.5844802186496, 0.09191919374782143, 0.31092970966717925, - 0.4417989757182038], - tspan = (0.0, 0.0001)) - # 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_eulermulti_two_interacting_blast_waves.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_eulermulti_two_interacting_blast_waves.jl"), + l2=[1.288867611915533, 82.71335258388848, 0.00350680272313187, + 0.013698784353152794, + 0.019179518517518084], + linf=[29.6413044707026, 1322.5844802186496, 0.09191919374782143, + 0.31092970966717925, + 0.4417989757182038], + tspan=(0.0, 0.0001)) + # 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 end # module diff --git a/test/test_tree_1d_fdsbp.jl b/test/test_tree_1d_fdsbp.jl index d11bf277807..33d67e3366f 100644 --- a/test/test_tree_1d_fdsbp.jl +++ b/test/test_tree_1d_fdsbp.jl @@ -8,148 +8,185 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_fdsbp") @testset "Linear scalar advection" begin - @trixi_testset "elixir_advection_upwind.jl" begin +#! format: noindent + +@trixi_testset "elixir_advection_upwind.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_upwind.jl"), - l2 = [1.7735637157305526e-6], - linf = [1.0418854521951328e-5], - tspan = (0.0, 0.5)) + l2=[1.7735637157305526e-6], + linf=[1.0418854521951328e-5], + tspan=(0.0, 0.5)) # 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 + 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 - @trixi_testset "elixir_advection_upwind_periodic.jl" begin +@trixi_testset "elixir_advection_upwind_periodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_upwind_periodic.jl"), - l2 = [1.1672962783692568e-5], - linf = [1.650514414558435e-5]) + l2=[1.1672962783692568e-5], + linf=[1.650514414558435e-5]) # 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 + 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 end @testset "Inviscid Burgers" begin - @trixi_testset "elixir_burgers_basic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_basic.jl"), - l2 = [8.316190308678742e-7], - linf = [7.1087263324720595e-6], - tspan = (0.0, 0.5)) + @trixi_testset "elixir_burgers_basic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_basic.jl"), + l2=[8.316190308678742e-7], + linf=[7.1087263324720595e-6], + tspan=(0.0, 0.5)) + + # 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 - # 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 + # same tolerances as above since the methods should be identical (up to + # machine precision) + @trixi_testset "elixir_burgers_basic.jl with SurfaceIntegralStrongForm and FluxUpwind" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_basic.jl"), + l2=[8.316190308678742e-7], + linf=[7.1087263324720595e-6], + tspan=(0.0, 0.5), + solver=DG(D_upw, nothing, + SurfaceIntegralStrongForm(FluxUpwind(flux_splitting)), + VolumeIntegralUpwind(flux_splitting))) + end + + @trixi_testset "elixir_burgers_linear_stability.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_linear_stability.jl"), + l2=[0.9999995642691271], + linf=[1.824702804788453], + tspan=(0.0, 0.25)) + + # 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 - - # same tolerances as above since the methods should be identical (up to - # machine precision) - @trixi_testset "elixir_burgers_basic.jl with SurfaceIntegralStrongForm and FluxUpwind" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_basic.jl"), - l2 = [8.316190308678742e-7], - linf = [7.1087263324720595e-6], - tspan = (0.0, 0.5), - solver = DG(D_upw, nothing, SurfaceIntegralStrongForm(FluxUpwind(flux_splitting)), VolumeIntegralUpwind(flux_splitting))) - end - - @trixi_testset "elixir_burgers_linear_stability.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_linear_stability.jl"), - l2 = [0.9999995642691271], - linf = [1.824702804788453], - tspan = (0.0, 0.25)) - - # 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 @testset "Compressible Euler" begin - @trixi_testset "elixir_euler_convergence.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), - l2 = [4.1370344463620254e-6, 4.297052451817826e-6, 9.857382045003056e-6], - linf = [1.675305070092392e-5, 1.3448113863834266e-5, 3.8185336878271414e-5], - tspan = (0.0, 0.5)) + @trixi_testset "elixir_euler_convergence.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), + l2=[ + 4.1370344463620254e-6, + 4.297052451817826e-6, + 9.857382045003056e-6, + ], + linf=[ + 1.675305070092392e-5, + 1.3448113863834266e-5, + 3.8185336878271414e-5, + ], + tspan=(0.0, 0.5)) + + # 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 - # 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 + @trixi_testset "elixir_euler_convergence.jl with splitting_vanleer_haenel" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), + l2=[ + 3.413790589105506e-6, + 4.243957977156001e-6, + 8.667369423676437e-6, + ], + linf=[ + 1.4228079689537765e-5, + 1.3249887941046978e-5, + 3.201552933251861e-5, + ], + tspan=(0.0, 0.5), + flux_splitting=splitting_vanleer_haenel) + + # 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_convergence.jl with VolumeIntegralStrongForm" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), + l2=[ + 8.6126767518378e-6, + 7.670897071480729e-6, + 1.4972772284191368e-5, + ], + linf=[ + 6.707982777909294e-5, + 3.487256699541419e-5, + 0.00010170331350556339, + ], + tspan=(0.0, 0.5), + solver=DG(D_upw.central, nothing, SurfaceIntegralStrongForm(), + VolumeIntegralStrongForm())) + + # 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_density_wave.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_density_wave.jl"), + l2=[ + 1.5894925236031034e-5, + 9.428412101106044e-6, + 0.0008986477358789918, + ], + linf=[ + 4.969438024382544e-5, + 2.393091812063694e-5, + 0.003271817388146303, + ], + tspan=(0.0, 0.005), abstol=1.0e-9, reltol=1.0e-9) + + # 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 - - @trixi_testset "elixir_euler_convergence.jl with splitting_vanleer_haenel" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), - l2 = [3.413790589105506e-6, 4.243957977156001e-6, 8.667369423676437e-6], - linf = [1.4228079689537765e-5, 1.3249887941046978e-5, 3.201552933251861e-5], - tspan = (0.0, 0.5), - flux_splitting = splitting_vanleer_haenel) - - # 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_convergence.jl with VolumeIntegralStrongForm" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), - l2 = [8.6126767518378e-6, 7.670897071480729e-6, 1.4972772284191368e-5], - linf = [6.707982777909294e-5, 3.487256699541419e-5, 0.00010170331350556339], - tspan = (0.0, 0.5), - solver = DG(D_upw.central, nothing, SurfaceIntegralStrongForm(), VolumeIntegralStrongForm())) - - # 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_density_wave.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_density_wave.jl"), - l2 = [1.5894925236031034e-5, 9.428412101106044e-6, 0.0008986477358789918], - linf = [4.969438024382544e-5, 2.393091812063694e-5, 0.003271817388146303], - tspan = (0.0, 0.005), abstol = 1.0e-9, reltol = 1.0e-9) - - # 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 end # module diff --git a/test/test_tree_1d_hypdiff.jl b/test/test_tree_1d_hypdiff.jl index 19200b26892..896a3d4c8d6 100644 --- a/test/test_tree_1d_hypdiff.jl +++ b/test/test_tree_1d_hypdiff.jl @@ -8,36 +8,38 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @testset "Hyperbolic diffusion" begin +#! format: noindent - @trixi_testset "elixir_hypdiff_nonperiodic.jl" begin +@trixi_testset "elixir_hypdiff_nonperiodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_nonperiodic.jl"), - l2 = [1.3655114954641076e-7, 1.0200345025539218e-6], - linf = [7.173286515893551e-7, 4.507116363683394e-6], - atol = 2.5e-13) - # 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 + l2=[1.3655114954641076e-7, 1.0200345025539218e-6], + linf=[7.173286515893551e-7, 4.507116363683394e-6], + atol=2.5e-13) + # 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_hypdiff_harmonic_nonperiodic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_harmonic_nonperiodic.jl"), - l2 = [3.0130941075207524e-12, 2.6240829677090014e-12], - linf = [4.054534485931072e-12, 3.8826719617190975e-12], - atol = 2.5e-13) - # 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) +@trixi_testset "elixir_hypdiff_harmonic_nonperiodic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_hypdiff_harmonic_nonperiodic.jl"), + l2=[3.0130941075207524e-12, 2.6240829677090014e-12], + linf=[4.054534485931072e-12, 3.8826719617190975e-12], + atol=2.5e-13) + # 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)) < 10000 - end - end + end +end end end # module diff --git a/test/test_tree_1d_mhd.jl b/test/test_tree_1d_mhd.jl index 77158001275..b34bdf0660c 100644 --- a/test/test_tree_1d_mhd.jl +++ b/test/test_tree_1d_mhd.jl @@ -8,145 +8,309 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @testset "MHD" begin +#! format: noindent - @trixi_testset "elixir_mhd_alfven_wave.jl with initial_condition_constant" begin +@trixi_testset "elixir_mhd_alfven_wave.jl with initial_condition_constant" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), - l2 = [1.440611823425164e-15, 1.1373567770134494e-14, 3.024482376149653e-15, 2.0553143516814395e-15, 3.9938347410210535e-14, 3.984545392098788e-16, 2.4782402104201577e-15, 1.551737464879987e-15], - linf = [1.9984014443252818e-15, 1.3405943022348765e-14, 3.3584246494910985e-15, 3.164135620181696e-15, 7.815970093361102e-14, 8.881784197001252e-16, 2.886579864025407e-15, 2.942091015256665e-15], - initial_condition = initial_condition_constant, - tspan = (0.0,1.0)) - # 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 + l2=[ + 1.440611823425164e-15, + 1.1373567770134494e-14, + 3.024482376149653e-15, + 2.0553143516814395e-15, + 3.9938347410210535e-14, + 3.984545392098788e-16, + 2.4782402104201577e-15, + 1.551737464879987e-15, + ], + linf=[ + 1.9984014443252818e-15, + 1.3405943022348765e-14, + 3.3584246494910985e-15, + 3.164135620181696e-15, + 7.815970093361102e-14, + 8.881784197001252e-16, + 2.886579864025407e-15, + 2.942091015256665e-15, + ], + initial_condition=initial_condition_constant, + tspan=(0.0, 1.0)) + # 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_mhd_alfven_wave.jl" begin +@trixi_testset "elixir_mhd_alfven_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), - l2 = [1.0375628983659061e-5, 6.571144191446236e-7, 3.5833569836289104e-5, 3.583356983615859e-5, 5.084863194951084e-6, 1.1963224165731992e-16, 3.598916927583752e-5, 3.598916927594727e-5], - linf = [2.614095879338585e-5, 9.577266731216823e-7, 0.00012406198007461344, 0.00012406198007509917, 1.5066209528846741e-5, 2.220446049250313e-16, 0.00012658678753942054, 0.00012658678753908748]) - # 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 + l2=[ + 1.0375628983659061e-5, + 6.571144191446236e-7, + 3.5833569836289104e-5, + 3.583356983615859e-5, + 5.084863194951084e-6, + 1.1963224165731992e-16, + 3.598916927583752e-5, + 3.598916927594727e-5, + ], + linf=[ + 2.614095879338585e-5, + 9.577266731216823e-7, + 0.00012406198007461344, + 0.00012406198007509917, + 1.5066209528846741e-5, + 2.220446049250313e-16, + 0.00012658678753942054, + 0.00012658678753908748, + ]) + # 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_mhd_alfven_wave.jl with flux_derigs_etal" begin +@trixi_testset "elixir_mhd_alfven_wave.jl with flux_derigs_etal" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), - l2 = [1.4396053943470756e-5, 1.1211016739165248e-5, 3.577870687983967e-5, 3.577870687982181e-5, 1.967962220860377e-6, 1.1963224165731992e-16, 3.583562899483433e-5, 3.583562899486565e-5], - linf = [5.830577969345718e-5, 3.280495696370357e-5, 0.00012279619948236953, 0.00012279619948227238, 6.978806516122482e-6, 2.220446049250313e-16, 0.00012564003648959932, 0.00012564003648994626], - volume_flux = flux_derigs_etal) - # 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 + l2=[ + 1.4396053943470756e-5, + 1.1211016739165248e-5, + 3.577870687983967e-5, + 3.577870687982181e-5, + 1.967962220860377e-6, + 1.1963224165731992e-16, + 3.583562899483433e-5, + 3.583562899486565e-5, + ], + linf=[ + 5.830577969345718e-5, + 3.280495696370357e-5, + 0.00012279619948236953, + 0.00012279619948227238, + 6.978806516122482e-6, + 2.220446049250313e-16, + 0.00012564003648959932, + 0.00012564003648994626, + ], + volume_flux=flux_derigs_etal) + # 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_mhd_ec.jl" begin +@trixi_testset "elixir_mhd_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ec.jl"), - l2 = [0.05815183849746399, 0.08166807325621023, 0.054659228513541165, 0.054659228513541165, 0.15578125987042743, 4.130462730494e-17, 0.05465258887150046, 0.05465258887150046], - linf = [0.12165312668363826, 0.1901920742264952, 0.10059813883022554, 0.10059813883022554, 0.44079257431070706, 1.1102230246251565e-16, 0.10528911365809579, 0.10528911365809579]) - # 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 + l2=[ + 0.05815183849746399, + 0.08166807325621023, + 0.054659228513541165, + 0.054659228513541165, + 0.15578125987042743, + 4.130462730494e-17, + 0.05465258887150046, + 0.05465258887150046, + ], + linf=[ + 0.12165312668363826, + 0.1901920742264952, + 0.10059813883022554, + 0.10059813883022554, + 0.44079257431070706, + 1.1102230246251565e-16, + 0.10528911365809579, + 0.10528911365809579, + ]) + # 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_mhd_briowu_shock_tube.jl" begin +@trixi_testset "elixir_mhd_briowu_shock_tube.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_briowu_shock_tube.jl"), - l2 = [0.17477712356961989, 0.19489623595086944, 0.3596546157640463, 0.0, 0.3723215736814466, 1.2060075775846403e-15, 0.36276754492568164, 0.0], - linf = [0.5797109945880677, 0.4372991899547103, 1.0906536287185835, 0.0, 1.0526758874956808, 5.995204332975845e-15, 1.5122922036932964, 0.0], - 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 - end + l2=[ + 0.17477712356961989, + 0.19489623595086944, + 0.3596546157640463, + 0.0, + 0.3723215736814466, + 1.2060075775846403e-15, + 0.36276754492568164, + 0.0, + ], + linf=[ + 0.5797109945880677, + 0.4372991899547103, + 1.0906536287185835, + 0.0, + 1.0526758874956808, + 5.995204332975845e-15, + 1.5122922036932964, + 0.0, + ], + 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 +end - @trixi_testset "elixir_mhd_torrilhon_shock_tube.jl" begin +@trixi_testset "elixir_mhd_torrilhon_shock_tube.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_torrilhon_shock_tube.jl"), - l2 = [0.45700904847931145, 0.4792535936512035, 0.340651203521865, 0.4478034694296928, 0.9204708961093411, 1.3216517820475193e-16, 0.28897419402047725, 0.25521206483145126], - linf = [1.2185238171352286, 0.8913202384963431, 0.8488793580488431, 0.973083603686, 1.660723397705417, 2.220446049250313e-16, 0.6874726847741993, 0.65536978110274]) - # 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 + l2=[ + 0.45700904847931145, + 0.4792535936512035, + 0.340651203521865, + 0.4478034694296928, + 0.9204708961093411, + 1.3216517820475193e-16, + 0.28897419402047725, + 0.25521206483145126, + ], + linf=[ + 1.2185238171352286, + 0.8913202384963431, + 0.8488793580488431, + 0.973083603686, + 1.660723397705417, + 2.220446049250313e-16, + 0.6874726847741993, + 0.65536978110274, + ]) + # 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_mhd_ryujones_shock_tube.jl" begin +@trixi_testset "elixir_mhd_ryujones_shock_tube.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ryujones_shock_tube.jl"), - l2 = [0.23469781891518154, 0.3916675299696121, 0.08245195301016353, 0.1745346945706147, 0.9606363432904367, 6.608258910237605e-17, 0.21542929107153735, 0.10705457908737925], - linf = [0.6447951791685409, 0.9461857095377463, 0.35074627554617605, 0.8515177411529542, 2.0770652030507053, 1.1102230246251565e-16, 0.49670855513788204, 0.24830199967863564], - tspan = (0.0, 0.1)) - # 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 + l2=[ + 0.23469781891518154, + 0.3916675299696121, + 0.08245195301016353, + 0.1745346945706147, + 0.9606363432904367, + 6.608258910237605e-17, + 0.21542929107153735, + 0.10705457908737925, + ], + linf=[ + 0.6447951791685409, + 0.9461857095377463, + 0.35074627554617605, + 0.8515177411529542, + 2.0770652030507053, + 1.1102230246251565e-16, + 0.49670855513788204, + 0.24830199967863564, + ], + tspan=(0.0, 0.1)) + # 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_mhd_shu_osher_shock_tube.jl" begin +@trixi_testset "elixir_mhd_shu_osher_shock_tube.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_shu_osher_shock_tube.jl"), - l2 = [1.01126210e+00, 8.27157902e+00, 1.30882545e+00, 0.00000000e+00, 5.21930435e+01, 6.56538824e-16, 1.01022340e+00, 0.00000000e+00], - linf = [2.87172004e+00, 2.26438057e+01, 4.16672442e+00, 0.00000000e+00, 1.35152372e+02, 3.44169138e-15, 2.83556069e+00, 0.00000000e+00], - tspan = (0.0, 0.2), - 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 - end + l2=[ + 1.01126210e+00, + 8.27157902e+00, + 1.30882545e+00, + 0.00000000e+00, + 5.21930435e+01, + 6.56538824e-16, + 1.01022340e+00, + 0.00000000e+00, + ], + linf=[ + 2.87172004e+00, + 2.26438057e+01, + 4.16672442e+00, + 0.00000000e+00, + 1.35152372e+02, + 3.44169138e-15, + 2.83556069e+00, + 0.00000000e+00, + ], + tspan=(0.0, 0.2), + 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 +end - @trixi_testset "elixir_mhd_shu_osher_shock_tube.jl with flipped shock direction" begin +@trixi_testset "elixir_mhd_shu_osher_shock_tube.jl with flipped shock direction" begin # Include this elixir to make `initial_condition_shu_osher_shock_tube_flipped` available, which is used below - trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_shu_osher_shock_tube.jl"), tspan=(0.0, 0.0)) + trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_shu_osher_shock_tube.jl"), + tspan = (0.0, 0.0)) @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_shu_osher_shock_tube.jl"), - l2 = [1.01539817e+00, 8.29625810e+00, 1.29548008e+00, 0.00000000e+00, 5.23565514e+01, 3.18641825e-16, 1.00485291e+00, 0.00000000e+00], - linf = [2.92876280e+00, 2.28341581e+01, 4.11643561e+00, 0.00000000e+00, 1.36966213e+02, 1.55431223e-15, 2.80548864e+00, 0.00000000e+00], - initial_condition = initial_condition_shu_osher_shock_tube_flipped, - boundary_conditions=BoundaryConditionDirichlet(initial_condition_shu_osher_shock_tube_flipped), - tspan = (0.0, 0.2), - 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 - end + l2=[ + 1.01539817e+00, + 8.29625810e+00, + 1.29548008e+00, + 0.00000000e+00, + 5.23565514e+01, + 3.18641825e-16, + 1.00485291e+00, + 0.00000000e+00, + ], + linf=[ + 2.92876280e+00, + 2.28341581e+01, + 4.11643561e+00, + 0.00000000e+00, + 1.36966213e+02, + 1.55431223e-15, + 2.80548864e+00, + 0.00000000e+00, + ], + initial_condition=initial_condition_shu_osher_shock_tube_flipped, + boundary_conditions=BoundaryConditionDirichlet(initial_condition_shu_osher_shock_tube_flipped), + tspan=(0.0, 0.2), + 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 +end end end # module diff --git a/test/test_tree_1d_mhdmulti.jl b/test/test_tree_1d_mhdmulti.jl index 9d0dbc65744..9bf34634886 100644 --- a/test/test_tree_1d_mhdmulti.jl +++ b/test/test_tree_1d_mhdmulti.jl @@ -8,99 +8,119 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @testset "MHD Multicomponent" begin +#! format: noindent - @trixi_testset "elixir_mhdmulti_ec.jl" begin +@trixi_testset "elixir_mhdmulti_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmulti_ec.jl"), - l2 = [0.08166807325620999, 0.054659228513541616, 0.054659228513541616, 0.15578125987042812, - 4.130462730494e-17, 0.054652588871500665, 0.054652588871500665, 0.008307405499637766, - 0.01661481099927553, 0.03322962199855106], - linf = [0.19019207422649645, 0.10059813883022888, 0.10059813883022888, 0.4407925743107146, - 1.1102230246251565e-16, 0.10528911365809623, 0.10528911365809623, 0.01737901809766182, - 0.03475803619532364, 0.06951607239064728]) - # 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 + l2=[0.08166807325620999, 0.054659228513541616, + 0.054659228513541616, 0.15578125987042812, + 4.130462730494e-17, 0.054652588871500665, + 0.054652588871500665, 0.008307405499637766, + 0.01661481099927553, 0.03322962199855106], + linf=[0.19019207422649645, 0.10059813883022888, + 0.10059813883022888, 0.4407925743107146, + 1.1102230246251565e-16, 0.10528911365809623, + 0.10528911365809623, 0.01737901809766182, + 0.03475803619532364, 0.06951607239064728]) + # 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_mhdmulti_ec.jl with flux_derigs_etal" begin +@trixi_testset "elixir_mhdmulti_ec.jl with flux_derigs_etal" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmulti_ec.jl"), - l2 = [0.08151404166186461, 0.054640238302693274, 0.054640238302693274, 0.15536125426328573, - 4.130462730494e-17, 0.054665489963920275, 0.054665489963920275, 0.008308349501359825, - 0.01661669900271965, 0.0332333980054393], - linf = [0.1824424257860952, 0.09734687137001484, 0.09734687137001484, 0.4243089502087325, - 1.1102230246251565e-16, 0.09558639591092555, 0.09558639591092555, 0.017364773041550624, - 0.03472954608310125, 0.0694590921662025], - volume_flux = flux_derigs_etal) - # 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 + l2=[0.08151404166186461, 0.054640238302693274, + 0.054640238302693274, 0.15536125426328573, + 4.130462730494e-17, 0.054665489963920275, + 0.054665489963920275, 0.008308349501359825, + 0.01661669900271965, 0.0332333980054393], + linf=[0.1824424257860952, 0.09734687137001484, + 0.09734687137001484, 0.4243089502087325, + 1.1102230246251565e-16, 0.09558639591092555, + 0.09558639591092555, 0.017364773041550624, + 0.03472954608310125, 0.0694590921662025], + volume_flux=flux_derigs_etal) + # 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_mhdmulti_es.jl" begin +@trixi_testset "elixir_mhdmulti_es.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmulti_es.jl"), - l2 = [0.07994082660130175, 0.053940174914031976, 0.053940174914031976, 0.15165513559250643, - 4.130462730494e-17, 0.05363207135290325, 0.05363207135290325, 0.008258265884659555, - 0.01651653176931911, 0.03303306353863822], - linf = [0.14101014428198477, 0.07762441749521025, 0.07762441749521025, 0.3381334453289866, - 1.1102230246251565e-16, 0.07003646400675223, 0.07003646400675223, 0.014962483760600165, - 0.02992496752120033, 0.05984993504240066]) - # 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 + l2=[0.07994082660130175, 0.053940174914031976, + 0.053940174914031976, 0.15165513559250643, + 4.130462730494e-17, 0.05363207135290325, + 0.05363207135290325, 0.008258265884659555, + 0.01651653176931911, 0.03303306353863822], + linf=[0.14101014428198477, 0.07762441749521025, + 0.07762441749521025, 0.3381334453289866, + 1.1102230246251565e-16, 0.07003646400675223, + 0.07003646400675223, 0.014962483760600165, + 0.02992496752120033, 0.05984993504240066]) + # 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_mhdmulti_convergence.jl" begin +@trixi_testset "elixir_mhdmulti_convergence.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmulti_convergence.jl"), - l2 = [1.7337265267786785e-5, 0.00032976971029271364, 0.0003297697102926479, 6.194071694759044e-5, - 4.130462730494001e-17, 0.00032596825025664136, 0.0003259682502567132, 2.5467510126885455e-5, - 5.093502025377091e-5, 0.00010187004050754182], - linf = [3.877554303711845e-5, 0.0012437848638874956, 0.0012437848638876898, 0.00016431262020277781, - 1.1102230246251565e-16, 0.0012443734922607112, 0.001244373492260704, 5.691007974162332e-5, - 0.00011382015948324664, 0.00022764031896649328]) - # 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 + l2=[1.7337265267786785e-5, 0.00032976971029271364, + 0.0003297697102926479, 6.194071694759044e-5, + 4.130462730494001e-17, 0.00032596825025664136, + 0.0003259682502567132, 2.5467510126885455e-5, + 5.093502025377091e-5, 0.00010187004050754182], + linf=[3.877554303711845e-5, 0.0012437848638874956, + 0.0012437848638876898, 0.00016431262020277781, + 1.1102230246251565e-16, 0.0012443734922607112, + 0.001244373492260704, 5.691007974162332e-5, + 0.00011382015948324664, 0.00022764031896649328]) + # 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_mhdmulti_briowu_shock_tube.jl" begin +@trixi_testset "elixir_mhdmulti_briowu_shock_tube.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmulti_briowu_shock_tube.jl"), - l2 = [0.1877830835572639, 0.3455841730726793, 0.0, 0.35413123388836687, - 8.745556626531982e-16, 0.3629920109231055, 0.0, 0.05329005553971236, - 0.10658011107942472], - linf = [0.4288187627971754, 1.0386547815614993, 0.0, 0.9541678878162702, - 5.773159728050814e-15, 1.4595119339458051, 0.0, 0.18201910908829552, - 0.36403821817659104], - 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 + l2=[0.1877830835572639, 0.3455841730726793, 0.0, + 0.35413123388836687, + 8.745556626531982e-16, 0.3629920109231055, 0.0, + 0.05329005553971236, + 0.10658011107942472], + linf=[0.4288187627971754, 1.0386547815614993, 0.0, + 0.9541678878162702, + 5.773159728050814e-15, 1.4595119339458051, 0.0, + 0.18201910908829552, + 0.36403821817659104], + 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 - +end end end # module diff --git a/test/test_tree_1d_shallowwater.jl b/test/test_tree_1d_shallowwater.jl index 27fe98c7d42..658f178c941 100644 --- a/test/test_tree_1d_shallowwater.jl +++ b/test/test_tree_1d_shallowwater.jl @@ -10,250 +10,381 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @testset "Shallow Water" begin - @trixi_testset "elixir_shallowwater_ec.jl" begin +#! format: noindent + +@trixi_testset "elixir_shallowwater_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_ec.jl"), - l2 = [0.244729018751225, 0.8583565222389505, 0.07330427577586297], - linf = [2.1635021283528504, 3.8717508164234453, 1.7711213427919539], - tspan = (0.0, 0.25)) - # 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 + l2=[0.244729018751225, 0.8583565222389505, 0.07330427577586297], + linf=[ + 2.1635021283528504, + 3.8717508164234453, + 1.7711213427919539, + ], + tspan=(0.0, 0.25)) + # 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_ec.jl with initial_condition_weak_blast_wave" begin +@trixi_testset "elixir_shallowwater_ec.jl with initial_condition_weak_blast_wave" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_ec.jl"), - l2 = [0.39464782107209717, 2.03880864210846, 4.1623084150546725e-10], - linf = [0.778905801278281, 3.2409883402608273, 7.419800190922032e-10], - initial_condition=initial_condition_weak_blast_wave, - tspan = (0.0, 0.25)) - # 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 + l2=[ + 0.39464782107209717, + 2.03880864210846, + 4.1623084150546725e-10, + ], + linf=[ + 0.778905801278281, + 3.2409883402608273, + 7.419800190922032e-10, + ], + initial_condition=initial_condition_weak_blast_wave, + tspan=(0.0, 0.25)) + # 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 +@trixi_testset "elixir_shallowwater_well_balanced.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced.jl"), - l2 = [0.10416666834254829, 1.4352935256803184e-14, 0.10416666834254838], - linf = [1.9999999999999996, 3.248036646353028e-14, 2.0], - tspan = (0.0, 0.25)) - # 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 + l2=[ + 0.10416666834254829, + 1.4352935256803184e-14, + 0.10416666834254838, + ], + linf=[1.9999999999999996, 3.248036646353028e-14, 2.0], + tspan=(0.0, 0.25)) + # 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 with FluxHydrostaticReconstruction" begin +@trixi_testset "elixir_shallowwater_well_balanced.jl with FluxHydrostaticReconstruction" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced.jl"), - l2 = [0.10416666834254835, 1.1891029971551825e-14, 0.10416666834254838], - linf = [2.0000000000000018, 2.4019608337954543e-14, 2.0], - surface_flux=(FluxHydrostaticReconstruction(flux_lax_friedrichs, hydrostatic_reconstruction_audusse_etal), flux_nonconservative_audusse_etal), - tspan = (0.0, 0.25)) - # 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 + l2=[ + 0.10416666834254835, + 1.1891029971551825e-14, + 0.10416666834254838, + ], + linf=[2.0000000000000018, 2.4019608337954543e-14, 2.0], + surface_flux=(FluxHydrostaticReconstruction(flux_lax_friedrichs, + hydrostatic_reconstruction_audusse_etal), + flux_nonconservative_audusse_etal), + tspan=(0.0, 0.25)) + # 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_wet_dry.jl with FluxHydrostaticReconstruction" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced_wet_dry.jl"), - l2 = [0.00965787167169024, 5.345454081916856e-14, 0.03857583749209928], - linf = [0.4999999999998892, 2.2447689894899726e-13, 1.9999999999999714], - tspan = (0.0, 0.25)) - # 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_wet_dry.jl with FluxHydrostaticReconstruction" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_well_balanced_wet_dry.jl"), + l2=[ + 0.00965787167169024, + 5.345454081916856e-14, + 0.03857583749209928, + ], + linf=[ + 0.4999999999998892, + 2.2447689894899726e-13, + 1.9999999999999714, + ], + tspan=(0.0, 0.25)) + # 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_source_terms.jl" begin +@trixi_testset "elixir_shallowwater_source_terms.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), - l2 = [0.0022363707373868713, 0.01576799981934617, 4.436491725585346e-5], - linf = [0.00893601803417754, 0.05939797350246456, 9.098379777405796e-5], - tspan = (0.0, 0.025)) - # 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 + l2=[ + 0.0022363707373868713, + 0.01576799981934617, + 4.436491725585346e-5, + ], + linf=[ + 0.00893601803417754, + 0.05939797350246456, + 9.098379777405796e-5, + ], + tspan=(0.0, 0.025)) + # 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_source_terms.jl with flux_hll" begin +@trixi_testset "elixir_shallowwater_source_terms.jl with flux_hll" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), - l2 = [0.0022758146627220154, 0.015864082886204556, 4.436491725585346e-5], - linf = [0.008457195427364006, 0.057201667446161064, 9.098379777405796e-5], - tspan = (0.0, 0.025), surface_flux=(flux_hll, flux_nonconservative_fjordholm_etal)) - # 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 + l2=[ + 0.0022758146627220154, + 0.015864082886204556, + 4.436491725585346e-5, + ], + linf=[ + 0.008457195427364006, + 0.057201667446161064, + 9.098379777405796e-5, + ], + tspan=(0.0, 0.025), + surface_flux=(flux_hll, flux_nonconservative_fjordholm_etal)) + # 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_source_terms_dirichlet.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms_dirichlet.jl"), - l2 = [0.0022851099219788917, 0.01560453773635554, 4.43649172558535e-5], - linf = [0.008934615705174398, 0.059403169140869405, 9.098379777405796e-5], - tspan = (0.0, 0.025)) - # 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_source_terms_dirichlet.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_source_terms_dirichlet.jl"), + l2=[ + 0.0022851099219788917, + 0.01560453773635554, + 4.43649172558535e-5, + ], + linf=[ + 0.008934615705174398, + 0.059403169140869405, + 9.098379777405796e-5, + ], + tspan=(0.0, 0.025)) + # 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_source_terms_dirichlet.jl with FluxHydrostaticReconstruction" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms_dirichlet.jl"), - l2 = [0.0022956052733432287, 0.015540053559855601, 4.43649172558535e-5], - linf = [0.008460440313118323, 0.05720939349382359, 9.098379777405796e-5], - surface_flux=(FluxHydrostaticReconstruction(flux_hll, hydrostatic_reconstruction_audusse_etal), flux_nonconservative_audusse_etal), - tspan = (0.0, 0.025)) - # 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_source_terms_dirichlet.jl with FluxHydrostaticReconstruction" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_source_terms_dirichlet.jl"), + l2=[ + 0.0022956052733432287, + 0.015540053559855601, + 4.43649172558535e-5, + ], + linf=[ + 0.008460440313118323, + 0.05720939349382359, + 9.098379777405796e-5, + ], + surface_flux=(FluxHydrostaticReconstruction(flux_hll, + hydrostatic_reconstruction_audusse_etal), + flux_nonconservative_audusse_etal), + tspan=(0.0, 0.025)) + # 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_nonperiodic.jl with Dirichlet boundary" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced_nonperiodic.jl"), - l2 = [1.725964362045055e-8, 5.0427180314307505e-16, 1.7259643530442137e-8], - linf = [3.844551077492042e-8, 3.469453422316143e-15, 3.844551077492042e-8], - tspan = (0.0, 0.25)) - # 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_nonperiodic.jl with Dirichlet boundary" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_well_balanced_nonperiodic.jl"), + l2=[ + 1.725964362045055e-8, + 5.0427180314307505e-16, + 1.7259643530442137e-8, + ], + linf=[ + 3.844551077492042e-8, + 3.469453422316143e-15, + 3.844551077492042e-8, + ], + tspan=(0.0, 0.25)) + # 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_nonperiodic.jl with wall boundary" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced_nonperiodic.jl"), - l2 = [1.7259643614361866e-8, 3.5519018243195145e-16, 1.7259643530442137e-8], - linf = [3.844551010878661e-8, 9.846474508971374e-16, 3.844551077492042e-8], - tspan = (0.0, 0.25), - boundary_condition = boundary_condition_slip_wall) - # 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_nonperiodic.jl with wall boundary" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_well_balanced_nonperiodic.jl"), + l2=[ + 1.7259643614361866e-8, + 3.5519018243195145e-16, + 1.7259643530442137e-8, + ], + linf=[ + 3.844551010878661e-8, + 9.846474508971374e-16, + 3.844551077492042e-8, + ], + tspan=(0.0, 0.25), + boundary_condition=boundary_condition_slip_wall) + # 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_shock_capturing.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_shock_capturing.jl"), - l2 = [0.07424140641160326, 0.2148642632748155, 0.0372579849000542], - linf = [1.1209754279344226, 1.3230788645853582, 0.8646939843534251], - tspan = (0.0, 0.05)) - # 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_shock_capturing.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_shock_capturing.jl"), + l2=[0.07424140641160326, 0.2148642632748155, 0.0372579849000542], + linf=[ + 1.1209754279344226, + 1.3230788645853582, + 0.8646939843534251, + ], + tspan=(0.0, 0.05)) + # 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_beach.jl" begin +@trixi_testset "elixir_shallowwater_beach.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_beach.jl"), - l2 = [0.17979210479598923, 1.2377495706611434, 6.289818963361573e-8], - linf = [0.845938394800688, 3.3740800777086575, 4.4541473087633676e-7], - tspan = (0.0, 0.05), - atol = 3e-10) # see https://github.com/trixi-framework/Trixi.jl/issues/1617 - # 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 + l2=[ + 0.17979210479598923, + 1.2377495706611434, + 6.289818963361573e-8, + ], + linf=[ + 0.845938394800688, + 3.3740800777086575, + 4.4541473087633676e-7, + ], + tspan=(0.0, 0.05), + atol=3e-10) # see https://github.com/trixi-framework/Trixi.jl/issues/1617 + # 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_parabolic_bowl.jl" begin +@trixi_testset "elixir_shallowwater_parabolic_bowl.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_parabolic_bowl.jl"), - l2 = [8.965981683033589e-5, 1.8565707397810857e-5, 4.1043039226164336e-17], - linf = [0.00041080213807871235, 0.00014823261488938177, 2.220446049250313e-16], - tspan = (0.0, 0.05)) - # 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 + l2=[ + 8.965981683033589e-5, + 1.8565707397810857e-5, + 4.1043039226164336e-17, + ], + linf=[ + 0.00041080213807871235, + 0.00014823261488938177, + 2.220446049250313e-16, + ], + tspan=(0.0, 0.05)) + # 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_shallow_water_quasi_1d_source_terms.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallow_water_quasi_1d_source_terms.jl"), + l2=[ + 6.37048760275098e-5, + 0.0002745658116815704, + 4.436491725647962e-6, + 8.872983451152218e-6, + ], + linf=[ + 0.00026747526881631956, + 0.0012106730729152249, + 9.098379777500165e-6, + 1.8196759554278685e-5, + ], + tspan=(0.0, 0.05)) + # 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_shallow_water_quasi_1d_source_terms.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallow_water_quasi_1d_source_terms.jl"), - l2 = [6.37048760275098e-5, 0.0002745658116815704, 4.436491725647962e-6, 8.872983451152218e-6], - linf = [0.00026747526881631956, 0.0012106730729152249, 9.098379777500165e-6, 1.8196759554278685e-5], - tspan = (0.0, 0.05)) - # 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_quasi_1d_well_balanced.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_quasi_1d_well_balanced.jl"), - l2 = [1.4250229186905198e-14, 2.495109919406496e-12, 7.408599286788738e-17, 2.7205812409138776e-16], - linf = [5.284661597215745e-14, 2.74056233065078e-12, 2.220446049250313e-16, 8.881784197001252e-16], - tspan = (0.0, 100.0)) - # 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_quasi_1d_well_balanced.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_quasi_1d_well_balanced.jl"), + l2=[ + 1.4250229186905198e-14, + 2.495109919406496e-12, + 7.408599286788738e-17, + 2.7205812409138776e-16, + ], + linf=[ + 5.284661597215745e-14, + 2.74056233065078e-12, + 2.220446049250313e-16, + 8.881784197001252e-16, + ], + tspan=(0.0, 100.0)) + # 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 end # module diff --git a/test/test_tree_1d_shallowwater_twolayer.jl b/test/test_tree_1d_shallowwater_twolayer.jl index 93b8a6f70a5..a504f4f93a6 100644 --- a/test/test_tree_1d_shallowwater_twolayer.jl +++ b/test/test_tree_1d_shallowwater_twolayer.jl @@ -10,75 +10,95 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @testset "Shallow Water Two layer" begin - @trixi_testset "elixir_shallowwater_twolayer_convergence.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_twolayer_convergence.jl"), - l2 = [0.0050681532925156945, 0.002089013899370176, 0.005105544300292713, 0.002526442122643306, - 0.0004744186597732706], - linf = [0.022256679217306008, 0.005421833004652266, 0.02233993939574197, 0.008765261497422516, - 0.0008992474511784199], - tspan = (0.0, 0.25)) - # 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 +#! format: noindent - @trixi_testset "elixir_shallowwater_twolayer_convergence.jl with flux_es_fjordholm_etal" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_twolayer_convergence.jl"), - l2 = [0.0027681377074701345, 0.0018007543202559165, 0.0028036917433720576, - 0.0013980358596935737, 0.0004744186597732706], - linf = [0.005699303919826093, 0.006432952918256296, 0.0058507082844360125, 0.002717615543961216, - 0.0008992474511784199], - surface_flux=(flux_es_fjordholm_etal, flux_nonconservative_fjordholm_etal), - tspan = (0.0, 0.25)) - # 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 +@trixi_testset "elixir_shallowwater_twolayer_convergence.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_twolayer_convergence.jl"), + l2=[0.0050681532925156945, 0.002089013899370176, + 0.005105544300292713, 0.002526442122643306, + 0.0004744186597732706], + linf=[0.022256679217306008, 0.005421833004652266, + 0.02233993939574197, 0.008765261497422516, + 0.0008992474511784199], + tspan=(0.0, 0.25)) + # 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 - @trixi_testset "elixir_shallowwater_twolayer_well_balanced.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_twolayer_well_balanced.jl"), - l2 = [8.949288784402005e-16, 4.0636427176237915e-17, 0.001002881985401548, - 2.133351105037203e-16, 0.0010028819854016578], - linf = [2.6229018956769323e-15, 1.878451903240623e-16, 0.005119880996670156, - 8.003199803957679e-16, 0.005119880996670666], - tspan = (0.0, 0.25)) - # 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 +@trixi_testset "elixir_shallowwater_twolayer_convergence.jl with flux_es_fjordholm_etal" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_twolayer_convergence.jl"), + l2=[0.0027681377074701345, 0.0018007543202559165, + 0.0028036917433720576, + 0.0013980358596935737, 0.0004744186597732706], + linf=[0.005699303919826093, 0.006432952918256296, + 0.0058507082844360125, 0.002717615543961216, + 0.0008992474511784199], + surface_flux=(flux_es_fjordholm_etal, + flux_nonconservative_fjordholm_etal), + tspan=(0.0, 0.25)) + # 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 - @trixi_testset "elixir_shallowwater_twolayer_dam_break.jl with flux_lax_friedrichs" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_twolayer_dam_break.jl"), - l2 = [0.10010269243463918, 0.5668733957648654, 0.08759617327649398, - 0.4538443183566172, 0.013638618139749523], - linf = [0.5854202777756559, 2.1278930820498934, 0.5193686074348809, 1.8071213168086229, 0.5], - surface_flux = (flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), - tspan = (0.0, 0.25)) - # 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 +@trixi_testset "elixir_shallowwater_twolayer_well_balanced.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_twolayer_well_balanced.jl"), + l2=[8.949288784402005e-16, 4.0636427176237915e-17, + 0.001002881985401548, + 2.133351105037203e-16, 0.0010028819854016578], + linf=[2.6229018956769323e-15, 1.878451903240623e-16, + 0.005119880996670156, + 8.003199803957679e-16, 0.005119880996670666], + tspan=(0.0, 0.25)) + # 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 +@trixi_testset "elixir_shallowwater_twolayer_dam_break.jl with flux_lax_friedrichs" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_twolayer_dam_break.jl"), + l2=[0.10010269243463918, 0.5668733957648654, + 0.08759617327649398, + 0.4538443183566172, 0.013638618139749523], + linf=[ + 0.5854202777756559, + 2.1278930820498934, + 0.5193686074348809, + 1.8071213168086229, + 0.5, + ], + surface_flux=(flux_lax_friedrichs, + flux_nonconservative_fjordholm_etal), + tspan=(0.0, 0.25)) + # 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 end # module diff --git a/test/test_tree_2d_acoustics.jl b/test/test_tree_2d_acoustics.jl index dbfe38dbde2..89bccbf8ca1 100644 --- a/test/test_tree_2d_acoustics.jl +++ b/test/test_tree_2d_acoustics.jl @@ -8,80 +8,137 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") @testset "Acoustic Perturbation" begin - @trixi_testset "elixir_acoustics_convergence.jl" begin +#! format: noindent + +@trixi_testset "elixir_acoustics_convergence.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_acoustics_convergence.jl"), - l2 = [0.0019921138796370834, 0.002090394698052287, 0.0006091925854593805, 0.0, 0.0, 0.0, 0.0], - linf = [0.00769282588065634, 0.008276649669227254, 0.004196479023954813, 0.0, 0.0, 0.0, 0.0]) - # 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 + l2=[ + 0.0019921138796370834, + 0.002090394698052287, + 0.0006091925854593805, + 0.0, + 0.0, + 0.0, + 0.0, + ], + linf=[ + 0.00769282588065634, + 0.008276649669227254, + 0.004196479023954813, + 0.0, + 0.0, + 0.0, + 0.0, + ]) + # 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_acoustics_gauss.jl" begin +@trixi_testset "elixir_acoustics_gauss.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_acoustics_gauss.jl"), - l2 = [0.08005276517890283, 0.08005276517890268, 0.4187202920734123, 0.0, 0.0, 0.0, 0.0], - linf = [0.17261097190220992, 0.17261097190220973, 1.13601894068238, 0.0, 0.0, 0.0, 0.0]) - # 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 + l2=[ + 0.08005276517890283, + 0.08005276517890268, + 0.4187202920734123, + 0.0, + 0.0, + 0.0, + 0.0, + ], + linf=[ + 0.17261097190220992, + 0.17261097190220973, + 1.13601894068238, + 0.0, + 0.0, + 0.0, + 0.0, + ]) + # 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_acoustics_gaussian_source.jl" begin +@trixi_testset "elixir_acoustics_gaussian_source.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_acoustics_gaussian_source.jl"), - l2 = [0.004296394903650806, 0.004241280404758938, 0.006269684906035964, 0.0, 0.0, 0.0, 0.0], - linf = [0.03970270697049378, 0.04151096349298151, 0.0640019829058819, 0.0, 0.0, 0.0, 0.0]) - # 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 + l2=[ + 0.004296394903650806, + 0.004241280404758938, + 0.006269684906035964, + 0.0, + 0.0, + 0.0, + 0.0, + ], + linf=[ + 0.03970270697049378, + 0.04151096349298151, + 0.0640019829058819, + 0.0, + 0.0, + 0.0, + 0.0, + ]) + # 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_acoustics_gauss_wall.jl" begin +@trixi_testset "elixir_acoustics_gauss_wall.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_acoustics_gauss_wall.jl"), - l2 = [0.019419398248465843, 0.019510701017551826, 0.04818246051887614, - 7.382060834820337e-17, 0.0, 1.4764121669640674e-16, 1.4764121669640674e-16], - linf = [0.18193631937316496, 0.1877464607867628, 1.0355388011792845, - 2.220446049250313e-16, 0.0, 4.440892098500626e-16, 4.440892098500626e-16]) - # 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 + l2=[0.019419398248465843, 0.019510701017551826, + 0.04818246051887614, + 7.382060834820337e-17, 0.0, 1.4764121669640674e-16, + 1.4764121669640674e-16], + linf=[0.18193631937316496, 0.1877464607867628, + 1.0355388011792845, + 2.220446049250313e-16, 0.0, 4.440892098500626e-16, + 4.440892098500626e-16]) + # 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_acoustics_monopole.jl" begin +@trixi_testset "elixir_acoustics_monopole.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_acoustics_monopole.jl"), - l2 = [0.006816790293009947, 0.0065068948357351625, 0.008724512056168938, - 0.0009894398191644543, 0.0, 7.144325530679576e-17, 7.144325530679576e-17], - linf = [1.000633375007386, 0.5599788929862504, 0.5738432957070382, - 0.015590137026938428, 0.0, 2.220446049250313e-16, 2.220446049250313e-16], - maxiters=50) - # 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 + l2=[0.006816790293009947, 0.0065068948357351625, + 0.008724512056168938, + 0.0009894398191644543, 0.0, 7.144325530679576e-17, + 7.144325530679576e-17], + linf=[1.000633375007386, 0.5599788929862504, 0.5738432957070382, + 0.015590137026938428, 0.0, 2.220446049250313e-16, + 2.220446049250313e-16], + maxiters=50) + # 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 -end # module \ No newline at end of file +end # module diff --git a/test/test_tree_2d_advection.jl b/test/test_tree_2d_advection.jl index 365011eef53..b111651aa6f 100644 --- a/test/test_tree_2d_advection.jl +++ b/test/test_tree_2d_advection.jl @@ -8,346 +8,349 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") @testset "Linear scalar advection" begin - @trixi_testset "elixir_advection_basic.jl" begin +#! format: noindent + +@trixi_testset "elixir_advection_basic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), - # Expected errors are exactly the same as in the parallel test! - l2 = [8.311947673061856e-6], - linf = [6.627000273229378e-5], - # Let the small basic test run to the end - coverage_override = (maxiters=10^5,)) - # 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 + # Expected errors are exactly the same as in the parallel test! + l2=[8.311947673061856e-6], + linf=[6.627000273229378e-5], + # Let the small basic test run to the end + coverage_override=(maxiters = 10^5,)) + # 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_extended.jl with polydeg=1" begin +@trixi_testset "elixir_advection_extended.jl with polydeg=1" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2 = [0.02134571266411136], - linf = [0.04347734797775926], - polydeg=1) - # 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 + l2=[0.02134571266411136], + linf=[0.04347734797775926], + polydeg=1) + # 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 - @trixi_testset "elixir_advection_restart.jl" begin +@trixi_testset "elixir_advection_restart.jl" begin using OrdinaryDiffEq: SSPRK43 println("═"^100) println(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl")) trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - alg = SSPRK43(), tspan = (0.0, 10.0)) + alg = SSPRK43(), tspan = (0.0, 10.0)) l2_expected, linf_expected = analysis_callback(sol) println("═"^100) println(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl")) # Errors are exactly the same as in the elixir_advection_extended.jl trixi_include(@__MODULE__, joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), - alg = SSPRK43()) + alg = SSPRK43()) l2_actual, linf_actual = analysis_callback(sol) - + @test l2_actual == l2_expected @test linf_actual == linf_expected - end +end - @trixi_testset "elixir_advection_mortar.jl" begin +@trixi_testset "elixir_advection_mortar.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_mortar.jl"), - # Expected errors are exactly the same as in the parallel test! - l2 = [0.0015188466707237375], - linf = [0.008446655719187679]) + # Expected errors are exactly the same as in the parallel test! + l2=[0.0015188466707237375], + linf=[0.008446655719187679]) - # 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 + # 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_amr.jl" begin +@trixi_testset "elixir_advection_amr.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr.jl"), - # Expected errors are exactly the same as in the parallel test! - l2 = [4.913300828257469e-5], - linf = [0.00045263895394385967], - # Let this test run to the end to cover some AMR code - coverage_override = (maxiters=10^5,)) - # 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 + # Expected errors are exactly the same as in the parallel test! + l2=[4.913300828257469e-5], + linf=[0.00045263895394385967], + # Let this test run to the end to cover some AMR code + coverage_override=(maxiters = 10^5,)) + # 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_amr_nonperiodic.jl" begin +@trixi_testset "elixir_advection_amr_nonperiodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_nonperiodic.jl"), - # Expected errors are exactly the same as in the parallel test! - l2 = [3.2207388565869075e-5], - linf = [0.0007508059772436404], - 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 - end + # Expected errors are exactly the same as in the parallel test! + l2=[3.2207388565869075e-5], + linf=[0.0007508059772436404], + 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 +end - @trixi_testset "elixir_advection_amr_solution_independent.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_solution_independent.jl"), - l2 = [4.949660644033807e-5], - linf = [0.0004867846262313763], - 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 +@trixi_testset "elixir_advection_amr_solution_independent.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_amr_solution_independent.jl"), + l2=[4.949660644033807e-5], + linf=[0.0004867846262313763], + 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 - end +end - @trixi_testset "elixir_advection_amr_visualization.jl" begin +@trixi_testset "elixir_advection_amr_visualization.jl" begin # To make CI tests work, disable showing a plot window with the GR backend of the Plots package # Xref: https://github.com/jheinen/GR.jl/issues/278 # Xref: https://github.com/JuliaPlots/Plots.jl/blob/8cc6d9d48755ba452a2835f9b89d3880e9945377/test/runtests.jl#L103 if !isinteractive() - restore = get(ENV, "GKSwstype", nothing) - ENV["GKSwstype"] = "100" + restore = get(ENV, "GKSwstype", nothing) + ENV["GKSwstype"] = "100" end @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_visualization.jl"), - l2 = [0.0007225529919720868], - linf = [0.005954447875428925], - coverage_override = (maxiters=6,)) + l2=[0.0007225529919720868], + linf=[0.005954447875428925], + coverage_override=(maxiters = 6,)) # Restore GKSwstype to previous value (if it was set) if !isinteractive() - if isnothing(restore) - delete!(ENV, "GKSwstype") - else - ENV["GKSwstype"] = restore - end + if isnothing(restore) + delete!(ENV, "GKSwstype") + else + ENV["GKSwstype"] = restore + end end - end +end - @trixi_testset "elixir_advection_timeintegration.jl" begin +@trixi_testset "elixir_advection_timeintegration.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_timeintegration.jl"), - l2 = [2.4976030518356626e-5], - linf = [0.0005531580316338533], - # Let this test terminate by time instead of maxiters to cover some lines - # in time_integration/methods_2N.jl - coverage_override = (maxiters=10^5, tspan=(0.0, 0.1))) - # 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)) < 15000 - end + l2=[2.4976030518356626e-5], + linf=[0.0005531580316338533], + # Let this test terminate by time instead of maxiters to cover some lines + # in time_integration/methods_2N.jl + coverage_override=(maxiters = 10^5, tspan = (0.0, 0.1))) + # 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)) < 15000 end - end +end +end - @trixi_testset "elixir_advection_timeintegration.jl with carpenter_kennedy_erk43" begin +@trixi_testset "elixir_advection_timeintegration.jl with carpenter_kennedy_erk43" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_timeintegration.jl"), - l2 = [2.5314747030031457e-5], - linf = [0.0005437136621948904], - ode_algorithm=Trixi.CarpenterKennedy2N43(), - cfl = 1.0) - # 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)) < 15000 - end - end + l2=[2.5314747030031457e-5], + linf=[0.0005437136621948904], + ode_algorithm=Trixi.CarpenterKennedy2N43(), + cfl=1.0) + # 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)) < 15000 + end +end - @trixi_testset "elixir_advection_timeintegration.jl with carpenter_kennedy_erk43 with maxiters=1" begin +@trixi_testset "elixir_advection_timeintegration.jl with carpenter_kennedy_erk43 with maxiters=1" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_timeintegration.jl"), - l2 = [1.2135350502911197e-5], - linf = [9.999985420537649e-5], - ode_algorithm=Trixi.CarpenterKennedy2N43(), - cfl = 1.0, - maxiters = 1) - # 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)) < 15000 - end - end + l2=[1.2135350502911197e-5], + linf=[9.999985420537649e-5], + ode_algorithm=Trixi.CarpenterKennedy2N43(), + cfl=1.0, + maxiters=1) + # 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)) < 15000 + end +end - @trixi_testset "elixir_advection_timeintegration.jl with parsani_ketcheson_deconinck_erk94" begin +@trixi_testset "elixir_advection_timeintegration.jl with parsani_ketcheson_deconinck_erk94" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_timeintegration.jl"), - l2 = [2.4976673477385313e-5], - linf = [0.0005534166916640881], - ode_algorithm=Trixi.ParsaniKetchesonDeconinck3Sstar94()) - # 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)) < 15000 - end - end + l2=[2.4976673477385313e-5], + linf=[0.0005534166916640881], + ode_algorithm=Trixi.ParsaniKetchesonDeconinck3Sstar94()) + # 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)) < 15000 + end +end - @trixi_testset "elixir_advection_timeintegration.jl with parsani_ketcheson_deconinck_erk32" begin +@trixi_testset "elixir_advection_timeintegration.jl with parsani_ketcheson_deconinck_erk32" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_timeintegration.jl"), - l2 = [3.667894656471403e-5], - linf = [0.0005799465470165757], - ode_algorithm=Trixi.ParsaniKetchesonDeconinck3Sstar32(), - cfl = 1.0) - # 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)) < 15000 - end - end + l2=[3.667894656471403e-5], + linf=[0.0005799465470165757], + ode_algorithm=Trixi.ParsaniKetchesonDeconinck3Sstar32(), + cfl=1.0) + # 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)) < 15000 + end +end - @trixi_testset "elixir_advection_timeintegration.jl with parsani_ketcheson_deconinck_erk32 with maxiters=1" begin +@trixi_testset "elixir_advection_timeintegration.jl with parsani_ketcheson_deconinck_erk32 with maxiters=1" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_timeintegration.jl"), - l2 = [1.2198725469737875e-5], - linf = [9.977247740793407e-5], - ode_algorithm=Trixi.ParsaniKetchesonDeconinck3Sstar32(), - cfl = 1.0, - maxiters = 1) - # 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)) < 15000 - end - end + l2=[1.2198725469737875e-5], + linf=[9.977247740793407e-5], + ode_algorithm=Trixi.ParsaniKetchesonDeconinck3Sstar32(), + cfl=1.0, + maxiters=1) + # 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)) < 15000 + end +end - @trixi_testset "elixir_advection_callbacks.jl" begin +@trixi_testset "elixir_advection_callbacks.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_callbacks.jl"), - l2 = [8.311947673061856e-6], - linf = [6.627000273229378e-5]) - # 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 + l2=[8.311947673061856e-6], + linf=[6.627000273229378e-5]) + # 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 # Coverage test for all initial conditions @testset "Linear scalar advection: Tests for initial conditions" begin - # Linear scalar advection - @trixi_testset "elixir_advection_extended.jl with initial_condition_sin_sin" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2 = [0.0001420618061089383], - linf = [0.0007140570281718439], - maxiters = 1, - initial_condition = Trixi.initial_condition_sin_sin) - # 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 + # Linear scalar advection + @trixi_testset "elixir_advection_extended.jl with initial_condition_sin_sin" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), + l2=[0.0001420618061089383], + linf=[0.0007140570281718439], + maxiters=1, + initial_condition=Trixi.initial_condition_sin_sin) + # 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 - @trixi_testset "elixir_advection_extended.jl with initial_condition_constant" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2 = [3.8302867746057483e-16], - linf = [1.3322676295501878e-15], - maxiters = 1, - initial_condition = initial_condition_constant) - # 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_extended.jl with initial_condition_constant" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), + l2=[3.8302867746057483e-16], + linf=[1.3322676295501878e-15], + maxiters=1, + initial_condition=initial_condition_constant) + # 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_extended.jl with initial_condition_linear_x_y" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2 = [2.7276160570381226e-16], - linf = [5.10702591327572e-15], - maxiters = 1, - initial_condition = Trixi.initial_condition_linear_x_y, - boundary_conditions = Trixi.boundary_condition_linear_x_y, - periodicity=false) - # 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 + @trixi_testset "elixir_advection_extended.jl with initial_condition_linear_x_y" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), + l2=[2.7276160570381226e-16], + linf=[5.10702591327572e-15], + maxiters=1, + initial_condition=Trixi.initial_condition_linear_x_y, + boundary_conditions=Trixi.boundary_condition_linear_x_y, + periodicity=false) + # 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 - @trixi_testset "elixir_advection_extended.jl with initial_condition_linear_x" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2 = [1.5121648229368207e-16], - linf = [1.3322676295501878e-15], - maxiters = 1, - initial_condition = Trixi.initial_condition_linear_x, - boundary_conditions = Trixi.boundary_condition_linear_x, - periodicity=false) - # 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_extended.jl with initial_condition_linear_x" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), + l2=[1.5121648229368207e-16], + linf=[1.3322676295501878e-15], + maxiters=1, + initial_condition=Trixi.initial_condition_linear_x, + boundary_conditions=Trixi.boundary_condition_linear_x, + periodicity=false) + # 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_extended.jl with initial_condition_linear_y" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2 = [1.714292614252588e-16], - linf = [2.220446049250313e-15], - maxiters = 1, - initial_condition = Trixi.initial_condition_linear_y, - boundary_conditions = Trixi.boundary_condition_linear_y, - periodicity=false) - # 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_extended.jl with initial_condition_linear_y" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), + l2=[1.714292614252588e-16], + linf=[2.220446049250313e-15], + maxiters=1, + initial_condition=Trixi.initial_condition_linear_y, + boundary_conditions=Trixi.boundary_condition_linear_y, + periodicity=false) + # 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 end # module diff --git a/test/test_tree_2d_euler.jl b/test/test_tree_2d_euler.jl index 79a650ded8a..af7c5d8324c 100644 --- a/test/test_tree_2d_euler.jl +++ b/test/test_tree_2d_euler.jl @@ -8,537 +8,915 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") @testset "Compressible Euler" begin - @trixi_testset "elixir_euler_source_terms.jl" begin +#! format: noindent + +@trixi_testset "elixir_euler_source_terms.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms.jl"), - l2 = [9.321181253186009e-7, 1.4181210743438511e-6, 1.4181210743487851e-6, 4.824553091276693e-6], - linf = [9.577246529612893e-6, 1.1707525976012434e-5, 1.1707525976456523e-5, 4.8869615580926506e-5]) - # 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_convergence_pure_fv.jl" begin + l2=[ + 9.321181253186009e-7, + 1.4181210743438511e-6, + 1.4181210743487851e-6, + 4.824553091276693e-6, + ], + linf=[ + 9.577246529612893e-6, + 1.1707525976012434e-5, + 1.1707525976456523e-5, + 4.8869615580926506e-5, + ]) + # 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_convergence_pure_fv.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence_pure_fv.jl"), - l2 = [0.026440292358506527, 0.013245905852168414, 0.013245905852168479, 0.03912520302609374], - linf = [0.042130817806361964, 0.022685499230187034, 0.022685499230187922, 0.06999771202145322]) - # 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_density_wave.jl" begin + l2=[ + 0.026440292358506527, + 0.013245905852168414, + 0.013245905852168479, + 0.03912520302609374, + ], + linf=[ + 0.042130817806361964, + 0.022685499230187034, + 0.022685499230187922, + 0.06999771202145322, + ]) + # 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_density_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_density_wave.jl"), - l2 = [0.0010600778457964775, 0.00010600778457634275, 0.00021201556915872665, 2.650194614399671e-5], - linf = [0.006614198043413566, 0.0006614198043973507, 0.001322839608837334, 0.000165354951256802], - tspan = (0.0, 0.5)) - # 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_source_terms_nonperiodic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonperiodic.jl"), - l2 = [2.259440511766445e-6, 2.318888155713922e-6, 2.3188881557894307e-6, 6.3327863238858925e-6], - linf = [1.498738264560373e-5, 1.9182011928187137e-5, 1.918201192685487e-5, 6.0526717141407005e-5]) - # 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_ec.jl" begin + l2=[ + 0.0010600778457964775, + 0.00010600778457634275, + 0.00021201556915872665, + 2.650194614399671e-5, + ], + linf=[ + 0.006614198043413566, + 0.0006614198043973507, + 0.001322839608837334, + 0.000165354951256802, + ], + tspan=(0.0, 0.5)) + # 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_source_terms_nonperiodic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonperiodic.jl"), + l2=[ + 2.259440511766445e-6, + 2.318888155713922e-6, + 2.3188881557894307e-6, + 6.3327863238858925e-6, + ], + linf=[ + 1.498738264560373e-5, + 1.9182011928187137e-5, + 1.918201192685487e-5, + 6.0526717141407005e-5, + ]) + # 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_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.061751715597716854, 0.05018223615408711, 0.05018989446443463, 0.225871559730513], - linf = [0.29347582879608825, 0.31081249232844693, 0.3107380389947736, 1.0540358049885143]) - # 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_ec.jl with flux_kennedy_gruber" begin + l2=[ + 0.061751715597716854, + 0.05018223615408711, + 0.05018989446443463, + 0.225871559730513, + ], + linf=[ + 0.29347582879608825, + 0.31081249232844693, + 0.3107380389947736, + 1.0540358049885143, + ]) + # 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_ec.jl with flux_kennedy_gruber" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.03481471610306124, 0.027694280613944234, 0.027697905866996532, 0.12932052501462554], - linf = [0.31052098400669004, 0.3481295959664616, 0.34807152194137336, 1.1044947556170719], - maxiters = 10, - surface_flux = flux_kennedy_gruber, - volume_flux = flux_kennedy_gruber) - # 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_ec.jl with flux_chandrashekar" begin + l2=[ + 0.03481471610306124, + 0.027694280613944234, + 0.027697905866996532, + 0.12932052501462554, + ], + linf=[ + 0.31052098400669004, + 0.3481295959664616, + 0.34807152194137336, + 1.1044947556170719, + ], + maxiters=10, + surface_flux=flux_kennedy_gruber, + volume_flux=flux_kennedy_gruber) + # 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_ec.jl with flux_chandrashekar" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.03481122603050542, 0.027662840593087695, 0.027665658732350273, 0.12927455860656786], - linf = [0.3110089578739834, 0.34888111987218107, 0.3488278669826813, 1.1056349046774305], - maxiters = 10, - surface_flux = flux_chandrashekar, - volume_flux = flux_chandrashekar) - # 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_shockcapturing.jl" begin + l2=[ + 0.03481122603050542, + 0.027662840593087695, + 0.027665658732350273, + 0.12927455860656786, + ], + linf=[ + 0.3110089578739834, + 0.34888111987218107, + 0.3488278669826813, + 1.1056349046774305, + ], + maxiters=10, + surface_flux=flux_chandrashekar, + volume_flux=flux_chandrashekar) + # 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_shockcapturing.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing.jl"), - l2 = [0.05380629130119074, 0.04696798008325309, 0.04697067787841479, 0.19687382235494968], - linf = [0.18527440131928286, 0.2404798030563736, 0.23269573860381076, 0.6874012187446894]) - # 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_shockcapturing_subcell.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing_subcell.jl"), - l2 = [0.08508147906199143, 0.04510299017724501, 0.045103019801950375, 0.6930704343869766], - linf = [0.31123546471463326, 0.5616274869594462, 0.5619692712224448, 2.88670199345138]) - # 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)) < 15000 - end - end - - @trixi_testset "elixir_euler_blast_wave.jl" begin + l2=[ + 0.05380629130119074, + 0.04696798008325309, + 0.04697067787841479, + 0.19687382235494968, + ], + linf=[ + 0.18527440131928286, + 0.2404798030563736, + 0.23269573860381076, + 0.6874012187446894, + ]) + # 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_shockcapturing_subcell.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_shockcapturing_subcell.jl"), + l2=[ + 0.08508147906199143, + 0.04510299017724501, + 0.045103019801950375, + 0.6930704343869766, + ], + linf=[ + 0.31123546471463326, + 0.5616274869594462, + 0.5619692712224448, + 2.88670199345138, + ]) + # 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)) < 15000 + end +end + +@trixi_testset "elixir_euler_blast_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blast_wave.jl"), - l2 = [0.14170569763947993, 0.11647068900798814, 0.11647072556898294, 0.3391989213659599], - linf = [1.6544204510794196, 1.35194638484646, 1.3519463848472744, 1.831228461662809], - maxiters = 30) - # 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_blast_wave_neuralnetwork_perssonperaire.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl"), - l2 = [0.4758794741390833, 0.21045415565179362, 0.21045325630191866, 0.7022517958549878], - linf = [1.710832148442441, 0.9711663578827681, 0.9703787873632452, 2.9619758810532653], - initial_refinement_level = 4, - maxiters = 50) - end - - @trixi_testset "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl"), - l2 = [0.472445774440313, 0.2090782039442978, 0.20885558673697927, 0.700569533591275], - linf = [1.7066492792835155, 0.9856122336679919, 0.9784316656930644, 2.9372978989672873], - initial_refinement_level = 4, - maxiters = 50) - end - - @trixi_testset "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl with mortars" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl"), - l2 = [0.016486406327766923, 0.03097329879894433, 0.03101012918167401, 0.15157175775429868], - linf = [0.27688647744873407, 0.5653724536715139, 0.565695523611447, 2.513047611639946], - refinement_patches=( - (type="box", coordinates_min=(-0.25, -0.25), coordinates_max=(0.25, 0.25)), - (type="box", coordinates_min=(-0.125, -0.125), coordinates_max=(0.125, 0.125)),), - initial_refinement_level = 4, - maxiters = 5) - end - - @trixi_testset "elixir_euler_blast_wave_neuralnetwork_cnn.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blast_wave_neuralnetwork_cnn.jl"), - l2 = [0.4795795496408325, 0.2125148972465021, 0.21311260934645868, 0.7033388737692883], - linf = [1.8295385992182336, 0.9687795218482794, 0.9616033072376108, 2.9513245978047133], - initial_refinement_level = 4, - maxiters = 50, - rtol = 1.0e-7) - end - - @trixi_testset "elixir_euler_blast_wave_pure_fv.jl" begin + l2=[ + 0.14170569763947993, + 0.11647068900798814, + 0.11647072556898294, + 0.3391989213659599, + ], + linf=[ + 1.6544204510794196, + 1.35194638484646, + 1.3519463848472744, + 1.831228461662809, + ], + maxiters=30) + # 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_blast_wave_neuralnetwork_perssonperaire.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl"), + l2=[ + 0.4758794741390833, + 0.21045415565179362, + 0.21045325630191866, + 0.7022517958549878, + ], + linf=[ + 1.710832148442441, + 0.9711663578827681, + 0.9703787873632452, + 2.9619758810532653, + ], + initial_refinement_level=4, + maxiters=50) +end + +@trixi_testset "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl"), + l2=[ + 0.472445774440313, + 0.2090782039442978, + 0.20885558673697927, + 0.700569533591275, + ], + linf=[ + 1.7066492792835155, + 0.9856122336679919, + 0.9784316656930644, + 2.9372978989672873, + ], + initial_refinement_level=4, + maxiters=50) +end + +@trixi_testset "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl with mortars" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl"), + l2=[ + 0.016486406327766923, + 0.03097329879894433, + 0.03101012918167401, + 0.15157175775429868, + ], + linf=[ + 0.27688647744873407, + 0.5653724536715139, + 0.565695523611447, + 2.513047611639946, + ], + refinement_patches=((type = "box", + coordinates_min = (-0.25, -0.25), + coordinates_max = (0.25, 0.25)), + (type = "box", + coordinates_min = (-0.125, -0.125), + coordinates_max = (0.125, 0.125))), + initial_refinement_level=4, + maxiters=5) +end + +@trixi_testset "elixir_euler_blast_wave_neuralnetwork_cnn.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_blast_wave_neuralnetwork_cnn.jl"), + l2=[ + 0.4795795496408325, + 0.2125148972465021, + 0.21311260934645868, + 0.7033388737692883, + ], + linf=[ + 1.8295385992182336, + 0.9687795218482794, + 0.9616033072376108, + 2.9513245978047133, + ], + initial_refinement_level=4, + maxiters=50, + rtol=1.0e-7) +end + +@trixi_testset "elixir_euler_blast_wave_pure_fv.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blast_wave_pure_fv.jl"), - l2 = [0.39957047631960346, 0.21006912294983154, 0.21006903549932, 0.6280328163981136], - linf = [2.20417889887697, 1.5487238480003327, 1.5486788679247812, 2.4656795949035857], - tspan = (0.0, 0.5), - # Let this test run longer to cover some lines in flux_hllc - coverage_override = (maxiters=10^5, tspan=(0.0, 0.1))) - # 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_blast_wave_amr.jl" begin + l2=[ + 0.39957047631960346, + 0.21006912294983154, + 0.21006903549932, + 0.6280328163981136, + ], + linf=[ + 2.20417889887697, + 1.5487238480003327, + 1.5486788679247812, + 2.4656795949035857, + ], + tspan=(0.0, 0.5), + # Let this test run longer to cover some lines in flux_hllc + coverage_override=(maxiters = 10^5, tspan = (0.0, 0.1))) + # 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_blast_wave_amr.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blast_wave_amr.jl"), - l2 = [0.6835576416907511, 0.2839963955262972, 0.28399565983676, 0.7229447806293277], - linf = [3.0969614882801393, 1.7967947300740248, 1.7967508302506658, 3.040149575567518], - tspan = (0.0, 1.0), - 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 - end - - @trixi_testset "elixir_euler_sedov_blast_wave.jl" begin + l2=[ + 0.6835576416907511, + 0.2839963955262972, + 0.28399565983676, + 0.7229447806293277, + ], + linf=[ + 3.0969614882801393, + 1.7967947300740248, + 1.7967508302506658, + 3.040149575567518, + ], + tspan=(0.0, 1.0), + 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 +end + +@trixi_testset "elixir_euler_sedov_blast_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov_blast_wave.jl"), - l2 = [0.4866953770742574, 0.1673477470091984, 0.16734774700934, 0.6184367248923149], - linf = [2.6724832723962053, 1.2916089288910635, 1.2916089289001427, 6.474699399394252], - tspan = (0.0, 1.0), - 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 - end - - @trixi_testset "elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl"), - l2 = [0.0845430093623868, 0.09271459184623232, 0.09271459184623232, 0.4377291875101709], - linf = [1.3608553480069898, 1.6822884847136004, 1.6822884847135997, 4.2201475428867035], - maxiters = 30, - coverage_override = (maxiters=6,)) - end - - @trixi_testset "elixir_euler_positivity.jl" begin + l2=[ + 0.4866953770742574, + 0.1673477470091984, + 0.16734774700934, + 0.6184367248923149, + ], + linf=[ + 2.6724832723962053, + 1.2916089288910635, + 1.2916089289001427, + 6.474699399394252, + ], + tspan=(0.0, 1.0), + 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 +end + +@trixi_testset "elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl"), + l2=[ + 0.0845430093623868, + 0.09271459184623232, + 0.09271459184623232, + 0.4377291875101709, + ], + linf=[ + 1.3608553480069898, + 1.6822884847136004, + 1.6822884847135997, + 4.2201475428867035, + ], + maxiters=30, + coverage_override=(maxiters = 6,)) +end + +@trixi_testset "elixir_euler_positivity.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_positivity.jl"), - l2 = [0.48862067511841695, 0.16787541578869494, 0.16787541578869422, 0.6184319933114926], - linf = [2.6766520821013002, 1.2910938760258996, 1.2910938760258899, 6.473385481404865], - tspan = (0.0, 1.0), - coverage_override = (maxiters=3,)) - # 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_blob_mortar.jl" begin + l2=[ + 0.48862067511841695, + 0.16787541578869494, + 0.16787541578869422, + 0.6184319933114926, + ], + linf=[ + 2.6766520821013002, + 1.2910938760258996, + 1.2910938760258899, + 6.473385481404865, + ], + tspan=(0.0, 1.0), + coverage_override=(maxiters = 3,)) + # 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_blob_mortar.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blob_mortar.jl"), - l2 = [0.22271619518391986, 0.6284824759323494, 0.24864213447943648, 2.9591811489995474], - linf = [9.15245400430106, 24.96562810334389, 10.388109127032374, 101.20581544156934], - tspan = (0.0, 0.5)) - # 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_blob_amr.jl" begin + l2=[ + 0.22271619518391986, + 0.6284824759323494, + 0.24864213447943648, + 2.9591811489995474, + ], + linf=[ + 9.15245400430106, + 24.96562810334389, + 10.388109127032374, + 101.20581544156934, + ], + tspan=(0.0, 0.5)) + # 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_blob_amr.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blob_amr.jl"), - l2 = [0.2086261501910662, 1.2118352377894666, 0.10255333189606497, 5.296238138639236], - linf = [14.829071984498198, 74.12967742435727, 6.863554388300223, 303.58813147491134], - tspan = (0.0, 0.12), - # Let this test run longer to cover the ControllerThreeLevelCombined lines - coverage_override = (maxiters=10^5,)) - # 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_kelvin_helmholtz_instability_fjordholm_etal.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_kelvin_helmholtz_instability_fjordholm_etal.jl"), - l2 = [0.1057230211245312, 0.10621112311257341, 0.07260957505339989, 0.11178239111065721], - linf = [2.998719417992662, 2.1400285015556166, 1.1569648700415078, 1.8922492268110913], - tspan = (0.0, 0.1)) - # 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_kelvin_helmholtz_instability.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_kelvin_helmholtz_instability.jl"), - l2 = [0.055691508271624536, 0.032986009333751655, 0.05224390923711999, 0.08009536362771563], - linf = [0.24043622527087494, 0.1660878796929941, 0.12355946691711608, 0.2694290787257758], - tspan = (0.0, 0.2)) - # 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_kelvin_helmholtz_instability_amr.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_kelvin_helmholtz_instability_amr.jl"), - l2 = [0.05569452733654995, 0.033107109983417926, 0.05223609622852158, 0.08007777597488817], - linf = [0.2535807803900303, 0.17397028249895308, 0.12321616095649354, 0.269046666668995], - tspan = (0.0, 0.2), - coverage_override = (maxiters=2,)) - # 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_kelvin_helmholtz_instability_amr_neuralnetwork_perssonperaire.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_kelvin_helmholtz_instability_amr_neuralnetwork_perssonperaire.jl"), - # This stuff is experimental and annoying to test. In the future, we plan - # to move it to another repository. Thus, we save developer time right now - # and do not run these tests anymore. - # l2 = [0.0009823702998067061, 0.004943231496200673, 0.0048604522073091815, 0.00496983530893294], - # linf = [0.00855717053383187, 0.02087422420794427, 0.017121993783086185, 0.02720703869972585], - maxiters = 30, - coverage_override = (maxiters=2,)) - end - - @trixi_testset "elixir_euler_colliding_flow.jl" begin + l2=[ + 0.2086261501910662, + 1.2118352377894666, + 0.10255333189606497, + 5.296238138639236, + ], + linf=[ + 14.829071984498198, + 74.12967742435727, + 6.863554388300223, + 303.58813147491134, + ], + tspan=(0.0, 0.12), + # Let this test run longer to cover the ControllerThreeLevelCombined lines + coverage_override=(maxiters = 10^5,)) + # 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_kelvin_helmholtz_instability_fjordholm_etal.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_kelvin_helmholtz_instability_fjordholm_etal.jl"), + l2=[ + 0.1057230211245312, + 0.10621112311257341, + 0.07260957505339989, + 0.11178239111065721, + ], + linf=[ + 2.998719417992662, + 2.1400285015556166, + 1.1569648700415078, + 1.8922492268110913, + ], + tspan=(0.0, 0.1)) + # 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_kelvin_helmholtz_instability.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_kelvin_helmholtz_instability.jl"), + l2=[ + 0.055691508271624536, + 0.032986009333751655, + 0.05224390923711999, + 0.08009536362771563, + ], + linf=[ + 0.24043622527087494, + 0.1660878796929941, + 0.12355946691711608, + 0.2694290787257758, + ], + tspan=(0.0, 0.2)) + # 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_kelvin_helmholtz_instability_amr.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_kelvin_helmholtz_instability_amr.jl"), + l2=[ + 0.05569452733654995, + 0.033107109983417926, + 0.05223609622852158, + 0.08007777597488817, + ], + linf=[ + 0.2535807803900303, + 0.17397028249895308, + 0.12321616095649354, + 0.269046666668995, + ], + tspan=(0.0, 0.2), + coverage_override=(maxiters = 2,)) + # 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_kelvin_helmholtz_instability_amr_neuralnetwork_perssonperaire.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_kelvin_helmholtz_instability_amr_neuralnetwork_perssonperaire.jl"), + # This stuff is experimental and annoying to test. In the future, we plan + # to move it to another repository. Thus, we save developer time right now + # and do not run these tests anymore. + # l2 = [0.0009823702998067061, 0.004943231496200673, 0.0048604522073091815, 0.00496983530893294], + # linf = [0.00855717053383187, 0.02087422420794427, 0.017121993783086185, 0.02720703869972585], + maxiters=30, + coverage_override=(maxiters = 2,)) +end + +@trixi_testset "elixir_euler_colliding_flow.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_colliding_flow.jl"), - l2 = [0.007237139090503349, 0.044887582765386916, 1.0453570959003603e-6, 0.6627307840935432], - linf = [0.19437260992446315, 0.5554343646648533, 5.943891455255412e-5, 15.188919846360125], - tspan = (0.0, 0.1)) - # 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_colliding_flow_amr.jl" begin + l2=[ + 0.007237139090503349, + 0.044887582765386916, + 1.0453570959003603e-6, + 0.6627307840935432, + ], + linf=[ + 0.19437260992446315, + 0.5554343646648533, + 5.943891455255412e-5, + 15.188919846360125, + ], + tspan=(0.0, 0.1)) + # 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_colliding_flow_amr.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_colliding_flow_amr.jl"), - l2 = [0.006768801432802192, 0.032184992228603666, 6.923887797276484e-7, 0.6784222932398366], - linf = [0.2508663007713608, 0.4097017076529792, 0.0003528986458217968, 22.435474993016918], - tspan = (0.0, 0.1), - coverage_override = (maxiters=2,)) - # 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_astro_jet_amr.jl" begin + l2=[ + 0.006768801432802192, + 0.032184992228603666, + 6.923887797276484e-7, + 0.6784222932398366, + ], + linf=[ + 0.2508663007713608, + 0.4097017076529792, + 0.0003528986458217968, + 22.435474993016918, + ], + tspan=(0.0, 0.1), + coverage_override=(maxiters = 2,)) + # 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_astro_jet_amr.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_astro_jet_amr.jl"), - l2 = [0.011338365293662804, 10.09743543555765, 0.00392429463200361, 4031.7811487690506], - linf = [3.3178633141984193, 2993.6445033486402, 8.031723414357423, 1.1918867260293828e6], - tspan = (0.0, 1.0e-7), - 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 - end - - @trixi_testset "elixir_euler_vortex.jl" begin + l2=[ + 0.011338365293662804, + 10.09743543555765, + 0.00392429463200361, + 4031.7811487690506, + ], + linf=[ + 3.3178633141984193, + 2993.6445033486402, + 8.031723414357423, + 1.1918867260293828e6, + ], + tspan=(0.0, 1.0e-7), + 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 +end + +@trixi_testset "elixir_euler_vortex.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex.jl"), - l2 = [0.00013492249515826863, 0.006615696236378061, 0.006782108219800376, 0.016393831451740604], - linf = [0.0020782600954247776, 0.08150078921935999, 0.08663621974991986, 0.2829930622010579]) - # 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_vortex_mortar.jl" begin + l2=[ + 0.00013492249515826863, + 0.006615696236378061, + 0.006782108219800376, + 0.016393831451740604, + ], + linf=[ + 0.0020782600954247776, + 0.08150078921935999, + 0.08663621974991986, + 0.2829930622010579, + ]) + # 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_vortex_mortar.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex_mortar.jl"), - # Expected errors are exactly the same as in the parallel test! - l2 = [0.0017208369388227673, 0.09628684992237334, 0.09620157717330868, 0.1758809552387432], - linf = [0.021869936355319086, 0.9956698009442038, 1.0002507727219028, 2.223249697515648]) - # 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_vortex_mortar_split.jl" begin + # Expected errors are exactly the same as in the parallel test! + l2=[ + 0.0017208369388227673, + 0.09628684992237334, + 0.09620157717330868, + 0.1758809552387432, + ], + linf=[ + 0.021869936355319086, + 0.9956698009442038, + 1.0002507727219028, + 2.223249697515648, + ]) + # 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_vortex_mortar_split.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex_mortar_split.jl"), - l2 = [0.0017203323613648241, 0.09628962878682261, 0.09621241164155782, 0.17585995600340926], - linf = [0.021740570456931674, 0.9938841665880938, 1.004140123355135, 2.224108857746245]) - # 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_vortex_shockcapturing.jl" begin + l2=[ + 0.0017203323613648241, + 0.09628962878682261, + 0.09621241164155782, + 0.17585995600340926, + ], + linf=[ + 0.021740570456931674, + 0.9938841665880938, + 1.004140123355135, + 2.224108857746245, + ]) + # 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_vortex_shockcapturing.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex_shockcapturing.jl"), - l2 = [0.0017158367642679273, 0.09619888722871434, 0.09616432767924141, 0.17553381166255197], - linf = [0.021853862449723982, 0.9878047229255944, 0.9880191167111795, 2.2154030488035588]) - # 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_vortex_mortar_shockcapturing.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex_mortar_shockcapturing.jl"), - l2 = [0.0017203324051381415, 0.09628962899999398, 0.0962124115572114, 0.1758599596626405], - linf = [0.021740568112562086, 0.9938841624655501, 1.0041401179009877, 2.2241087041100798]) - # 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_vortex_amr.jl" begin + l2=[ + 0.0017158367642679273, + 0.09619888722871434, + 0.09616432767924141, + 0.17553381166255197, + ], + linf=[ + 0.021853862449723982, + 0.9878047229255944, + 0.9880191167111795, + 2.2154030488035588, + ]) + # 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_vortex_mortar_shockcapturing.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_vortex_mortar_shockcapturing.jl"), + l2=[ + 0.0017203324051381415, + 0.09628962899999398, + 0.0962124115572114, + 0.1758599596626405, + ], + linf=[ + 0.021740568112562086, + 0.9938841624655501, + 1.0041401179009877, + 2.2241087041100798, + ]) + # 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_vortex_amr.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex_amr.jl"), - # Expected errors are exactly the same as in the parallel test! - l2 = [5.051719943432265e-5, 0.0022574259317084747, 0.0021755998463189713, 0.004346492398617521], - linf = [0.0012880114865917447, 0.03857193149447702, 0.031090457959835893, 0.12125130332971423], - # Let this test run longer to cover some lines in the AMR indicator - coverage_override = (maxiters=10^5, tspan=(0.0, 10.5))) - # 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_ec.jl with boundary_condition_slip_wall" begin + # Expected errors are exactly the same as in the parallel test! + l2=[ + 5.051719943432265e-5, + 0.0022574259317084747, + 0.0021755998463189713, + 0.004346492398617521, + ], + linf=[ + 0.0012880114865917447, + 0.03857193149447702, + 0.031090457959835893, + 0.12125130332971423, + ], + # Let this test run longer to cover some lines in the AMR indicator + coverage_override=(maxiters = 10^5, tspan = (0.0, 10.5))) + # 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_ec.jl with boundary_condition_slip_wall" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.03341239373099515, 0.026673245711492915, 0.026678871434568822, 0.12397486476145089], - linf = [0.3290981764688339, 0.3812055782309788, 0.3812041851225023, 1.168251216556933], - periodicity = false, boundary_conditions = boundary_condition_slip_wall, - cfl = 0.3, tspan = (0.0, 0.1)) # this test is sensitive to the CFL factor - # 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 + l2=[ + 0.03341239373099515, + 0.026673245711492915, + 0.026678871434568822, + 0.12397486476145089, + ], + linf=[ + 0.3290981764688339, + 0.3812055782309788, + 0.3812041851225023, + 1.168251216556933, + ], + periodicity=false, + boundary_conditions=boundary_condition_slip_wall, + cfl=0.3, tspan=(0.0, 0.1)) # this test is sensitive to the CFL factor + # 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 # Coverage test for all initial conditions @testset "Compressible Euler: Tests for initial conditions" begin - @trixi_testset "elixir_euler_vortex.jl one step with initial_condition_constant" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex.jl"), - l2 = [1.1790213022362371e-16, 8.580657423476384e-17, 1.3082387431804115e-16, 1.6182739965672862e-15], - linf = [3.3306690738754696e-16, 2.220446049250313e-16, 5.273559366969494e-16, 3.552713678800501e-15], - maxiters = 1, - initial_condition = initial_condition_constant) - # 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_blast_wave.jl one step" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov_blast_wave.jl"), - l2 = [0.0021196114178949396, 0.010703549234544042, 0.01070354923454404, 0.10719124037195142], - linf = [0.11987270645890724, 0.7468615461136827, 0.7468615461136827, 3.910689155287799], - maxiters=1) - - # 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_vortex.jl one step with initial_condition_constant" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex.jl"), + l2=[ + 1.1790213022362371e-16, + 8.580657423476384e-17, + 1.3082387431804115e-16, + 1.6182739965672862e-15, + ], + linf=[ + 3.3306690738754696e-16, + 2.220446049250313e-16, + 5.273559366969494e-16, + 3.552713678800501e-15, + ], + maxiters=1, + initial_condition=initial_condition_constant) + # 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_blast_wave.jl one step" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov_blast_wave.jl"), + l2=[ + 0.0021196114178949396, + 0.010703549234544042, + 0.01070354923454404, + 0.10719124037195142, + ], + linf=[ + 0.11987270645890724, + 0.7468615461136827, + 0.7468615461136827, + 3.910689155287799, + ], + maxiters=1) + + # 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 end -end # module \ No newline at end of file +end # module diff --git a/test/test_tree_2d_euleracoustics.jl b/test/test_tree_2d_euleracoustics.jl index df4bd5d7bfc..e3a4d65f398 100644 --- a/test/test_tree_2d_euleracoustics.jl +++ b/test/test_tree_2d_euleracoustics.jl @@ -8,22 +8,40 @@ include("test_trixi.jl") EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") @testset "Acoustic perturbation coupled with compressible Euler" begin - @trixi_testset "elixir_euleracoustics_co-rotating_vortex_pair.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euleracoustics_co-rotating_vortex_pair.jl"), +#! format: noindent + +@trixi_testset "elixir_euleracoustics_co-rotating_vortex_pair.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euleracoustics_co-rotating_vortex_pair.jl"), initial_refinement_level=5, tspan1=(0.0, 1.0), tspan_averaging=(0.0, 1.0), tspan=(0.0, 1.0), - l2 = [0.00013268029905807722, 0.0001335062197031223, 0.00021776333678401362, 13.000001753042364, 26.00000080243847, 38.00000884725549, 51.000000003859995], - linf = [0.22312716933051027, 0.1579924424942319, 0.25194831158255576, 13.468872744263273, 26.54666679978679, 38.139032147739684, 51.378134660241294] - ) - # 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 + l2=[ + 0.00013268029905807722, + 0.0001335062197031223, + 0.00021776333678401362, + 13.000001753042364, + 26.00000080243847, + 38.00000884725549, + 51.000000003859995, + ], + linf=[ + 0.22312716933051027, + 0.1579924424942319, + 0.25194831158255576, + 13.468872744263273, + 26.54666679978679, + 38.139032147739684, + 51.378134660241294, + ]) + # 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 end -end # module \ No newline at end of file +end # module diff --git a/test/test_tree_2d_eulermulti.jl b/test/test_tree_2d_eulermulti.jl index c454a6bcfbf..2e808af6473 100644 --- a/test/test_tree_2d_eulermulti.jl +++ b/test/test_tree_2d_eulermulti.jl @@ -8,116 +8,205 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") @testset "Compressible Euler Multicomponent" begin - # NOTE: Some of the L2/Linf errors are comparably large. This is due to the fact that some of the - # simulations are set up with dimensional states. For example, the reference pressure in SI - # units is 101325 Pa, i.e., pressure has values of O(10^5) +#! format: noindent - @trixi_testset "elixir_eulermulti_shock_bubble.jl" begin +# NOTE: Some of the L2/Linf errors are comparably large. This is due to the fact that some of the +# simulations are set up with dimensional states. For example, the reference pressure in SI +# units is 101325 Pa, i.e., pressure has values of O(10^5) + +@trixi_testset "elixir_eulermulti_shock_bubble.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_shock_bubble.jl"), - l2 = [73.78467629094177, 0.9174752929795251, 57942.83587826468, 0.1828847253029943, 0.011127037850925347], - linf = [196.81051991521073, 7.8456811648529605, 158891.88930113698, 0.811379581519794, 0.08011973559187913], - tspan = (0.0, 0.001)) - # 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 + l2=[ + 73.78467629094177, + 0.9174752929795251, + 57942.83587826468, + 0.1828847253029943, + 0.011127037850925347, + ], + linf=[ + 196.81051991521073, + 7.8456811648529605, + 158891.88930113698, + 0.811379581519794, + 0.08011973559187913, + ], + tspan=(0.0, 0.001)) + # 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_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl" begin - rm("out/deviations.txt", force=true) - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl"), - l2 = [81.52845664909304, 2.5455678559421346, 63229.190712645846, 0.19929478404550321, 0.011068604228443425], - linf = [249.21708417382013, 40.33299887640794, 174205.0118831558, 0.6881458768113586, 0.11274401158173972], - initial_refinement_level = 3, - tspan = (0.0, 0.001), - output_directory="out") - lines = readlines("out/deviations.txt") - @test lines[1] == "# iter, simu_time, rho1_min, rho2_min" - @test startswith(lines[end], "1") - # 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)) < 15000 - end - end +@trixi_testset "elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl" begin + rm("out/deviations.txt", force = true) + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl"), + l2=[ + 81.52845664909304, + 2.5455678559421346, + 63229.190712645846, + 0.19929478404550321, + 0.011068604228443425, + ], + linf=[ + 249.21708417382013, + 40.33299887640794, + 174205.0118831558, + 0.6881458768113586, + 0.11274401158173972, + ], + initial_refinement_level=3, + tspan=(0.0, 0.001), + output_directory="out") + lines = readlines("out/deviations.txt") + @test lines[1] == "# iter, simu_time, rho1_min, rho2_min" + @test startswith(lines[end], "1") + # 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)) < 15000 + end +end - @trixi_testset "elixir_eulermulti_ec.jl" begin +@trixi_testset "elixir_eulermulti_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_ec.jl"), - l2 = [0.050182236154087095, 0.050189894464434635, 0.2258715597305131, 0.06175171559771687], - linf = [0.3108124923284472, 0.3107380389947733, 1.054035804988521, 0.29347582879608936]) - # 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 + l2=[ + 0.050182236154087095, + 0.050189894464434635, + 0.2258715597305131, + 0.06175171559771687, + ], + linf=[ + 0.3108124923284472, + 0.3107380389947733, + 1.054035804988521, + 0.29347582879608936, + ]) + # 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_eulermulti_es.jl" begin +@trixi_testset "elixir_eulermulti_es.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_es.jl"), - l2 = [0.0496546258404055, 0.04965550099933263, 0.22425206549856372, 0.004087155041747821, 0.008174310083495642, 0.016348620166991283, 0.032697240333982566], - linf = [0.2488251110766228, 0.24832493304479406, 0.9310354690058298, 0.017452870465607374, 0.03490574093121475, 0.0698114818624295, 0.139622963724859]) - # 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 + l2=[ + 0.0496546258404055, + 0.04965550099933263, + 0.22425206549856372, + 0.004087155041747821, + 0.008174310083495642, + 0.016348620166991283, + 0.032697240333982566, + ], + linf=[ + 0.2488251110766228, + 0.24832493304479406, + 0.9310354690058298, + 0.017452870465607374, + 0.03490574093121475, + 0.0698114818624295, + 0.139622963724859, + ]) + # 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_eulermulti_convergence_ec.jl" begin +@trixi_testset "elixir_eulermulti_convergence_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_ec.jl"), - l2 = [0.00012290225488326508, 0.00012290225488321876, 0.00018867397906337653, 4.8542321753649044e-5, 9.708464350729809e-5], - linf = [0.0006722819239133315, 0.0006722819239128874, 0.0012662292789555885, 0.0002843844182700561, 0.0005687688365401122]) - # 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 + l2=[ + 0.00012290225488326508, + 0.00012290225488321876, + 0.00018867397906337653, + 4.8542321753649044e-5, + 9.708464350729809e-5, + ], + linf=[ + 0.0006722819239133315, + 0.0006722819239128874, + 0.0012662292789555885, + 0.0002843844182700561, + 0.0005687688365401122, + ]) + # 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_eulermulti_convergence_es.jl" begin +@trixi_testset "elixir_eulermulti_convergence_es.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_es.jl"), - l2 = [2.2661773867001696e-6, 2.266177386666318e-6, 6.593514692980009e-6, 8.836308667348217e-7, 1.7672617334696433e-6], - linf = [1.4713170997993075e-5, 1.4713170997104896e-5, 5.115618808515521e-5, 5.3639516094383666e-6, 1.0727903218876733e-5]) - # 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 + l2=[ + 2.2661773867001696e-6, + 2.266177386666318e-6, + 6.593514692980009e-6, + 8.836308667348217e-7, + 1.7672617334696433e-6, + ], + linf=[ + 1.4713170997993075e-5, + 1.4713170997104896e-5, + 5.115618808515521e-5, + 5.3639516094383666e-6, + 1.0727903218876733e-5, + ]) + # 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_eulermulti_convergence_es.jl with flux_chandrashekar" begin +@trixi_testset "elixir_eulermulti_convergence_es.jl with flux_chandrashekar" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_es.jl"), - l2 = [1.8621737639352465e-6, 1.862173764098385e-6, 5.942585713809631e-6, 6.216263279534722e-7, 1.2432526559069443e-6], - linf = [1.6235495582606063e-5, 1.6235495576388814e-5, 5.854523678827661e-5, 5.790274858807898e-6, 1.1580549717615796e-5], - volume_flux = flux_chandrashekar) - # 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 + l2=[ + 1.8621737639352465e-6, + 1.862173764098385e-6, + 5.942585713809631e-6, + 6.216263279534722e-7, + 1.2432526559069443e-6, + ], + linf=[ + 1.6235495582606063e-5, + 1.6235495576388814e-5, + 5.854523678827661e-5, + 5.790274858807898e-6, + 1.1580549717615796e-5, + ], + volume_flux=flux_chandrashekar) + # 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 end # module diff --git a/test/test_tree_2d_fdsbp.jl b/test/test_tree_2d_fdsbp.jl index efb24562e57..c0844ee5dba 100644 --- a/test/test_tree_2d_fdsbp.jl +++ b/test/test_tree_2d_fdsbp.jl @@ -8,105 +8,152 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_fdsbp") @testset "Linear scalar advection" begin - @trixi_testset "elixir_advection_extended.jl" begin +#! format: noindent + +@trixi_testset "elixir_advection_extended.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2 = [2.898644263922225e-6], - linf = [8.491517930142578e-6], - rtol = 1.0e-7) # These results change a little bit and depend on the CI system + l2=[2.898644263922225e-6], + linf=[8.491517930142578e-6], + rtol=1.0e-7) # These results change a little bit and depend on the CI system # 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 + 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 - @trixi_testset "elixir_advection_extended.jl with periodic operators" begin +@trixi_testset "elixir_advection_extended.jl with periodic operators" begin + global D = SummationByPartsOperators.periodic_derivative_operator(derivative_order = 1, + accuracy_order = 4, + xmin = 0.0, + xmax = 1.0, + N = 40) @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2 = [1.1239649404463432e-5], - linf = [1.5895264629195438e-5], - D_SBP = SummationByPartsOperators.periodic_derivative_operator( - derivative_order = 1, accuracy_order = 4, xmin = 0.0, xmax = 1.0, N = 40), - initial_refinement_level = 0) + l2=[1.1239649404463432e-5], + linf=[1.5895264629195438e-5], + D_SBP=D, + initial_refinement_level=0) # 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 + 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 end @testset "Compressible Euler" begin - @trixi_testset "elixir_euler_convergence.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), - l2 = [1.7088389997042244e-6, 1.7437997855125774e-6, 1.7437997855350776e-6, 5.457223460127621e-6], - linf = [9.796504903736292e-6, 9.614745892783105e-6, 9.614745892783105e-6, 4.026107182575345e-5], - tspan = (0.0, 0.1)) + @trixi_testset "elixir_euler_convergence.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), + l2=[ + 1.7088389997042244e-6, + 1.7437997855125774e-6, + 1.7437997855350776e-6, + 5.457223460127621e-6, + ], + linf=[ + 9.796504903736292e-6, + 9.614745892783105e-6, + 9.614745892783105e-6, + 4.026107182575345e-5, + ], + tspan=(0.0, 0.1)) + + # 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 - # 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 + @trixi_testset "elixir_euler_convergence.jl with Lax-Friedrichs splitting" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), + l2=[ + 2.1149087345799973e-6, + 1.9391438806845798e-6, + 1.9391438806759794e-6, + 5.842833764682604e-6, + ], + linf=[ + 1.3679037540903494e-5, + 1.1770587849069258e-5, + 1.1770587848403125e-5, + 4.68952678644996e-5, + ], + tspan=(0.0, 0.1), flux_splitting=splitting_lax_friedrichs) + + # 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 - @trixi_testset "elixir_euler_convergence.jl with Lax-Friedrichs splitting" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), - l2 = [2.1149087345799973e-6, 1.9391438806845798e-6, 1.9391438806759794e-6, 5.842833764682604e-6], - linf = [1.3679037540903494e-5, 1.1770587849069258e-5, 1.1770587848403125e-5, 4.68952678644996e-5], - tspan = (0.0, 0.1), flux_splitting = splitting_lax_friedrichs) + @trixi_testset "elixir_euler_kelvin_helmholtz_instability.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_kelvin_helmholtz_instability.jl"), + l2=[ + 0.02607850081951497, + 0.020357717558016252, + 0.028510191844948945, + 0.02951535039734857, + ], + linf=[ + 0.12185328623662173, + 0.1065055387595834, + 0.06257122956937419, + 0.11992349951978643, + ], + tspan=(0.0, 0.1)) + + # 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 - # 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_kelvin_helmholtz_instability.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_kelvin_helmholtz_instability.jl"), - l2 = [0.02607850081951497, 0.020357717558016252, 0.028510191844948945, 0.02951535039734857], - linf = [0.12185328623662173, 0.1065055387595834, 0.06257122956937419, 0.11992349951978643], - tspan = (0.0, 0.1)) - - # 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_vortex.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex.jl"), - l2 = [0.0005330228930711585, 0.028475888529345014, 0.02847513865894387, 0.056259951995581196], - linf = [0.007206088611304784, 0.31690373882847234, 0.31685665067192326, 0.7938167296134893], - tspan = (0.0, 0.25)) - - # 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_vortex.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_vortex.jl"), + l2=[ + 0.0005330228930711585, + 0.028475888529345014, + 0.02847513865894387, + 0.056259951995581196, + ], + linf=[ + 0.007206088611304784, + 0.31690373882847234, + 0.31685665067192326, + 0.7938167296134893, + ], + tspan=(0.0, 0.25)) + + # 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 end # module diff --git a/test/test_tree_2d_hypdiff.jl b/test/test_tree_2d_hypdiff.jl index 30481fe910a..8c5973cbf07 100644 --- a/test/test_tree_2d_hypdiff.jl +++ b/test/test_tree_2d_hypdiff.jl @@ -8,62 +8,97 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") @testset "Hyperbolic diffusion" begin - @trixi_testset "elixir_hypdiff_lax_friedrichs.jl" begin +#! format: noindent + +@trixi_testset "elixir_hypdiff_lax_friedrichs.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_lax_friedrichs.jl"), - l2 = [0.00015687751817403066, 0.001025986772216324, 0.0010259867722164071], - linf = [0.001198695637957381, 0.006423873515531753, 0.006423873515533529]) - # 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)) < 15000 - end - end + l2=[ + 0.00015687751817403066, + 0.001025986772216324, + 0.0010259867722164071, + ], + linf=[ + 0.001198695637957381, + 0.006423873515531753, + 0.006423873515533529, + ]) + # 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)) < 15000 + end +end - @trixi_testset "elixir_hypdiff_harmonic_nonperiodic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_harmonic_nonperiodic.jl"), - l2 = [8.618132355121019e-8, 5.619399844384306e-7, 5.619399844844044e-7], - linf = [1.1248618588430072e-6, 8.622436487026874e-6, 8.622436487915053e-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 - end +@trixi_testset "elixir_hypdiff_harmonic_nonperiodic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_hypdiff_harmonic_nonperiodic.jl"), + l2=[ + 8.618132355121019e-8, + 5.619399844384306e-7, + 5.619399844844044e-7, + ], + linf=[ + 1.1248618588430072e-6, + 8.622436487026874e-6, + 8.622436487915053e-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 +end - @trixi_testset "elixir_hypdiff_nonperiodic.jl" begin +@trixi_testset "elixir_hypdiff_nonperiodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_nonperiodic.jl"), - l2 = [8.523077653954864e-6, 2.8779323653020624e-5, 5.454942769125663e-5], - linf = [5.522740952468297e-5, 0.00014544895978971679, 0.00032396328684924924]) - # 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 + l2=[ + 8.523077653954864e-6, + 2.8779323653020624e-5, + 5.454942769125663e-5, + ], + linf=[ + 5.522740952468297e-5, + 0.00014544895978971679, + 0.00032396328684924924, + ]) + # 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_hypdiff_godunov.jl" begin +@trixi_testset "elixir_hypdiff_godunov.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_godunov.jl"), - l2 = [5.868147556427088e-6, 3.80517927324465e-5, 3.805179273249344e-5], - linf = [3.701965498725812e-5, 0.0002122422943138247, 0.00021224229431116015], - atol = 2.0e-12 #= required for CI on macOS =#) - # 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 + l2=[ + 5.868147556427088e-6, + 3.80517927324465e-5, + 3.805179273249344e-5, + ], + linf=[ + 3.701965498725812e-5, + 0.0002122422943138247, + 0.00021224229431116015, + ], + atol=2.0e-12) #= required for CI on macOS =# + # 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 end # module diff --git a/test/test_tree_2d_kpp.jl b/test/test_tree_2d_kpp.jl index fb2a212ddf8..c9af68c6cc4 100644 --- a/test/test_tree_2d_kpp.jl +++ b/test/test_tree_2d_kpp.jl @@ -8,26 +8,28 @@ include("test_trixi.jl") EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") @testset "KPP" begin - @trixi_testset "elixir_kpp.jl" begin +#! format: noindent + +@trixi_testset "elixir_kpp.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_kpp.jl"), - l2 = [0.36563290910786106], - linf = [9.116732052340398], - max_refinement_level = 6, - tspan = (0.0, 0.01), - atol = 1e-6, - rtol = 1e-6, - skip_coverage = true) - if @isdefined sol # Skipped in coverage run + l2=[0.36563290910786106], + linf=[9.116732052340398], + max_refinement_level=6, + tspan=(0.0, 0.01), + atol=1e-6, + rtol=1e-6, + skip_coverage=true) + if @isdefined sol # Skipped in coverage run # 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 + 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 + end +end end end # module diff --git a/test/test_tree_2d_lbm.jl b/test/test_tree_2d_lbm.jl index 690c04ceae3..4705c9d0d03 100644 --- a/test/test_tree_2d_lbm.jl +++ b/test/test_tree_2d_lbm.jl @@ -8,120 +8,154 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") @testset "Lattice-Boltzmann" begin - @trixi_testset "elixir_lbm_constant.jl" begin +#! format: noindent + +@trixi_testset "elixir_lbm_constant.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_lbm_constant.jl"), - l2 = [4.888991832247047e-15, 4.8856380534982224e-15, 5.140829677785587e-16, - 7.340293204570167e-16, 2.0559494114924474e-15, 6.125746684189216e-16, - 1.6545443003155128e-16, 6.001333022242579e-16, 9.450994018139234e-15], - linf = [5.551115123125783e-15, 5.662137425588298e-15, 1.2212453270876722e-15, - 1.27675647831893e-15, 2.4980018054066022e-15, 7.494005416219807e-16, - 4.3021142204224816e-16, 8.881784197001252e-16, 1.0436096431476471e-14]) - # 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 + l2=[4.888991832247047e-15, 4.8856380534982224e-15, + 5.140829677785587e-16, + 7.340293204570167e-16, 2.0559494114924474e-15, + 6.125746684189216e-16, + 1.6545443003155128e-16, 6.001333022242579e-16, + 9.450994018139234e-15], + linf=[5.551115123125783e-15, 5.662137425588298e-15, + 1.2212453270876722e-15, + 1.27675647831893e-15, 2.4980018054066022e-15, + 7.494005416219807e-16, + 4.3021142204224816e-16, 8.881784197001252e-16, + 1.0436096431476471e-14]) + # 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_lbm_couette.jl" begin +@trixi_testset "elixir_lbm_couette.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_lbm_couette.jl"), - l2 = [0.0007899749117603378, 7.0995283148275575e-6, 0.0007454191223764233, - 1.6482025869100257e-5, 0.00012684365365448903, 0.0001198942846383015, - 0.00028436349827736705, 0.0003005161103138576, 4.496683876631818e-5], - linf = [0.005596384769998769, 4.771160474496827e-5, 0.005270322068908595, - 0.00011747787108790098, 0.00084326349695725, 0.000795551892211168, - 0.001956482118303543, 0.0020739599893902436, 0.00032606270109525326], - tspan = (0.0, 1.0)) - # 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 + l2=[0.0007899749117603378, 7.0995283148275575e-6, + 0.0007454191223764233, + 1.6482025869100257e-5, 0.00012684365365448903, + 0.0001198942846383015, + 0.00028436349827736705, 0.0003005161103138576, + 4.496683876631818e-5], + linf=[0.005596384769998769, 4.771160474496827e-5, + 0.005270322068908595, + 0.00011747787108790098, 0.00084326349695725, + 0.000795551892211168, + 0.001956482118303543, 0.0020739599893902436, + 0.00032606270109525326], + tspan=(0.0, 1.0)) + # 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_lbm_lid_driven_cavity.jl" begin +@trixi_testset "elixir_lbm_lid_driven_cavity.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_lbm_lid_driven_cavity.jl"), - l2 = [0.0013628495945172754, 0.00021475256243322154, 0.0012579141312268184, - 0.00036542734715110765, 0.00024127756258120715, 0.00022899415795341014, - 0.0004225564518328741, 0.0004593854895507851, 0.00044244398903669927], - linf = [0.025886626070758242, 0.00573859077176217, 0.027568805277855102, 0.00946724671122974, - 0.004031686575556803, 0.0038728927083346437, 0.020038695575169005, - 0.02061789496737146, 0.05568236920459335], - tspan = (0.0, 1.0)) - # 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 + l2=[0.0013628495945172754, 0.00021475256243322154, + 0.0012579141312268184, + 0.00036542734715110765, 0.00024127756258120715, + 0.00022899415795341014, + 0.0004225564518328741, 0.0004593854895507851, + 0.00044244398903669927], + linf=[0.025886626070758242, 0.00573859077176217, + 0.027568805277855102, 0.00946724671122974, + 0.004031686575556803, 0.0038728927083346437, + 0.020038695575169005, + 0.02061789496737146, 0.05568236920459335], + tspan=(0.0, 1.0)) + # 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_lbm_couette.jl with initial_condition_couette_steady" begin +@trixi_testset "elixir_lbm_couette.jl with initial_condition_couette_steady" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_lbm_couette.jl"), - l2 = [9.321369073400123e-16, 1.6498793963435488e-6, 5.211495843124065e-16, - 1.6520893954826173e-6, 1.0406056181388841e-5, 8.801606429417205e-6, - 8.801710065560555e-6, 1.040614383799995e-5, 2.6135657178357052e-15], - linf = [1.4432899320127035e-15, 2.1821189867266e-6, 8.881784197001252e-16, - 2.2481261510165496e-6, 1.0692966335143494e-5, 9.606391697600247e-6, - 9.62138334279633e-6, 1.0725969916147021e-5, 3.3861802251067274e-15], - initial_condition=function initial_condition_couette_steady(x, t, equations::LatticeBoltzmannEquations2D) - # Initial state for a *steady* Couette flow setup. To be used in combination with - # [`boundary_condition_couette`](@ref) and [`boundary_condition_noslip_wall`](@ref). - @unpack L, u0, rho0 = equations + l2=[9.321369073400123e-16, 1.6498793963435488e-6, + 5.211495843124065e-16, + 1.6520893954826173e-6, 1.0406056181388841e-5, + 8.801606429417205e-6, + 8.801710065560555e-6, 1.040614383799995e-5, + 2.6135657178357052e-15], + linf=[1.4432899320127035e-15, 2.1821189867266e-6, + 8.881784197001252e-16, + 2.2481261510165496e-6, 1.0692966335143494e-5, + 9.606391697600247e-6, + 9.62138334279633e-6, 1.0725969916147021e-5, + 3.3861802251067274e-15], + initial_condition=function initial_condition_couette_steady(x, + t, + equations::LatticeBoltzmannEquations2D) + # Initial state for a *steady* Couette flow setup. To be used in combination with + # [`boundary_condition_couette`](@ref) and [`boundary_condition_noslip_wall`](@ref). + @unpack L, u0, rho0 = equations - rho = rho0 - v1 = u0 * x[2] / L - v2 = 0 + rho = rho0 + v1 = u0 * x[2] / L + v2 = 0 - return equilibrium_distribution(rho, v1, v2, equations) - # 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, - tspan = (0.0, 1.0)) - # 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 + return equilibrium_distribution(rho, v1, v2, equations) + # 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, + tspan=(0.0, 1.0)) + # 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 - @trixi_testset "elixir_lbm_lid_driven_cavity.jl with stationary walls" begin +@trixi_testset "elixir_lbm_lid_driven_cavity.jl with stationary walls" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_lbm_lid_driven_cavity.jl"), - l2 = [1.7198203373689985e-16, 1.685644347036533e-16, 2.1604974801394525e-16, - 2.1527076266915764e-16, 4.2170298143732604e-17, 5.160156233016299e-17, - 6.167794865198169e-17, 5.24166554417795e-17, 6.694740573885739e-16], - linf = [5.967448757360216e-16, 6.522560269672795e-16, 6.522560269672795e-16, - 6.245004513516506e-16, 2.1163626406917047e-16, 2.185751579730777e-16, - 2.185751579730777e-16, 2.393918396847994e-16, 1.887379141862766e-15], - boundary_conditions=boundary_condition_noslip_wall, - tspan = (0, 0.1)) + l2=[1.7198203373689985e-16, 1.685644347036533e-16, + 2.1604974801394525e-16, + 2.1527076266915764e-16, 4.2170298143732604e-17, + 5.160156233016299e-17, + 6.167794865198169e-17, 5.24166554417795e-17, + 6.694740573885739e-16], + linf=[5.967448757360216e-16, 6.522560269672795e-16, + 6.522560269672795e-16, + 6.245004513516506e-16, 2.1163626406917047e-16, + 2.185751579730777e-16, + 2.185751579730777e-16, 2.393918396847994e-16, + 1.887379141862766e-15], + boundary_conditions=boundary_condition_noslip_wall, + tspan=(0, 0.1)) - # 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 + # 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 end # module diff --git a/test/test_tree_2d_linearizedeuler.jl b/test/test_tree_2d_linearizedeuler.jl index 93da887e73f..7bdb83e328e 100644 --- a/test/test_tree_2d_linearizedeuler.jl +++ b/test/test_tree_2d_linearizedeuler.jl @@ -7,33 +7,54 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") @testset "Linearized Euler Equations 2D" begin - @trixi_testset "elixir_linearizedeuler_convergence.jl" begin +#! format: noindent + +@trixi_testset "elixir_linearizedeuler_convergence.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_linearizedeuler_convergence.jl"), - l2 = [0.00020601485381444888, 0.00013380483421751216, 0.0001338048342174503, 0.00020601485381444888], - linf = [0.0011006084408365924, 0.0005788678074691855, 0.0005788678074701847, 0.0011006084408365924] - ) - # 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 + l2=[ + 0.00020601485381444888, + 0.00013380483421751216, + 0.0001338048342174503, + 0.00020601485381444888, + ], + linf=[ + 0.0011006084408365924, + 0.0005788678074691855, + 0.0005788678074701847, + 0.0011006084408365924, + ]) + # 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 - @trixi_testset "elixir_linearizedeuler_gauss_wall.jl" begin +@trixi_testset "elixir_linearizedeuler_gauss_wall.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_linearizedeuler_gauss_wall.jl"), - l2 = [0.048185623945503485, 0.01941899333212175, 0.019510224816991825, 0.048185623945503485], - linf = [1.0392165942153189, 0.18188777290819994, 0.1877028372108587, 1.0392165942153189]) + l2=[ + 0.048185623945503485, + 0.01941899333212175, + 0.019510224816991825, + 0.048185623945503485, + ], + linf=[ + 1.0392165942153189, + 0.18188777290819994, + 0.1877028372108587, + 1.0392165942153189, + ]) - # 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 + # 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 diff --git a/test/test_tree_2d_mhd.jl b/test/test_tree_2d_mhd.jl index 270bdc19fa3..af264561027 100644 --- a/test/test_tree_2d_mhd.jl +++ b/test/test_tree_2d_mhd.jl @@ -8,143 +8,326 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") @testset "MHD" begin - @trixi_testset "elixir_mhd_alfven_wave.jl" begin +#! format: noindent + +@trixi_testset "elixir_mhd_alfven_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), - l2 = [0.00011149543672225127, 5.888242524520296e-6, 5.888242524510072e-6, 8.476931432519067e-6, 1.3160738644036652e-6, 1.2542675002588144e-6, 1.2542675002747718e-6, 1.8705223407238346e-6, 4.651717010670585e-7], - linf = [0.00026806333988971254, 1.6278838272418272e-5, 1.627883827305665e-5, 2.7551183488072617e-5, 5.457878055614707e-6, 8.130129322880819e-6, 8.130129322769797e-6, 1.2406302192291552e-5, 2.373765544951732e-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 - end + l2=[ + 0.00011149543672225127, + 5.888242524520296e-6, + 5.888242524510072e-6, + 8.476931432519067e-6, + 1.3160738644036652e-6, + 1.2542675002588144e-6, + 1.2542675002747718e-6, + 1.8705223407238346e-6, + 4.651717010670585e-7, + ], + linf=[ + 0.00026806333988971254, + 1.6278838272418272e-5, + 1.627883827305665e-5, + 2.7551183488072617e-5, + 5.457878055614707e-6, + 8.130129322880819e-6, + 8.130129322769797e-6, + 1.2406302192291552e-5, + 2.373765544951732e-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 +end - @trixi_testset "elixir_mhd_alfven_wave.jl with flux_derigs_etal" begin +@trixi_testset "elixir_mhd_alfven_wave.jl with flux_derigs_etal" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), - l2 = [1.7201098719531215e-6, 8.692057393373005e-7, 8.69205739320643e-7, 1.2726508184718958e-6, 1.040607127595208e-6, 1.07029565814218e-6, 1.0702956581404748e-6, 1.3291748105236525e-6, 4.6172239295786824e-7], - linf = [9.865325754310206e-6, 7.352074675170961e-6, 7.352074674185638e-6, 1.0675656902672803e-5, 5.112498347226158e-6, 7.789533065905019e-6, 7.789533065905019e-6, 1.0933531593274037e-5, 2.340244047768378e-6], - volume_flux = (flux_derigs_etal, flux_nonconservative_powell)) - # 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 + l2=[ + 1.7201098719531215e-6, + 8.692057393373005e-7, + 8.69205739320643e-7, + 1.2726508184718958e-6, + 1.040607127595208e-6, + 1.07029565814218e-6, + 1.0702956581404748e-6, + 1.3291748105236525e-6, + 4.6172239295786824e-7, + ], + linf=[ + 9.865325754310206e-6, + 7.352074675170961e-6, + 7.352074674185638e-6, + 1.0675656902672803e-5, + 5.112498347226158e-6, + 7.789533065905019e-6, + 7.789533065905019e-6, + 1.0933531593274037e-5, + 2.340244047768378e-6, + ], + volume_flux=(flux_derigs_etal, flux_nonconservative_powell)) + # 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_mhd_alfven_wave_mortar.jl" begin +@trixi_testset "elixir_mhd_alfven_wave_mortar.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave_mortar.jl"), - l2 = [3.7762324533854616e-6, 1.5534623833573546e-6, 1.4577234868196855e-6, 1.7647724628707057e-6, 1.4831911814574333e-6, 1.456369119716533e-6, 1.4115666913995062e-6, 1.804758237422838e-6, 8.320469738087189e-7], - linf = [3.670661330201774e-5, 1.530289442645827e-5, 1.3592183785327006e-5, 1.5173897443654383e-5, 9.43771379136038e-6, 1.0906323046233624e-5, 1.0603954940346938e-5, 1.5900499596113726e-5, 5.978772247650426e-6], - tspan = (0.0, 1.0)) - # 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 + l2=[ + 3.7762324533854616e-6, + 1.5534623833573546e-6, + 1.4577234868196855e-6, + 1.7647724628707057e-6, + 1.4831911814574333e-6, + 1.456369119716533e-6, + 1.4115666913995062e-6, + 1.804758237422838e-6, + 8.320469738087189e-7, + ], + linf=[ + 3.670661330201774e-5, + 1.530289442645827e-5, + 1.3592183785327006e-5, + 1.5173897443654383e-5, + 9.43771379136038e-6, + 1.0906323046233624e-5, + 1.0603954940346938e-5, + 1.5900499596113726e-5, + 5.978772247650426e-6, + ], + tspan=(0.0, 1.0)) + # 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_mhd_ec.jl" begin +@trixi_testset "elixir_mhd_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ec.jl"), - l2 = [0.03637302248881514, 0.043002991956758996, 0.042987505670836056, 0.02574718055258975, 0.1621856170457943, 0.01745369341302589, 0.017454552320664566, 0.026873190440613117, 5.336243933079389e-16], - linf = [0.23623816236321427, 0.3137152204179957, 0.30378397831730597, 0.21500228807094865, 0.9042495730546518, 0.09398098096581875, 0.09470282020962917, 0.15277253978297378, 4.307694418935709e-15]) - # 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 + l2=[ + 0.03637302248881514, + 0.043002991956758996, + 0.042987505670836056, + 0.02574718055258975, + 0.1621856170457943, + 0.01745369341302589, + 0.017454552320664566, + 0.026873190440613117, + 5.336243933079389e-16, + ], + linf=[ + 0.23623816236321427, + 0.3137152204179957, + 0.30378397831730597, + 0.21500228807094865, + 0.9042495730546518, + 0.09398098096581875, + 0.09470282020962917, + 0.15277253978297378, + 4.307694418935709e-15, + ]) + # 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_mhd_orszag_tang.jl" begin +@trixi_testset "elixir_mhd_orszag_tang.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_orszag_tang.jl"), - l2 = [0.21967600768935716, 0.2643126515795721, 0.31488287201980875, 0.0, 0.5160141621186931, 0.23028914748088603, 0.34413527376463915, 0.0, 0.003178793090381426], - linf = [1.2749969218080568, 0.6737013368774057, 0.8604154399895696, 0.0, 2.799342099887639, 0.6473347557712643, 0.9691773375490476, 0.0, 0.05729832038724348], - tspan = (0.0, 0.09)) - # 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 + l2=[ + 0.21967600768935716, + 0.2643126515795721, + 0.31488287201980875, + 0.0, + 0.5160141621186931, + 0.23028914748088603, + 0.34413527376463915, + 0.0, + 0.003178793090381426, + ], + linf=[ + 1.2749969218080568, + 0.6737013368774057, + 0.8604154399895696, + 0.0, + 2.799342099887639, + 0.6473347557712643, + 0.9691773375490476, + 0.0, + 0.05729832038724348, + ], + tspan=(0.0, 0.09)) + # 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_mhd_orszag_tang.jl with flux_hll" begin +@trixi_testset "elixir_mhd_orszag_tang.jl with flux_hll" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_orszag_tang.jl"), - l2 = [0.10806619664693064, 0.20199136742199922, 0.22984589847526207, 0.0, 0.29950152196422647, 0.15688413207147794, 0.24293641543490646, 0.0, 0.003246181006326598], - linf = [0.560316034595759, 0.5095520363866776, 0.6536748458764621, 0.0, 0.9627447086204038, 0.3981375420906146, 0.673472146198816, 0.0, 0.04879208429337193], - tspan = (0.0, 0.06), surface_flux = (flux_hll, flux_nonconservative_powell)) - # 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 + l2=[ + 0.10806619664693064, + 0.20199136742199922, + 0.22984589847526207, + 0.0, + 0.29950152196422647, + 0.15688413207147794, + 0.24293641543490646, + 0.0, + 0.003246181006326598, + ], + linf=[ + 0.560316034595759, + 0.5095520363866776, + 0.6536748458764621, + 0.0, + 0.9627447086204038, + 0.3981375420906146, + 0.673472146198816, + 0.0, + 0.04879208429337193, + ], + tspan=(0.0, 0.06), + surface_flux=(flux_hll, flux_nonconservative_powell)) + # 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_mhd_alfven_wave.jl one step with initial_condition_constant" begin +@trixi_testset "elixir_mhd_alfven_wave.jl one step with initial_condition_constant" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), - l2 = [7.144325530681224e-17, 2.123397983547417e-16, 5.061138912500049e-16, 3.6588423152083e-17, 8.449816179702522e-15, 3.9171737639099993e-16, 2.445565690318772e-16, 3.6588423152083e-17, 9.971153407737885e-17], - linf = [2.220446049250313e-16, 8.465450562766819e-16, 1.8318679906315083e-15, 1.1102230246251565e-16, 1.4210854715202004e-14, 8.881784197001252e-16, 4.440892098500626e-16, 1.1102230246251565e-16, 4.779017148551244e-16], - maxiters = 1, - initial_condition = initial_condition_constant, - atol = 2.0e-13) - # 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 + l2=[ + 7.144325530681224e-17, + 2.123397983547417e-16, + 5.061138912500049e-16, + 3.6588423152083e-17, + 8.449816179702522e-15, + 3.9171737639099993e-16, + 2.445565690318772e-16, + 3.6588423152083e-17, + 9.971153407737885e-17, + ], + linf=[ + 2.220446049250313e-16, + 8.465450562766819e-16, + 1.8318679906315083e-15, + 1.1102230246251565e-16, + 1.4210854715202004e-14, + 8.881784197001252e-16, + 4.440892098500626e-16, + 1.1102230246251565e-16, + 4.779017148551244e-16, + ], + maxiters=1, + initial_condition=initial_condition_constant, + atol=2.0e-13) + # 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_mhd_rotor.jl" begin +@trixi_testset "elixir_mhd_rotor.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_rotor.jl"), - l2 = [1.2623319195262743, 1.8273050553090515, 1.7004151198284634, 0.0, 2.2978570581460818, 0.2147235065899803, 0.23558337696054493, 0.0, 0.0032515115395693483], - linf = [11.003677581472843, 14.70614192714736, 15.687648666952708, 0.0, 17.098104835553823, 1.3283750501377847, 1.4365828094434892, 0.0, 0.07886241196068537], - tspan = (0.0, 0.05)) - # 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 + l2=[ + 1.2623319195262743, + 1.8273050553090515, + 1.7004151198284634, + 0.0, + 2.2978570581460818, + 0.2147235065899803, + 0.23558337696054493, + 0.0, + 0.0032515115395693483, + ], + linf=[ + 11.003677581472843, + 14.70614192714736, + 15.687648666952708, + 0.0, + 17.098104835553823, + 1.3283750501377847, + 1.4365828094434892, + 0.0, + 0.07886241196068537, + ], + tspan=(0.0, 0.05)) + # 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_mhd_blast_wave.jl" begin +@trixi_testset "elixir_mhd_blast_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_blast_wave.jl"), - l2 = [0.17646728395490927, 3.866230215339417, 2.4867304651291255, 0.0, 355.4562971958441, 2.359493623565687, 1.4030741420730297, 0.0, 0.029613599942667133], - linf = [1.581630420824181, 44.15725488910748, 13.056964982196554, 0.0, 2244.875490238186, 13.07679044647926, 9.14612176426092, 0.0, 0.5154756722488522], - tspan = (0.0, 0.003), - # Calling the AnalysisCallback before iteration 9 causes the interpolation - # of this IC to have negative density/pressure values, crashing the simulation. - coverage_override = (maxiters=9,)) - # 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 + l2=[ + 0.17646728395490927, + 3.866230215339417, + 2.4867304651291255, + 0.0, + 355.4562971958441, + 2.359493623565687, + 1.4030741420730297, + 0.0, + 0.029613599942667133, + ], + linf=[ + 1.581630420824181, + 44.15725488910748, + 13.056964982196554, + 0.0, + 2244.875490238186, + 13.07679044647926, + 9.14612176426092, + 0.0, + 0.5154756722488522, + ], + tspan=(0.0, 0.003), + # Calling the AnalysisCallback before iteration 9 causes the interpolation + # of this IC to have negative density/pressure values, crashing the simulation. + coverage_override=(maxiters = 9,)) + # 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 end # module diff --git a/test/test_tree_2d_mhdmulti.jl b/test/test_tree_2d_mhdmulti.jl index a73e39a6d6d..d36554a6679 100644 --- a/test/test_tree_2d_mhdmulti.jl +++ b/test/test_tree_2d_mhdmulti.jl @@ -8,102 +8,126 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") @testset "MHD Multicomponent" begin +#! format: noindent - @trixi_testset "elixir_mhdmulti_ec.jl" begin +@trixi_testset "elixir_mhdmulti_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmulti_ec.jl"), - l2 = [0.04300299195675897, 0.042987505670835945, 0.025747180552589767, 0.1621856170457937, - 0.017453693413025828, 0.0174545523206645, 0.026873190440613162, 1.364647699274761e-15, - 0.012124340829605002, 0.024248681659210004], - linf = [0.31371522041799105, 0.3037839783173047, 0.21500228807094351, 0.904249573054642, - 0.0939809809658183, 0.09470282020962761, 0.1527725397829759, 8.245701827530042e-15, - 0.0787460541210726, 0.1574921082421452]) - # 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 + l2=[0.04300299195675897, 0.042987505670835945, + 0.025747180552589767, 0.1621856170457937, + 0.017453693413025828, 0.0174545523206645, + 0.026873190440613162, 1.364647699274761e-15, + 0.012124340829605002, 0.024248681659210004], + linf=[0.31371522041799105, 0.3037839783173047, + 0.21500228807094351, 0.904249573054642, + 0.0939809809658183, 0.09470282020962761, 0.1527725397829759, + 8.245701827530042e-15, + 0.0787460541210726, 0.1574921082421452]) + # 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_mhdmulti_ec.jl with flux_derigs_etal" begin +@trixi_testset "elixir_mhdmulti_ec.jl with flux_derigs_etal" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmulti_ec.jl"), - l2 = [0.04301155595653799, 0.04299735787276207, 0.025745530869947714, - 0.16206102676791553, 0.017454384272339165, 0.01745523378100091, - 0.026879482381500154, 0.0002038008756963954, 0.012094208262809778, - 0.024188416525619556], - linf = [0.3156206778985397, 0.30941696929809526, 0.21167563519254176, - 0.9688251298546122, 0.09076254289155083, 0.09160589769498295, - 0.15698032974768705, 0.006131914796912965, 0.07839287555951036, - 0.1567857511190207], - volume_flux = (flux_derigs_etal, flux_nonconservative_powell), - surface_flux = (flux_derigs_etal, flux_nonconservative_powell)) - # 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 + l2=[0.04301155595653799, 0.04299735787276207, + 0.025745530869947714, + 0.16206102676791553, 0.017454384272339165, + 0.01745523378100091, + 0.026879482381500154, 0.0002038008756963954, + 0.012094208262809778, + 0.024188416525619556], + linf=[0.3156206778985397, 0.30941696929809526, + 0.21167563519254176, + 0.9688251298546122, 0.09076254289155083, + 0.09160589769498295, + 0.15698032974768705, 0.006131914796912965, + 0.07839287555951036, + 0.1567857511190207], + volume_flux=(flux_derigs_etal, flux_nonconservative_powell), + surface_flux=(flux_derigs_etal, flux_nonconservative_powell)) + # 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_mhdmulti_es.jl" begin +@trixi_testset "elixir_mhdmulti_es.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmulti_es.jl"), - l2 = [0.042511527162267, 0.04250603277530184, 0.02385422747993974, 0.11555081362726903, - 0.016366641053738043, 0.01636681584592762, 0.02581748418797907, 0.00023394429554818215, - 0.010834603551662698, 0.021669207103325396], - linf = [0.23454607703107877, 0.23464789247380322, 0.11898832084115452, 0.5331209602648022, - 0.061744814466827336, 0.061767127585091286, 0.09595041452184983, 0.004421037168524759, - 0.06186597801911198, 0.12373195603822396]) - # 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 + l2=[0.042511527162267, 0.04250603277530184, 0.02385422747993974, + 0.11555081362726903, + 0.016366641053738043, 0.01636681584592762, + 0.02581748418797907, 0.00023394429554818215, + 0.010834603551662698, 0.021669207103325396], + linf=[0.23454607703107877, 0.23464789247380322, + 0.11898832084115452, 0.5331209602648022, + 0.061744814466827336, 0.061767127585091286, + 0.09595041452184983, 0.004421037168524759, + 0.06186597801911198, 0.12373195603822396]) + # 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_mhdmulti_convergence.jl" begin +@trixi_testset "elixir_mhdmulti_convergence.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmulti_convergence.jl"), - l2 = [0.0003808877028249613, 0.0003808877028249593, 0.0005155994511260122, 0.000570394227652563, - 0.000439568811048544, 0.0004395688110485541, 0.0005074093477702055, 0.0003859005258180428, - 7.4611207452221e-5, 0.000149222414904442, 0.000298444829808884], - linf = [0.0013324014301672943, 0.0013324014301669181, 0.002684449324758791, 0.0016236816790307085, - 0.0019172373117153363, 0.0019172373117148922, 0.002664932274107224, 0.0011872396664042962, - 0.0002855492944235094, 0.0005710985888470188, 0.0011421971776940376]) - # 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 + l2=[0.0003808877028249613, 0.0003808877028249593, + 0.0005155994511260122, 0.000570394227652563, + 0.000439568811048544, 0.0004395688110485541, + 0.0005074093477702055, 0.0003859005258180428, + 7.4611207452221e-5, 0.000149222414904442, + 0.000298444829808884], + linf=[0.0013324014301672943, 0.0013324014301669181, + 0.002684449324758791, 0.0016236816790307085, + 0.0019172373117153363, 0.0019172373117148922, + 0.002664932274107224, 0.0011872396664042962, + 0.0002855492944235094, 0.0005710985888470188, + 0.0011421971776940376]) + # 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_mhdmulti_rotor.jl" begin +@trixi_testset "elixir_mhdmulti_rotor.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmulti_rotor.jl"), - l2 = [0.6574605535168556, 0.6623234319361953, 0.0, 0.689806698245354, - 0.04883686128677976, 0.08382459729494686, 0.0, 0.0021114516459281177, - 0.15909290019096098, 0.07954645009548049], - linf = [9.362339085941425, 9.169838118652539, 0.0, 10.600957847359556, - 0.6628317732399827, 1.4185626901435056, 0.0, 0.06914316292003836, - 3.328770801731456, 1.664385400865728], - tspan = (0.0, 0.01)) - # 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 + l2=[0.6574605535168556, 0.6623234319361953, 0.0, + 0.689806698245354, + 0.04883686128677976, 0.08382459729494686, 0.0, + 0.0021114516459281177, + 0.15909290019096098, 0.07954645009548049], + linf=[9.362339085941425, 9.169838118652539, 0.0, + 10.600957847359556, + 0.6628317732399827, 1.4185626901435056, 0.0, + 0.06914316292003836, + 3.328770801731456, 1.664385400865728], + tspan=(0.0, 0.01)) + # 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 end # module diff --git a/test/test_tree_2d_part1.jl b/test/test_tree_2d_part1.jl index c2076a7e235..2af1f29fcb6 100644 --- a/test/test_tree_2d_part1.jl +++ b/test/test_tree_2d_part1.jl @@ -9,82 +9,94 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) @testset "TreeMesh2D Part 1" begin +#! format: noindent # Run basic tests @testset "Examples 2D" begin - # Linear advection - include("test_tree_2d_advection.jl") + # Linear advection + include("test_tree_2d_advection.jl") - # Hyperbolic diffusion - include("test_tree_2d_hypdiff.jl") + # Hyperbolic diffusion + include("test_tree_2d_hypdiff.jl") end - @testset "Displaying components 2D" begin - @test_nowarn include(joinpath(EXAMPLES_DIR, "elixir_advection_amr.jl")) - - # test both short and long printing formats - @test_nowarn show(mesh); println() - @test_nowarn println(mesh) - @test_nowarn display(mesh) - - @test_nowarn show(equations); println() - @test_nowarn println(equations) - @test_nowarn display(equations) - - @test_nowarn show(solver); println() - @test_nowarn println(solver) - @test_nowarn display(solver) - - @test_nowarn show(solver.basis); println() - @test_nowarn println(solver.basis) - @test_nowarn display(solver.basis) - - @test_nowarn show(solver.mortar); println() - @test_nowarn println(solver.mortar) - @test_nowarn display(solver.mortar) - - @test_nowarn show(semi); println() - @test_nowarn println(semi) - @test_nowarn display(semi) - - @test_nowarn show(summary_callback); println() - @test_nowarn println(summary_callback) - @test_nowarn display(summary_callback) - - @test_nowarn show(amr_controller); println() - @test_nowarn println(amr_controller) - @test_nowarn display(amr_controller) - - @test_nowarn show(amr_callback); println() - @test_nowarn println(amr_callback) - @test_nowarn display(amr_callback) - - @test_nowarn show(stepsize_callback); println() - @test_nowarn println(stepsize_callback) - @test_nowarn display(stepsize_callback) - - @test_nowarn show(save_solution); println() - @test_nowarn println(save_solution) - @test_nowarn display(save_solution) - - @test_nowarn show(analysis_callback); println() - @test_nowarn println(analysis_callback) - @test_nowarn display(analysis_callback) - - @test_nowarn show(alive_callback); println() - @test_nowarn println(alive_callback) - @test_nowarn display(alive_callback) - - @test_nowarn println(callbacks) + @test_nowarn include(joinpath(EXAMPLES_DIR, "elixir_advection_amr.jl")) + + # test both short and long printing formats + @test_nowarn show(mesh) + println() + @test_nowarn println(mesh) + @test_nowarn display(mesh) + + @test_nowarn show(equations) + println() + @test_nowarn println(equations) + @test_nowarn display(equations) + + @test_nowarn show(solver) + println() + @test_nowarn println(solver) + @test_nowarn display(solver) + + @test_nowarn show(solver.basis) + println() + @test_nowarn println(solver.basis) + @test_nowarn display(solver.basis) + + @test_nowarn show(solver.mortar) + println() + @test_nowarn println(solver.mortar) + @test_nowarn display(solver.mortar) + + @test_nowarn show(semi) + println() + @test_nowarn println(semi) + @test_nowarn display(semi) + + @test_nowarn show(summary_callback) + println() + @test_nowarn println(summary_callback) + @test_nowarn display(summary_callback) + + @test_nowarn show(amr_controller) + println() + @test_nowarn println(amr_controller) + @test_nowarn display(amr_controller) + + @test_nowarn show(amr_callback) + println() + @test_nowarn println(amr_callback) + @test_nowarn display(amr_callback) + + @test_nowarn show(stepsize_callback) + println() + @test_nowarn println(stepsize_callback) + @test_nowarn display(stepsize_callback) + + @test_nowarn show(save_solution) + println() + @test_nowarn println(save_solution) + @test_nowarn display(save_solution) + + @test_nowarn show(analysis_callback) + println() + @test_nowarn println(analysis_callback) + @test_nowarn display(analysis_callback) + + @test_nowarn show(alive_callback) + println() + @test_nowarn println(alive_callback) + @test_nowarn display(alive_callback) + + @test_nowarn println(callbacks) end # Clean up afterwards: delete Trixi.jl output directory -@test_nowarn rm(outdir, recursive=true) - +@test_nowarn rm(outdir, recursive = true) end # TreeMesh2D Part 1 end #module diff --git a/test/test_tree_2d_part2.jl b/test/test_tree_2d_part2.jl index e25b5888c63..d8e86d14f18 100644 --- a/test/test_tree_2d_part2.jl +++ b/test/test_tree_2d_part2.jl @@ -7,34 +7,34 @@ include("test_trixi.jl") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) @testset "TreeMesh2D Part 2" begin +#! format: noindent # Run basic tests @testset "Examples 2D" begin - # Acoustic perturbation - include("test_tree_2d_acoustics.jl") + # Acoustic perturbation + include("test_tree_2d_acoustics.jl") - # Linearized Euler - include("test_tree_2d_linearizedeuler.jl") + # Linearized Euler + include("test_tree_2d_linearizedeuler.jl") - # Compressible Euler - include("test_tree_2d_euler.jl") + # Compressible Euler + include("test_tree_2d_euler.jl") - # Compressible Euler Multicomponent - include("test_tree_2d_eulermulti.jl") + # Compressible Euler Multicomponent + include("test_tree_2d_eulermulti.jl") - # Compressible Euler coupled with acoustic perturbation equations - include("test_tree_2d_euleracoustics.jl") + # Compressible Euler coupled with acoustic perturbation equations + include("test_tree_2d_euleracoustics.jl") - # KPP problem - include("test_tree_2d_kpp.jl") + # KPP problem + include("test_tree_2d_kpp.jl") end # Clean up afterwards: delete Trixi.jl output directory -@test_nowarn rm(outdir, recursive=true) - +@test_nowarn rm(outdir, recursive = true) end # TreeMesh2D Part 2 end #module diff --git a/test/test_tree_2d_part3.jl b/test/test_tree_2d_part3.jl index 450dad6eadd..ce9b3bc04f8 100644 --- a/test/test_tree_2d_part3.jl +++ b/test/test_tree_2d_part3.jl @@ -7,34 +7,34 @@ include("test_trixi.jl") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) @testset "TreeMesh2D Part 3" begin +#! format: noindent # Run basic tests @testset "Examples 2D" begin - # MHD - include("test_tree_2d_mhd.jl") + # MHD + include("test_tree_2d_mhd.jl") - # MHD Multicomponent - include("test_tree_2d_mhdmulti.jl") + # MHD Multicomponent + include("test_tree_2d_mhdmulti.jl") - # Lattice-Boltzmann - include("test_tree_2d_lbm.jl") + # Lattice-Boltzmann + include("test_tree_2d_lbm.jl") - # Shallow water - include("test_tree_2d_shallowwater.jl") + # Shallow water + include("test_tree_2d_shallowwater.jl") - # Two-Layer Shallow Water - include("test_tree_2d_shallowwater_twolayer.jl") + # Two-Layer Shallow Water + include("test_tree_2d_shallowwater_twolayer.jl") - # FDSBP methods on the TreeMesh - include("test_tree_2d_fdsbp.jl") + # FDSBP methods on the TreeMesh + include("test_tree_2d_fdsbp.jl") end # Clean up afterwards: delete Trixi.jl output directory -@test_nowarn rm(outdir, recursive=true) - +@test_nowarn rm(outdir, recursive = true) end # TreeMesh2D Part 3 end #module diff --git a/test/test_tree_2d_shallowwater.jl b/test/test_tree_2d_shallowwater.jl index 126c16e3356..d280e380192 100644 --- a/test/test_tree_2d_shallowwater.jl +++ b/test/test_tree_2d_shallowwater.jl @@ -10,157 +10,265 @@ include("test_trixi.jl") EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") @testset "Shallow Water" begin - @trixi_testset "elixir_shallowwater_ec.jl" begin +#! format: noindent + +@trixi_testset "elixir_shallowwater_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_ec.jl"), - l2 = [0.991181203601035, 0.734130029040644, 0.7447696147162621, 0.5875351036989047], - linf = [2.0117744577945413, 2.9962317608172127, 2.6554999727293653, 3.0], - tspan = (0.0, 0.25)) - # 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 + l2=[ + 0.991181203601035, + 0.734130029040644, + 0.7447696147162621, + 0.5875351036989047, + ], + linf=[ + 2.0117744577945413, + 2.9962317608172127, + 2.6554999727293653, + 3.0, + ], + tspan=(0.0, 0.25)) + # 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 = [0.9130579602987144, 1.0602847041965408e-14, 1.082225645390032e-14, 0.9130579602987147], - linf = [2.113062037615659, 4.6613606802974e-14, 5.4225772771633196e-14, 2.1130620376156584], - tspan = (0.0, 0.25)) - # 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_wall.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced_wall.jl"), - l2 = [0.9130579602987144, 1.0602847041965408e-14, 1.082225645390032e-14, 0.9130579602987147], - linf = [2.113062037615659, 4.6613606802974e-14, 5.4225772771633196e-14, 2.1130620376156584], - tspan = (0.0, 0.25)) - # 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 with FluxHydrostaticReconstruction" begin + l2=[ + 0.9130579602987144, + 1.0602847041965408e-14, + 1.082225645390032e-14, + 0.9130579602987147, + ], + linf=[ + 2.113062037615659, + 4.6613606802974e-14, + 5.4225772771633196e-14, + 2.1130620376156584, + ], + tspan=(0.0, 0.25)) + # 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_wall.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_well_balanced_wall.jl"), + l2=[ + 0.9130579602987144, + 1.0602847041965408e-14, + 1.082225645390032e-14, + 0.9130579602987147, + ], + linf=[ + 2.113062037615659, + 4.6613606802974e-14, + 5.4225772771633196e-14, + 2.1130620376156584, + ], + tspan=(0.0, 0.25)) + # 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 with FluxHydrostaticReconstruction" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced.jl"), - l2 = [0.9130579602987147, 9.68729463970494e-15, 9.694538537436981e-15, 0.9130579602987147], - linf = [2.1130620376156584, 2.3875905654916432e-14, 2.2492839032269154e-14, 2.1130620376156584], - surface_flux=(FluxHydrostaticReconstruction(flux_lax_friedrichs, hydrostatic_reconstruction_audusse_etal), flux_nonconservative_audusse_etal), - tspan = (0.0, 0.25)) - # 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_wet_dry.jl with FluxHydrostaticReconstruction" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced_wet_dry.jl"), - l2 = [0.030186039395610056, 2.513287752536758e-14, 1.3631397744897607e-16, 0.10911781485920438], - linf = [0.49999999999993505, 5.5278950497971455e-14, 7.462550826772548e-16, 2.0], - tspan = (0.0, 0.25)) - # 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_source_terms.jl" begin + l2=[ + 0.9130579602987147, + 9.68729463970494e-15, + 9.694538537436981e-15, + 0.9130579602987147, + ], + linf=[ + 2.1130620376156584, + 2.3875905654916432e-14, + 2.2492839032269154e-14, + 2.1130620376156584, + ], + surface_flux=(FluxHydrostaticReconstruction(flux_lax_friedrichs, + hydrostatic_reconstruction_audusse_etal), + flux_nonconservative_audusse_etal), + tspan=(0.0, 0.25)) + # 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_wet_dry.jl with FluxHydrostaticReconstruction" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_well_balanced_wet_dry.jl"), + l2=[ + 0.030186039395610056, + 2.513287752536758e-14, + 1.3631397744897607e-16, + 0.10911781485920438, + ], + linf=[ + 0.49999999999993505, + 5.5278950497971455e-14, + 7.462550826772548e-16, + 2.0, + ], + tspan=(0.0, 0.25)) + # 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_source_terms.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), - l2 = [0.001868474306068482, 0.01731687445878443, 0.017649083171490863, 6.274146767717023e-5], - linf = [0.016962486402209986, 0.08768628853889782, 0.09038488750767648, 0.0001819675955490041], - tspan = (0.0, 0.025)) - # 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_source_terms_dirichlet.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms_dirichlet.jl"), - l2 = [0.0018746929418489125, 0.017332321628469628, 0.01634953679145536, 6.274146767717023e-5], - linf = [0.016262353691956388, 0.08726160620859424, 0.09043621801418844, 0.0001819675955490041], - tspan = (0.0, 0.025)) - # 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_source_terms.jl with flux_hll" begin + l2=[ + 0.001868474306068482, + 0.01731687445878443, + 0.017649083171490863, + 6.274146767717023e-5, + ], + linf=[ + 0.016962486402209986, + 0.08768628853889782, + 0.09038488750767648, + 0.0001819675955490041, + ], + tspan=(0.0, 0.025)) + # 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_source_terms_dirichlet.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_source_terms_dirichlet.jl"), + l2=[ + 0.0018746929418489125, + 0.017332321628469628, + 0.01634953679145536, + 6.274146767717023e-5, + ], + linf=[ + 0.016262353691956388, + 0.08726160620859424, + 0.09043621801418844, + 0.0001819675955490041, + ], + tspan=(0.0, 0.025)) + # 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_source_terms.jl with flux_hll" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), - l2 = [0.0018957692481057034, 0.016943229710439864, 0.01755623297390675, 6.274146767717414e-5], - linf = [0.015156105797771602, 0.07964811135780492, 0.0839787097210376, 0.0001819675955490041], - tspan = (0.0, 0.025), surface_flux=(flux_hll, flux_nonconservative_fjordholm_etal)) - # 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_conical_island.jl" begin + l2=[ + 0.0018957692481057034, + 0.016943229710439864, + 0.01755623297390675, + 6.274146767717414e-5, + ], + linf=[ + 0.015156105797771602, + 0.07964811135780492, + 0.0839787097210376, + 0.0001819675955490041, + ], + tspan=(0.0, 0.025), + surface_flux=(flux_hll, flux_nonconservative_fjordholm_etal)) + # 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_conical_island.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_conical_island.jl"), - l2 = [0.0459315416430658, 0.1644534881916991, 0.16445348819169914, 0.0011537702354532694], - linf = [0.21100717610846464, 0.9501592344310412, 0.9501592344310417, 0.021790250683516282], - tspan = (0.0, 0.025)) - # 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_parabolic_bowl.jl" begin + l2=[ + 0.0459315416430658, + 0.1644534881916991, + 0.16445348819169914, + 0.0011537702354532694, + ], + linf=[ + 0.21100717610846464, + 0.9501592344310412, + 0.9501592344310417, + 0.021790250683516282, + ], + tspan=(0.0, 0.025)) + # 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_parabolic_bowl.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_parabolic_bowl.jl"), - l2 = [0.00025345501281482687, 4.4525120338817177e-5, 0.00015991819160294247, 7.750412064917294e-15], - linf = [0.004664246019836723, 0.0004972780116736669, 0.0028735707270457628, 6.866729407306593e-14], - tspan = (0.0, 0.025), - basis = LobattoLegendreBasis(3)) - # 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 + l2=[ + 0.00025345501281482687, + 4.4525120338817177e-5, + 0.00015991819160294247, + 7.750412064917294e-15, + ], + linf=[ + 0.004664246019836723, + 0.0004972780116736669, + 0.0028735707270457628, + 6.866729407306593e-14, + ], + tspan=(0.0, 0.025), + basis=LobattoLegendreBasis(3)) + # 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 end # module diff --git a/test/test_tree_2d_shallowwater_twolayer.jl b/test/test_tree_2d_shallowwater_twolayer.jl index d98d682506e..5959e7ed882 100644 --- a/test/test_tree_2d_shallowwater_twolayer.jl +++ b/test/test_tree_2d_shallowwater_twolayer.jl @@ -10,81 +10,105 @@ include("test_trixi.jl") EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") @testset "Two-Layer Shallow Water" begin - @trixi_testset "elixir_shallowwater_twolayer_convergence.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_twolayer_convergence.jl"), - l2 = [0.0004040147445601598, 0.005466848793475609, 0.006149138398472166, 0.0002908599437447256, - 0.003011817461911792, 0.0026806180089700674, 8.873630921431545e-6], - linf = [0.002822006686981293, 0.014859895905040332, 0.017590546190827894, 0.0016323702636176218, - 0.009361402900653015, 0.008411036357379165, 3.361991620143279e-5], - tspan = (0.0, 0.25)) - # 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 +#! format: noindent + +@trixi_testset "elixir_shallowwater_twolayer_convergence.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_twolayer_convergence.jl"), + l2=[0.0004040147445601598, 0.005466848793475609, + 0.006149138398472166, 0.0002908599437447256, + 0.003011817461911792, 0.0026806180089700674, + 8.873630921431545e-6], + linf=[0.002822006686981293, 0.014859895905040332, + 0.017590546190827894, 0.0016323702636176218, + 0.009361402900653015, 0.008411036357379165, + 3.361991620143279e-5], + tspan=(0.0, 0.25)) + # 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 - @trixi_testset "elixir_shallowwater_twolayer_convergence.jl with flux_es_fjordholm_etal" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_twolayer_convergence.jl"), - l2 = [0.00024709443131137236, 0.0019215286339769443, 0.0023833298173254447, - 0.00021258247976270914, 0.0011299428031136195, 0.0009191313765262401, - 8.873630921431545e-6], - linf = [0.0016099763244645793, 0.007659242165565017, 0.009123320235427057, - 0.0013496983982568267, 0.0035573687287770994, 0.00296823235874899, - 3.361991620143279e-5], - surface_flux = (flux_es_fjordholm_etal, flux_nonconservative_fjordholm_etal), - tspan = (0.0, 0.25)) - # 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 +@trixi_testset "elixir_shallowwater_twolayer_convergence.jl with flux_es_fjordholm_etal" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_twolayer_convergence.jl"), + l2=[0.00024709443131137236, 0.0019215286339769443, + 0.0023833298173254447, + 0.00021258247976270914, 0.0011299428031136195, + 0.0009191313765262401, + 8.873630921431545e-6], + linf=[0.0016099763244645793, 0.007659242165565017, + 0.009123320235427057, + 0.0013496983982568267, 0.0035573687287770994, + 0.00296823235874899, + 3.361991620143279e-5], + surface_flux=(flux_es_fjordholm_etal, + flux_nonconservative_fjordholm_etal), + tspan=(0.0, 0.25)) + # 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 - @trixi_testset "elixir_shallowwater_twolayer_well_balanced.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_twolayer_well_balanced.jl"), - l2 = [3.2935164267930016e-16, 4.6800825611195103e-17, 4.843057532147818e-17, - 0.0030769233188015013, 1.4809161150389857e-16, 1.509071695038043e-16, - 0.0030769233188014935], - linf = [2.248201624865942e-15, 2.346382070278936e-16, 2.208565017494899e-16, - 0.026474051138910493, 9.237568031609006e-16, 7.520758026187046e-16, - 0.026474051138910267], - tspan = (0.0, 0.25)) - # 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 +@trixi_testset "elixir_shallowwater_twolayer_well_balanced.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_twolayer_well_balanced.jl"), + l2=[3.2935164267930016e-16, 4.6800825611195103e-17, + 4.843057532147818e-17, + 0.0030769233188015013, 1.4809161150389857e-16, + 1.509071695038043e-16, + 0.0030769233188014935], + linf=[2.248201624865942e-15, 2.346382070278936e-16, + 2.208565017494899e-16, + 0.026474051138910493, 9.237568031609006e-16, + 7.520758026187046e-16, + 0.026474051138910267], + tspan=(0.0, 0.25)) + # 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 - @trixi_testset "elixir_shallowwater_twolayer_well_balanced with flux_lax_friedrichs.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_twolayer_well_balanced.jl"), - l2 = [2.0525741072929735e-16, 6.000589392730905e-17, 6.102759428478984e-17, - 0.0030769233188014905, 1.8421386173122792e-16, 1.8473184927121752e-16, - 0.0030769233188014935], - linf = [7.355227538141662e-16, 2.960836949170518e-16, 4.2726562436938764e-16, - 0.02647405113891016, 1.038795478061861e-15, 1.0401789378532516e-15, - 0.026474051138910267], - surface_flux = (flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), - tspan = (0.0, 0.25)) - # 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 +@trixi_testset "elixir_shallowwater_twolayer_well_balanced with flux_lax_friedrichs.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_twolayer_well_balanced.jl"), + l2=[2.0525741072929735e-16, 6.000589392730905e-17, + 6.102759428478984e-17, + 0.0030769233188014905, 1.8421386173122792e-16, + 1.8473184927121752e-16, + 0.0030769233188014935], + linf=[7.355227538141662e-16, 2.960836949170518e-16, + 4.2726562436938764e-16, + 0.02647405113891016, 1.038795478061861e-15, + 1.0401789378532516e-15, + 0.026474051138910267], + surface_flux=(flux_lax_friedrichs, + flux_nonconservative_fjordholm_etal), + tspan=(0.0, 0.25)) + # 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 end end # module diff --git a/test/test_tree_3d_advection.jl b/test/test_tree_3d_advection.jl index 24e65934e60..56278629417 100644 --- a/test/test_tree_3d_advection.jl +++ b/test/test_tree_3d_advection.jl @@ -8,110 +8,114 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") @testset "Linear scalar advection" begin - @trixi_testset "elixir_advection_basic.jl" begin +#! format: noindent + +@trixi_testset "elixir_advection_basic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), - l2 = [0.00016263963870641478], - linf = [0.0014537194925779984]) - # 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 + l2=[0.00016263963870641478], + linf=[0.0014537194925779984]) + # 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_restart.jl" begin +@trixi_testset "elixir_advection_restart.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), - l2 = [0.00016017848135651983], - linf = [0.0014175368788298393]) - # 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 + l2=[0.00016017848135651983], + linf=[0.0014175368788298393]) + # 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_extended.jl with initial_condition_sin" begin +@trixi_testset "elixir_advection_extended.jl with initial_condition_sin" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2 = [0.002647730309275237], - linf = [0.02114324070353557], - initial_condition=Trixi.initial_condition_sin) - # 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 + l2=[0.002647730309275237], + linf=[0.02114324070353557], + initial_condition=Trixi.initial_condition_sin) + # 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 - @trixi_testset "elixir_advection_extended.jl with initial_condition_constant" begin +@trixi_testset "elixir_advection_extended.jl with initial_condition_constant" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2 = [7.728011630010656e-16], - linf = [3.9968028886505635e-15], - initial_condition=initial_condition_constant) - # 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 + l2=[7.728011630010656e-16], + linf=[3.9968028886505635e-15], + initial_condition=initial_condition_constant) + # 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_extended.jl with initial_condition_linear_z and periodicity=false" begin +@trixi_testset "elixir_advection_extended.jl with initial_condition_linear_z and periodicity=false" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2 = [3.007995700405795e-16], - linf = [2.886579864025407e-15], - initial_condition=Trixi.initial_condition_linear_z, - boundary_conditions=Trixi.boundary_condition_linear_z, periodicity=false) - # 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 + l2=[3.007995700405795e-16], + linf=[2.886579864025407e-15], + initial_condition=Trixi.initial_condition_linear_z, + boundary_conditions=Trixi.boundary_condition_linear_z, + periodicity=false) + # 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 - @trixi_testset "elixir_advection_mortar.jl" begin +@trixi_testset "elixir_advection_mortar.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_mortar.jl"), - l2 = [0.001810141301577316], - linf = [0.017848192256602058]) + l2=[0.001810141301577316], + linf=[0.017848192256602058]) # 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 + 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 - @trixi_testset "elixir_advection_amr.jl" begin +@trixi_testset "elixir_advection_amr.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr.jl"), - l2 = [9.773852895157622e-6], - linf = [0.0005853874124926162], - coverage_override = (maxiters=6, initial_refinement_level=1, base_level=1, med_level=1, max_level=3)) + l2=[9.773852895157622e-6], + linf=[0.0005853874124926162], + coverage_override=(maxiters = 6, initial_refinement_level = 1, + base_level = 1, med_level = 1, max_level = 3)) - # 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 + # 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 end # module diff --git a/test/test_tree_3d_euler.jl b/test/test_tree_3d_euler.jl index fe5e42843f8..d96dcff3977 100644 --- a/test/test_tree_3d_euler.jl +++ b/test/test_tree_3d_euler.jl @@ -8,262 +8,471 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") @testset "Compressible Euler" begin - @trixi_testset "elixir_euler_source_terms.jl" begin +#! format: noindent + +@trixi_testset "elixir_euler_source_terms.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms.jl"), - l2 = [0.010385936842224346, 0.009776048833895767, 0.00977604883389591, 0.009776048833895733, 0.01506687097416608], - linf = [0.03285848350791731, 0.0321792316408982, 0.032179231640894645, 0.032179231640895534, 0.0655408023333299]) - # 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 + l2=[ + 0.010385936842224346, + 0.009776048833895767, + 0.00977604883389591, + 0.009776048833895733, + 0.01506687097416608, + ], + linf=[ + 0.03285848350791731, + 0.0321792316408982, + 0.032179231640894645, + 0.032179231640895534, + 0.0655408023333299, + ]) + # 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_convergence_pure_fv.jl" begin +@trixi_testset "elixir_euler_convergence_pure_fv.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence_pure_fv.jl"), - l2 = [0.037182410351406, 0.032062252638283974, 0.032062252638283974, 0.03206225263828395, 0.12228177813586687], - linf = [0.0693648413632646, 0.0622101894740843, 0.06221018947408474, 0.062210189474084965, 0.24196451799555962]) - # 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 + l2=[ + 0.037182410351406, + 0.032062252638283974, + 0.032062252638283974, + 0.03206225263828395, + 0.12228177813586687, + ], + linf=[ + 0.0693648413632646, + 0.0622101894740843, + 0.06221018947408474, + 0.062210189474084965, + 0.24196451799555962, + ]) + # 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_source_terms.jl with split_form" begin +@trixi_testset "elixir_euler_source_terms.jl with split_form" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms.jl"), - l2 = [0.010385936842223388, 0.009776048833894784, 0.009776048833894784, 0.009776048833894765, 0.015066870974164096], - linf = [0.03285848350791687, 0.032179231640897754, 0.0321792316408942, 0.0321792316408982, 0.06554080233333615], - volume_integral=VolumeIntegralFluxDifferencing(flux_central)) - # 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 + l2=[ + 0.010385936842223388, + 0.009776048833894784, + 0.009776048833894784, + 0.009776048833894765, + 0.015066870974164096, + ], + linf=[ + 0.03285848350791687, + 0.032179231640897754, + 0.0321792316408942, + 0.0321792316408982, + 0.06554080233333615, + ], + volume_integral=VolumeIntegralFluxDifferencing(flux_central)) + # 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_convergence.jl" begin +@trixi_testset "elixir_euler_convergence.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), - l2 = [0.0003637241020254405, 0.0003955570866382718, 0.0003955570866383613, 0.00039555708663834417, 0.0007811613481640202], - linf = [0.0024000660244674066, 0.0029635410025339315, 0.0029635410025292686, 0.002963541002525938, 0.007191437359396424]) - # 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 + l2=[ + 0.0003637241020254405, + 0.0003955570866382718, + 0.0003955570866383613, + 0.00039555708663834417, + 0.0007811613481640202, + ], + linf=[ + 0.0024000660244674066, + 0.0029635410025339315, + 0.0029635410025292686, + 0.002963541002525938, + 0.007191437359396424, + ]) + # 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_mortar.jl" begin +@trixi_testset "elixir_euler_mortar.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_mortar.jl"), - l2 = [0.0019428114665068841, 0.0018659907926698422, 0.0018659907926698589, 0.0018659907926698747, 0.0034549095578444056], - linf = [0.011355360771142298, 0.011526889155693887, 0.011526889155689002, 0.011526889155701436, 0.02299726519821288]) - # 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 + l2=[ + 0.0019428114665068841, + 0.0018659907926698422, + 0.0018659907926698589, + 0.0018659907926698747, + 0.0034549095578444056, + ], + linf=[ + 0.011355360771142298, + 0.011526889155693887, + 0.011526889155689002, + 0.011526889155701436, + 0.02299726519821288, + ]) + # 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_amr.jl" begin +@trixi_testset "elixir_euler_amr.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_amr.jl"), - l2 = [0.0038281920613404716, 0.003828192061340465, 0.0038281920613404694, 0.0038281920613404672, 0.005742288092010652], - linf = [0.07390396464027349, 0.07390396464027305, 0.07390396464027305, 0.07390396464027305, 0.11085594696041134], - tspan=(0.0, 0.1), - coverage_override = (maxiters=6, initial_refinement_level=0, base_level=0, med_level=0, max_level=1)) - # 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 + l2=[ + 0.0038281920613404716, + 0.003828192061340465, + 0.0038281920613404694, + 0.0038281920613404672, + 0.005742288092010652, + ], + linf=[ + 0.07390396464027349, + 0.07390396464027305, + 0.07390396464027305, + 0.07390396464027305, + 0.11085594696041134, + ], + tspan=(0.0, 0.1), + coverage_override=(maxiters = 6, initial_refinement_level = 0, + base_level = 0, med_level = 0, max_level = 1)) + # 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_taylor_green_vortex.jl" begin +@trixi_testset "elixir_euler_taylor_green_vortex.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_taylor_green_vortex.jl"), - l2 = [0.00034949871748737876, 0.03133384111621587, 0.03133384111621582, 0.04378599329988925, 0.015796137903453026], - linf = [0.0013935237751798724, 0.0724080091006194, 0.07240800910061806, 0.12795921224174792, 0.07677156293692633], - tspan = (0.0, 0.5)) - # 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 + l2=[ + 0.00034949871748737876, + 0.03133384111621587, + 0.03133384111621582, + 0.04378599329988925, + 0.015796137903453026, + ], + linf=[ + 0.0013935237751798724, + 0.0724080091006194, + 0.07240800910061806, + 0.12795921224174792, + 0.07677156293692633, + ], + tspan=(0.0, 0.5)) + # 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_shockcapturing.jl" begin +@trixi_testset "elixir_euler_shockcapturing.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing.jl"), - l2 = [0.02570137197844877, 0.016179934130642552, 0.01617993413064253, 0.016172648598753545, 0.09261669328795467], - linf = [0.3954458125573179, 0.26876916180359345, 0.26876916180359345, 0.26933123042178553, 1.3724137121660251]) - # 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 + l2=[ + 0.02570137197844877, + 0.016179934130642552, + 0.01617993413064253, + 0.016172648598753545, + 0.09261669328795467, + ], + linf=[ + 0.3954458125573179, + 0.26876916180359345, + 0.26876916180359345, + 0.26933123042178553, + 1.3724137121660251, + ]) + # 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_shockcapturing_amr.jl" begin +@trixi_testset "elixir_euler_shockcapturing_amr.jl" begin # OBS! This setup does not make much practical sense. It is only added to exercise the # `sedov_self_gravity` AMR indicator, which in its original configuration is too expensive for # CI testing @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing_amr.jl"), - l2 = [0.02217299067704248, 0.012771561294571411, 0.01277156129457143, 0.012770635779336643, 0.08091898488262424], - linf = [0.4047819603427084, 0.27493532130155474, 0.2749353213015551, 0.2749304638368023, 1.4053942765487641], - maxiters=10, - coverage_override = (maxiters=2,)) - # 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 + l2=[ + 0.02217299067704248, + 0.012771561294571411, + 0.01277156129457143, + 0.012770635779336643, + 0.08091898488262424, + ], + linf=[ + 0.4047819603427084, + 0.27493532130155474, + 0.2749353213015551, + 0.2749304638368023, + 1.4053942765487641, + ], + maxiters=10, + coverage_override=(maxiters = 2,)) + # 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_density_pulse.jl" begin +@trixi_testset "elixir_euler_density_pulse.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_density_pulse.jl"), - l2 = [0.057196526814004715, 0.057196526814004715, 0.05719652681400473, 0.057196526814004736, 0.08579479022100575], - linf = [0.27415246703018203, 0.2741524670301829, 0.2741524670301827, 0.27415246703018226, 0.41122870054527816]) - # 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 + l2=[ + 0.057196526814004715, + 0.057196526814004715, + 0.05719652681400473, + 0.057196526814004736, + 0.08579479022100575, + ], + linf=[ + 0.27415246703018203, + 0.2741524670301829, + 0.2741524670301827, + 0.27415246703018226, + 0.41122870054527816, + ]) + # 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_ec.jl" begin +@trixi_testset "elixir_euler_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.02526341317987378, 0.016632068583699623, 0.016632068583699623, 0.01662548715216875, 0.0913477018048886], - linf = [0.4372549540810414, 0.28613118232798984, 0.28613118232799006, 0.28796686065271876, 1.5072828647309124]) - # 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 + l2=[ + 0.02526341317987378, + 0.016632068583699623, + 0.016632068583699623, + 0.01662548715216875, + 0.0913477018048886, + ], + linf=[ + 0.4372549540810414, + 0.28613118232798984, + 0.28613118232799006, + 0.28796686065271876, + 1.5072828647309124, + ]) + # 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_ec.jl with initial_condition=initial_condition_constant" begin +@trixi_testset "elixir_euler_ec.jl with initial_condition=initial_condition_constant" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [4.183721551616214e-16, 6.059779958716338e-16, 4.916596221090319e-16, 9.739943366304456e-16, 3.7485908743251566e-15], - linf = [2.4424906541753444e-15, 3.733124920302089e-15, 4.440892098500626e-15, 5.329070518200751e-15, 2.4868995751603507e-14], - initial_condition=initial_condition_constant) - # 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 + l2=[ + 4.183721551616214e-16, + 6.059779958716338e-16, + 4.916596221090319e-16, + 9.739943366304456e-16, + 3.7485908743251566e-15, + ], + linf=[ + 2.4424906541753444e-15, + 3.733124920302089e-15, + 4.440892098500626e-15, + 5.329070518200751e-15, + 2.4868995751603507e-14, + ], + initial_condition=initial_condition_constant) + # 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_ec.jl with flux_chandrashekar" begin +@trixi_testset "elixir_euler_ec.jl with flux_chandrashekar" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.025265721172813106, 0.016649800693500427, 0.01664980069350042, 0.01664379306708522, 0.09137248646784184], - linf = [0.4373399329742198, 0.28434487167605427, 0.28434487167605427, 0.28522678968890774, 1.532471676033761], - surface_flux=flux_chandrashekar, volume_flux=flux_chandrashekar) - # 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 + l2=[ + 0.025265721172813106, + 0.016649800693500427, + 0.01664980069350042, + 0.01664379306708522, + 0.09137248646784184, + ], + linf=[ + 0.4373399329742198, + 0.28434487167605427, + 0.28434487167605427, + 0.28522678968890774, + 1.532471676033761, + ], + surface_flux=flux_chandrashekar, volume_flux=flux_chandrashekar) + # 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_ec.jl with flux_kennedy_gruber" begin +@trixi_testset "elixir_euler_ec.jl with flux_kennedy_gruber" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.025280033869871984, 0.016675487948639846, 0.016675487948639853, 0.016668992714991282, 0.091455613470441], - linf = [0.43348628145015766, 0.28853549062014217, 0.28853549062014217, 0.2903943042772536, 1.5236557526482426], - surface_flux=flux_kennedy_gruber, volume_flux=flux_kennedy_gruber) - # 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 + l2=[ + 0.025280033869871984, + 0.016675487948639846, + 0.016675487948639853, + 0.016668992714991282, + 0.091455613470441, + ], + linf=[ + 0.43348628145015766, + 0.28853549062014217, + 0.28853549062014217, + 0.2903943042772536, + 1.5236557526482426, + ], + surface_flux=flux_kennedy_gruber, + volume_flux=flux_kennedy_gruber) + # 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_ec.jl with flux_shima_etal" begin +@trixi_testset "elixir_euler_ec.jl with flux_shima_etal" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.025261716925811403, 0.016637655557848952, 0.01663765555784895, 0.01663105921013437, 0.09136239054024566], - linf = [0.43692416928732536, 0.28622033209064734, 0.28622033209064746, 0.2881197143457632, 1.506534270303663], - surface_flux=flux_shima_etal, volume_flux=flux_shima_etal) - # 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 + l2=[ + 0.025261716925811403, + 0.016637655557848952, + 0.01663765555784895, + 0.01663105921013437, + 0.09136239054024566, + ], + linf=[ + 0.43692416928732536, + 0.28622033209064734, + 0.28622033209064746, + 0.2881197143457632, + 1.506534270303663, + ], + surface_flux=flux_shima_etal, volume_flux=flux_shima_etal) + # 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_blob_amr.jl" begin +@trixi_testset "elixir_euler_blob_amr.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blob_amr.jl"), - l2 = [0.04867856452253151, 0.2640486962336911, 0.0354927658652858, 0.03549276586528571, 1.0777274757408568], - linf = [9.558543313792217, 49.4518309553356, 10.319859082570309, 10.319859082570487, 195.1066220797401], - tspan = (0.0, 0.2), - # Let this test run longer to cover some lines in the positivity preserving limiter - # and some AMR lines - coverage_override = (maxiters=10^5,)) - # 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 + l2=[ + 0.04867856452253151, + 0.2640486962336911, + 0.0354927658652858, + 0.03549276586528571, + 1.0777274757408568, + ], + linf=[ + 9.558543313792217, + 49.4518309553356, + 10.319859082570309, + 10.319859082570487, + 195.1066220797401, + ], + tspan=(0.0, 0.2), + # Let this test run longer to cover some lines in the positivity preserving limiter + # and some AMR lines + coverage_override=(maxiters = 10^5,)) + # 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_blast_wave.jl" begin +@trixi_testset "elixir_euler_sedov_blast_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov_blast_wave.jl"), - l2 = [0.0007127163978031706, 0.0023166296394624025, 0.002316629639462401, 0.0023166296394624038, 0.010200581509653256], - linf = [0.06344190883105805, 0.6292607955969378, 0.6292607955969377, 0.6292607955969377, 2.397746252817731], - maxiters=5, max_level=6, - coverage_override = (maxiters=2, initial_refinement_level=1, base_level=1, max_level=3)) - # 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 + l2=[ + 0.0007127163978031706, + 0.0023166296394624025, + 0.002316629639462401, + 0.0023166296394624038, + 0.010200581509653256, + ], + linf=[ + 0.06344190883105805, + 0.6292607955969378, + 0.6292607955969377, + 0.6292607955969377, + 2.397746252817731, + ], + maxiters=5, max_level=6, + coverage_override=(maxiters = 2, initial_refinement_level = 1, + base_level = 1, max_level = 3)) + # 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 end # module diff --git a/test/test_tree_3d_eulergravity.jl b/test/test_tree_3d_eulergravity.jl index 3146b88aeb0..1b5e715f774 100644 --- a/test/test_tree_3d_eulergravity.jl +++ b/test/test_tree_3d_eulergravity.jl @@ -8,20 +8,34 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") @testset "Compressible Euler with self-gravity" begin - @trixi_testset "elixir_eulergravity_convergence.jl" begin +#! format: noindent + +@trixi_testset "elixir_eulergravity_convergence.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulergravity_convergence.jl"), - l2 = [0.0004276779201667428, 0.00047204222332596204, 0.00047204222332608705, 0.0004720422233259819, 0.0010987026250960728], - linf = [0.003496616916238704, 0.003764418290373106, 0.003764418290377103, 0.0037644182903766588, 0.008370424899251105], - resid_tol = 1.0e-4, tspan = (0.0, 0.2)) - # 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 + l2=[ + 0.0004276779201667428, + 0.00047204222332596204, + 0.00047204222332608705, + 0.0004720422233259819, + 0.0010987026250960728, + ], + linf=[ + 0.003496616916238704, + 0.003764418290373106, + 0.003764418290377103, + 0.0037644182903766588, + 0.008370424899251105, + ], + resid_tol=1.0e-4, tspan=(0.0, 0.2)) + # 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 end # module diff --git a/test/test_tree_3d_fdsbp.jl b/test/test_tree_3d_fdsbp.jl index f45f2b0f78a..16508df300e 100644 --- a/test/test_tree_3d_fdsbp.jl +++ b/test/test_tree_3d_fdsbp.jl @@ -8,90 +8,133 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_fdsbp") @testset "Linear scalar advection" begin - @trixi_testset "elixir_advection_extended.jl" begin +#! format: noindent + +@trixi_testset "elixir_advection_extended.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2 = [0.005355755365412444], - linf = [0.01856044696350767]) + l2=[0.005355755365412444], + linf=[0.01856044696350767]) # 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 + 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 - @trixi_testset "elixir_advection_extended.jl with periodic operators" begin +@trixi_testset "elixir_advection_extended.jl with periodic operators" begin + global D = SummationByPartsOperators.periodic_derivative_operator(derivative_order = 1, + accuracy_order = 4, + xmin = 0.0, + xmax = 1.0, + N = 10) @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2 = [1.3819894522373702e-8], - linf = [3.381866298113323e-8], - D_SBP = SummationByPartsOperators.periodic_derivative_operator( - derivative_order = 1, accuracy_order = 4, xmin = 0.0, xmax = 1.0, N = 10), - initial_refinement_level = 0, - tspan = (0.0, 5.0)) + l2=[1.3819894522373702e-8], + linf=[3.381866298113323e-8], + D_SBP=D, + initial_refinement_level=0, + tspan=(0.0, 5.0)) # 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 + 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 end @testset "Compressible Euler" begin - @trixi_testset "elixir_euler_convergence.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), - l2 = [2.247522803543667e-5, 2.2499169224681058e-5, 2.24991692246826e-5, 2.2499169224684707e-5, 5.814121361417382e-5], - linf = [9.579357410749445e-5, 9.544871933409027e-5, 9.54487193367548e-5, 9.544871933453436e-5, 0.0004192294529472562], - tspan = (0.0, 0.2)) + @trixi_testset "elixir_euler_convergence.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), + l2=[ + 2.247522803543667e-5, + 2.2499169224681058e-5, + 2.24991692246826e-5, + 2.2499169224684707e-5, + 5.814121361417382e-5, + ], + linf=[ + 9.579357410749445e-5, + 9.544871933409027e-5, + 9.54487193367548e-5, + 9.544871933453436e-5, + 0.0004192294529472562, + ], + tspan=(0.0, 0.2)) - # 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 + # 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 - @trixi_testset "elixir_euler_convergence.jl with VolumeIntegralStrongForm" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), - l2 = [4.084919840272202e-5, 4.1320630860402814e-5, 4.132063086040211e-5, 4.132063086039092e-5, 8.502518355874354e-5], - linf = [0.0001963934848161486, 0.00020239883896255861, 0.0002023988389729947, 0.00020239883896766564, 0.00052605624510349], - tspan = (0.0, 0.2), - solver = DG(D_upw.central, nothing, SurfaceIntegralStrongForm(), VolumeIntegralStrongForm())) + @trixi_testset "elixir_euler_convergence.jl with VolumeIntegralStrongForm" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_convergence.jl"), + l2=[ + 4.084919840272202e-5, + 4.1320630860402814e-5, + 4.132063086040211e-5, + 4.132063086039092e-5, + 8.502518355874354e-5, + ], + linf=[ + 0.0001963934848161486, + 0.00020239883896255861, + 0.0002023988389729947, + 0.00020239883896766564, + 0.00052605624510349, + ], + tspan=(0.0, 0.2), + solver=DG(D_upw.central, nothing, SurfaceIntegralStrongForm(), + VolumeIntegralStrongForm())) - # 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 + # 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_taylor_green_vortex.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_taylor_green_vortex.jl"), - l2 = [3.529693407280806e-6, 0.0004691301922633193, 0.00046913019226332234, 0.0006630180220973541, 0.0015732759680929076], - linf = [3.4253965106145756e-5, 0.0010033197685090707, 0.0010033197685091054, 0.0018655642702542635, 0.008479800046757191], - tspan = (0.0, 0.0075), abstol = 1.0e-9, reltol = 1.0e-9) + @trixi_testset "elixir_euler_taylor_green_vortex.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_taylor_green_vortex.jl"), + l2=[ + 3.529693407280806e-6, + 0.0004691301922633193, + 0.00046913019226332234, + 0.0006630180220973541, + 0.0015732759680929076, + ], + linf=[ + 3.4253965106145756e-5, + 0.0010033197685090707, + 0.0010033197685091054, + 0.0018655642702542635, + 0.008479800046757191, + ], + tspan=(0.0, 0.0075), abstol=1.0e-9, reltol=1.0e-9) - # 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 + # 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 end # module diff --git a/test/test_tree_3d_hypdiff.jl b/test/test_tree_3d_hypdiff.jl index 42231a9aaf6..5c9dacbd87d 100644 --- a/test/test_tree_3d_hypdiff.jl +++ b/test/test_tree_3d_hypdiff.jl @@ -8,49 +8,81 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") @testset "Hyperbolic diffusion" begin - @trixi_testset "elixir_hypdiff_lax_friedrichs.jl" begin +#! format: noindent + +@trixi_testset "elixir_hypdiff_lax_friedrichs.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_lax_friedrichs.jl"), - l2 = [0.001530331609036682, 0.011314177033289238, 0.011314177033289402, 0.011314177033289631], - linf = [0.02263459033909354, 0.10139777904683545, 0.10139777904683545, 0.10139777904683545], - initial_refinement_level=2) - # 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)) < 15000 - end - end - - @trixi_testset "elixir_hypdiff_lax_friedrichs.jl with surface_flux=flux_godunov)" begin + l2=[ + 0.001530331609036682, + 0.011314177033289238, + 0.011314177033289402, + 0.011314177033289631, + ], + linf=[ + 0.02263459033909354, + 0.10139777904683545, + 0.10139777904683545, + 0.10139777904683545, + ], + initial_refinement_level=2) + # 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)) < 15000 + end +end + +@trixi_testset "elixir_hypdiff_lax_friedrichs.jl with surface_flux=flux_godunov)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_lax_friedrichs.jl"), - l2 = [0.0015377731806850128, 0.01137685274151801, 0.011376852741518175, 0.011376852741518494], - linf = [0.022715420630041172, 0.10183745338964201, 0.10183745338964201, 0.1018374533896429], - initial_refinement_level=2, surface_flux=flux_godunov) - # 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)) < 15000 - end - end - - @trixi_testset "elixir_hypdiff_nonperiodic.jl" begin + l2=[ + 0.0015377731806850128, + 0.01137685274151801, + 0.011376852741518175, + 0.011376852741518494, + ], + linf=[ + 0.022715420630041172, + 0.10183745338964201, + 0.10183745338964201, + 0.1018374533896429, + ], + initial_refinement_level=2, surface_flux=flux_godunov) + # 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)) < 15000 + end +end + +@trixi_testset "elixir_hypdiff_nonperiodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_hypdiff_nonperiodic.jl"), - l2 = [0.00022868320512754316, 0.0007974309948540525, 0.0015035143230654987, 0.0015035143230655293], - linf = [0.0016405001653623241, 0.0029870057159104594, 0.009410031618285686, 0.009410031618287462]) - # 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)) < 15000 - end - end + l2=[ + 0.00022868320512754316, + 0.0007974309948540525, + 0.0015035143230654987, + 0.0015035143230655293, + ], + linf=[ + 0.0016405001653623241, + 0.0029870057159104594, + 0.009410031618285686, + 0.009410031618287462, + ]) + # 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)) < 15000 + end +end end end # module diff --git a/test/test_tree_3d_lbm.jl b/test/test_tree_3d_lbm.jl index af7b147e609..dc7e770dfa4 100644 --- a/test/test_tree_3d_lbm.jl +++ b/test/test_tree_3d_lbm.jl @@ -8,68 +8,104 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") @testset "Lattice-Boltzmann" begin - @trixi_testset "elixir_lbm_constant.jl" begin +#! format: noindent + +@trixi_testset "elixir_lbm_constant.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_lbm_constant.jl"), - l2 = [5.861930511199053e-16, 6.282772442363201e-16, 5.47591540767842e-16, - 6.379244339335046e-16, 5.81421258408584e-16, 6.634626069779352e-16, - 2.9188639102691596e-16, 2.1539168764807097e-16, 3.0131714783573674e-16, - 2.2126555191449657e-16, 2.622901122013102e-16, 2.2115776381362187e-16, - 6.32031843208421e-17, 6.103875364141341e-17, 6.821138567646266e-17, - 6.48022057541854e-17, 5.013642264182462e-17, 7.169498358338181e-17, - 1.3879946832660896e-16, 5.649850447603551e-17, 3.4686869828797276e-17, - 3.8719518141614167e-17, 3.5852179230919525e-17, 4.292415147083455e-17, - 3.608945206319316e-17, 4.187850903422495e-17, 8.254587760492495e-16], - linf = [1.1657341758564144e-15, 1.5543122344752192e-15, 1.1657341758564144e-15, - 1.4710455076283324e-15, 1.0547118733938987e-15, 1.4988010832439613e-15, - 5.273559366969494e-16, 5.065392549852277e-16, 5.967448757360216e-16, - 5.342948306008566e-16, 5.412337245047638e-16, 5.967448757360216e-16, - 3.608224830031759e-16, 3.469446951953614e-16, 2.42861286636753e-16, - 2.498001805406602e-16, 2.2898349882893854e-16, 4.3021142204224816e-16, - 2.1510571102112408e-16, 1.43982048506075e-16, 1.214306433183765e-16, - 1.4224732503009818e-16, 1.214306433183765e-16, 1.3877787807814457e-16, - 8.673617379884035e-17, 9.71445146547012e-17, 2.7755575615628914e-15], - tspan=(0.0, 0.5)) - # 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 + l2=[5.861930511199053e-16, 6.282772442363201e-16, + 5.47591540767842e-16, + 6.379244339335046e-16, 5.81421258408584e-16, + 6.634626069779352e-16, + 2.9188639102691596e-16, 2.1539168764807097e-16, + 3.0131714783573674e-16, + 2.2126555191449657e-16, 2.622901122013102e-16, + 2.2115776381362187e-16, + 6.32031843208421e-17, 6.103875364141341e-17, + 6.821138567646266e-17, + 6.48022057541854e-17, 5.013642264182462e-17, + 7.169498358338181e-17, + 1.3879946832660896e-16, 5.649850447603551e-17, + 3.4686869828797276e-17, + 3.8719518141614167e-17, 3.5852179230919525e-17, + 4.292415147083455e-17, + 3.608945206319316e-17, 4.187850903422495e-17, + 8.254587760492495e-16], + linf=[1.1657341758564144e-15, 1.5543122344752192e-15, + 1.1657341758564144e-15, + 1.4710455076283324e-15, 1.0547118733938987e-15, + 1.4988010832439613e-15, + 5.273559366969494e-16, 5.065392549852277e-16, + 5.967448757360216e-16, + 5.342948306008566e-16, 5.412337245047638e-16, + 5.967448757360216e-16, + 3.608224830031759e-16, 3.469446951953614e-16, + 2.42861286636753e-16, + 2.498001805406602e-16, 2.2898349882893854e-16, + 4.3021142204224816e-16, + 2.1510571102112408e-16, 1.43982048506075e-16, + 1.214306433183765e-16, + 1.4224732503009818e-16, 1.214306433183765e-16, + 1.3877787807814457e-16, + 8.673617379884035e-17, 9.71445146547012e-17, + 2.7755575615628914e-15], + tspan=(0.0, 0.5)) + # 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_lbm_taylor_green_vortex.jl" begin +@trixi_testset "elixir_lbm_taylor_green_vortex.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_lbm_taylor_green_vortex.jl"), - l2 = [7.516128821554829e-5, 7.516128821554695e-5, 7.516128821554932e-5, - 7.516128821554856e-5, 7.022624942862394e-6, 7.022624942862171e-6, - 2.961794427142361e-6, 2.961794427142168e-6, 2.6527195181287848e-5, - 2.6527195181287404e-5, 2.652719518128811e-5, 2.6527195181287916e-5, - 2.9617944271423104e-6, 2.961794427142108e-6, 2.652719518128758e-5, - 2.6527195181287513e-5, 2.6527195181287916e-5, 2.6527195181287872e-5, - 6.697526775466e-6, 6.697526775466029e-6, 6.697526775465903e-6, 6.697526775465986e-6, - 6.697526775466051e-6, 6.697526775465938e-6, 6.697526775465983e-6, - 6.697526775466005e-6, 2.8805380887802028e-6], - linf = [0.00021570074723312183, 0.0002157007472331357, 0.00021570074723314958, - 0.00021570074723316346, 1.9675688146578163e-5, 1.967568814660592e-5, - 9.53539471547013e-6, 9.53539471547013e-6, 5.7339968249785905e-5, - 5.7339968249778966e-5, 5.7339968249792844e-5, 5.7339968249778966e-5, - 9.535394715480539e-6, 9.53539471546666e-6, 5.73399682497755e-5, 5.7339968249785905e-5, - 5.7339968249782436e-5, 5.7339968249782436e-5, 1.3570400471223966e-5, - 1.3570400471222231e-5, 1.3570400471220496e-5, 1.3570400471224833e-5, - 1.3570400471223966e-5, 1.3570400471221364e-5, 1.3570400471224833e-5, - 1.3570400471224833e-5, 1.4249297322244114e-5], - tspan=(0.0, 0.1), - initial_refinement_level=3) - # 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 + l2=[7.516128821554829e-5, 7.516128821554695e-5, + 7.516128821554932e-5, + 7.516128821554856e-5, 7.022624942862394e-6, + 7.022624942862171e-6, + 2.961794427142361e-6, 2.961794427142168e-6, + 2.6527195181287848e-5, + 2.6527195181287404e-5, 2.652719518128811e-5, + 2.6527195181287916e-5, + 2.9617944271423104e-6, 2.961794427142108e-6, + 2.652719518128758e-5, + 2.6527195181287513e-5, 2.6527195181287916e-5, + 2.6527195181287872e-5, + 6.697526775466e-6, 6.697526775466029e-6, + 6.697526775465903e-6, 6.697526775465986e-6, + 6.697526775466051e-6, 6.697526775465938e-6, + 6.697526775465983e-6, + 6.697526775466005e-6, 2.8805380887802028e-6], + linf=[0.00021570074723312183, 0.0002157007472331357, + 0.00021570074723314958, + 0.00021570074723316346, 1.9675688146578163e-5, + 1.967568814660592e-5, + 9.53539471547013e-6, 9.53539471547013e-6, + 5.7339968249785905e-5, + 5.7339968249778966e-5, 5.7339968249792844e-5, + 5.7339968249778966e-5, + 9.535394715480539e-6, 9.53539471546666e-6, + 5.73399682497755e-5, 5.7339968249785905e-5, + 5.7339968249782436e-5, 5.7339968249782436e-5, + 1.3570400471223966e-5, + 1.3570400471222231e-5, 1.3570400471220496e-5, + 1.3570400471224833e-5, + 1.3570400471223966e-5, 1.3570400471221364e-5, + 1.3570400471224833e-5, + 1.3570400471224833e-5, 1.4249297322244114e-5], + tspan=(0.0, 0.1), + initial_refinement_level=3) + # 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 end # module diff --git a/test/test_tree_3d_mhd.jl b/test/test_tree_3d_mhd.jl index 708f2a1a038..7ce5ef1d18f 100644 --- a/test/test_tree_3d_mhd.jl +++ b/test/test_tree_3d_mhd.jl @@ -8,143 +8,288 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_3d_dgsem") @testset "MHD" begin - @trixi_testset "elixir_mhd_ec.jl" begin +#! format: noindent + +@trixi_testset "elixir_mhd_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ec.jl"), - l2 = [0.017590099293094203, 0.017695875823827714, 0.017695875823827686, 0.017698038279620777, 0.07495006099352074, 0.010391801950005755, 0.010391801950005759, 0.010393502246627087, 2.524766553484067e-16], - linf = [0.28173002819718196, 0.3297583616136297, 0.32975836161363004, 0.356862935505337, 1.2893514981209626, 0.10950981489747313, 0.10950981489747136, 0.11517234329681891, 2.0816911067714202e-15]) - # 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 + l2=[ + 0.017590099293094203, + 0.017695875823827714, + 0.017695875823827686, + 0.017698038279620777, + 0.07495006099352074, + 0.010391801950005755, + 0.010391801950005759, + 0.010393502246627087, + 2.524766553484067e-16, + ], + linf=[ + 0.28173002819718196, + 0.3297583616136297, + 0.32975836161363004, + 0.356862935505337, + 1.2893514981209626, + 0.10950981489747313, + 0.10950981489747136, + 0.11517234329681891, + 2.0816911067714202e-15, + ]) + # 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_mhd_ec.jl with initial_condition=initial_condition_constant" begin +@trixi_testset "elixir_mhd_ec.jl with initial_condition=initial_condition_constant" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ec.jl"), - l2 = [4.270231310667203e-16, 2.4381208042014784e-15, 5.345107673575357e-15, 3.00313882171883e-15, 1.7772703118758417e-14, 1.0340110783830874e-15, 1.1779095371939702e-15, 9.961878521814573e-16, 8.1201730630719145e-16], - linf = [2.4424906541753444e-15, 2.881028748902281e-14, 2.4646951146678475e-14, 2.3092638912203256e-14, 2.3447910280083306e-13, 1.7763568394002505e-14, 1.0436096431476471e-14, 2.042810365310288e-14, 7.057203733035201e-15], - atol = 1000*eps(), - initial_condition=initial_condition_constant) - # 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 + l2=[ + 4.270231310667203e-16, + 2.4381208042014784e-15, + 5.345107673575357e-15, + 3.00313882171883e-15, + 1.7772703118758417e-14, + 1.0340110783830874e-15, + 1.1779095371939702e-15, + 9.961878521814573e-16, + 8.1201730630719145e-16, + ], + linf=[ + 2.4424906541753444e-15, + 2.881028748902281e-14, + 2.4646951146678475e-14, + 2.3092638912203256e-14, + 2.3447910280083306e-13, + 1.7763568394002505e-14, + 1.0436096431476471e-14, + 2.042810365310288e-14, + 7.057203733035201e-15, + ], + atol=1000 * eps(), + initial_condition=initial_condition_constant) + # 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_mhd_alfven_wave.jl" begin +@trixi_testset "elixir_mhd_alfven_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), - l2 = [0.0032217291057246157, 0.009511644936958913, 0.004217358459420256, 0.011591709179125335, 0.009456218722393708, 0.00916500047763897, 0.005069863732625444, 0.011503011541926135, 0.003988175543749985], - linf = [0.01188593784273051, 0.03638015998373141, 0.01568200398945724, 0.04666974730787579, 0.031235294705421968, 0.03316343064943483, 0.011539436992528018, 0.04896687646520839, 0.018714054039927555]) - # 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 + l2=[ + 0.0032217291057246157, + 0.009511644936958913, + 0.004217358459420256, + 0.011591709179125335, + 0.009456218722393708, + 0.00916500047763897, + 0.005069863732625444, + 0.011503011541926135, + 0.003988175543749985, + ], + linf=[ + 0.01188593784273051, + 0.03638015998373141, + 0.01568200398945724, + 0.04666974730787579, + 0.031235294705421968, + 0.03316343064943483, + 0.011539436992528018, + 0.04896687646520839, + 0.018714054039927555, + ]) + # 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_mhd_alfven_wave.jl with flux_derigs_etal" begin +@trixi_testset "elixir_mhd_alfven_wave.jl with flux_derigs_etal" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), - l2 = [0.003755235939722358, 0.009062519246840721, 0.004096299856228109, 0.011429935838448906, 0.006897420817511043, 0.00900886245212482, 0.004926537542780259, 0.01153285554590683, 0.0037842060148666886], - linf = [0.012982853115883541, 0.0320228076558316, 0.011575276754611022, 0.04425778643430531, 0.02478109022285846, 0.03198699034954189, 0.009761077061886558, 0.04433669321441455, 0.01618905441148782], - volume_flux = (flux_derigs_etal, flux_nonconservative_powell)) - # 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 + l2=[ + 0.003755235939722358, + 0.009062519246840721, + 0.004096299856228109, + 0.011429935838448906, + 0.006897420817511043, + 0.00900886245212482, + 0.004926537542780259, + 0.01153285554590683, + 0.0037842060148666886, + ], + linf=[ + 0.012982853115883541, + 0.0320228076558316, + 0.011575276754611022, + 0.04425778643430531, + 0.02478109022285846, + 0.03198699034954189, + 0.009761077061886558, + 0.04433669321441455, + 0.01618905441148782, + ], + volume_flux=(flux_derigs_etal, flux_nonconservative_powell)) + # 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_mhd_alfven_wave_mortar.jl" begin +@trixi_testset "elixir_mhd_alfven_wave_mortar.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave_mortar.jl"), - l2 = [0.001879021634926363, 0.007032724521848316, 0.0032793932234187325, 0.009056594733320348, 0.007514150120617965, 0.007328739509868727, 0.00309794018112387, 0.009026356949274878, 0.0035732583778049776], - linf = [0.013734346970999622, 0.06173467158736011, 0.02183946452704291, 0.06258216169457917, 0.03672304497348122, 0.055120532123884625, 0.018202716205672487, 0.06133688282205586, 0.019888161885935608], - tspan = (0.0, 0.25)) - # 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 + l2=[ + 0.001879021634926363, + 0.007032724521848316, + 0.0032793932234187325, + 0.009056594733320348, + 0.007514150120617965, + 0.007328739509868727, + 0.00309794018112387, + 0.009026356949274878, + 0.0035732583778049776, + ], + linf=[ + 0.013734346970999622, + 0.06173467158736011, + 0.02183946452704291, + 0.06258216169457917, + 0.03672304497348122, + 0.055120532123884625, + 0.018202716205672487, + 0.06133688282205586, + 0.019888161885935608, + ], + tspan=(0.0, 0.25)) + # 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_mhd_alfven_wave.jl with Orszag-Tang setup + flux_hll" begin +@trixi_testset "elixir_mhd_alfven_wave.jl with Orszag-Tang setup + flux_hll" begin # OBS! This setup does not make much sense and is only used to exercise all components of the # flux_hll implementation @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), - l2 = [0.004391143689111404, 0.04144737547475548, 0.041501307637678286, 0.04150353006408862, 0.03693135855995625, 0.021125605214031118, 0.03295607553556973, 0.03296235755245784, 7.16035229384135e-6], - linf = [0.017894703320895378, 0.08486850681397005, 0.0891044523165206, 0.08492024792056754, 0.10448301878352373, 0.05381260695579509, 0.0884774018719996, 0.07784546966765199, 7.71609149516089e-5], - initial_condition = function initial_condition_orszag_tang(x, t, equations::IdealGlmMhdEquations3D) - # The classical Orszag-Tang vortex test case adapted to 3D. Setup is taken from - # Table 4 of the paper - # - M. Bohm, A. R. Winters, G. J. Gassner, D. Derigs, F. Hindenlang, & J. Saur (2020) - # An entropy stable nodal discontinuous Galerkin method for the resistive MHD - # equations. Part I: Theory and numerical verification - # [doi: 10.1016/j.jcp.2018.06.027](https://doi.org/10.1016/j.jcp.2018.06.027) - # Domain must be [0, 1]^3 , γ = 5/3 - rho = 25.0 / (36.0 * pi) - v1 = -sin(2.0*pi*x[3]) - v2 = sin(2.0*pi*x[1]) - v3 = sin(2.0*pi*x[2]) - p = 5.0 / (12.0 * pi) - B1 = -sin(2.0*pi*x[3]) / (4.0*pi) - B2 = sin(4.0*pi*x[1]) / (4.0*pi) - B3 = sin(4.0*pi*x[2]) / (4.0*pi) - psi = 0.0 - return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3, psi), equations) - # 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, - surface_flux = (flux_hll, flux_nonconservative_powell), - volume_flux = (flux_central, flux_nonconservative_powell), - coordinates_min = (0.0, 0.0, 0.0), - coordinates_max = (1.0, 1.0, 1.0), - initial_refinement_level=3, - cfl = 1.1, - tspan = (0.0, 0.06)) - # 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 + l2=[ + 0.004391143689111404, + 0.04144737547475548, + 0.041501307637678286, + 0.04150353006408862, + 0.03693135855995625, + 0.021125605214031118, + 0.03295607553556973, + 0.03296235755245784, + 7.16035229384135e-6, + ], + linf=[ + 0.017894703320895378, + 0.08486850681397005, + 0.0891044523165206, + 0.08492024792056754, + 0.10448301878352373, + 0.05381260695579509, + 0.0884774018719996, + 0.07784546966765199, + 7.71609149516089e-5, + ], + initial_condition=function initial_condition_orszag_tang(x, t, + equations::IdealGlmMhdEquations3D) + # The classical Orszag-Tang vortex test case adapted to 3D. Setup is taken from + # Table 4 of the paper + # - M. Bohm, A. R. Winters, G. J. Gassner, D. Derigs, F. Hindenlang, & J. Saur (2020) + # An entropy stable nodal discontinuous Galerkin method for the resistive MHD + # equations. Part I: Theory and numerical verification + # [doi: 10.1016/j.jcp.2018.06.027](https://doi.org/10.1016/j.jcp.2018.06.027) + # Domain must be [0, 1]^3 , γ = 5/3 + rho = 25.0 / (36.0 * pi) + v1 = -sin(2.0 * pi * x[3]) + v2 = sin(2.0 * pi * x[1]) + v3 = sin(2.0 * pi * x[2]) + p = 5.0 / (12.0 * pi) + B1 = -sin(2.0 * pi * x[3]) / (4.0 * pi) + B2 = sin(4.0 * pi * x[1]) / (4.0 * pi) + B3 = sin(4.0 * pi * x[2]) / (4.0 * pi) + psi = 0.0 + return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3, + psi), equations) + # 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, + surface_flux=(flux_hll, flux_nonconservative_powell), + volume_flux=(flux_central, flux_nonconservative_powell), + coordinates_min=(0.0, 0.0, 0.0), + coordinates_max=(1.0, 1.0, 1.0), + initial_refinement_level=3, + cfl=1.1, + tspan=(0.0, 0.06)) + # 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_mhd_ec_shockcapturing.jl" begin +@trixi_testset "elixir_mhd_ec_shockcapturing.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ec_shockcapturing.jl"), - l2 = [0.0186712969755079, 0.01620736832264799, 0.01620736832264803, 0.016207474382769683, 0.07306422729650594, 0.007355137041002365, 0.0073551370410023425, 0.00735520932001833, 0.000506140942330923], - linf = [0.28040713666979633, 0.27212885844703694, 0.2721288584470349, 0.2837380205051839, 0.7915852408267114, 0.08770240288089526, 0.08770240288089792, 0.08773409387876674, 0.050221095224119834]) - # 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 + l2=[ + 0.0186712969755079, + 0.01620736832264799, + 0.01620736832264803, + 0.016207474382769683, + 0.07306422729650594, + 0.007355137041002365, + 0.0073551370410023425, + 0.00735520932001833, + 0.000506140942330923, + ], + linf=[ + 0.28040713666979633, + 0.27212885844703694, + 0.2721288584470349, + 0.2837380205051839, + 0.7915852408267114, + 0.08770240288089526, + 0.08770240288089792, + 0.08773409387876674, + 0.050221095224119834, + ]) + # 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 end # module diff --git a/test/test_tree_3d_part1.jl b/test/test_tree_3d_part1.jl index b1bf313d1b6..3fdddc77239 100644 --- a/test/test_tree_3d_part1.jl +++ b/test/test_tree_3d_part1.jl @@ -7,20 +7,19 @@ include("test_trixi.jl") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) @testset "TreeMesh3D Part 1" begin +#! format: noindent # Run basic tests @testset "Examples 3D" begin - # Compressible Euler - include("test_tree_3d_euler.jl") + # Compressible Euler + include("test_tree_3d_euler.jl") end - # Clean up afterwards: delete Trixi.jl output directory -@test_nowarn rm(outdir, recursive=true) - +@test_nowarn rm(outdir, recursive = true) end # TreeMesh3D Part 1 end #module diff --git a/test/test_tree_3d_part2.jl b/test/test_tree_3d_part2.jl index 77af51c7481..5c7301654ad 100644 --- a/test/test_tree_3d_part2.jl +++ b/test/test_tree_3d_part2.jl @@ -7,102 +7,113 @@ include("test_trixi.jl") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) @testset "TreeMesh3D Part 2" begin +#! format: noindent # Run basic tests @testset "Examples 3D" begin - # Linear scalar advection - include("test_tree_3d_advection.jl") + # Linear scalar advection + include("test_tree_3d_advection.jl") - # Hyperbolic diffusion - include("test_tree_3d_hypdiff.jl") + # Hyperbolic diffusion + include("test_tree_3d_hypdiff.jl") - # Compressible Euler with self-gravity - include("test_tree_3d_eulergravity.jl") + # Compressible Euler with self-gravity + include("test_tree_3d_eulergravity.jl") end - @trixi_testset "Additional tests in 3D" begin - @trixi_testset "compressible Euler" begin - eqn = CompressibleEulerEquations3D(1.4) - - @test isapprox(energy_total([1.0, 2.0, 3.0, 4.0, 20.0], eqn), 20.0) - @test isapprox(energy_kinetic([1.0, 2.0, 3.0, 4.0, 20], eqn), 14.5) - @test isapprox(energy_internal([1.0, 2.0, 3.0, 4.0, 20], eqn), 5.5) - end - - @trixi_testset "hyperbolic diffusion" begin - @test_nowarn HyperbolicDiffusionEquations3D(nu=1.0) - eqn = HyperbolicDiffusionEquations3D(nu=1.0) - end + @trixi_testset "compressible Euler" begin + eqn = CompressibleEulerEquations3D(1.4) + + @test isapprox(energy_total([1.0, 2.0, 3.0, 4.0, 20.0], eqn), 20.0) + @test isapprox(energy_kinetic([1.0, 2.0, 3.0, 4.0, 20], eqn), 14.5) + @test isapprox(energy_internal([1.0, 2.0, 3.0, 4.0, 20], eqn), 5.5) + end + + @trixi_testset "hyperbolic diffusion" begin + @test_nowarn HyperbolicDiffusionEquations3D(nu = 1.0) + eqn = HyperbolicDiffusionEquations3D(nu = 1.0) + end end - @trixi_testset "Displaying components 3D" begin - @test_nowarn include(joinpath(examples_dir(), "tree_3d_dgsem", "elixir_advection_amr.jl")) - - # test both short and long printing formats - @test_nowarn show(mesh); println() - @test_nowarn println(mesh) - @test_nowarn display(mesh) - - @test_nowarn show(equations); println() - @test_nowarn println(equations) - @test_nowarn display(equations) - - @test_nowarn show(solver); println() - @test_nowarn println(solver) - @test_nowarn display(solver) - - @test_nowarn show(solver.basis); println() - @test_nowarn println(solver.basis) - @test_nowarn display(solver.basis) - - @test_nowarn show(solver.mortar); println() - @test_nowarn println(solver.mortar) - @test_nowarn display(solver.mortar) - - @test_nowarn show(semi); println() - @test_nowarn println(semi) - @test_nowarn display(semi) - - @test_nowarn show(summary_callback); println() - @test_nowarn println(summary_callback) - @test_nowarn display(summary_callback) - - @test_nowarn show(amr_controller); println() - @test_nowarn println(amr_controller) - @test_nowarn display(amr_controller) - - @test_nowarn show(amr_callback); println() - @test_nowarn println(amr_callback) - @test_nowarn display(amr_callback) - - @test_nowarn show(stepsize_callback); println() - @test_nowarn println(stepsize_callback) - @test_nowarn display(stepsize_callback) - - @test_nowarn show(save_solution); println() - @test_nowarn println(save_solution) - @test_nowarn display(save_solution) - - @test_nowarn show(analysis_callback); println() - @test_nowarn println(analysis_callback) - @test_nowarn display(analysis_callback) - - @test_nowarn show(alive_callback); println() - @test_nowarn println(alive_callback) - @test_nowarn display(alive_callback) - - @test_nowarn println(callbacks) + @test_nowarn include(joinpath(examples_dir(), "tree_3d_dgsem", + "elixir_advection_amr.jl")) + + # test both short and long printing formats + @test_nowarn show(mesh) + println() + @test_nowarn println(mesh) + @test_nowarn display(mesh) + + @test_nowarn show(equations) + println() + @test_nowarn println(equations) + @test_nowarn display(equations) + + @test_nowarn show(solver) + println() + @test_nowarn println(solver) + @test_nowarn display(solver) + + @test_nowarn show(solver.basis) + println() + @test_nowarn println(solver.basis) + @test_nowarn display(solver.basis) + + @test_nowarn show(solver.mortar) + println() + @test_nowarn println(solver.mortar) + @test_nowarn display(solver.mortar) + + @test_nowarn show(semi) + println() + @test_nowarn println(semi) + @test_nowarn display(semi) + + @test_nowarn show(summary_callback) + println() + @test_nowarn println(summary_callback) + @test_nowarn display(summary_callback) + + @test_nowarn show(amr_controller) + println() + @test_nowarn println(amr_controller) + @test_nowarn display(amr_controller) + + @test_nowarn show(amr_callback) + println() + @test_nowarn println(amr_callback) + @test_nowarn display(amr_callback) + + @test_nowarn show(stepsize_callback) + println() + @test_nowarn println(stepsize_callback) + @test_nowarn display(stepsize_callback) + + @test_nowarn show(save_solution) + println() + @test_nowarn println(save_solution) + @test_nowarn display(save_solution) + + @test_nowarn show(analysis_callback) + println() + @test_nowarn println(analysis_callback) + @test_nowarn display(analysis_callback) + + @test_nowarn show(alive_callback) + println() + @test_nowarn println(alive_callback) + @test_nowarn display(alive_callback) + + @test_nowarn println(callbacks) end - # Clean up afterwards: delete Trixi.jl output directory -@test_nowarn rm(outdir, recursive=true) - +@test_nowarn rm(outdir, recursive = true) end # TreeMesh3D Part 2 end #module diff --git a/test/test_tree_3d_part3.jl b/test/test_tree_3d_part3.jl index 7a77f0e4927..9e1e8bc4dc9 100644 --- a/test/test_tree_3d_part3.jl +++ b/test/test_tree_3d_part3.jl @@ -7,49 +7,47 @@ include("test_trixi.jl") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) @testset "TreeMesh3D Part 2" begin +#! format: noindent # Run basic tests @testset "Examples 3D" begin - # MHD - include("test_tree_3d_mhd.jl") + # MHD + include("test_tree_3d_mhd.jl") - # Lattice-Boltzmann - include("test_tree_3d_lbm.jl") + # Lattice-Boltzmann + include("test_tree_3d_lbm.jl") - # FDSBP methods on the TreeMesh - include("test_tree_3d_fdsbp.jl") + # FDSBP methods on the TreeMesh + include("test_tree_3d_fdsbp.jl") end - @trixi_testset "Additional tests in 3D" begin - @testset "ideal GLM MHD" begin - eqn = IdealGlmMhdEquations3D(1.4) - u = [1.0, 2.0, 3.0, 4.0, 20.0, 0.1, 0.2, 0.3, 1.5] + @testset "ideal GLM MHD" begin + eqn = IdealGlmMhdEquations3D(1.4) + u = [1.0, 2.0, 3.0, 4.0, 20.0, 0.1, 0.2, 0.3, 1.5] - @test isapprox(density(u, eqn), 1.0) - @test isapprox(pressure(u, eqn), 1.7219999999999995) - @test isapprox(density_pressure(u, eqn), 1.7219999999999995) + @test isapprox(density(u, eqn), 1.0) + @test isapprox(pressure(u, eqn), 1.7219999999999995) + @test isapprox(density_pressure(u, eqn), 1.7219999999999995) - @test isapprox(Trixi.entropy_thermodynamic(u, eqn), 0.5434864060055388) - @test isapprox(Trixi.entropy_math(u, eqn), -1.3587160150138473) - @test isapprox(Trixi.entropy(u, eqn), -1.3587160150138473) + @test isapprox(Trixi.entropy_thermodynamic(u, eqn), 0.5434864060055388) + @test isapprox(Trixi.entropy_math(u, eqn), -1.3587160150138473) + @test isapprox(Trixi.entropy(u, eqn), -1.3587160150138473) - @test isapprox(energy_total(u, eqn), 20.0) - @test isapprox(energy_kinetic(u, eqn), 14.5) - @test isapprox(energy_magnetic(u, eqn), 0.07) - @test isapprox(energy_internal(u, eqn), 4.305) + @test isapprox(energy_total(u, eqn), 20.0) + @test isapprox(energy_kinetic(u, eqn), 14.5) + @test isapprox(energy_magnetic(u, eqn), 0.07) + @test isapprox(energy_internal(u, eqn), 4.305) - @test isapprox(cross_helicity(u, eqn), 2.0) - end + @test isapprox(cross_helicity(u, eqn), 2.0) + end end - # Clean up afterwards: delete Trixi.jl output directory -@test_nowarn rm(outdir, recursive=true) - +@test_nowarn rm(outdir, recursive = true) end # TreeMesh3D Part 2 end #module diff --git a/test/test_trixi.jl b/test/test_trixi.jl index f2cd0cab94d..245efbc0175 100644 --- a/test/test_trixi.jl +++ b/test/test_trixi.jl @@ -15,165 +15,162 @@ are compared approximately against these reference values, using `atol, rtol` 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 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)) - # maxiters in coverage_override defaults to 1 - coverage_override = (; coverage_override..., maxiters=1) - end - - local cmd = string(Base.julia_cmd()) - local coverage = occursin("--code-coverage", cmd) && !occursin("--code-coverage=none", cmd) - - local kwargs = Pair{Symbol, Any}[] - for arg in args - if (arg.head == :(=) && !(arg.args[1] in (:l2, :linf, :atol, :rtol, :coverage_override)) - && !(coverage && arg.args[1] in keys(coverage_override))) - push!(kwargs, Pair(arg.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 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)) + # maxiters in coverage_override defaults to 1 + coverage_override = (; coverage_override..., maxiters = 1) end - end - if coverage - for key in keys(coverage_override) - push!(kwargs, Pair(key, coverage_override[key])) - end - end - - if coverage && skip_coverage - return quote - if Trixi.mpi_isroot() - println("═"^100) - println("Skipping coverage test of ", $elixir) - println("═"^100) - println("\n\n") - end - end - end - - quote - Trixi.mpi_isroot() && println("═"^100) - Trixi.mpi_isroot() && println($elixir) - - # if `maxiters` is set in tests, it is usually set to a small number to - # run only a few steps - ignore possible warnings coming from that - if any(==(:maxiters) ∘ first, $kwargs) - additional_ignore_content = [ - r"┌ Warning: Interrupted\. Larger maxiters is needed\..*\n└ @ SciMLBase .+\n", - r"┌ Warning: Interrupted\. Larger maxiters is needed\..*\n└ @ Trixi .+\n"] - else - additional_ignore_content = [] + local cmd = string(Base.julia_cmd()) + local coverage = occursin("--code-coverage", cmd) && + !occursin("--code-coverage=none", cmd) + + local kwargs = Pair{Symbol, Any}[] + for arg in args + if (arg.head == :(=) && + !(arg.args[1] in (:l2, :linf, :atol, :rtol, :coverage_override)) + && !(coverage && arg.args[1] in keys(coverage_override))) + push!(kwargs, Pair(arg.args...)) + end end - # evaluate examples in the scope of the module they're called from - @test_nowarn_mod trixi_include(@__MODULE__, $elixir; $kwargs...) additional_ignore_content + if coverage + for key in keys(coverage_override) + push!(kwargs, Pair(key, coverage_override[key])) + end + end - # if present, compare l2 and linf errors against reference values - if !$coverage && (!isnothing($l2) || !isnothing($linf)) - l2_measured, linf_measured = analysis_callback(sol) + if coverage && skip_coverage + return quote + if Trixi.mpi_isroot() + println("═"^100) + println("Skipping coverage test of ", $elixir) + println("═"^100) + println("\n\n") + end + end + end - if Trixi.mpi_isroot() && !isnothing($l2) - @test length($l2) == length(l2_measured) - for (l2_expected, l2_actual) in zip($l2, l2_measured) - @test isapprox(l2_expected, l2_actual, atol=$atol, rtol=$rtol) + quote + Trixi.mpi_isroot() && println("═"^100) + Trixi.mpi_isroot() && println($elixir) + + # if `maxiters` is set in tests, it is usually set to a small number to + # run only a few steps - ignore possible warnings coming from that + if any(==(:maxiters) ∘ first, $kwargs) + additional_ignore_content = [ + r"┌ Warning: Interrupted\. Larger maxiters is needed\..*\n└ @ SciMLBase .+\n", + r"┌ Warning: Interrupted\. Larger maxiters is needed\..*\n└ @ Trixi .+\n"] + else + additional_ignore_content = [] end - end - if Trixi.mpi_isroot() && !isnothing($linf) - @test length($linf) == length(linf_measured) - for (linf_expected, linf_actual) in zip($linf, linf_measured) - @test isapprox(linf_expected, linf_actual, atol=$atol, rtol=$rtol) + # evaluate examples in the scope of the module they're called from + @test_nowarn_mod trixi_include(@__MODULE__, $elixir; $kwargs...) additional_ignore_content + + # if present, compare l2 and linf errors against reference values + if !$coverage && (!isnothing($l2) || !isnothing($linf)) + l2_measured, linf_measured = analysis_callback(sol) + + if Trixi.mpi_isroot() && !isnothing($l2) + @test length($l2) == length(l2_measured) + for (l2_expected, l2_actual) in zip($l2, l2_measured) + @test isapprox(l2_expected, l2_actual, atol = $atol, rtol = $rtol) + end + end + + if Trixi.mpi_isroot() && !isnothing($linf) + @test length($linf) == length(linf_measured) + for (linf_expected, linf_actual) in zip($linf, linf_measured) + @test isapprox(linf_expected, linf_actual, atol = $atol, rtol = $rtol) + end + end end - end - end - Trixi.mpi_isroot() && println("═"^100) - Trixi.mpi_isroot() && println("\n\n") - end + Trixi.mpi_isroot() && println("═"^100) + Trixi.mpi_isroot() && println("\n\n") + end end - # Get the first value assigned to `keyword` in `args` and return `default_value` # if there are no assignments to `keyword` in `args`. function get_kwarg(args, keyword, default_value) - val = default_value - for arg in args - if arg.head == :(=) && arg.args[1] == keyword - val = arg.args[2] - break + val = default_value + for arg in args + if arg.head == :(=) && arg.args[1] == keyword + val = arg.args[2] + break + end end - end - return val + return val end function expr_to_named_tuple(expr) - result = (;) + result = (;) - for arg in expr.args - if arg.head != :(=) - error("Invalid expression") + for arg in expr.args + if arg.head != :(=) + error("Invalid expression") + end + result = (; result..., arg.args[1] => arg.args[2]) end - result = (; result..., arg.args[1] => arg.args[2]) - end - return result + return result end - # Modified version of `@test_nowarn` that prints the content of `stderr` when # it is not empty and ignores module replacements. -macro test_nowarn_mod(expr, additional_ignore_content=String[]) - quote - let fname = tempname() - try - ret = open(fname, "w") do f - redirect_stderr(f) do - $(esc(expr)) - end +macro test_nowarn_mod(expr, additional_ignore_content = String[]) + quote + let fname = tempname() + try + ret = open(fname, "w") do f + redirect_stderr(f) do + $(esc(expr)) + end + end + stderr_content = read(fname, String) + if !isempty(stderr_content) + println("Content of `stderr`:\n", stderr_content) + end + + # Patterns matching the following ones will be ignored. Additional patterns + # passed as arguments can also be regular expressions, so we just use the + # type `Any` for `ignore_content`. + ignore_content = Any[ + # We need to ignore steady state information reported by our callbacks + r"┌ Info: Steady state tolerance reached\n│ steady_state_callback .+\n└ t = .+\n", + # We also ignore our own compilation messages + "[ Info: You just called `trixi_include`. Julia may now compile the code, please be patient.\n", + # TODO: Upstream (PlotUtils). This should be removed again once the + # deprecated stuff is fixed upstream. + "WARNING: importing deprecated binding Colors.RGB1 into Plots.\n", + "WARNING: importing deprecated binding Colors.RGB4 into Plots.\n", + r"┌ Warning: Keyword argument letter not supported with Plots.+\n└ @ Plots.+\n", + r"┌ Warning: `parse\(::Type, ::Coloarant\)` is deprecated.+\n│.+\n│.+\n└ @ Plots.+\n", + # TODO: Silence warning introduced by Flux v0.13.13. Should be properly fixed. + r"┌ Warning: Layer with Float32 parameters got Float64 input.+\n│.+\n│.+\n│.+\n└ @ Flux.+\n"] + append!(ignore_content, $additional_ignore_content) + for pattern in ignore_content + stderr_content = replace(stderr_content, pattern => "") + end + + # We also ignore simple module redefinitions for convenience. Thus, we + # check whether every line of `stderr_content` is of the form of a + # module replacement warning. + @test occursin(r"^(WARNING: replacing module .+\.\n)*$", stderr_content) + ret + finally + rm(fname, force = true) + end end - stderr_content = read(fname, String) - if !isempty(stderr_content) - println("Content of `stderr`:\n", stderr_content) - end - - # Patterns matching the following ones will be ignored. Additional patterns - # passed as arguments can also be regular expressions, so we just use the - # type `Any` for `ignore_content`. - ignore_content = Any[ - # We need to ignore steady state information reported by our callbacks - r"┌ Info: Steady state tolerance reached\n│ steady_state_callback .+\n└ t = .+\n", - # We also ignore our own compilation messages - "[ Info: You just called `trixi_include`. Julia may now compile the code, please be patient.\n", - # TODO: Upstream (PlotUtils). This should be removed again once the - # deprecated stuff is fixed upstream. - "WARNING: importing deprecated binding Colors.RGB1 into Plots.\n", - "WARNING: importing deprecated binding Colors.RGB4 into Plots.\n", - r"┌ Warning: Keyword argument letter not supported with Plots.+\n└ @ Plots.+\n", - r"┌ Warning: `parse\(::Type, ::Coloarant\)` is deprecated.+\n│.+\n│.+\n└ @ Plots.+\n", - # TODO: Silence warning introduced by Flux v0.13.13. Should be properly fixed. - r"┌ Warning: Layer with Float32 parameters got Float64 input.+\n│.+\n│.+\n│.+\n└ @ Flux.+\n", - ] - append!(ignore_content, $additional_ignore_content) - for pattern in ignore_content - stderr_content = replace(stderr_content, pattern => "") - end - - # We also ignore simple module redefinitions for convenience. Thus, we - # check whether every line of `stderr_content` is of the form of a - # module replacement warning. - @test occursin(r"^(WARNING: replacing module .+\.\n)*$", stderr_content) - ret - finally - rm(fname, force=true) - end end - end end - """ @timed_testset "name of the testset" #= code to test #= @@ -181,21 +178,20 @@ Similar to `@testset`, but prints the name of the testset and its runtime after execution. """ macro timed_testset(name, expr) - @assert name isa String - quote - local time_start = time_ns() - @testset $name $expr - local time_stop = time_ns() - if Trixi.mpi_isroot() - flush(stdout) - @info("Testset " * $name * " finished in " - * string(1.0e-9 * (time_stop - time_start)) * " seconds.\n") - flush(stdout) + @assert name isa String + quote + local time_start = time_ns() + @testset $name $expr + local time_stop = time_ns() + if Trixi.mpi_isroot() + flush(stdout) + @info("Testset "*$name*" finished in " + *string(1.0e-9 * (time_stop - time_start))*" seconds.\n") + flush(stdout) + end end - end end - """ @trixi_testset "name of the testset" #= code to test #= @@ -205,38 +201,38 @@ definition of `@test_trixi_include`. Moreover, it records the execution time of the testset similarly to [`timed_testset`](@ref). """ macro trixi_testset(name, expr) - @assert name isa String - # TODO: `@eval` is evil - # We would like to use - # mod = gensym(name) - # ... - # module $mod - # to create new module names for every test set. However, this is not - # compatible with the dirty hack using `@eval` to get the mapping when - # loading structured, curvilinear meshes. Thus, we need to use a plain - # module name here. - quote - local time_start = time_ns() - @eval module TrixiTestModule - using Test - using Trixi - include(@__FILE__) - # We define `EXAMPLES_DIR` in (nearly) all test modules and use it to - # get the path to the elixirs to be tested. However, that's not required - # and we want to fail gracefully if it's not defined. - try - import ..EXAMPLES_DIR - catch + @assert name isa String + # TODO: `@eval` is evil + # We would like to use + # mod = gensym(name) + # ... + # module $mod + # to create new module names for every test set. However, this is not + # compatible with the dirty hack using `@eval` to get the mapping when + # loading structured, curvilinear meshes. Thus, we need to use a plain + # module name here. + quote + local time_start = time_ns() + @eval module TrixiTestModule + using Test + using Trixi + include(@__FILE__) + # We define `EXAMPLES_DIR` in (nearly) all test modules and use it to + # get the path to the elixirs to be tested. However, that's not required + # and we want to fail gracefully if it's not defined. + try + import ..EXAMPLES_DIR + catch + nothing + end + @testset $name $expr + end + local time_stop = time_ns() + if Trixi.mpi_isroot() + flush(stdout) + @info("Testset "*$name*" finished in " + *string(1.0e-9 * (time_stop - time_start))*" seconds.\n") + end nothing - end - @testset $name $expr - end - local time_stop = time_ns() - if Trixi.mpi_isroot() - flush(stdout) - @info("Testset " * $name * " finished in " - * string(1.0e-9 * (time_stop - time_start)) * " seconds.\n") end - nothing - end end diff --git a/test/test_unit.jl b/test/test_unit.jl index 5c5291c2430..5422db7a66d 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -7,396 +7,408 @@ include("test_trixi.jl") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) # Run various unit (= non-elixir-triggered) tests @testset "Unit tests" begin - @timed_testset "SerialTree" begin +#! format: noindent + +@timed_testset "SerialTree" begin @testset "constructors" begin - @test_nowarn Trixi.SerialTree(Val(1), 10, 0.0, 1.0) + @test_nowarn Trixi.SerialTree(Val(1), 10, 0.0, 1.0) end @testset "helper functions" begin - t = Trixi.SerialTree(Val(1), 10, 0.0, 1.0) - @test_nowarn display(t) - @test Trixi.ndims(t) == 1 - @test Trixi.has_any_neighbor(t, 1, 1) == true - @test Trixi.isperiodic(t, 1) == true - @test Trixi.n_children_per_cell(t) == 2 - @test Trixi.n_directions(t) == 2 + t = Trixi.SerialTree(Val(1), 10, 0.0, 1.0) + @test_nowarn display(t) + @test Trixi.ndims(t) == 1 + @test Trixi.has_any_neighbor(t, 1, 1) == true + @test Trixi.isperiodic(t, 1) == true + @test Trixi.n_children_per_cell(t) == 2 + @test Trixi.n_directions(t) == 2 end @testset "refine!/coarsen!" begin - t = Trixi.SerialTree(Val(1), 10, 0.0, 1.0) - @test Trixi.refine!(t) == [1] - @test Trixi.coarsen!(t) == [1] - @test Trixi.refine!(t) == [1] - @test Trixi.coarsen!(t, 1) == [1] - @test Trixi.coarsen!(t) == Int[] # Coarsen twice to check degenerate case of single-cell tree - @test Trixi.refine!(t) == [1] - @test Trixi.refine!(t) == [2,3] - @test Trixi.coarsen_box!(t, [-0.5], [0.0]) == [2] - @test Trixi.coarsen_box!(t, 0.0, 0.5) == [3] - @test isnothing(Trixi.reset_data_structures!(t)) - end - end - - @timed_testset "ParallelTree" begin + t = Trixi.SerialTree(Val(1), 10, 0.0, 1.0) + @test Trixi.refine!(t) == [1] + @test Trixi.coarsen!(t) == [1] + @test Trixi.refine!(t) == [1] + @test Trixi.coarsen!(t, 1) == [1] + @test Trixi.coarsen!(t) == Int[] # Coarsen twice to check degenerate case of single-cell tree + @test Trixi.refine!(t) == [1] + @test Trixi.refine!(t) == [2, 3] + @test Trixi.coarsen_box!(t, [-0.5], [0.0]) == [2] + @test Trixi.coarsen_box!(t, 0.0, 0.5) == [3] + @test isnothing(Trixi.reset_data_structures!(t)) + end +end + +@timed_testset "ParallelTree" begin @testset "constructors" begin - @test_nowarn Trixi.ParallelTree(Val(1), 10, 0.0, 1.0) + @test_nowarn Trixi.ParallelTree(Val(1), 10, 0.0, 1.0) end @testset "helper functions" begin - t = Trixi.ParallelTree(Val(1), 10, 0.0, 1.0) - @test isnothing(display(t)) - @test isnothing(Trixi.reset_data_structures!(t)) + t = Trixi.ParallelTree(Val(1), 10, 0.0, 1.0) + @test isnothing(display(t)) + @test isnothing(Trixi.reset_data_structures!(t)) end - end +end - @timed_testset "TreeMesh" begin +@timed_testset "TreeMesh" begin @testset "constructors" begin - @test TreeMesh{1, Trixi.SerialTree{1}}(1, 5.0, 2.0) isa TreeMesh + @test TreeMesh{1, Trixi.SerialTree{1}}(1, 5.0, 2.0) isa TreeMesh end - end +end - @timed_testset "ParallelTreeMesh" begin +@timed_testset "ParallelTreeMesh" begin @testset "partition!" begin - @testset "mpi_nranks() = 2" begin - Trixi.mpi_nranks() = 2 - let - @test Trixi.mpi_nranks() == 2 - - mesh = TreeMesh{2, Trixi.ParallelTree{2}}(30, (0.0, 0.0), 1) - # Refine twice - Trixi.refine!(mesh.tree) - Trixi.refine!(mesh.tree) - - # allow_coarsening = true - Trixi.partition!(mesh) - # Use parent for OffsetArray - @test parent(mesh.n_cells_by_rank) == [11, 10] - @test mesh.tree.mpi_ranks[1:21] == - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] - @test parent(mesh.first_cell_by_rank) == [1, 12] - - # allow_coarsening = false - Trixi.partition!(mesh; allow_coarsening=false) - @test parent(mesh.n_cells_by_rank) == [11, 10] - @test mesh.tree.mpi_ranks[1:21] == - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] - @test parent(mesh.first_cell_by_rank) == [1, 12] + @testset "mpi_nranks() = 2" begin + Trixi.mpi_nranks() = 2 + let + @test Trixi.mpi_nranks() == 2 + + mesh = TreeMesh{2, Trixi.ParallelTree{2}}(30, (0.0, 0.0), 1) + # Refine twice + Trixi.refine!(mesh.tree) + Trixi.refine!(mesh.tree) + + # allow_coarsening = true + Trixi.partition!(mesh) + # Use parent for OffsetArray + @test parent(mesh.n_cells_by_rank) == [11, 10] + @test mesh.tree.mpi_ranks[1:21] == + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + @test parent(mesh.first_cell_by_rank) == [1, 12] + + # allow_coarsening = false + Trixi.partition!(mesh; allow_coarsening = false) + @test parent(mesh.n_cells_by_rank) == [11, 10] + @test mesh.tree.mpi_ranks[1:21] == + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + @test parent(mesh.first_cell_by_rank) == [1, 12] + end + Trixi.mpi_nranks() = Trixi.MPI_SIZE[] # restore the original behavior end - Trixi.mpi_nranks() = Trixi.MPI_SIZE[] # restore the original behavior - end - - @testset "mpi_nranks() = 3" begin - Trixi.mpi_nranks() = 3 - let - @test Trixi.mpi_nranks() == 3 - - mesh = TreeMesh{2, Trixi.ParallelTree{2}}(100, (0.0, 0.0), 1) - # Refine twice - Trixi.refine!(mesh.tree) - Trixi.refine!(mesh.tree) - - # allow_coarsening = true - Trixi.partition!(mesh) - # Use parent for OffsetArray - @test parent(mesh.n_cells_by_rank) == [11, 5, 5] - @test mesh.tree.mpi_ranks[1:21] == - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2] - @test parent(mesh.first_cell_by_rank) == [1, 12, 17] - - # allow_coarsening = false - Trixi.partition!(mesh; allow_coarsening=false) - @test parent(mesh.n_cells_by_rank) == [9, 6, 6] - @test mesh.tree.mpi_ranks[1:21] == - [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2] - @test parent(mesh.first_cell_by_rank) == [1, 10, 16] + + @testset "mpi_nranks() = 3" begin + Trixi.mpi_nranks() = 3 + let + @test Trixi.mpi_nranks() == 3 + + mesh = TreeMesh{2, Trixi.ParallelTree{2}}(100, (0.0, 0.0), 1) + # Refine twice + Trixi.refine!(mesh.tree) + Trixi.refine!(mesh.tree) + + # allow_coarsening = true + Trixi.partition!(mesh) + # Use parent for OffsetArray + @test parent(mesh.n_cells_by_rank) == [11, 5, 5] + @test mesh.tree.mpi_ranks[1:21] == + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2] + @test parent(mesh.first_cell_by_rank) == [1, 12, 17] + + # allow_coarsening = false + Trixi.partition!(mesh; allow_coarsening = false) + @test parent(mesh.n_cells_by_rank) == [9, 6, 6] + @test mesh.tree.mpi_ranks[1:21] == + [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2] + @test parent(mesh.first_cell_by_rank) == [1, 10, 16] + end + Trixi.mpi_nranks() = Trixi.MPI_SIZE[] # restore the original behavior end - Trixi.mpi_nranks() = Trixi.MPI_SIZE[] # restore the original behavior - end - - @testset "mpi_nranks() = 9" begin - Trixi.mpi_nranks() = 9 - let - @test Trixi.mpi_nranks() == 9 - - mesh = TreeMesh{2, Trixi.ParallelTree{2}}(1000, (0.0, 0.0), 1) - # Refine twice - Trixi.refine!(mesh.tree) - Trixi.refine!(mesh.tree) - Trixi.refine!(mesh.tree) - Trixi.refine!(mesh.tree) - - # allow_coarsening = true - Trixi.partition!(mesh) - # Use parent for OffsetArray - @test parent(mesh.n_cells_by_rank) == [44, 37, 38, 37, 37, 37, 38, 37, 36] - @test parent(mesh.first_cell_by_rank) == [1, 45, 82, 120, 157, 194, 231, 269, 306] + + @testset "mpi_nranks() = 9" begin + Trixi.mpi_nranks() = 9 + let + @test Trixi.mpi_nranks() == 9 + + mesh = TreeMesh{2, Trixi.ParallelTree{2}}(1000, (0.0, 0.0), 1) + # Refine twice + Trixi.refine!(mesh.tree) + Trixi.refine!(mesh.tree) + Trixi.refine!(mesh.tree) + Trixi.refine!(mesh.tree) + + # allow_coarsening = true + Trixi.partition!(mesh) + # Use parent for OffsetArray + @test parent(mesh.n_cells_by_rank) == + [44, 37, 38, 37, 37, 37, 38, 37, 36] + @test parent(mesh.first_cell_by_rank) == + [1, 45, 82, 120, 157, 194, 231, 269, 306] + end + Trixi.mpi_nranks() = Trixi.MPI_SIZE[] # restore the original behavior end - Trixi.mpi_nranks() = Trixi.MPI_SIZE[] # restore the original behavior - end - - @testset "mpi_nranks() = 3 non-uniform" begin - Trixi.mpi_nranks() = 3 - let - @test Trixi.mpi_nranks() == 3 - - mesh = TreeMesh{2, Trixi.ParallelTree{2}}(100, (0.0, 0.0), 1) - # Refine whole tree - Trixi.refine!(mesh.tree) - # Refine left leaf - Trixi.refine!(mesh.tree, [2]) - - # allow_coarsening = true - Trixi.partition!(mesh) - # Use parent for OffsetArray - @test parent(mesh.n_cells_by_rank) == [6, 1, 2] - @test mesh.tree.mpi_ranks[1:9] == [0, 0, 0, 0, 0, 0, 1, 2, 2] - @test parent(mesh.first_cell_by_rank) == [1, 7, 8] - - # allow_coarsening = false - Trixi.partition!(mesh; allow_coarsening=false) - @test parent(mesh.n_cells_by_rank) == [5, 2, 2] - @test mesh.tree.mpi_ranks[1:9] == [0, 0, 0, 0, 0, 1, 1, 2, 2] - @test parent(mesh.first_cell_by_rank) == [1, 6, 8] + + @testset "mpi_nranks() = 3 non-uniform" begin + Trixi.mpi_nranks() = 3 + let + @test Trixi.mpi_nranks() == 3 + + mesh = TreeMesh{2, Trixi.ParallelTree{2}}(100, (0.0, 0.0), 1) + # Refine whole tree + Trixi.refine!(mesh.tree) + # Refine left leaf + Trixi.refine!(mesh.tree, [2]) + + # allow_coarsening = true + Trixi.partition!(mesh) + # Use parent for OffsetArray + @test parent(mesh.n_cells_by_rank) == [6, 1, 2] + @test mesh.tree.mpi_ranks[1:9] == [0, 0, 0, 0, 0, 0, 1, 2, 2] + @test parent(mesh.first_cell_by_rank) == [1, 7, 8] + + # allow_coarsening = false + Trixi.partition!(mesh; allow_coarsening = false) + @test parent(mesh.n_cells_by_rank) == [5, 2, 2] + @test mesh.tree.mpi_ranks[1:9] == [0, 0, 0, 0, 0, 1, 1, 2, 2] + @test parent(mesh.first_cell_by_rank) == [1, 6, 8] + end + Trixi.mpi_nranks() = Trixi.MPI_SIZE[] # restore the original behavior end - Trixi.mpi_nranks() = Trixi.MPI_SIZE[] # restore the original behavior - end - @testset "not enough ranks" begin - Trixi.mpi_nranks() = 3 - let - @test Trixi.mpi_nranks() == 3 + @testset "not enough ranks" begin + Trixi.mpi_nranks() = 3 + let + @test Trixi.mpi_nranks() == 3 - mesh = TreeMesh{2, Trixi.ParallelTree{2}}(100, (0.0, 0.0), 1) + mesh = TreeMesh{2, Trixi.ParallelTree{2}}(100, (0.0, 0.0), 1) - # Only one leaf - @test_throws AssertionError( - "Too many ranks to properly partition the mesh!") Trixi.partition!(mesh) + # Only one leaf + @test_throws AssertionError("Too many ranks to properly partition the mesh!") Trixi.partition!(mesh) - # Refine to 4 leaves - Trixi.refine!(mesh.tree) + # Refine to 4 leaves + Trixi.refine!(mesh.tree) - # All four leaves will need to be on one rank to allow coarsening - @test_throws AssertionError( - "Too many ranks to properly partition the mesh!") Trixi.partition!(mesh) - @test_nowarn Trixi.partition!(mesh; allow_coarsening=false) + # All four leaves will need to be on one rank to allow coarsening + @test_throws AssertionError("Too many ranks to properly partition the mesh!") Trixi.partition!(mesh) + @test_nowarn Trixi.partition!(mesh; allow_coarsening = false) + end + Trixi.mpi_nranks() = Trixi.MPI_SIZE[] # restore the original behavior end - Trixi.mpi_nranks() = Trixi.MPI_SIZE[] # restore the original behavior - end end - end +end - @timed_testset "curved mesh" begin +@timed_testset "curved mesh" begin @testset "calc_jacobian_matrix" begin - @testset "identity map" begin - basis = LobattoLegendreBasis(5) - nodes = Trixi.get_nodes(basis) - jacobian_matrix = Array{Float64, 5}(undef, 2, 2, 6, 6, 1) - - node_coordinates = Array{Float64, 4}(undef, 2, 6, 6, 1) - node_coordinates[1, :, :, 1] .= [nodes[i] for i in 1:6, j in 1:6] - node_coordinates[2, :, :, 1] .= [nodes[j] for i in 1:6, j in 1:6] - expected = zeros(2, 2, 6, 6, 1) - expected[1, 1, :, :, 1] .= 1 - expected[2, 2, :, :, 1] .= 1 - @test Trixi.calc_jacobian_matrix!(jacobian_matrix, 1, node_coordinates, basis) ≈ expected - end - - @testset "maximum exact polydeg" begin - basis = LobattoLegendreBasis(3) - nodes = Trixi.get_nodes(basis) - jacobian_matrix = Array{Float64, 5}(undef, 2, 2, 4, 4, 1) - - # f(x, y) = [x^3, xy^2] - node_coordinates = Array{Float64, 4}(undef, 2, 4, 4, 1) - node_coordinates[1, :, :, 1] .= [nodes[i]^3 for i in 1:4, j in 1:4] - node_coordinates[2, :, :, 1] .= [nodes[i] * nodes[j]^2 for i in 1:4, j in 1:4] - - # Df(x, y) = [3x^2 0; - # y^2 2xy] - expected = zeros(2, 2, 4, 4, 1) - expected[1, 1, :, :, 1] .= [3 * nodes[i]^2 for i in 1:4, j in 1:4] - expected[2, 1, :, :, 1] .= [nodes[j]^2 for i in 1:4, j in 1:4] - expected[2, 2, :, :, 1] .= [2 * nodes[i] * nodes[j] for i in 1:4, j in 1:4] - @test Trixi.calc_jacobian_matrix!(jacobian_matrix, 1, node_coordinates, basis) ≈ expected - end - end - end - - @timed_testset "interpolation" begin + @testset "identity map" begin + basis = LobattoLegendreBasis(5) + nodes = Trixi.get_nodes(basis) + jacobian_matrix = Array{Float64, 5}(undef, 2, 2, 6, 6, 1) + + node_coordinates = Array{Float64, 4}(undef, 2, 6, 6, 1) + node_coordinates[1, :, :, 1] .= [nodes[i] for i in 1:6, j in 1:6] + node_coordinates[2, :, :, 1] .= [nodes[j] for i in 1:6, j in 1:6] + expected = zeros(2, 2, 6, 6, 1) + expected[1, 1, :, :, 1] .= 1 + expected[2, 2, :, :, 1] .= 1 + @test Trixi.calc_jacobian_matrix!(jacobian_matrix, 1, node_coordinates, + basis) ≈ expected + end + + @testset "maximum exact polydeg" begin + basis = LobattoLegendreBasis(3) + nodes = Trixi.get_nodes(basis) + jacobian_matrix = Array{Float64, 5}(undef, 2, 2, 4, 4, 1) + + # f(x, y) = [x^3, xy^2] + node_coordinates = Array{Float64, 4}(undef, 2, 4, 4, 1) + node_coordinates[1, :, :, 1] .= [nodes[i]^3 for i in 1:4, j in 1:4] + node_coordinates[2, :, :, 1] .= [nodes[i] * nodes[j]^2 + for i in 1:4, j in 1:4] + + # Df(x, y) = [3x^2 0; + # y^2 2xy] + expected = zeros(2, 2, 4, 4, 1) + expected[1, 1, :, :, 1] .= [3 * nodes[i]^2 for i in 1:4, j in 1:4] + expected[2, 1, :, :, 1] .= [nodes[j]^2 for i in 1:4, j in 1:4] + expected[2, 2, :, :, 1] .= [2 * nodes[i] * nodes[j] for i in 1:4, j in 1:4] + @test Trixi.calc_jacobian_matrix!(jacobian_matrix, 1, node_coordinates, + basis) ≈ expected + end + end +end + +@timed_testset "interpolation" begin @testset "nodes and weights" begin - @test Trixi.gauss_nodes_weights(1) == ([0.0], [2.0]) + @test Trixi.gauss_nodes_weights(1) == ([0.0], [2.0]) end @testset "multiply_dimensionwise" begin - nodes_in = [0.0, 0.5, 1.0] - nodes_out = [0.0, 1/3, 2/3, 1.0] - matrix = Trixi.polynomial_interpolation_matrix(nodes_in, nodes_out) - data_in = [3.0 4.5 6.0] - @test isapprox(Trixi.multiply_dimensionwise(matrix, data_in), [3.0 4.0 5.0 6.0]) - - n_vars = 3 - size_in = 2 - size_out = 3 - matrix = randn(size_out, size_in) - # 1D - data_in = randn(n_vars, size_in) - data_out = Trixi.multiply_dimensionwise_naive(matrix, data_in) - @test isapprox(data_out, Trixi.multiply_dimensionwise(matrix, data_in)) - # 2D - data_in = randn(n_vars, size_in, size_in) - data_out = Trixi.multiply_dimensionwise_naive(matrix, data_in) - @test isapprox(data_out, Trixi.multiply_dimensionwise(matrix, data_in)) - # 3D - data_in = randn(n_vars, size_in, size_in, size_in) - data_out = Trixi.multiply_dimensionwise_naive(matrix, data_in) - @test isapprox(data_out, Trixi.multiply_dimensionwise(matrix, data_in)) - end - end - - @timed_testset "L2 projection" begin + nodes_in = [0.0, 0.5, 1.0] + nodes_out = [0.0, 1 / 3, 2 / 3, 1.0] + matrix = Trixi.polynomial_interpolation_matrix(nodes_in, nodes_out) + data_in = [3.0 4.5 6.0] + @test isapprox(Trixi.multiply_dimensionwise(matrix, data_in), [3.0 4.0 5.0 6.0]) + + n_vars = 3 + size_in = 2 + size_out = 3 + matrix = randn(size_out, size_in) + # 1D + data_in = randn(n_vars, size_in) + data_out = Trixi.multiply_dimensionwise_naive(matrix, data_in) + @test isapprox(data_out, Trixi.multiply_dimensionwise(matrix, data_in)) + # 2D + data_in = randn(n_vars, size_in, size_in) + data_out = Trixi.multiply_dimensionwise_naive(matrix, data_in) + @test isapprox(data_out, Trixi.multiply_dimensionwise(matrix, data_in)) + # 3D + data_in = randn(n_vars, size_in, size_in, size_in) + data_out = Trixi.multiply_dimensionwise_naive(matrix, data_in) + @test isapprox(data_out, Trixi.multiply_dimensionwise(matrix, data_in)) + end +end + +@timed_testset "L2 projection" begin @testset "calc_reverse_upper for LGL" begin - @test isapprox(Trixi.calc_reverse_upper(2, Val(:gauss_lobatto)), [[0.25, 0.25] [0.0, 0.5]]) + @test isapprox(Trixi.calc_reverse_upper(2, Val(:gauss_lobatto)), + [[0.25, 0.25] [0.0, 0.5]]) end @testset "calc_reverse_lower for LGL" begin - @test isapprox(Trixi.calc_reverse_lower(2, Val(:gauss_lobatto)), [[0.5, 0.0] [0.25, 0.25]]) + @test isapprox(Trixi.calc_reverse_lower(2, Val(:gauss_lobatto)), + [[0.5, 0.0] [0.25, 0.25]]) end - end +end - @testset "containers" begin +@testset "containers" begin # Set up mock container mutable struct MyContainer <: Trixi.AbstractContainer - data::Vector{Int} - capacity::Int - length::Int - dummy::Int + data::Vector{Int} + capacity::Int + length::Int + dummy::Int end function MyContainer(data, capacity) - c = MyContainer(Vector{Int}(undef, capacity+1), capacity, length(data), capacity+1) - c.data[1:length(data)] .= data - return c + c = MyContainer(Vector{Int}(undef, capacity + 1), capacity, length(data), + capacity + 1) + c.data[1:length(data)] .= data + return c end MyContainer(data::AbstractArray) = MyContainer(data, length(data)) Trixi.invalidate!(c::MyContainer, first, last) = (c.data[first:last] .= 0; c) - function Trixi.raw_copy!(target::MyContainer, source::MyContainer, first, last, destination) - Trixi.copy_data!(target.data, source.data, first, last, destination) - return target + function Trixi.raw_copy!(target::MyContainer, source::MyContainer, first, last, + destination) + Trixi.copy_data!(target.data, source.data, first, last, destination) + return target end Trixi.move_connectivity!(c::MyContainer, first, last, destination) = c Trixi.delete_connectivity!(c::MyContainer, first, last) = c - Trixi.reset_data_structures!(c::MyContainer) = (c.data = Vector{Int}(undef, c.capacity+1); c) + Trixi.reset_data_structures!(c::MyContainer) = (c.data = Vector{Int}(undef, + c.capacity + 1); + c) function Base.:(==)(c1::MyContainer, c2::MyContainer) - return (c1.capacity == c2.capacity && - c1.length == c2.length && - c1.dummy == c2.dummy && - c1.data[1:c1.length] == c2.data[1:c2.length]) + return (c1.capacity == c2.capacity && + c1.length == c2.length && + c1.dummy == c2.dummy && + c1.data[1:(c1.length)] == c2.data[1:(c2.length)]) end @testset "size" begin - c = MyContainer([1, 2, 3]) - @test size(c) == (3,) + c = MyContainer([1, 2, 3]) + @test size(c) == (3,) end @testset "resize!" begin - c = MyContainer([1, 2, 3]) - @test length(resize!(c, 2)) == 2 + c = MyContainer([1, 2, 3]) + @test length(resize!(c, 2)) == 2 end @testset "copy!" begin - c1 = MyContainer([1, 2, 3]) - c2 = MyContainer([4, 5]) - @test Trixi.copy!(c1, c2, 2, 1, 2) == MyContainer([1, 2, 3]) # no-op + c1 = MyContainer([1, 2, 3]) + c2 = MyContainer([4, 5]) + @test Trixi.copy!(c1, c2, 2, 1, 2) == MyContainer([1, 2, 3]) # no-op - c1 = MyContainer([1, 2, 3]) - c2 = MyContainer([4, 5]) - @test Trixi.copy!(c1, c2, 1, 2, 2) == MyContainer([1, 4, 5]) + c1 = MyContainer([1, 2, 3]) + c2 = MyContainer([4, 5]) + @test Trixi.copy!(c1, c2, 1, 2, 2) == MyContainer([1, 4, 5]) - c1 = MyContainer([1, 2, 3]) - @test Trixi.copy!(c1, c2, 1, 2) == MyContainer([1, 4, 3]) + c1 = MyContainer([1, 2, 3]) + @test Trixi.copy!(c1, c2, 1, 2) == MyContainer([1, 4, 3]) - c1 = MyContainer([1, 2, 3]) - @test Trixi.copy!(c1, 2, 3, 1) == MyContainer([2, 3, 3]) + c1 = MyContainer([1, 2, 3]) + @test Trixi.copy!(c1, 2, 3, 1) == MyContainer([2, 3, 3]) - c1 = MyContainer([1, 2, 3]) - @test Trixi.copy!(c1, 1, 3) == MyContainer([1, 2, 1]) + c1 = MyContainer([1, 2, 3]) + @test Trixi.copy!(c1, 1, 3) == MyContainer([1, 2, 1]) end @testset "move!" begin - c = MyContainer([1, 2, 3]) - @test Trixi.move!(c, 1, 1) == MyContainer([1, 2, 3]) # no-op + c = MyContainer([1, 2, 3]) + @test Trixi.move!(c, 1, 1) == MyContainer([1, 2, 3]) # no-op - c = MyContainer([1, 2, 3]) - @test Trixi.move!(c, 1, 2) == MyContainer([0, 1, 3]) + c = MyContainer([1, 2, 3]) + @test Trixi.move!(c, 1, 2) == MyContainer([0, 1, 3]) end @testset "swap!" begin - c = MyContainer([1,2]) - @test Trixi.swap!(c, 1, 1) == MyContainer([1, 2]) # no-op + c = MyContainer([1, 2]) + @test Trixi.swap!(c, 1, 1) == MyContainer([1, 2]) # no-op - c = MyContainer([1,2]) - @test Trixi.swap!(c, 1, 2) == MyContainer([2,1]) + c = MyContainer([1, 2]) + @test Trixi.swap!(c, 1, 2) == MyContainer([2, 1]) end @testset "erase!" begin - c = MyContainer([1, 2]) - @test Trixi.erase!(c, 2, 1) == MyContainer([1, 2]) # no-op + c = MyContainer([1, 2]) + @test Trixi.erase!(c, 2, 1) == MyContainer([1, 2]) # no-op - c = MyContainer([1, 2]) - @test Trixi.erase!(c, 1) == MyContainer([0, 2]) + c = MyContainer([1, 2]) + @test Trixi.erase!(c, 1) == MyContainer([0, 2]) end @testset "remove_shift!" begin - c = MyContainer([1, 2, 3, 4]) - @test Trixi.remove_shift!(c, 2, 1) == MyContainer([1, 2, 3, 4]) # no-op + c = MyContainer([1, 2, 3, 4]) + @test Trixi.remove_shift!(c, 2, 1) == MyContainer([1, 2, 3, 4]) # no-op - c = MyContainer([1, 2, 3, 4]) - @test Trixi.remove_shift!(c, 2, 2) == MyContainer([1, 3, 4], 4) + c = MyContainer([1, 2, 3, 4]) + @test Trixi.remove_shift!(c, 2, 2) == MyContainer([1, 3, 4], 4) - c = MyContainer([1, 2, 3, 4]) - @test Trixi.remove_shift!(c, 2) == MyContainer([1, 3, 4], 4) + c = MyContainer([1, 2, 3, 4]) + @test Trixi.remove_shift!(c, 2) == MyContainer([1, 3, 4], 4) end @testset "remove_fill!" begin - c = MyContainer([1, 2, 3, 4]) - @test Trixi.remove_fill!(c, 2, 1) == MyContainer([1, 2, 3, 4]) # no-op + c = MyContainer([1, 2, 3, 4]) + @test Trixi.remove_fill!(c, 2, 1) == MyContainer([1, 2, 3, 4]) # no-op - c = MyContainer([1, 2, 3, 4]) - @test Trixi.remove_fill!(c, 2, 2) == MyContainer([1, 4, 3], 4) + c = MyContainer([1, 2, 3, 4]) + @test Trixi.remove_fill!(c, 2, 2) == MyContainer([1, 4, 3], 4) end @testset "reset!" begin - c = MyContainer([1, 2, 3]) - @test Trixi.reset!(c, 2) == MyContainer(Int[], 2) + c = MyContainer([1, 2, 3]) + @test Trixi.reset!(c, 2) == MyContainer(Int[], 2) end - end +end - @timed_testset "example elixirs" begin +@timed_testset "example elixirs" begin @test basename(examples_dir()) == "examples" @test !isempty(get_examples()) @test endswith(default_example(), "elixir_advection_basic.jl") - end +end - @timed_testset "HLL flux with vanishing wave speed estimates (#502)" begin +@timed_testset "HLL flux with vanishing wave speed estimates (#502)" begin equations = CompressibleEulerEquations1D(1.4) u = SVector(1.0, 0.0, 0.0) @test !any(isnan, flux_hll(u, u, 1, equations)) - end +end - @timed_testset "DG L2 mortar container debug output" begin +@timed_testset "DG L2 mortar container debug output" begin c2d = Trixi.L2MortarContainer2D{Float64}(1, 1, 1) @test isnothing(display(c2d)) c3d = Trixi.L2MortarContainer3D{Float64}(1, 1, 1) @test isnothing(display(c3d)) - end +end - @timed_testset "Printing indicators/controllers" begin +@timed_testset "Printing indicators/controllers" begin # OBS! Constructing indicators/controllers using the parameters below doesn't make sense. It's # just useful to run basic tests of `show` methods. - c = ControllerThreeLevelCombined(1, 2, 3, 10.0, 11.0, 12.0, "primary", "secondary", "cache") + c = ControllerThreeLevelCombined(1, 2, 3, 10.0, 11.0, 12.0, "primary", "secondary", + "cache") @test_nowarn show(stdout, c) indicator_hg = IndicatorHennemannGassner(1.0, 0.0, true, "variable", "cache") @@ -406,194 +418,208 @@ isdir(outdir) && rm(outdir, recursive=true) @test_nowarn show(stdout, limiter_idp) # TODO: TrixiShallowWater: move unit test - indicator_hg_swe = IndicatorHennemannGassnerShallowWater(1.0, 0.0, true, "variable", "cache") + indicator_hg_swe = IndicatorHennemannGassnerShallowWater(1.0, 0.0, true, "variable", + "cache") @test_nowarn show(stdout, indicator_hg_swe) - indicator_loehner = IndicatorLöhner(1.0, "variable", (; cache=nothing)) + indicator_loehner = IndicatorLöhner(1.0, "variable", (; cache = nothing)) @test_nowarn show(stdout, indicator_loehner) - indicator_max = IndicatorMax("variable", (; cache=nothing)) + indicator_max = IndicatorMax("variable", (; cache = nothing)) @test_nowarn show(stdout, indicator_max) equations = CompressibleEulerEquations2D(1.4) basis = LobattoLegendreBasis(3) - indicator_neuralnetwork = IndicatorNeuralNetwork( - equations, basis, indicator_type=NeuralNetworkPerssonPeraire(), variable=density, - network=nothing) + indicator_neuralnetwork = IndicatorNeuralNetwork(equations, basis, + indicator_type = NeuralNetworkPerssonPeraire(), + variable = density, + network = nothing) @test_nowarn show(stdout, indicator_neuralnetwork) - end +end - @timed_testset "LBM 2D constructor" begin +@timed_testset "LBM 2D constructor" begin # Neither Mach number nor velocity set - @test_throws ErrorException LatticeBoltzmannEquations2D(Ma=nothing, Re=1000) + @test_throws ErrorException LatticeBoltzmannEquations2D(Ma = nothing, Re = 1000) # Both Mach number and velocity set - @test_throws ErrorException LatticeBoltzmannEquations2D(Ma=0.1, Re=1000, u0=1) + @test_throws ErrorException LatticeBoltzmannEquations2D(Ma = 0.1, Re = 1000, u0 = 1) # Neither Reynolds number nor viscosity set - @test_throws ErrorException LatticeBoltzmannEquations2D(Ma=0.1, Re=nothing) + @test_throws ErrorException LatticeBoltzmannEquations2D(Ma = 0.1, Re = nothing) # Both Reynolds number and viscosity set - @test_throws ErrorException LatticeBoltzmannEquations2D(Ma=0.1, Re=1000, nu=1) + @test_throws ErrorException LatticeBoltzmannEquations2D(Ma = 0.1, Re = 1000, nu = 1) # No non-dimensional values set - @test LatticeBoltzmannEquations2D(Ma=nothing, Re=nothing, u0=1, nu=1) isa LatticeBoltzmannEquations2D - end + @test LatticeBoltzmannEquations2D(Ma = nothing, Re = nothing, u0 = 1, nu = 1) isa + LatticeBoltzmannEquations2D +end - @timed_testset "LBM 3D constructor" begin +@timed_testset "LBM 3D constructor" begin # Neither Mach number nor velocity set - @test_throws ErrorException LatticeBoltzmannEquations3D(Ma=nothing, Re=1000) + @test_throws ErrorException LatticeBoltzmannEquations3D(Ma = nothing, Re = 1000) # Both Mach number and velocity set - @test_throws ErrorException LatticeBoltzmannEquations3D(Ma=0.1, Re=1000, u0=1) + @test_throws ErrorException LatticeBoltzmannEquations3D(Ma = 0.1, Re = 1000, u0 = 1) # Neither Reynolds number nor viscosity set - @test_throws ErrorException LatticeBoltzmannEquations3D(Ma=0.1, Re=nothing) + @test_throws ErrorException LatticeBoltzmannEquations3D(Ma = 0.1, Re = nothing) # Both Reynolds number and viscosity set - @test_throws ErrorException LatticeBoltzmannEquations3D(Ma=0.1, Re=1000, nu=1) + @test_throws ErrorException LatticeBoltzmannEquations3D(Ma = 0.1, Re = 1000, nu = 1) # No non-dimensional values set - @test LatticeBoltzmannEquations3D(Ma=nothing, Re=nothing, u0=1, nu=1) isa LatticeBoltzmannEquations3D - end + @test LatticeBoltzmannEquations3D(Ma = nothing, Re = nothing, u0 = 1, nu = 1) isa + LatticeBoltzmannEquations3D +end - @timed_testset "LBM 2D functions" begin +@timed_testset "LBM 2D functions" begin # Set up LBM struct and dummy distribution - equation = LatticeBoltzmannEquations2D(Ma=0.1, Re=1000) + equation = LatticeBoltzmannEquations2D(Ma = 0.1, Re = 1000) u = Trixi.equilibrium_distribution(1, 2, 3, equation) # Component-wise velocity @test isapprox(Trixi.velocity(u, 1, equation), 2) @test isapprox(Trixi.velocity(u, 2, equation), 3) - end +end - @timed_testset "LBM 3D functions" begin +@timed_testset "LBM 3D functions" begin # Set up LBM struct and dummy distribution - equation = LatticeBoltzmannEquations3D(Ma=0.1, Re=1000) + equation = LatticeBoltzmannEquations3D(Ma = 0.1, Re = 1000) u = Trixi.equilibrium_distribution(1, 2, 3, 4, equation) # Component-wise velocity @test isapprox(velocity(u, 1, equation), 2) @test isapprox(velocity(u, 2, equation), 3) @test isapprox(velocity(u, 3, equation), 4) - end +end - @timed_testset "LBMCollisionCallback" begin +@timed_testset "LBMCollisionCallback" begin # Printing of LBM collision callback callback = LBMCollisionCallback() @test_nowarn show(stdout, callback) println() @test_nowarn show(stdout, "text/plain", callback) println() - end +end - @timed_testset "Acoustic perturbation 2D varnames" begin +@timed_testset "Acoustic perturbation 2D varnames" begin v_mean_global = (0.0, 0.0) c_mean_global = 1.0 rho_mean_global = 1.0 - equations = AcousticPerturbationEquations2D(v_mean_global, c_mean_global, rho_mean_global) + equations = AcousticPerturbationEquations2D(v_mean_global, c_mean_global, + rho_mean_global) - @test Trixi.varnames(cons2state, equations) == ("v1_prime", "v2_prime", "p_prime_scaled") - @test Trixi.varnames(cons2mean, equations) == ("v1_mean", "v2_mean", "c_mean", "rho_mean") - end + @test Trixi.varnames(cons2state, equations) == + ("v1_prime", "v2_prime", "p_prime_scaled") + @test Trixi.varnames(cons2mean, equations) == + ("v1_mean", "v2_mean", "c_mean", "rho_mean") +end - @timed_testset "Euler conversion between conservative/entropy variables" begin +@timed_testset "Euler conversion between conservative/entropy variables" begin rho, v1, v2, v3, p = 1.0, 0.1, 0.2, 0.3, 2.0 let equations = CompressibleEulerEquations1D(1.4) - cons_vars = prim2cons(SVector(rho, v1, p),equations) - entropy_vars = cons2entropy(cons_vars, equations) - @test cons_vars ≈ entropy2cons(entropy_vars, equations) + cons_vars = prim2cons(SVector(rho, v1, p), equations) + entropy_vars = cons2entropy(cons_vars, equations) + @test cons_vars ≈ entropy2cons(entropy_vars, equations) - # test tuple args - cons_vars = prim2cons((rho, v1, p),equations) - entropy_vars = cons2entropy(cons_vars, equations) - @test cons_vars ≈ entropy2cons(entropy_vars, equations) + # test tuple args + cons_vars = prim2cons((rho, v1, p), equations) + entropy_vars = cons2entropy(cons_vars, equations) + @test cons_vars ≈ entropy2cons(entropy_vars, equations) end let equations = CompressibleEulerEquations2D(1.4) - cons_vars = prim2cons(SVector(rho,v1,v2,p),equations) - entropy_vars = cons2entropy(cons_vars,equations) - @test cons_vars ≈ entropy2cons(entropy_vars,equations) + cons_vars = prim2cons(SVector(rho, v1, v2, p), equations) + entropy_vars = cons2entropy(cons_vars, equations) + @test cons_vars ≈ entropy2cons(entropy_vars, equations) - # test tuple args - cons_vars = prim2cons((rho, v1, v2, p), equations) - entropy_vars = cons2entropy(cons_vars, equations) - @test cons_vars ≈ entropy2cons(entropy_vars, equations) + # test tuple args + cons_vars = prim2cons((rho, v1, v2, p), equations) + entropy_vars = cons2entropy(cons_vars, equations) + @test cons_vars ≈ entropy2cons(entropy_vars, equations) end let equations = CompressibleEulerEquations3D(1.4) - cons_vars = prim2cons(SVector(rho,v1,v2,v3,p),equations) - entropy_vars = cons2entropy(cons_vars,equations) - @test cons_vars ≈ entropy2cons(entropy_vars,equations) + cons_vars = prim2cons(SVector(rho, v1, v2, v3, p), equations) + entropy_vars = cons2entropy(cons_vars, equations) + @test cons_vars ≈ entropy2cons(entropy_vars, equations) - # test tuple args - cons_vars = prim2cons((rho, v1, v2, v3, p), equations) - entropy_vars = cons2entropy(cons_vars, equations) - @test cons_vars ≈ entropy2cons(entropy_vars, equations) + # test tuple args + cons_vars = prim2cons((rho, v1, v2, v3, p), equations) + entropy_vars = cons2entropy(cons_vars, equations) + @test cons_vars ≈ entropy2cons(entropy_vars, equations) end - end +end - @timed_testset "Shallow water conversion between conservative/entropy variables" begin +@timed_testset "Shallow water conversion between conservative/entropy variables" begin H, v1, v2, b = 3.5, 0.25, 0.1, 0.4 - let equations = ShallowWaterEquations1D(gravity_constant=9.8) - cons_vars = prim2cons(SVector(H, v1, b),equations) - entropy_vars = cons2entropy(cons_vars,equations) - @test cons_vars ≈ entropy2cons(entropy_vars,equations) + let equations = ShallowWaterEquations1D(gravity_constant = 9.8) + cons_vars = prim2cons(SVector(H, v1, b), equations) + entropy_vars = cons2entropy(cons_vars, equations) + @test cons_vars ≈ entropy2cons(entropy_vars, equations) - total_energy = energy_total(cons_vars, equations) - @test total_energy ≈ entropy(cons_vars, equations) + total_energy = energy_total(cons_vars, equations) + @test total_energy ≈ entropy(cons_vars, equations) - # test tuple args - cons_vars = prim2cons((H, v1, b), equations) - entropy_vars = cons2entropy(cons_vars, equations) - @test cons_vars ≈ entropy2cons(entropy_vars, equations) + # test tuple args + cons_vars = prim2cons((H, v1, b), equations) + entropy_vars = cons2entropy(cons_vars, equations) + @test cons_vars ≈ entropy2cons(entropy_vars, equations) end - let equations = ShallowWaterEquations2D(gravity_constant=9.8) - cons_vars = prim2cons(SVector(H,v1,v2,b),equations) - entropy_vars = cons2entropy(cons_vars,equations) - @test cons_vars ≈ entropy2cons(entropy_vars,equations) + let equations = ShallowWaterEquations2D(gravity_constant = 9.8) + cons_vars = prim2cons(SVector(H, v1, v2, b), equations) + entropy_vars = cons2entropy(cons_vars, equations) + @test cons_vars ≈ entropy2cons(entropy_vars, equations) - total_energy = energy_total(cons_vars, equations) - @test total_energy ≈ entropy(cons_vars, equations) + total_energy = energy_total(cons_vars, equations) + @test total_energy ≈ entropy(cons_vars, equations) - # test tuple args - cons_vars = prim2cons((H, v1, v2, b), equations) - entropy_vars = cons2entropy(cons_vars, equations) - @test cons_vars ≈ entropy2cons(entropy_vars, equations) + # test tuple args + cons_vars = prim2cons((H, v1, v2, b), equations) + entropy_vars = cons2entropy(cons_vars, equations) + @test cons_vars ≈ entropy2cons(entropy_vars, equations) end - end +end - @timed_testset "boundary_condition_do_nothing" begin +@timed_testset "boundary_condition_do_nothing" begin rho, v1, v2, p = 1.0, 0.1, 0.2, 0.3, 2.0 let equations = CompressibleEulerEquations2D(1.4) - u = prim2cons(SVector(rho, v1, v2, p), equations) - x = SVector(1.0, 2.0) - t = 0.5 - surface_flux = flux_lax_friedrichs - - outward_direction = SVector(0.2, -0.3) - @test flux(u, outward_direction, equations) ≈ boundary_condition_do_nothing(u, outward_direction, x, t, surface_flux, equations) - - orientation = 2 - direction = 4 - @test flux(u, orientation, equations) ≈ boundary_condition_do_nothing(u, orientation, direction, x, t, surface_flux, equations) + u = prim2cons(SVector(rho, v1, v2, p), equations) + x = SVector(1.0, 2.0) + t = 0.5 + surface_flux = flux_lax_friedrichs + + outward_direction = SVector(0.2, -0.3) + @test flux(u, outward_direction, equations) ≈ + boundary_condition_do_nothing(u, outward_direction, x, t, surface_flux, + equations) + + orientation = 2 + direction = 4 + @test flux(u, orientation, equations) ≈ + boundary_condition_do_nothing(u, orientation, direction, x, t, + surface_flux, equations) end - end +end - @timed_testset "TimeSeriesCallback" begin +@timed_testset "TimeSeriesCallback" begin @test_nowarn_mod trixi_include(@__MODULE__, - joinpath(examples_dir(), "tree_2d_dgsem", "elixir_acoustics_gaussian_source.jl"), - tspan=(0, 0.05)) + joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_acoustics_gaussian_source.jl"), + tspan = (0, 0.05)) point_data_1 = time_series.affect!.point_data[1] - @test all(isapprox.(point_data_1[1:7], [-2.4417734981719132e-5, -3.4296207289200194e-5, - 0.0018130846385739788, -0.5, 0.25, 1.0, 1.0])) - @test_throws DimensionMismatch Trixi.get_elements_by_coordinates!([1, 2], rand(2, 4), mesh, + @test all(isapprox.(point_data_1[1:7], + [-2.4417734981719132e-5, -3.4296207289200194e-5, + 0.0018130846385739788, -0.5, 0.25, 1.0, 1.0])) + @test_throws DimensionMismatch Trixi.get_elements_by_coordinates!([1, 2], + rand(2, 4), mesh, solver, nothing) @test_nowarn show(stdout, time_series) - @test_throws ArgumentError TimeSeriesCallback(semi, [(1.0, 1.0)]; interval=-1) + @test_throws ArgumentError TimeSeriesCallback(semi, [(1.0, 1.0)]; interval = -1) @test_throws ArgumentError TimeSeriesCallback(semi, [1.0 1.0 1.0; 2.0 2.0 2.0]) - end +end - @timed_testset "Consistency check for HLL flux (naive): CEE" begin +@timed_testset "Consistency check for HLL flux (naive): CEE" begin flux_hll = FluxHLL(min_max_speed_naive) # Set up equations and dummy conservative variables state @@ -602,7 +628,7 @@ isdir(outdir) && rm(outdir, recursive=true) orientations = [1] for orientation in orientations - @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) end equations = CompressibleEulerEquations2D(1.4) @@ -610,7 +636,7 @@ isdir(outdir) && rm(outdir, recursive=true) orientations = [1, 2] for orientation in orientations - @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) end equations = CompressibleEulerEquations3D(1.4) @@ -618,11 +644,11 @@ isdir(outdir) && rm(outdir, recursive=true) orientations = [1, 2, 3] for orientation in orientations - @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) end - end +end - @timed_testset "Consistency check for HLL flux (naive): LEE" begin +@timed_testset "Consistency check for HLL flux (naive): LEE" begin flux_hll = FluxHLL(min_max_speed_naive) equations = LinearizedEulerEquations2D(SVector(1.0, 1.0), 1.0, 1.0) @@ -630,87 +656,91 @@ isdir(outdir) && rm(outdir, recursive=true) orientations = [1, 2] for orientation in orientations - @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) end normal_directions = [SVector(1.0, 0.0), - SVector(0.0, 1.0), - SVector(0.5, -0.5), - SVector(-1.2, 0.3)] + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] for normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + @test flux_hll(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) end - end +end - @timed_testset "Consistency check for HLL flux (naive): SWE" begin +@timed_testset "Consistency check for HLL flux (naive): SWE" begin flux_hll = FluxHLL(min_max_speed_naive) - equations = ShallowWaterEquations1D(gravity_constant=9.81) + equations = ShallowWaterEquations1D(gravity_constant = 9.81) u = SVector(1, 0.5, 0.0) @test flux_hll(u, u, 1, equations) ≈ flux(u, 1, equations) - equations = ShallowWaterEquations2D(gravity_constant=9.81) + equations = ShallowWaterEquations2D(gravity_constant = 9.81) normal_directions = [SVector(1.0, 0.0), - SVector(0.0, 1.0), - SVector(0.5, -0.5), - SVector(-1.2, 0.3)] + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] u = SVector(1, 0.5, 0.5, 0.0) for normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + @test flux_hll(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) end - end +end - @timed_testset "Consistency check for HLL flux (naive): MHD" begin +@timed_testset "Consistency check for HLL flux (naive): MHD" begin flux_hll = FluxHLL(min_max_speed_naive) equations = IdealGlmMhdEquations1D(1.4) u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1), - SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2),] + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2)] for u in u_values - @test flux_hll(u, u, 1, equations) ≈ flux(u, 1, equations) + @test flux_hll(u, u, 1, equations) ≈ flux(u, 1, equations) end - equations = IdealGlmMhdEquations2D(1.4, 5.0 #= c_h =#) + equations = IdealGlmMhdEquations2D(1.4, 5.0) #= c_h =# normal_directions = [SVector(1.0, 0.0), - SVector(0.0, 1.0), - SVector(0.5, -0.5), - SVector(-1.2, 0.3)] + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] orientations = [1, 2] u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), - SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2)] for u in u_values, orientation in orientations - @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) end for u in u_values, normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + @test flux_hll(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) end - equations = IdealGlmMhdEquations3D(1.4, 5.0 #= c_h =#) + equations = IdealGlmMhdEquations3D(1.4, 5.0) #= c_h =# normal_directions = [SVector(1.0, 0.0, 0.0), - SVector(0.0, 1.0, 0.0), - SVector(0.0, 0.0, 1.0), - SVector(0.5, -0.5, 0.2), - SVector(-1.2, 0.3, 1.4)] + SVector(0.0, 1.0, 0.0), + SVector(0.0, 0.0, 1.0), + SVector(0.5, -0.5, 0.2), + SVector(-1.2, 0.3, 1.4)] orientations = [1, 2, 3] u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), - SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2)] for u in u_values, orientation in orientations - @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) end for u in u_values, normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + @test flux_hll(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) end - end +end - @timed_testset "Consistency check for HLL flux with Davis wave speed estimates: CEE" begin +@timed_testset "Consistency check for HLL flux with Davis wave speed estimates: CEE" begin flux_hll = FluxHLL(min_max_speed_davis) # Set up equations and dummy conservative variables state @@ -719,7 +749,7 @@ isdir(outdir) && rm(outdir, recursive=true) orientations = [1] for orientation in orientations - @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) end equations = CompressibleEulerEquations2D(1.4) @@ -727,16 +757,17 @@ isdir(outdir) && rm(outdir, recursive=true) orientations = [1, 2] for orientation in orientations - @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) end normal_directions = [SVector(1.0, 0.0), - SVector(0.0, 1.0), - SVector(0.5, -0.5), - SVector(-1.2, 0.3)] + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] for normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + @test flux_hll(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) end equations = CompressibleEulerEquations3D(1.4) @@ -744,21 +775,22 @@ isdir(outdir) && rm(outdir, recursive=true) orientations = [1, 2, 3] for orientation in orientations - @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) end normal_directions = [SVector(1.0, 0.0, 0.0), - SVector(0.0, 1.0, 0.0), - SVector(0.0, 0.0, 1.0), - SVector(0.5, -0.5, 0.2), - SVector(-1.2, 0.3, 1.4)] + SVector(0.0, 1.0, 0.0), + SVector(0.0, 0.0, 1.0), + SVector(0.5, -0.5, 0.2), + SVector(-1.2, 0.3, 1.4)] for normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + @test flux_hll(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) end - end +end - @timed_testset "Consistency check for HLL flux with Davis wave speed estimates: LEE" begin +@timed_testset "Consistency check for HLL flux with Davis wave speed estimates: LEE" begin flux_hll = FluxHLL(min_max_speed_davis) equations = LinearizedEulerEquations2D(SVector(1.0, 1.0), 1.0, 1.0) @@ -766,99 +798,103 @@ isdir(outdir) && rm(outdir, recursive=true) orientations = [1, 2] for orientation in orientations - @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) end normal_directions = [SVector(1.0, 0.0), - SVector(0.0, 1.0), - SVector(0.5, -0.5), - SVector(-1.2, 0.3)] + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] for normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + @test flux_hll(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) end - end +end - @timed_testset "Consistency check for HLL flux with Davis wave speed estimates: SWE" begin +@timed_testset "Consistency check for HLL flux with Davis wave speed estimates: SWE" begin flux_hll = FluxHLL(min_max_speed_davis) - equations = ShallowWaterEquations1D(gravity_constant=9.81) + equations = ShallowWaterEquations1D(gravity_constant = 9.81) u = SVector(1, 0.5, 0.0) @test flux_hll(u, u, 1, equations) ≈ flux(u, 1, equations) - equations = ShallowWaterEquations2D(gravity_constant=9.81) + equations = ShallowWaterEquations2D(gravity_constant = 9.81) normal_directions = [SVector(1.0, 0.0), - SVector(0.0, 1.0), - SVector(0.5, -0.5), - SVector(-1.2, 0.3)] + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] u = SVector(1, 0.5, 0.5, 0.0) for normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + @test flux_hll(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) end orientations = [1, 2] for orientation in orientations - @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) end - end +end - @timed_testset "Consistency check for HLL flux with Davis wave speed estimates: MHD" begin +@timed_testset "Consistency check for HLL flux with Davis wave speed estimates: MHD" begin flux_hll = FluxHLL(min_max_speed_davis) equations = IdealGlmMhdEquations1D(1.4) u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1), - SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2),] + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2)] for u in u_values - @test flux_hll(u, u, 1, equations) ≈ flux(u, 1, equations) + @test flux_hll(u, u, 1, equations) ≈ flux(u, 1, equations) end - equations = IdealGlmMhdEquations2D(1.4, 5.0 #= c_h =#) + equations = IdealGlmMhdEquations2D(1.4, 5.0) #= c_h =# normal_directions = [SVector(1.0, 0.0), - SVector(0.0, 1.0), - SVector(0.5, -0.5), - SVector(-1.2, 0.3)] + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] orientations = [1, 2] u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), - SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2)] for u in u_values, orientation in orientations - @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) end for u in u_values, normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + @test flux_hll(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) end - equations = IdealGlmMhdEquations3D(1.4, 5.0 #= c_h =#) + equations = IdealGlmMhdEquations3D(1.4, 5.0) #= c_h =# normal_directions = [SVector(1.0, 0.0, 0.0), - SVector(0.0, 1.0, 0.0), - SVector(0.0, 0.0, 1.0), - SVector(0.5, -0.5, 0.2), - SVector(-1.2, 0.3, 1.4)] + SVector(0.0, 1.0, 0.0), + SVector(0.0, 0.0, 1.0), + SVector(0.5, -0.5, 0.2), + SVector(-1.2, 0.3, 1.4)] orientations = [1, 2, 3] u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), - SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2)] for u in u_values, orientation in orientations - @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) end for u in u_values, normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + @test flux_hll(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) end - end +end - @timed_testset "Consistency check for HLLE flux: CEE" begin +@timed_testset "Consistency check for HLLE flux: CEE" begin # Set up equations and dummy conservative variables state equations = CompressibleEulerEquations1D(1.4) u = SVector(1.1, 2.34, 5.5) orientations = [1] for orientation in orientations - @test flux_hlle(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hlle(u, u, orientation, equations) ≈ flux(u, orientation, equations) end equations = CompressibleEulerEquations2D(1.4) @@ -866,16 +902,17 @@ isdir(outdir) && rm(outdir, recursive=true) orientations = [1, 2] for orientation in orientations - @test flux_hlle(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hlle(u, u, orientation, equations) ≈ flux(u, orientation, equations) end normal_directions = [SVector(1.0, 0.0), - SVector(0.0, 1.0), - SVector(0.5, -0.5), - SVector(-1.2, 0.3)] + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] for normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + @test flux_hll(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) end equations = CompressibleEulerEquations3D(1.4) @@ -883,97 +920,101 @@ isdir(outdir) && rm(outdir, recursive=true) orientations = [1, 2, 3] for orientation in orientations - @test flux_hlle(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hlle(u, u, orientation, equations) ≈ flux(u, orientation, equations) end normal_directions = [SVector(1.0, 0.0, 0.0), - SVector(0.0, 1.0, 0.0), - SVector(0.0, 0.0, 1.0), - SVector(0.5, -0.5, 0.2), - SVector(-1.2, 0.3, 1.4)] + SVector(0.0, 1.0, 0.0), + SVector(0.0, 0.0, 1.0), + SVector(0.5, -0.5, 0.2), + SVector(-1.2, 0.3, 1.4)] for normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + @test flux_hll(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) end - end +end - @timed_testset "Consistency check for HLLE flux: SWE" begin +@timed_testset "Consistency check for HLLE flux: SWE" begin # Test HLL flux with min_max_speed_einfeldt flux_hll = FluxHLL(min_max_speed_einfeldt) - equations = ShallowWaterEquations1D(gravity_constant=9.81) + equations = ShallowWaterEquations1D(gravity_constant = 9.81) u = SVector(1, 0.5, 0.0) @test flux_hll(u, u, 1, equations) ≈ flux(u, 1, equations) - equations = ShallowWaterEquations2D(gravity_constant=9.81) + equations = ShallowWaterEquations2D(gravity_constant = 9.81) normal_directions = [SVector(1.0, 0.0), - SVector(0.0, 1.0), - SVector(0.5, -0.5), - SVector(-1.2, 0.3)] + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] orientations = [1, 2] u = SVector(1, 0.5, 0.5, 0.0) for orientation in orientations - @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) end for normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + @test flux_hll(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) end - end +end - @timed_testset "Consistency check for HLLE flux: MHD" begin +@timed_testset "Consistency check for HLLE flux: MHD" begin # Test HLL flux with min_max_speed_einfeldt flux_hll = FluxHLL(min_max_speed_naive) equations = IdealGlmMhdEquations1D(1.4) u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1), - SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2),] + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2)] for u in u_values - @test flux_hll(u, u, 1, equations) ≈ flux(u, 1, equations) + @test flux_hll(u, u, 1, equations) ≈ flux(u, 1, equations) end - equations = IdealGlmMhdEquations2D(1.4, 5.0 #= c_h =#) + equations = IdealGlmMhdEquations2D(1.4, 5.0) #= c_h =# normal_directions = [SVector(1.0, 0.0), - SVector(0.0, 1.0), - SVector(0.5, -0.5), - SVector(-1.2, 0.3)] + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] orientations = [1, 2] u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), - SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2)] for u in u_values, orientation in orientations - @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) end for u in u_values, normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + @test flux_hll(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) end - equations = IdealGlmMhdEquations3D(1.4, 5.0 #= c_h =#) + equations = IdealGlmMhdEquations3D(1.4, 5.0) #= c_h =# normal_directions = [SVector(1.0, 0.0, 0.0), - SVector(0.0, 1.0, 0.0), - SVector(0.0, 0.0, 1.0), - SVector(0.5, -0.5, 0.2), - SVector(-1.2, 0.3, 1.4)] + SVector(0.0, 1.0, 0.0), + SVector(0.0, 0.0, 1.0), + SVector(0.5, -0.5, 0.2), + SVector(-1.2, 0.3, 1.4)] orientations = [1, 2, 3] u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), - SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2)] for u in u_values, orientation in orientations - @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) end for u in u_values, normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) + @test flux_hll(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) end - end +end - @timed_testset "Consistency check for Godunov flux" begin +@timed_testset "Consistency check for Godunov flux" begin # Set up equations and dummy conservative variables state # Burgers' Equation @@ -982,7 +1023,7 @@ isdir(outdir) && rm(outdir, recursive=true) orientations = [1] for orientation in orientations, u in u_values - @test flux_godunov(u, u, orientation, equation) ≈ flux(u, orientation, equation) + @test flux_godunov(u, u, orientation, equation) ≈ flux(u, orientation, equation) end # Linear Advection 1D @@ -991,7 +1032,7 @@ isdir(outdir) && rm(outdir, recursive=true) orientations = [1] for orientation in orientations - @test flux_godunov(u, u, orientation, equation) ≈ flux(u, orientation, equation) + @test flux_godunov(u, u, orientation, equation) ≈ flux(u, orientation, equation) end # Linear Advection 2D @@ -1000,16 +1041,17 @@ isdir(outdir) && rm(outdir, recursive=true) orientations = [1, 2] for orientation in orientations - @test flux_godunov(u, u, orientation, equation) ≈ flux(u, orientation, equation) + @test flux_godunov(u, u, orientation, equation) ≈ flux(u, orientation, equation) end normal_directions = [SVector(1.0, 0.0), - SVector(0.0, 1.0), - SVector(0.5, -0.5), - SVector(-1.2, 0.3)] + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] for normal_direction in normal_directions - @test flux_godunov(u, u, normal_direction, equation) ≈ flux(u, normal_direction, equation) + @test flux_godunov(u, u, normal_direction, equation) ≈ + flux(u, normal_direction, equation) end # Linear Advection 3D @@ -1018,48 +1060,52 @@ isdir(outdir) && rm(outdir, recursive=true) orientations = [1, 2, 3] for orientation in orientations - @test flux_godunov(u, u, orientation, equation) ≈ flux(u, orientation, equation) + @test flux_godunov(u, u, orientation, equation) ≈ flux(u, orientation, equation) end normal_directions = [SVector(1.0, 0.0, 0.0), - SVector(0.0, 1.0, 0.0), - SVector(0.0, 0.0, 1.0), - SVector(0.5, -0.5, 0.2), - SVector(-1.2, 0.3, 1.4)] + SVector(0.0, 1.0, 0.0), + SVector(0.0, 0.0, 1.0), + SVector(0.5, -0.5, 0.2), + SVector(-1.2, 0.3, 1.4)] for normal_direction in normal_directions - @test flux_godunov(u, u, normal_direction, equation) ≈ flux(u, normal_direction, equation) + @test flux_godunov(u, u, normal_direction, equation) ≈ + flux(u, normal_direction, equation) end # Linearized Euler 2D - equation = LinearizedEulerEquations2D(v_mean_global=(0.5, -0.7), c_mean_global=1.1, - rho_mean_global=1.2) + equation = LinearizedEulerEquations2D(v_mean_global = (0.5, -0.7), + c_mean_global = 1.1, + rho_mean_global = 1.2) u_values = [SVector(1.0, 0.5, -0.7, 1.0), - SVector(1.5, -0.2, 0.1, 5.0),] + SVector(1.5, -0.2, 0.1, 5.0)] orientations = [1, 2] for orientation in orientations, u in u_values - @test flux_godunov(u, u, orientation, equation) ≈ flux(u, orientation, equation) + @test flux_godunov(u, u, orientation, equation) ≈ flux(u, orientation, equation) end normal_directions = [SVector(1.0, 0.0), - SVector(0.0, 1.0), - SVector(0.5, -0.5), - SVector(-1.2, 0.3)] + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] for normal_direction in normal_directions, u in u_values - @test flux_godunov(u, u, normal_direction, equation) ≈ flux(u, normal_direction, equation) + @test flux_godunov(u, u, normal_direction, equation) ≈ + flux(u, normal_direction, equation) end - end +end - @timed_testset "Consistency check for Engquist-Osher flux" begin +@timed_testset "Consistency check for Engquist-Osher flux" begin # Set up equations and dummy conservative variables state equation = InviscidBurgersEquation1D() u_values = [SVector(42.0), SVector(-42.0)] orientations = [1] for orientation in orientations, u in u_values - @test Trixi.flux_engquist_osher(u, u, orientation, equation) ≈ flux(u, orientation, equation) + @test Trixi.flux_engquist_osher(u, u, orientation, equation) ≈ + flux(u, orientation, equation) end equation = LinearScalarAdvectionEquation1D(-4.2) @@ -1067,11 +1113,12 @@ isdir(outdir) && rm(outdir, recursive=true) orientations = [1] for orientation in orientations - @test Trixi.flux_engquist_osher(u, u, orientation, equation) ≈ flux(u, orientation, equation) + @test Trixi.flux_engquist_osher(u, u, orientation, equation) ≈ + flux(u, orientation, equation) end - end +end - @testset "Equivalent Fluxes" begin +@testset "Equivalent Fluxes" begin # Set up equations and dummy conservative variables state # Burgers' Equation @@ -1080,7 +1127,8 @@ isdir(outdir) && rm(outdir, recursive=true) orientations = [1] for orientation in orientations, u in u_values - @test flux_godunov(0.75*u, u, orientation, equation) ≈ Trixi.flux_engquist_osher(0.75*u, u, orientation, equation) + @test flux_godunov(0.75 * u, u, orientation, equation) ≈ + Trixi.flux_engquist_osher(0.75 * u, u, orientation, equation) end # Linear Advection 1D @@ -1089,8 +1137,10 @@ isdir(outdir) && rm(outdir, recursive=true) orientations = [1] for orientation in orientations - @test flux_godunov(0.5*u, u, orientation, equation) ≈ flux_lax_friedrichs(0.5*u, u, orientation, equation) - @test flux_godunov(2*u, u, orientation, equation) ≈ Trixi.flux_engquist_osher(2*u, u, orientation, equation) + @test flux_godunov(0.5 * u, u, orientation, equation) ≈ + flux_lax_friedrichs(0.5 * u, u, orientation, equation) + @test flux_godunov(2 * u, u, orientation, equation) ≈ + Trixi.flux_engquist_osher(2 * u, u, orientation, equation) end # Linear Advection 2D @@ -1099,16 +1149,18 @@ isdir(outdir) && rm(outdir, recursive=true) orientations = [1, 2] for orientation in orientations - @test flux_godunov(0.25*u, u, orientation, equation) ≈ flux_lax_friedrichs(0.25*u, u, orientation, equation) + @test flux_godunov(0.25 * u, u, orientation, equation) ≈ + flux_lax_friedrichs(0.25 * u, u, orientation, equation) end normal_directions = [SVector(1.0, 0.0), - SVector(0.0, 1.0), - SVector(0.5, -0.5), - SVector(-1.2, 0.3)] + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] for normal_direction in normal_directions - @test flux_godunov(3*u, u, normal_direction, equation) ≈ flux_lax_friedrichs(3*u, u, normal_direction, equation) + @test flux_godunov(3 * u, u, normal_direction, equation) ≈ + flux_lax_friedrichs(3 * u, u, normal_direction, equation) end # Linear Advection 3D @@ -1117,113 +1169,137 @@ isdir(outdir) && rm(outdir, recursive=true) orientations = [1, 2, 3] for orientation in orientations - @test flux_godunov(1.5*u, u, orientation, equation) ≈ flux_lax_friedrichs(1.5*u, u, orientation, equation) + @test flux_godunov(1.5 * u, u, orientation, equation) ≈ + flux_lax_friedrichs(1.5 * u, u, orientation, equation) end normal_directions = [SVector(1.0, 0.0, 0.0), - SVector(0.0, 1.0, 0.0), - SVector(0.0, 0.0, 1.0), - SVector(0.5, -0.5, 0.2), - SVector(-1.2, 0.3, 1.4)] + SVector(0.0, 1.0, 0.0), + SVector(0.0, 0.0, 1.0), + SVector(0.5, -0.5, 0.2), + SVector(-1.2, 0.3, 1.4)] for normal_direction in normal_directions - @test flux_godunov(1.3*u, u, normal_direction, equation) ≈ flux_lax_friedrichs(1.3*u, u, normal_direction, equation) + @test flux_godunov(1.3 * u, u, normal_direction, equation) ≈ + flux_lax_friedrichs(1.3 * u, u, normal_direction, equation) end - end +end - @testset "FluxRotated vs. direct implementation" begin +@testset "FluxRotated vs. direct implementation" begin @timed_testset "CompressibleEulerEquations2D" begin - equations = CompressibleEulerEquations2D(1.4) - normal_directions = [SVector(1.0, 0.0), - SVector(0.0, 1.0), - SVector(0.5, -0.5), - SVector(-1.2, 0.3)] - u_values = [SVector(1.0, 0.5, -0.7, 1.0), - SVector(1.5, -0.2, 0.1, 5.0),] - fluxes = [flux_central, flux_ranocha, flux_shima_etal, flux_kennedy_gruber, - flux_hll, FluxHLL(min_max_speed_davis)] - - for f_std in fluxes - f_rot = FluxRotated(f_std) - for u_ll in u_values, u_rr in u_values, normal_direction in normal_directions - @test f_rot(u_ll, u_rr, normal_direction, equations) ≈ f_std(u_ll, u_rr, normal_direction, equations) + equations = CompressibleEulerEquations2D(1.4) + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + u_values = [SVector(1.0, 0.5, -0.7, 1.0), + SVector(1.5, -0.2, 0.1, 5.0)] + fluxes = [flux_central, flux_ranocha, flux_shima_etal, flux_kennedy_gruber, + flux_hll, FluxHLL(min_max_speed_davis)] + + for f_std in fluxes + f_rot = FluxRotated(f_std) + for u_ll in u_values, u_rr in u_values, + normal_direction in normal_directions + + @test f_rot(u_ll, u_rr, normal_direction, equations) ≈ + f_std(u_ll, u_rr, normal_direction, equations) + end end - end end @timed_testset "CompressibleEulerEquations3D" begin - equations = CompressibleEulerEquations3D(1.4) - normal_directions = [SVector(1.0, 0.0, 0.0), - SVector(0.0, 1.0, 0.0), - SVector(0.0, 0.0, 1.0), - SVector(0.5, -0.5, 0.2), - SVector(-1.2, 0.3, 1.4)] - u_values = [SVector(1.0, 0.5, -0.7, 0.1, 1.0), - SVector(1.5, -0.2, 0.1, 0.2, 5.0),] - fluxes = [flux_central, flux_ranocha, flux_shima_etal, flux_kennedy_gruber, FluxLMARS(340), - flux_hll, FluxHLL(min_max_speed_davis)] - - for f_std in fluxes - f_rot = FluxRotated(f_std) - for u_ll in u_values, u_rr in u_values, normal_direction in normal_directions - @test f_rot(u_ll, u_rr, normal_direction, equations) ≈ f_std(u_ll, u_rr, normal_direction, equations) + equations = CompressibleEulerEquations3D(1.4) + normal_directions = [SVector(1.0, 0.0, 0.0), + SVector(0.0, 1.0, 0.0), + SVector(0.0, 0.0, 1.0), + SVector(0.5, -0.5, 0.2), + SVector(-1.2, 0.3, 1.4)] + u_values = [SVector(1.0, 0.5, -0.7, 0.1, 1.0), + SVector(1.5, -0.2, 0.1, 0.2, 5.0)] + fluxes = [flux_central, flux_ranocha, flux_shima_etal, flux_kennedy_gruber, + FluxLMARS(340), + flux_hll, FluxHLL(min_max_speed_davis)] + + for f_std in fluxes + f_rot = FluxRotated(f_std) + for u_ll in u_values, u_rr in u_values, + normal_direction in normal_directions + + @test f_rot(u_ll, u_rr, normal_direction, equations) ≈ + f_std(u_ll, u_rr, normal_direction, equations) + end end - end end @timed_testset "ShallowWaterEquations2D" begin - equations = ShallowWaterEquations2D(gravity_constant=9.81) - normal_directions = [SVector(1.0, 0.0), - SVector(0.0, 1.0), - SVector(0.5, -0.5), - SVector(-1.2, 0.3)] - - u = SVector(1, 0.5, 0.5, 0.0) + equations = ShallowWaterEquations2D(gravity_constant = 9.81) + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] - fluxes = [flux_central, flux_fjordholm_etal, flux_wintermeyer_etal, - flux_hll, FluxHLL(min_max_speed_davis), FluxHLL(min_max_speed_einfeldt)] + u = SVector(1, 0.5, 0.5, 0.0) + fluxes = [flux_central, flux_fjordholm_etal, flux_wintermeyer_etal, + flux_hll, FluxHLL(min_max_speed_davis), FluxHLL(min_max_speed_einfeldt)] end @timed_testset "IdealGlmMhdEquations2D" begin - equations = IdealGlmMhdEquations2D(1.4, 5.0 #= c_h =#) - normal_directions = [SVector(1.0, 0.0), - SVector(0.0, 1.0), - SVector(0.5, -0.5), - SVector(-1.2, 0.3)] - u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), - SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] - fluxes = [flux_central, flux_hindenlang_gassner, flux_hll, FluxHLL(min_max_speed_davis)] - - for f_std in fluxes - f_rot = FluxRotated(f_std) - for u_ll in u_values, u_rr in u_values, normal_direction in normal_directions - @test f_rot(u_ll, u_rr, normal_direction, equations) ≈ f_std(u_ll, u_rr, normal_direction, equations) + equations = IdealGlmMhdEquations2D(1.4, 5.0) #= c_h =# + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2)] + fluxes = [ + flux_central, + flux_hindenlang_gassner, + flux_hll, + FluxHLL(min_max_speed_davis), + ] + + for f_std in fluxes + f_rot = FluxRotated(f_std) + for u_ll in u_values, u_rr in u_values, + normal_direction in normal_directions + + @test f_rot(u_ll, u_rr, normal_direction, equations) ≈ + f_std(u_ll, u_rr, normal_direction, equations) + end end - end end @timed_testset "IdealGlmMhdEquations3D" begin - equations = IdealGlmMhdEquations3D(1.4, 5.0 #= c_h =#) - normal_directions = [SVector(1.0, 0.0, 0.0), - SVector(0.0, 1.0, 0.0), - SVector(0.0, 0.0, 1.0), - SVector(0.5, -0.5, 0.2), - SVector(-1.2, 0.3, 1.4)] - u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), - SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2),] - fluxes = [flux_central, flux_hindenlang_gassner, flux_hll, FluxHLL(min_max_speed_davis)] - - for f_std in fluxes - f_rot = FluxRotated(f_std) - for u_ll in u_values, u_rr in u_values, normal_direction in normal_directions - @test f_rot(u_ll, u_rr, normal_direction, equations) ≈ f_std(u_ll, u_rr, normal_direction, equations) + equations = IdealGlmMhdEquations3D(1.4, 5.0) #= c_h =# + normal_directions = [SVector(1.0, 0.0, 0.0), + SVector(0.0, 1.0, 0.0), + SVector(0.0, 0.0, 1.0), + SVector(0.5, -0.5, 0.2), + SVector(-1.2, 0.3, 1.4)] + u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1, 0.0), + SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2)] + fluxes = [ + flux_central, + flux_hindenlang_gassner, + flux_hll, + FluxHLL(min_max_speed_davis), + ] + + for f_std in fluxes + f_rot = FluxRotated(f_std) + for u_ll in u_values, u_rr in u_values, + normal_direction in normal_directions + + @test f_rot(u_ll, u_rr, normal_direction, equations) ≈ + f_std(u_ll, u_rr, normal_direction, equations) + end end - end end - end +end - @testset "SimpleKronecker" begin +@testset "SimpleKronecker" begin N = 3 NDIMS = 2 @@ -1240,30 +1316,28 @@ isdir(outdir) && rm(outdir, recursive=true) Trixi.mul!(b, V, x) Trixi.mul!(b_kron, V_kron, x) @test b ≈ b_kron - end +end - @testset "SummationByPartsOperators + StartUpDG" begin - dg = DGMulti(polydeg = 3, element_type = Quad(), - approximation_type = derivative_operator( - SummationByPartsOperators.MattssonNordström2004(), - derivative_order=1, accuracy_order=4, - xmin=0.0, xmax=1.0, N=10)) +@testset "SummationByPartsOperators + StartUpDG" begin + global D = derivative_operator(SummationByPartsOperators.MattssonNordström2004(), + derivative_order = 1, + accuracy_order = 4, + xmin = 0.0, xmax = 1.0, + N = 10) + dg = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = D) @test StartUpDG.inverse_trace_constant(dg.basis) ≈ 50.8235294117647 - end +end - @testset "1D non-periodic DGMultiMesh" begin +@testset "1D non-periodic DGMultiMesh" begin # checks whether or not boundary faces are initialized correctly for DGMultiMesh in 1D dg = DGMulti(polydeg = 1, element_type = Line(), approximation_type = Polynomial(), surface_integral = SurfaceIntegralWeakForm(flux_central), volume_integral = VolumeIntegralFluxDifferencing(flux_central)) - mesh = DGMultiMesh(dg, cells_per_dimension=(1,), periodicity=false) + mesh = DGMultiMesh(dg, cells_per_dimension = (1,), periodicity = false) @test mesh.boundary_faces[:entire_boundary] == [1, 2] - end - end - - +end end #module diff --git a/test/test_unstructured_2d.jl b/test/test_unstructured_2d.jl index 567cbd9ea57..26483931cf3 100644 --- a/test/test_unstructured_2d.jl +++ b/test/test_unstructured_2d.jl @@ -11,394 +11,601 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "unstructured_2d_dgsem") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) @testset "UnstructuredMesh2D" begin - @trixi_testset "elixir_euler_periodic.jl" begin +#! format: noindent + +@trixi_testset "elixir_euler_periodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_periodic.jl"), - l2 = [0.00010978828464875207, 0.00013010359527356914, 0.00013010359527326057, 0.0002987656724828824], - linf = [0.00638626102818618, 0.009804042508242183, 0.009804042508253286, 0.02183139311614468]) - # 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.jl" begin + l2=[ + 0.00010978828464875207, + 0.00013010359527356914, + 0.00013010359527326057, + 0.0002987656724828824, + ], + linf=[ + 0.00638626102818618, + 0.009804042508242183, + 0.009804042508253286, + 0.02183139311614468, + ]) + # 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.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_free_stream.jl"), - l2 = [3.3937971107485363e-14, 2.447586447887882e-13, 1.4585205789296455e-13, 4.716993468962946e-13], - linf = [8.804734719092266e-12, 6.261270668606045e-11, 2.93670088247211e-11, 1.205400224080222e-10], - tspan = (0.0, 0.1), - atol = 3.0e-13) - # 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_wall_bc.jl" begin + l2=[ + 3.3937971107485363e-14, + 2.447586447887882e-13, + 1.4585205789296455e-13, + 4.716993468962946e-13, + ], + linf=[ + 8.804734719092266e-12, + 6.261270668606045e-11, + 2.93670088247211e-11, + 1.205400224080222e-10, + ], + tspan=(0.0, 0.1), + atol=3.0e-13) + # 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_wall_bc.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_wall_bc.jl"), - l2 = [0.040189107976346644, 0.04256154998030852, 0.03734120743842209, 0.10057425897733507], - linf = [0.24455374304626365, 0.2970686406973577, 0.29339040847600434, 0.5915610037764794], - tspan = (0.0, 0.25)) - # 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_basic.jl" begin + l2=[ + 0.040189107976346644, + 0.04256154998030852, + 0.03734120743842209, + 0.10057425897733507, + ], + linf=[ + 0.24455374304626365, + 0.2970686406973577, + 0.29339040847600434, + 0.5915610037764794, + ], + tspan=(0.0, 0.25)) + # 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_basic.jl" begin @test_trixi_include(default_example_unstructured(), - l2 = [0.0007213418215265047, 0.0006752337675043779, 0.0006437485997536973, 0.0014782883071363362], - linf = [0.004301288971032324, 0.005243995459478956, 0.004685630332338153, 0.01750217718347713], - tspan = (0.0, 1.0)) - # 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_restart.jl" begin + l2=[ + 0.0007213418215265047, + 0.0006752337675043779, + 0.0006437485997536973, + 0.0014782883071363362, + ], + linf=[ + 0.004301288971032324, + 0.005243995459478956, + 0.004685630332338153, + 0.01750217718347713, + ], + tspan=(0.0, 1.0)) + # 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_restart.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_restart.jl"), - l2 = [0.0007213418215265047, 0.0006752337675043779, 0.0006437485997536973, 0.0014782883071363362], - linf = [0.004301288971032324, 0.005243995459478956, 0.004685630332338153, 0.01750217718347713]) - # 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_ec.jl" begin + l2=[ + 0.0007213418215265047, + 0.0006752337675043779, + 0.0006437485997536973, + 0.0014782883071363362, + ], + linf=[ + 0.004301288971032324, + 0.005243995459478956, + 0.004685630332338153, + 0.01750217718347713, + ]) + # 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_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), - l2 = [0.06594600495903137, 0.10803914821786433, 0.10805946357846291, 0.1738171782368222], - linf = [0.31880214280781305, 0.3468488554333352, 0.34592958184413264, 0.784555926860546], - tspan = (0.0, 1.0)) - # 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_basic.jl" begin + l2=[ + 0.06594600495903137, + 0.10803914821786433, + 0.10805946357846291, + 0.1738171782368222, + ], + linf=[ + 0.31880214280781305, + 0.3468488554333352, + 0.34592958184413264, + 0.784555926860546, + ], + tspan=(0.0, 1.0)) + # 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_basic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), - l2 = [0.00018729339078205488], - linf = [0.0018997287705734278]) - # 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 + l2=[0.00018729339078205488], + linf=[0.0018997287705734278]) + # 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 = [2.19945600e-01, 1.71050453e-01, 1.71050453e-01, 1.21719195e+00], - linf = [7.44218635e-01, 7.02887039e-01, 7.02887039e-01, 6.11732719e+00], - tspan = (0.0, 0.3)) - # 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_acoustics_gauss_wall.jl" begin + l2=[ + 2.19945600e-01, + 1.71050453e-01, + 1.71050453e-01, + 1.21719195e+00, + ], + linf=[ + 7.44218635e-01, + 7.02887039e-01, + 7.02887039e-01, + 6.11732719e+00, + ], + tspan=(0.0, 0.3)) + # 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_acoustics_gauss_wall.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_acoustics_gauss_wall.jl"), - l2 = [0.029330394861252995, 0.029345079728907965, 0.03803795043486467, 0.0, - 7.175152371650832e-16, 1.4350304743301665e-15, 1.4350304743301665e-15], - linf = [0.36236334472179443, 0.3690785638275256, 0.8475748723784078, 0.0, - 8.881784197001252e-16, 1.7763568394002505e-15, 1.7763568394002505e-15], - tspan = (0.0, 5.0)) - # 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_mhd_ec.jl" begin + l2=[0.029330394861252995, 0.029345079728907965, + 0.03803795043486467, 0.0, + 7.175152371650832e-16, 1.4350304743301665e-15, + 1.4350304743301665e-15], + linf=[0.36236334472179443, 0.3690785638275256, + 0.8475748723784078, 0.0, + 8.881784197001252e-16, 1.7763568394002505e-15, + 1.7763568394002505e-15], + tspan=(0.0, 5.0)) + # 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_mhd_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ec.jl"), - l2 = [0.06418293357851637, 0.12085176618704108, 0.12085099342419513, 0.07743005602933221, - 0.1622218916638482, 0.04044434425257972, 0.04044440614962498, 0.05735896706356321, - 0.0020992340041681734], - linf = [0.1417000509328017, 0.3210578460652491, 0.335041095545175, 0.22500796423572675, - 0.44230628074326406, 0.16743171716317784, 0.16745989278866702, 0.17700588224362557, - 0.02692320090677309], - tspan = (0.0, 0.5)) - # 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_mhd_alfven_wave.jl" begin + l2=[0.06418293357851637, 0.12085176618704108, + 0.12085099342419513, 0.07743005602933221, + 0.1622218916638482, 0.04044434425257972, + 0.04044440614962498, 0.05735896706356321, + 0.0020992340041681734], + linf=[0.1417000509328017, 0.3210578460652491, 0.335041095545175, + 0.22500796423572675, + 0.44230628074326406, 0.16743171716317784, + 0.16745989278866702, 0.17700588224362557, + 0.02692320090677309], + tspan=(0.0, 0.5)) + # 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_mhd_alfven_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), - l2 = [5.377518922553881e-5, 0.09999999206243514, 0.09999999206243441, 0.1414213538550799, - 8.770450430886394e-6, 0.0999999926130084, 0.0999999926130088, 0.14142135396487032, - 1.1553833987291942e-5], - linf = [0.00039334982566352483, 0.14144904937275282, 0.14144904937277897, 0.20003315928443416, - 6.826863293230012e-5, 0.14146512909995967, 0.14146512909994702, 0.20006706837452526, - 0.00013645610312810813], - tspan = (0.0, 0.5)) - # 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_ec.jl" begin + l2=[5.377518922553881e-5, 0.09999999206243514, + 0.09999999206243441, 0.1414213538550799, + 8.770450430886394e-6, 0.0999999926130084, + 0.0999999926130088, 0.14142135396487032, + 1.1553833987291942e-5], + linf=[0.00039334982566352483, 0.14144904937275282, + 0.14144904937277897, 0.20003315928443416, + 6.826863293230012e-5, 0.14146512909995967, + 0.14146512909994702, 0.20006706837452526, + 0.00013645610312810813], + tspan=(0.0, 0.5)) + # 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_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_ec.jl"), - l2 = [0.6106939484178353, 0.48586236867426724, 0.48234490854514356, 0.29467422718511727], - linf = [2.775979948281604, 3.1721242154451548, 3.5713448319601393, 2.052861364219655], - tspan = (0.0, 0.25)) - # 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 + l2=[ + 0.6106939484178353, + 0.48586236867426724, + 0.48234490854514356, + 0.29467422718511727, + ], + linf=[ + 2.775979948281604, + 3.1721242154451548, + 3.5713448319601393, + 2.052861364219655, + ], + tspan=(0.0, 0.25)) + # 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 = [1.2164292510839076, 2.6118925543469468e-12, 1.1636046671473883e-12, 1.2164292510839079], - linf = [1.5138512282315846, 4.998482888288039e-11, 2.0246214978154587e-11, 1.513851228231574], - tspan = (0.0, 0.25)) - # 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 with FluxHydrostaticReconstruction" begin + l2=[ + 1.2164292510839076, + 2.6118925543469468e-12, + 1.1636046671473883e-12, + 1.2164292510839079, + ], + linf=[ + 1.5138512282315846, + 4.998482888288039e-11, + 2.0246214978154587e-11, + 1.513851228231574, + ], + tspan=(0.0, 0.25)) + # 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 with FluxHydrostaticReconstruction" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced.jl"), - l2 = [1.2164292510839085, 1.2643106818778908e-12, 7.46884905098358e-13, 1.2164292510839079], - linf = [1.513851228231562, 1.6287765844373185e-11, 6.8766999132716964e-12, 1.513851228231574], - surface_flux=(FluxHydrostaticReconstruction(flux_lax_friedrichs, hydrostatic_reconstruction_audusse_etal), flux_nonconservative_audusse_etal), - tspan = (0.0, 0.2)) - # 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_source_terms.jl" begin + l2=[ + 1.2164292510839085, + 1.2643106818778908e-12, + 7.46884905098358e-13, + 1.2164292510839079, + ], + linf=[ + 1.513851228231562, + 1.6287765844373185e-11, + 6.8766999132716964e-12, + 1.513851228231574, + ], + surface_flux=(FluxHydrostaticReconstruction(flux_lax_friedrichs, + hydrostatic_reconstruction_audusse_etal), + flux_nonconservative_audusse_etal), + tspan=(0.0, 0.2)) + # 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_source_terms.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), - l2 = [0.0011197623982310795, 0.04456344888447023, 0.014317376629669337, 5.089218476758975e-6], - linf = [0.007835284004819698, 0.3486891284278597, 0.11242778979399048, 2.6407324614119432e-5], - tspan = (0.0, 0.025)) - # 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_source_terms.jl with FluxHydrostaticReconstruction" begin + l2=[ + 0.0011197623982310795, + 0.04456344888447023, + 0.014317376629669337, + 5.089218476758975e-6, + ], + linf=[ + 0.007835284004819698, + 0.3486891284278597, + 0.11242778979399048, + 2.6407324614119432e-5, + ], + tspan=(0.0, 0.025)) + # 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_source_terms.jl with FluxHydrostaticReconstruction" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), - l2 = [0.0011197139793938152, 0.015430259691310781, 0.017081031802719724, 5.089218476758271e-6], - linf = [0.014300809338967824, 0.12783372461225184, 0.17625472321992852, 2.6407324614341476e-5], - surface_flux=(FluxHydrostaticReconstruction(flux_hll, hydrostatic_reconstruction_audusse_etal), flux_nonconservative_audusse_etal), - tspan = (0.0, 0.025)) - # 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_source_terms.jl with flux_hll" begin + l2=[ + 0.0011197139793938152, + 0.015430259691310781, + 0.017081031802719724, + 5.089218476758271e-6, + ], + linf=[ + 0.014300809338967824, + 0.12783372461225184, + 0.17625472321992852, + 2.6407324614341476e-5, + ], + surface_flux=(FluxHydrostaticReconstruction(flux_hll, + hydrostatic_reconstruction_audusse_etal), + flux_nonconservative_audusse_etal), + tspan=(0.0, 0.025)) + # 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_source_terms.jl with flux_hll" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), - l2 = [0.0011197139793938727, 0.015430259691311309, 0.017081031802719554, 5.089218476759981e-6], - linf = [0.014300809338967824, 0.12783372461224918, 0.17625472321993918, 2.6407324614341476e-5], - surface_flux=(flux_hll, flux_nonconservative_fjordholm_etal), - tspan = (0.0, 0.025)) - # 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_dirichlet.jl" begin + l2=[ + 0.0011197139793938727, + 0.015430259691311309, + 0.017081031802719554, + 5.089218476759981e-6, + ], + linf=[ + 0.014300809338967824, + 0.12783372461224918, + 0.17625472321993918, + 2.6407324614341476e-5, + ], + surface_flux=(flux_hll, flux_nonconservative_fjordholm_etal), + tspan=(0.0, 0.025)) + # 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_dirichlet.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_dirichlet.jl"), - l2 = [1.1577518608940115e-5, 4.867189932537344e-13, 4.647273240470541e-13, 1.1577518608933468e-5], - linf = [8.394063878602864e-5, 1.1469760027632646e-10, 1.1146619484429974e-10, 8.394063879602065e-5], - tspan = (0.0, 2.0)) - # 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_wall_bc_shockcapturing.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_wall_bc_shockcapturing.jl"), - l2 = [0.04444388691670699, 0.1527771788033111, 0.1593763537203512, 6.225080476986749e-8], - linf = [0.6526506870169639, 1.980765893182952, 2.4807635459119757, 3.982097158683473e-7], - tspan = (0.0, 0.05)) - # 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_ec_shockcapturing.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_ec_shockcapturing.jl"), - l2 = [0.6124656312639043, 0.504371951785709, 0.49180896200746366, 0.29467422718511727], - linf = [2.7639232436274392, 3.3985508653311767, 3.3330308209196224, 2.052861364219655], - tspan = (0.0, 0.25)) - # 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_three_mound_dam_break.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_three_mound_dam_break.jl"), - l2 = [0.0892957892027502, 0.30648836484407915, 2.28712547616214e-15, 0.0008778654298684622], - linf = [0.850329472915091, 2.330631694956507, 5.783660020252348e-14, 0.04326237921249021], - basis = LobattoLegendreBasis(3), - tspan = (0.0, 0.25)) - # 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_twolayer_convergence.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_twolayer_convergence.jl"), - l2 = [0.0007953969898161991, 0.00882074628714633, 0.0024322572528892934, - 0.0007597425017400447, 0.004501238950166439, 0.0015784803573661104, - 6.849532064729749e-6], - linf = [0.00592559068081977, 0.08072451118697077, 0.0344854497419107, 0.005892196680485795, - 0.04262651217675306, 0.014006223513881366, 2.5829318284764646e-5], - tspan = (0.0, 0.25)) - # 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_twolayer_well_balanced.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_twolayer_well_balanced.jl"), - l2 = [4.706532184998499e-16, 1.1215950712872183e-15, 6.7822712922421565e-16, - 0.002192812926266047, 5.506855295923691e-15, 3.3105180099689275e-15, - 0.0021928129262660085], - linf = [4.468647674116255e-15, 1.3607872120431166e-14, 9.557155049520056e-15, - 0.024280130945632084, 6.68910907640583e-14, 4.7000983997100496e-14, - 0.024280130945632732], - tspan = (0.0, 0.25)) - # 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_twolayer_dam_break.jl with flux_lax_friedrichs" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_twolayer_dam_break.jl"), - l2 = [0.012471300561905669, 0.012363413819726868, 0.0009541478004413331, - 0.09120260327331643, 0.015269590815749993, 0.0012064657396853422, - 0.09991983966647647], - linf = [0.04497814714937959, 0.03286959000796511, 0.010746094385294369, - 0.11138723974511211, 0.03640850605444494, 0.014368386516056392, 0.10000000000000003], - surface_flux = (flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), - tspan = (0.0, 0.25)) - # 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 + l2=[ + 1.1577518608940115e-5, + 4.867189932537344e-13, + 4.647273240470541e-13, + 1.1577518608933468e-5, + ], + linf=[ + 8.394063878602864e-5, + 1.1469760027632646e-10, + 1.1146619484429974e-10, + 8.394063879602065e-5, + ], + tspan=(0.0, 2.0)) + # 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_wall_bc_shockcapturing.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_wall_bc_shockcapturing.jl"), + l2=[ + 0.04444388691670699, + 0.1527771788033111, + 0.1593763537203512, + 6.225080476986749e-8, + ], + linf=[ + 0.6526506870169639, + 1.980765893182952, + 2.4807635459119757, + 3.982097158683473e-7, + ], + tspan=(0.0, 0.05)) + # 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_ec_shockcapturing.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_ec_shockcapturing.jl"), + l2=[ + 0.6124656312639043, + 0.504371951785709, + 0.49180896200746366, + 0.29467422718511727, + ], + linf=[ + 2.7639232436274392, + 3.3985508653311767, + 3.3330308209196224, + 2.052861364219655, + ], + tspan=(0.0, 0.25)) + # 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_three_mound_dam_break.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_three_mound_dam_break.jl"), + l2=[ + 0.0892957892027502, + 0.30648836484407915, + 2.28712547616214e-15, + 0.0008778654298684622, + ], + linf=[ + 0.850329472915091, + 2.330631694956507, + 5.783660020252348e-14, + 0.04326237921249021, + ], + basis=LobattoLegendreBasis(3), + tspan=(0.0, 0.25)) + # 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_twolayer_convergence.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_twolayer_convergence.jl"), + l2=[0.0007953969898161991, 0.00882074628714633, + 0.0024322572528892934, + 0.0007597425017400447, 0.004501238950166439, + 0.0015784803573661104, + 6.849532064729749e-6], + linf=[0.00592559068081977, 0.08072451118697077, + 0.0344854497419107, 0.005892196680485795, + 0.04262651217675306, 0.014006223513881366, + 2.5829318284764646e-5], + tspan=(0.0, 0.25)) + # 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_twolayer_well_balanced.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_twolayer_well_balanced.jl"), + l2=[4.706532184998499e-16, 1.1215950712872183e-15, + 6.7822712922421565e-16, + 0.002192812926266047, 5.506855295923691e-15, + 3.3105180099689275e-15, + 0.0021928129262660085], + linf=[4.468647674116255e-15, 1.3607872120431166e-14, + 9.557155049520056e-15, + 0.024280130945632084, 6.68910907640583e-14, + 4.7000983997100496e-14, + 0.024280130945632732], + tspan=(0.0, 0.25)) + # 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_twolayer_dam_break.jl with flux_lax_friedrichs" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_twolayer_dam_break.jl"), + l2=[0.012471300561905669, 0.012363413819726868, + 0.0009541478004413331, + 0.09120260327331643, 0.015269590815749993, + 0.0012064657396853422, + 0.09991983966647647], + linf=[0.04497814714937959, 0.03286959000796511, + 0.010746094385294369, + 0.11138723974511211, 0.03640850605444494, + 0.014368386516056392, 0.10000000000000003], + surface_flux=(flux_lax_friedrichs, + flux_nonconservative_fjordholm_etal), + tspan=(0.0, 0.25)) + # 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 -@test_nowarn rm(outdir, recursive=true) +@test_nowarn rm(outdir, recursive = true) end # module diff --git a/test/test_visualization.jl b/test/test_visualization.jl index b700fc71a8f..48164a70fb3 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -15,33 +15,40 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" -isdir(outdir) && rm(outdir, recursive=true) +isdir(outdir) && rm(outdir, recursive = true) # Run various visualization tests @testset "Visualization tests" begin - # Run 2D tests with elixirs for all mesh types - test_examples_2d = Dict( - "TreeMesh" => ("tree_2d_dgsem", "elixir_euler_blast_wave_amr.jl"), - "StructuredMesh" => ("structured_2d_dgsem", "elixir_euler_source_terms_waving_flag.jl"), - "UnstructuredMesh" => ("unstructured_2d_dgsem", "elixir_euler_basic.jl"), - "P4estMesh" => ("p4est_2d_dgsem", "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), - "DGMulti" => ("dgmulti_2d", "elixir_euler_weakform.jl"), - ) - - @testset "PlotData2D, PlotDataSeries, PlotMesh with $mesh" for mesh in keys(test_examples_2d) +#! format: noindent + +# Run 2D tests with elixirs for all mesh types +test_examples_2d = Dict("TreeMesh" => ("tree_2d_dgsem", + "elixir_euler_blast_wave_amr.jl"), + "StructuredMesh" => ("structured_2d_dgsem", + "elixir_euler_source_terms_waving_flag.jl"), + "UnstructuredMesh" => ("unstructured_2d_dgsem", + "elixir_euler_basic.jl"), + "P4estMesh" => ("p4est_2d_dgsem", + "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), + "DGMulti" => ("dgmulti_2d", "elixir_euler_weakform.jl")) + +@testset "PlotData2D, PlotDataSeries, PlotMesh with $mesh" for mesh in keys(test_examples_2d) # Run Trixi.jl directory, elixir = test_examples_2d[mesh] - @test_nowarn_mod trixi_include(@__MODULE__, joinpath(examples_dir(), directory, elixir), - tspan=(0,0.1)) + @test_nowarn_mod trixi_include(@__MODULE__, + joinpath(examples_dir(), directory, elixir), + tspan = (0, 0.1)) # Constructor tests if mesh == "TreeMesh" - @test PlotData2D(sol) isa Trixi.PlotData2DCartesian - @test PlotData2D(sol; nvisnodes=0, grid_lines=false, solution_variables=cons2cons) isa Trixi.PlotData2DCartesian - @test Trixi.PlotData2DTriangulated(sol) isa Trixi.PlotData2DTriangulated + @test PlotData2D(sol) isa Trixi.PlotData2DCartesian + @test PlotData2D(sol; nvisnodes = 0, grid_lines = false, + solution_variables = cons2cons) isa Trixi.PlotData2DCartesian + @test Trixi.PlotData2DTriangulated(sol) isa Trixi.PlotData2DTriangulated else - @test PlotData2D(sol) isa Trixi.PlotData2DTriangulated - @test PlotData2D(sol; nvisnodes=0, solution_variables=cons2cons) isa Trixi.PlotData2DTriangulated + @test PlotData2D(sol) isa Trixi.PlotData2DTriangulated + @test PlotData2D(sol; nvisnodes = 0, solution_variables = cons2cons) isa + Trixi.PlotData2DTriangulated end pd = PlotData2D(sol) @@ -64,9 +71,9 @@ isdir(outdir) && rm(outdir, recursive=true) @test keys(pd) == ("rho", "v1", "v2", "p") @test eltype(pd) <: Pair{String, <:Trixi.PlotDataSeries} @test [v for v in pd] == ["rho" => Trixi.PlotDataSeries(pd, 1), - "v1" => Trixi.PlotDataSeries(pd, 2), - "v2" => Trixi.PlotDataSeries(pd, 3), - "p" => Trixi.PlotDataSeries(pd, 4)] + "v1" => Trixi.PlotDataSeries(pd, 2), + "v2" => Trixi.PlotDataSeries(pd, 3), + "p" => Trixi.PlotDataSeries(pd, 4)] # PlotDataSeries pds = pd["p"] @@ -82,48 +89,52 @@ isdir(outdir) && rm(outdir, recursive=true) println(stdout) @testset "2D plot recipes" begin - pd = PlotData2D(sol) - - @test_nowarn_mod Plots.plot(sol) - @test_nowarn_mod Plots.plot(pd) - @test_nowarn_mod Plots.plot(pd["p"]) - @test_nowarn_mod Plots.plot(getmesh(pd)) - - semi = sol.prob.p - if mesh == "DGMulti" - scalar_data = StructArrays.component(sol.u[end], 1) - @test_nowarn_mod Plots.plot(ScalarPlotData2D(scalar_data, semi)) - else - cache = semi.cache - x = view(cache.elements.node_coordinates, 1, :, :, :) - @test_nowarn_mod Plots.plot(ScalarPlotData2D(x, semi)) - end + pd = PlotData2D(sol) + + @test_nowarn_mod Plots.plot(sol) + @test_nowarn_mod Plots.plot(pd) + @test_nowarn_mod Plots.plot(pd["p"]) + @test_nowarn_mod Plots.plot(getmesh(pd)) + + semi = sol.prob.p + if mesh == "DGMulti" + scalar_data = StructArrays.component(sol.u[end], 1) + @test_nowarn_mod Plots.plot(ScalarPlotData2D(scalar_data, semi)) + else + cache = semi.cache + x = view(cache.elements.node_coordinates, 1, :, :, :) + @test_nowarn_mod Plots.plot(ScalarPlotData2D(x, semi)) + end end @testset "1D plot from 2D solution" begin - if mesh != "DGMulti" - @testset "Create 1D plot as slice" begin - @test_nowarn_mod PlotData1D(sol, slice=:y, point=(0.5, 0.0)) isa PlotData1D - @test_nowarn_mod PlotData1D(sol, slice=:x, point=(0.5, 0.0)) isa PlotData1D - pd1D = PlotData1D(sol, slice=:y, point=(0.5, 0.0)) - @test_nowarn_mod Plots.plot(pd1D) - - @testset "Create 1D plot along curve" begin - curve = zeros(2, 10) - curve[1, :] = range(-1, 1,length=10) - @test_nowarn_mod PlotData1D(sol, curve=curve) isa PlotData1D - pd1D = PlotData1D(sol, curve=curve) - @test_nowarn_mod Plots.plot(pd1D) - end + if mesh != "DGMulti" + @testset "Create 1D plot as slice" begin + @test_nowarn_mod PlotData1D(sol, slice = :y, point = (0.5, 0.0)) isa + PlotData1D + @test_nowarn_mod PlotData1D(sol, slice = :x, point = (0.5, 0.0)) isa + PlotData1D + pd1D = PlotData1D(sol, slice = :y, point = (0.5, 0.0)) + @test_nowarn_mod Plots.plot(pd1D) + + @testset "Create 1D plot along curve" begin + curve = zeros(2, 10) + curve[1, :] = range(-1, 1, length = 10) + @test_nowarn_mod PlotData1D(sol, curve = curve) isa PlotData1D + pd1D = PlotData1D(sol, curve = curve) + @test_nowarn_mod Plots.plot(pd1D) + end + end end - end end - end +end - @timed_testset "PlotData1D, PlotDataSeries, PlotMesh" begin +@timed_testset "PlotData1D, PlotDataSeries, PlotMesh" begin # Run Trixi.jl - @test_nowarn_mod trixi_include(@__MODULE__, joinpath(examples_dir(), "tree_1d_dgsem", "elixir_euler_blast_wave.jl"), - tspan=(0,0.1)) + @test_nowarn_mod trixi_include(@__MODULE__, + joinpath(examples_dir(), "tree_1d_dgsem", + "elixir_euler_blast_wave.jl"), + tspan = (0, 0.1)) # Constructor @test PlotData1D(sol) isa PlotData1D @@ -147,8 +158,8 @@ isdir(outdir) && rm(outdir, recursive=true) @test keys(pd) == ("rho", "v1", "p") @test eltype(pd) <: Pair{String, <:Trixi.PlotDataSeries} @test [v for v in pd] == ["rho" => Trixi.PlotDataSeries(pd, 1), - "v1" => Trixi.PlotDataSeries(pd, 2), - "p" => Trixi.PlotDataSeries(pd, 3)] + "v1" => Trixi.PlotDataSeries(pd, 2), + "p" => Trixi.PlotDataSeries(pd, 3)] # PlotDataSeries pds = pd["p"] @@ -165,174 +176,195 @@ isdir(outdir) && rm(outdir, recursive=true) # nvisnodes @test size(pd.data) == (512, 3) - pd0 = PlotData1D(sol, nvisnodes=0) + pd0 = PlotData1D(sol, nvisnodes = 0) @test size(pd0.data) == (256, 3) - pd2 = PlotData1D(sol, nvisnodes=2) + pd2 = PlotData1D(sol, nvisnodes = 2) @test size(pd2.data) == (128, 3) @testset "1D plot recipes" begin - pd = PlotData1D(sol) + pd = PlotData1D(sol) - @test_nowarn_mod Plots.plot(sol) - @test_nowarn_mod Plots.plot(pd) - @test_nowarn_mod Plots.plot(pd["p"]) - @test_nowarn_mod Plots.plot(getmesh(pd)) + @test_nowarn_mod Plots.plot(sol) + @test_nowarn_mod Plots.plot(pd) + @test_nowarn_mod Plots.plot(pd["p"]) + @test_nowarn_mod Plots.plot(getmesh(pd)) end # Fake a PlotDataXD objects to test code for plotting multiple variables on at least two rows # with at least one plot remaining empty @testset "plotting multiple variables" begin - x = collect(0.0:0.1:1.0) - data1d = rand(5, 11) - variable_names = string.('a':'e') - mesh_vertices_x1d = [x[begin], x[end]] - fake1d = PlotData1D(x, data1d, variable_names, mesh_vertices_x1d, 0) - @test_nowarn_mod Plots.plot(fake1d) - - y = x - data2d = [rand(11,11) for _ in 1:5] - mesh_vertices_x2d = [0.0, 1.0, 1.0, 0.0] - mesh_vertices_y2d = [0.0, 0.0, 1.0, 1.0] - fake2d = Trixi.PlotData2DCartesian(x, y, data2d, variable_names, mesh_vertices_x2d, mesh_vertices_y2d, 0, 0) - @test_nowarn_mod Plots.plot(fake2d) + x = collect(0.0:0.1:1.0) + data1d = rand(5, 11) + variable_names = string.('a':'e') + mesh_vertices_x1d = [x[begin], x[end]] + fake1d = PlotData1D(x, data1d, variable_names, mesh_vertices_x1d, 0) + @test_nowarn_mod Plots.plot(fake1d) + + y = x + data2d = [rand(11, 11) for _ in 1:5] + mesh_vertices_x2d = [0.0, 1.0, 1.0, 0.0] + mesh_vertices_y2d = [0.0, 0.0, 1.0, 1.0] + fake2d = Trixi.PlotData2DCartesian(x, y, data2d, variable_names, + mesh_vertices_x2d, mesh_vertices_y2d, 0, 0) + @test_nowarn_mod Plots.plot(fake2d) end - end +end - @timed_testset "PlotData1D (DGMulti)" begin +@timed_testset "PlotData1D (DGMulti)" begin # Test two different approximation types since these use different memory layouts: # - structure of arrays for `Polynomial()` # - array of structures for `SBP()` @test_nowarn_mod trixi_include(@__MODULE__, - joinpath(examples_dir(), "dgmulti_1d", "elixir_euler_flux_diff.jl"), tspan=(0.0 ,0.0), - approximation_type=Polynomial()) + joinpath(examples_dir(), "dgmulti_1d", + "elixir_euler_flux_diff.jl"), + tspan = (0.0, 0.0), + approximation_type = Polynomial()) @test PlotData1D(sol) isa PlotData1D @test_nowarn_mod trixi_include(@__MODULE__, - joinpath(examples_dir(), "dgmulti_1d", "elixir_euler_flux_diff.jl"), tspan=(0.0 ,0.0), - approximation_type=SBP()) + joinpath(examples_dir(), "dgmulti_1d", + "elixir_euler_flux_diff.jl"), + tspan = (0.0, 0.0), + approximation_type = SBP()) @test PlotData1D(sol) isa PlotData1D - end +end - @timed_testset "plot time series" begin +@timed_testset "plot time series" begin @test_nowarn_mod trixi_include(@__MODULE__, - joinpath(examples_dir(), "tree_2d_dgsem", "elixir_acoustics_gaussian_source.jl"), - tspan=(0, 0.05)) + joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_acoustics_gaussian_source.jl"), + tspan = (0, 0.05)) @test_nowarn_mod Plots.plot(time_series, 1) @test PlotData1D(time_series, 1) isa PlotData1D - end +end - @timed_testset "adapt_to_mesh_level" begin - @test_nowarn_mod trixi_include(@__MODULE__, joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_basic.jl"), - tspan=(0,0.1), analysis_callback=Trixi.TrivialCallback()) +@timed_testset "adapt_to_mesh_level" begin + @test_nowarn_mod trixi_include(@__MODULE__, + joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_advection_basic.jl"), + tspan = (0, 0.1), + analysis_callback = Trixi.TrivialCallback()) @test adapt_to_mesh_level(sol, 5) isa Tuple u_ode_level5, semi_level5 = adapt_to_mesh_level(sol, 5) u_ode_level4, semi_level4 = adapt_to_mesh_level(u_ode_level5, semi_level5, 4) - @test isapprox(sol.u[end], u_ode_level4, atol=1e-13) + @test isapprox(sol.u[end], u_ode_level4, atol = 1e-13) @test adapt_to_mesh_level!(sol, 5) isa Tuple - @test isapprox(sol.u[end], u_ode_level5, atol=1e-13) - end + @test isapprox(sol.u[end], u_ode_level5, atol = 1e-13) +end - @timed_testset "plot 3D" begin - @test_nowarn_mod trixi_include(@__MODULE__, joinpath(examples_dir(), "tree_3d_dgsem", "elixir_advection_basic.jl"), - tspan=(0,0.1), analysis_callback=Trixi.TrivialCallback(), initial_refinement_level=1) +@timed_testset "plot 3D" begin + @test_nowarn_mod trixi_include(@__MODULE__, + joinpath(examples_dir(), "tree_3d_dgsem", + "elixir_advection_basic.jl"), + tspan = (0, 0.1), + analysis_callback = Trixi.TrivialCallback(), + initial_refinement_level = 1) @test PlotData2D(sol) isa Trixi.PlotData2DCartesian - @test PlotData2D(sol, slice =:yz) isa Trixi.PlotData2DCartesian - @test PlotData2D(sol, slice =:xz) isa Trixi.PlotData2DCartesian + @test PlotData2D(sol, slice = :yz) isa Trixi.PlotData2DCartesian + @test PlotData2D(sol, slice = :xz) isa Trixi.PlotData2DCartesian @testset "1D plot from 3D solution and Tree-mesh" begin - @testset "Create 1D plot as slice" begin - @test_nowarn_mod PlotData1D(sol) isa PlotData1D - pd1D = PlotData1D(sol) - @test_nowarn_mod Plots.plot(pd1D) - @test_nowarn_mod PlotData1D(sol, slice=:y, point = (0.5, 0.3, 0.1)) isa PlotData1D - @test_nowarn_mod PlotData1D(sol, slice=:z, point = (0.1, 0.3, 0.3)) isa PlotData1D - - end - - @testset "Create 1D plot along curve" begin - curve = zeros(3, 10) - curve[1, :] = range(-1.0, -0.5, length=10) - @test_nowarn_mod PlotData1D(sol, curve=curve) isa PlotData1D - pd1D = PlotData1D(sol, curve=curve) - @test_nowarn_mod Plots.plot(pd1D) - end + @testset "Create 1D plot as slice" begin + @test_nowarn_mod PlotData1D(sol) isa PlotData1D + pd1D = PlotData1D(sol) + @test_nowarn_mod Plots.plot(pd1D) + @test_nowarn_mod PlotData1D(sol, slice = :y, point = (0.5, 0.3, 0.1)) isa + PlotData1D + @test_nowarn_mod PlotData1D(sol, slice = :z, point = (0.1, 0.3, 0.3)) isa + PlotData1D + end + + @testset "Create 1D plot along curve" begin + curve = zeros(3, 10) + curve[1, :] = range(-1.0, -0.5, length = 10) + @test_nowarn_mod PlotData1D(sol, curve = curve) isa PlotData1D + pd1D = PlotData1D(sol, curve = curve) + @test_nowarn_mod Plots.plot(pd1D) + end end - @test_nowarn_mod trixi_include(@__MODULE__, joinpath(examples_dir(), "structured_3d_dgsem", "elixir_advection_basic.jl"), - tspan=(0,0.1)) + @test_nowarn_mod trixi_include(@__MODULE__, + joinpath(examples_dir(), "structured_3d_dgsem", + "elixir_advection_basic.jl"), + tspan = (0, 0.1)) @testset "1D plot from 3D solution and general mesh" begin - @testset "Create 1D plot as slice" begin - @test_nowarn_mod PlotData1D(sol) isa PlotData1D - pd1D = PlotData1D(sol) - @test_nowarn_mod Plots.plot(pd1D) - @test_nowarn_mod PlotData1D(sol, slice=:y, point = (0.5, 0.3, 0.1)) isa PlotData1D - @test_nowarn_mod PlotData1D(sol, slice=:z, point = (0.1, 0.3, 0.3)) isa PlotData1D - - end - - @testset "Create 1D plot along curve" begin - curve = zeros(3, 10) - curve[1, :] = range(-1.0, 1.0, length=10) - @test_nowarn_mod PlotData1D(sol, curve=curve) isa PlotData1D - pd1D = PlotData1D(sol, curve=curve) - @test_nowarn_mod Plots.plot(pd1D) - end + @testset "Create 1D plot as slice" begin + @test_nowarn_mod PlotData1D(sol) isa PlotData1D + pd1D = PlotData1D(sol) + @test_nowarn_mod Plots.plot(pd1D) + @test_nowarn_mod PlotData1D(sol, slice = :y, point = (0.5, 0.3, 0.1)) isa + PlotData1D + @test_nowarn_mod PlotData1D(sol, slice = :z, point = (0.1, 0.3, 0.3)) isa + PlotData1D + end + + @testset "Create 1D plot along curve" begin + curve = zeros(3, 10) + curve[1, :] = range(-1.0, 1.0, length = 10) + @test_nowarn_mod PlotData1D(sol, curve = curve) isa PlotData1D + pd1D = PlotData1D(sol, curve = curve) + @test_nowarn_mod Plots.plot(pd1D) + end end - end +end - @timed_testset "plotting TimeIntegratorSolution" begin - @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_hypdiff_lax_friedrichs.jl"), +@timed_testset "plotting TimeIntegratorSolution" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_hypdiff_lax_friedrichs.jl"), maxiters=1, analysis_callback=Trixi.TrivialCallback(), initial_refinement_level=1) @test_nowarn_mod Plots.plot(sol) - end +end - @timed_testset "VisualizationCallback" begin +@timed_testset "VisualizationCallback" begin # To make CI tests work, disable showing a plot window with the GR backend of the Plots package # Xref: https://github.com/jheinen/GR.jl/issues/278 # Xref: https://github.com/JuliaPlots/Plots.jl/blob/8cc6d9d48755ba452a2835f9b89d3880e9945377/test/runtests.jl#L103 if !isinteractive() - restore = get(ENV, "GKSwstype", nothing) - ENV["GKSwstype"] = "100" + restore = get(ENV, "GKSwstype", nothing) + ENV["GKSwstype"] = "100" end @test_nowarn_mod trixi_include(@__MODULE__, - joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_amr_visualization.jl"), - visualization = VisualizationCallback(interval=20, - clims=(0,1), - plot_creator=Trixi.save_plot), - tspan=(0.0, 3.0)) + joinpath(examples_dir(), "tree_2d_dgsem", + "elixir_advection_amr_visualization.jl"), + visualization = VisualizationCallback(interval = 20, + clims = (0, 1), + plot_creator = Trixi.save_plot), + tspan = (0.0, 3.0)) @testset "elixir_advection_amr_visualization.jl with save_plot" begin - @test isfile(joinpath(outdir, "solution_000000.png")) - @test isfile(joinpath(outdir, "solution_000020.png")) - @test isfile(joinpath(outdir, "solution_000022.png")) + @test isfile(joinpath(outdir, "solution_000000.png")) + @test isfile(joinpath(outdir, "solution_000020.png")) + @test isfile(joinpath(outdir, "solution_000022.png")) end @testset "show" begin - @test_nowarn_mod show(stdout, visualization) - println(stdout) + @test_nowarn_mod show(stdout, visualization) + println(stdout) - @test_nowarn_mod show(stdout, "text/plain", visualization) - println(stdout) + @test_nowarn_mod show(stdout, "text/plain", visualization) + println(stdout) end # Restore GKSwstype to previous value (if it was set) if !isinteractive() - if isnothing(restore) - delete!(ENV, "GKSwstype") - else - ENV["GKSwstype"] = restore - end + if isnothing(restore) + delete!(ENV, "GKSwstype") + else + ENV["GKSwstype"] = restore + end end - end +end - @timed_testset "Makie visualization tests for UnstructuredMesh2D" begin - @test_nowarn_mod trixi_include(@__MODULE__, joinpath(examples_dir(), "unstructured_2d_dgsem", "elixir_euler_wall_bc.jl")) +@timed_testset "Makie visualization tests for UnstructuredMesh2D" begin + @test_nowarn_mod trixi_include(@__MODULE__, + joinpath(examples_dir(), "unstructured_2d_dgsem", + "elixir_euler_wall_bc.jl")) # test interactive surface plot @test_nowarn_mod Trixi.iplot(sol) @@ -343,12 +375,12 @@ isdir(outdir) && rm(outdir, recursive=true) # test interactive ScalarPlotData2D plotting semi = sol.prob.p - x = view(semi.cache.elements.node_coordinates, 1, :, :, :); # extracts the node x coordinates - y = view(semi.cache.elements.node_coordinates, 2, :, :, :); # extracts the node x coordinates - @test_nowarn_mod iplot(ScalarPlotData2D(x.+y, semi), plot_mesh=true) + x = view(semi.cache.elements.node_coordinates, 1, :, :, :) # extracts the node x coordinates + y = view(semi.cache.elements.node_coordinates, 2, :, :, :) # extracts the node x coordinates + @test_nowarn_mod iplot(ScalarPlotData2D(x .+ y, semi), plot_mesh = true) # test heatmap plot - @test_nowarn_mod Makie.plot(sol, plot_mesh=true) + @test_nowarn_mod Makie.plot(sol, plot_mesh = true) # test unpacking/iteration for FigureAndAxes fa = Makie.plot(sol) @@ -360,11 +392,10 @@ isdir(outdir) && rm(outdir, recursive=true) # test plotting of constant solutions with Makie # related issue: https://github.com/MakieOrg/Makie.jl/issues/931 for i in eachindex(sol.u) - fill!(sol.u[i], one(eltype(sol.u[i]))) + fill!(sol.u[i], one(eltype(sol.u[i]))) end @test_nowarn_mod Trixi.iplot(sol) - end end - +end end #module From 61c33b0af6a7a49ed11258e8f230b471b05c6ed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 31 Oct 2023 09:14:11 +0100 Subject: [PATCH 146/263] Implement subcell limiting for non-conservative systems (#1670) Co-authored-by: Hendrik Ranocha Co-authored-by: Benjamin Bolm <74359358+bennibolm@users.noreply.github.com> Co-authored-by: Michael Schlottke-Lakemper --- .../elixir_mhd_shockcapturing_subcell.jl | 108 ++++++ src/Trixi.jl | 2 +- .../subcell_limiter_idp_correction_2d.jl | 10 +- src/equations/equations.jl | 26 ++ src/equations/ideal_glm_mhd_2d.jl | 190 ++++++++++ src/solvers/dgsem_tree/containers_2d.jl | 84 +++-- .../dgsem_tree/dg_2d_subcell_limiters.jl | 343 ++++++++++++++++-- src/solvers/dgsem_tree/subcell_limiters_2d.jl | 10 +- src/time_integration/methods_SSP.jl | 5 + test/test_tree_2d_mhd.jl | 31 ++ 10 files changed, 733 insertions(+), 76 deletions(-) create mode 100644 examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl diff --git a/examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl b/examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl new file mode 100644 index 00000000000..f40da6676c2 --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl @@ -0,0 +1,108 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible ideal GLM-MHD equations + +equations = IdealGlmMhdEquations2D(1.4) + +""" + initial_condition_blast_wave(x, t, equations::IdealGlmMhdEquations2D) + +An MHD blast wave modified from: +- Dominik Derigs, Gregor J. Gassner, Stefanie Walch & Andrew R. Winters (2018) + Entropy Stable Finite Volume Approximations for Ideal Magnetohydrodynamics + [doi: 10.1365/s13291-018-0178-9](https://doi.org/10.1365/s13291-018-0178-9) +This setup needs a positivity limiter for the density. +""" +function initial_condition_blast_wave(x, t, equations::IdealGlmMhdEquations2D) + # setup taken from Derigs et al. DMV article (2018) + # domain must be [-0.5, 0.5] x [-0.5, 0.5], γ = 1.4 + r = sqrt(x[1]^2 + x[2]^2) + + pmax = 10.0 + pmin = 1.0 + rhomax = 1.0 + rhomin = 0.01 + if r <= 0.09 + p = pmax + rho = rhomax + elseif r >= 0.1 + p = pmin + rho = rhomin + else + p = pmin + (0.1 - r) * (pmax - pmin) / 0.01 + rho = rhomin + (0.1 - r) * (rhomax - rhomin) / 0.01 + end + v1 = 0.0 + v2 = 0.0 + v3 = 0.0 + B1 = 1.0/sqrt(4.0*pi) + B2 = 0.0 + B3 = 0.0 + psi = 0.0 + return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3, psi), equations) +end +initial_condition = initial_condition_blast_wave + +surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell_local_symmetric) +volume_flux = (flux_derigs_etal, flux_nonconservative_powell_local_symmetric) +basis = LobattoLegendreBasis(3) + +limiter_idp = SubcellLimiterIDP(equations, basis; + positivity_variables_cons=[1], + positivity_correction_factor=0.5) +volume_integral = VolumeIntegralSubcellLimiting(limiter_idp; + volume_flux_dg=volume_flux, + volume_flux_fv=surface_flux) +solver = DGSEM(basis, surface_flux, volume_integral) + +coordinates_min = (-0.5, -0.5) +coordinates_max = ( 0.5, 0.5) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + n_cells_max=10_000) + + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.1) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) + +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +save_solution = SaveSolutionCallback(interval=100, + save_initial_solution=true, + save_final_solution=true, + solution_variables=cons2prim) + +cfl = 0.5 +stepsize_callback = StepsizeCallback(cfl=cfl) + +glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback, + glm_speed_callback) + +############################################################################### +# run the simulation +stage_callbacks = (SubcellLimiterIDPCorrection(), BoundsCheckCallback()) + +sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks=stage_callbacks); + 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/src/Trixi.jl b/src/Trixi.jl index 5cb3cf0a9fe..97d518d5b78 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -162,7 +162,7 @@ export GradientVariablesPrimitive, GradientVariablesEntropy export flux, flux_central, flux_lax_friedrichs, flux_hll, flux_hllc, flux_hlle, flux_godunov, flux_chandrashekar, flux_ranocha, flux_derigs_etal, flux_hindenlang_gassner, - flux_nonconservative_powell, + flux_nonconservative_powell, flux_nonconservative_powell_local_symmetric, flux_kennedy_gruber, flux_shima_etal, flux_ec, flux_fjordholm_etal, flux_nonconservative_fjordholm_etal, flux_es_fjordholm_etal, flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal, diff --git a/src/callbacks_stage/subcell_limiter_idp_correction_2d.jl b/src/callbacks_stage/subcell_limiter_idp_correction_2d.jl index f6b91444578..6f1723e2a98 100644 --- a/src/callbacks_stage/subcell_limiter_idp_correction_2d.jl +++ b/src/callbacks_stage/subcell_limiter_idp_correction_2d.jl @@ -7,7 +7,7 @@ function perform_idp_correction!(u, dt, mesh::TreeMesh2D, equations, dg, cache) @unpack inverse_weights = dg.basis - @unpack antidiffusive_flux1, antidiffusive_flux2 = cache.antidiffusive_fluxes + @unpack antidiffusive_flux1_L, antidiffusive_flux2_L, antidiffusive_flux1_R, antidiffusive_flux2_R = cache.antidiffusive_fluxes @unpack alpha1, alpha2 = dg.volume_integral.limiter.cache.subcell_limiter_coefficients @threaded for element in eachelement(dg, cache) @@ -17,16 +17,16 @@ function perform_idp_correction!(u, dt, mesh::TreeMesh2D, equations, dg, cache) for j in eachnode(dg), i in eachnode(dg) # Note: antidiffusive_flux1[v, i, xi, element] = antidiffusive_flux2[v, xi, i, element] = 0 for all i in 1:nnodes and xi in {1, nnodes+1} alpha_flux1 = (1 - alpha1[i, j, element]) * - get_node_vars(antidiffusive_flux1, equations, dg, i, j, + get_node_vars(antidiffusive_flux1_R, equations, dg, i, j, element) alpha_flux1_ip1 = (1 - alpha1[i + 1, j, element]) * - get_node_vars(antidiffusive_flux1, equations, dg, i + 1, + get_node_vars(antidiffusive_flux1_L, equations, dg, i + 1, j, element) alpha_flux2 = (1 - alpha2[i, j, element]) * - get_node_vars(antidiffusive_flux2, equations, dg, i, j, + get_node_vars(antidiffusive_flux2_R, equations, dg, i, j, element) alpha_flux2_jp1 = (1 - alpha2[i, j + 1, element]) * - get_node_vars(antidiffusive_flux2, equations, dg, i, + get_node_vars(antidiffusive_flux2_L, equations, dg, i, j + 1, element) for v in eachvariable(equations) diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 3142dcc2765..0e77b92e045 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -208,6 +208,24 @@ struct BoundaryConditionNeumann{B} boundary_normal_flux_function::B end +""" + NonConservativeLocal() + +Struct used for multiple dispatch on non-conservative flux functions in the format of "local * symmetric". +When the argument `nonconservative_type` is of type `NonConservativeLocal`, +the function returns the local part of the non-conservative term. +""" +struct NonConservativeLocal end + +""" + NonConservativeSymmetric() + +Struct used for multiple dispatch on non-conservative flux functions in the format of "local * symmetric". +When the argument `nonconservative_type` is of type `NonConservativeSymmetric`, +the function returns the symmetric part of the non-conservative term. +""" +struct NonConservativeSymmetric end + # set sensible default values that may be overwritten by specific equations """ have_nonconservative_terms(equations) @@ -220,6 +238,14 @@ example of equations with nonconservative terms. The return value will be `True()` or `False()` to allow dispatching on the return type. """ have_nonconservative_terms(::AbstractEquations) = False() +""" + n_nonconservative_terms(equations) + +Number of nonconservative terms in the form local * symmetric for a particular equation. +This function needs to be specialized only if equations with nonconservative terms are +combined with certain solvers (e.g., subcell limiting). +""" +function n_nonconservative_terms end have_constant_speed(::AbstractEquations) = False() default_analysis_errors(::AbstractEquations) = (:l2_error, :linf_error) diff --git a/src/equations/ideal_glm_mhd_2d.jl b/src/equations/ideal_glm_mhd_2d.jl index 8fef1ee22c9..e8de0cedde1 100644 --- a/src/equations/ideal_glm_mhd_2d.jl +++ b/src/equations/ideal_glm_mhd_2d.jl @@ -29,6 +29,8 @@ function IdealGlmMhdEquations2D(gamma; initial_c_h = convert(typeof(gamma), NaN) end have_nonconservative_terms(::IdealGlmMhdEquations2D) = True() +n_nonconservative_terms(::IdealGlmMhdEquations2D) = 2 + function varnames(::typeof(cons2cons), ::IdealGlmMhdEquations2D) ("rho", "rho_v1", "rho_v2", "rho_v3", "rho_e", "B1", "B2", "B3", "psi") end @@ -279,6 +281,194 @@ end return f end +""" + flux_nonconservative_powell_local_symmetric(u_ll, u_rr, + orientation::Integer, + equations::IdealGlmMhdEquations2D) + +Non-symmetric two-point flux discretizing the nonconservative (source) term of +Powell and the Galilean nonconservative term associated with the GLM multiplier +of the [`IdealGlmMhdEquations2D`](@ref). + +This implementation uses a non-conservative term that can be written as the product +of local and symmetric parts. It is equivalent to the non-conservative flux of Bohm +et al. (`flux_nonconservative_powell`) for conforming meshes but it yields different +results on non-conforming meshes(!). + +The two other flux functions with the same name return either the local +or symmetric portion of the non-conservative flux based on the type of the +nonconservative_type argument, employing multiple dispatch. They are used to +compute the subcell fluxes in dg_2d_subcell_limiters.jl. + +## References +- Rueda-Ramírez, Gassner (2023). A Flux-Differencing Formula for Split-Form Summation By Parts + Discretizations of Non-Conservative Systems. https://arxiv.org/pdf/2211.14009.pdf. +""" +@inline function flux_nonconservative_powell_local_symmetric(u_ll, u_rr, + orientation::Integer, + equations::IdealGlmMhdEquations2D) + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll, B1_ll, B2_ll, B3_ll, psi_ll = u_ll + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr, B1_rr, B2_rr, B3_rr, psi_rr = u_rr + + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + v_dot_B_ll = v1_ll * B1_ll + v2_ll * B2_ll + v3_ll * B3_ll + + # Powell nonconservative term: (0, B_1, B_2, B_3, v⋅B, v_1, v_2, v_3, 0) + # Galilean nonconservative term: (0, 0, 0, 0, ψ v_{1,2}, 0, 0, 0, v_{1,2}) + psi_avg = (psi_ll + psi_rr) #* 0.5 # The flux is already multiplied by 0.5 wherever it is used in the code + if orientation == 1 + B1_avg = (B1_ll + B1_rr) #* 0.5 # The flux is already multiplied by 0.5 wherever it is used in the code + f = SVector(0, + B1_ll * B1_avg, + B2_ll * B1_avg, + B3_ll * B1_avg, + v_dot_B_ll * B1_avg + v1_ll * psi_ll * psi_avg, + v1_ll * B1_avg, + v2_ll * B1_avg, + v3_ll * B1_avg, + v1_ll * psi_avg) + else # orientation == 2 + B2_avg = (B2_ll + B2_rr) #* 0.5 # The flux is already multiplied by 0.5 wherever it is used in the code + f = SVector(0, + B1_ll * B2_avg, + B2_ll * B2_avg, + B3_ll * B2_avg, + v_dot_B_ll * B2_avg + v2_ll * psi_ll * psi_avg, + v1_ll * B2_avg, + v2_ll * B2_avg, + v3_ll * B2_avg, + v2_ll * psi_avg) + end + + return f +end + +""" + flux_nonconservative_powell_local_symmetric(u_ll, orientation::Integer, + equations::IdealGlmMhdEquations2D, + nonconservative_type::NonConservativeLocal, + nonconservative_term::Integer) + +Local part of the Powell and GLM non-conservative terms. Needed for the calculation of +the non-conservative staggered "fluxes" for subcell limiting. See, e.g., +- Rueda-Ramírez, Gassner (2023). A Flux-Differencing Formula for Split-Form Summation By Parts + Discretizations of Non-Conservative Systems. https://arxiv.org/pdf/2211.14009.pdf. +This function is used to compute the subcell fluxes in dg_2d_subcell_limiters.jl. +""" +@inline function flux_nonconservative_powell_local_symmetric(u_ll, orientation::Integer, + equations::IdealGlmMhdEquations2D, + nonconservative_type::NonConservativeLocal, + nonconservative_term::Integer) + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll, B1_ll, B2_ll, B3_ll, psi_ll = u_ll + + if nonconservative_term == 1 + # Powell nonconservative term: (0, B_1, B_2, B_3, v⋅B, v_1, v_2, v_3, 0) + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + v_dot_B_ll = v1_ll * B1_ll + v2_ll * B2_ll + v3_ll * B3_ll + f = SVector(0, + B1_ll, + B2_ll, + B3_ll, + v_dot_B_ll, + v1_ll, + v2_ll, + v3_ll, + 0) + else #nonconservative_term ==2 + # Galilean nonconservative term: (0, 0, 0, 0, ψ v_{1,2}, 0, 0, 0, v_{1,2}) + if orientation == 1 + v1_ll = rho_v1_ll / rho_ll + f = SVector(0, + 0, + 0, + 0, + v1_ll * psi_ll, + 0, + 0, + 0, + v1_ll) + else #orientation == 2 + v2_ll = rho_v2_ll / rho_ll + f = SVector(0, + 0, + 0, + 0, + v2_ll * psi_ll, + 0, + 0, + 0, + v2_ll) + end + end + return f +end + +""" + flux_nonconservative_powell_local_symmetric(u_ll, orientation::Integer, + equations::IdealGlmMhdEquations2D, + nonconservative_type::NonConservativeSymmetric, + nonconservative_term::Integer) + +Symmetric part of the Powell and GLM non-conservative terms. Needed for the calculation of +the non-conservative staggered "fluxes" for subcell limiting. See, e.g., +- Rueda-Ramírez, Gassner (2023). A Flux-Differencing Formula for Split-Form Summation By Parts + Discretizations of Non-Conservative Systems. https://arxiv.org/pdf/2211.14009.pdf. +This function is used to compute the subcell fluxes in dg_2d_subcell_limiters.jl. +""" +@inline function flux_nonconservative_powell_local_symmetric(u_ll, u_rr, + orientation::Integer, + equations::IdealGlmMhdEquations2D, + nonconservative_type::NonConservativeSymmetric, + nonconservative_term::Integer) + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll, B1_ll, B2_ll, B3_ll, psi_ll = u_ll + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr, B1_rr, B2_rr, B3_rr, psi_rr = u_rr + + if nonconservative_term == 1 + # Powell nonconservative term: (0, B_1, B_2, B_3, v⋅B, v_1, v_2, v_3, 0) + if orientation == 1 + B1_avg = (B1_ll + B1_rr)#* 0.5 # The flux is already multiplied by 0.5 wherever it is used in the code + f = SVector(0, + B1_avg, + B1_avg, + B1_avg, + B1_avg, + B1_avg, + B1_avg, + B1_avg, + 0) + else # orientation == 2 + B2_avg = (B2_ll + B2_rr)#* 0.5 # The flux is already multiplied by 0.5 wherever it is used in the code + f = SVector(0, + B2_avg, + B2_avg, + B2_avg, + B2_avg, + B2_avg, + B2_avg, + B2_avg, + 0) + end + else #nonconservative_term == 2 + # Galilean nonconservative term: (0, 0, 0, 0, ψ v_{1,2}, 0, 0, 0, v_{1,2}) + psi_avg = (psi_ll + psi_rr)#* 0.5 # The flux is already multiplied by 0.5 wherever it is used in the code + f = SVector(0, + 0, + 0, + 0, + psi_avg, + 0, + 0, + 0, + psi_avg) + end + + return f +end + """ flux_derigs_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdEquations2D) diff --git a/src/solvers/dgsem_tree/containers_2d.jl b/src/solvers/dgsem_tree/containers_2d.jl index 9e9fe88c15b..4bfbddead9a 100644 --- a/src/solvers/dgsem_tree/containers_2d.jl +++ b/src/solvers/dgsem_tree/containers_2d.jl @@ -1266,11 +1266,15 @@ end # | # (i, j-1) mutable struct ContainerAntidiffusiveFlux2D{uEltype <: Real} - antidiffusive_flux1::Array{uEltype, 4} # [variables, i, j, elements] - antidiffusive_flux2::Array{uEltype, 4} # [variables, i, j, elements] + antidiffusive_flux1_L::Array{uEltype, 4} # [variables, i, j, elements] + antidiffusive_flux1_R::Array{uEltype, 4} # [variables, i, j, elements] + antidiffusive_flux2_L::Array{uEltype, 4} # [variables, i, j, elements] + antidiffusive_flux2_R::Array{uEltype, 4} # [variables, i, j, elements] # internal `resize!`able storage - _antidiffusive_flux1::Vector{uEltype} - _antidiffusive_flux2::Vector{uEltype} + _antidiffusive_flux1_L::Vector{uEltype} + _antidiffusive_flux1_R::Vector{uEltype} + _antidiffusive_flux2_L::Vector{uEltype} + _antidiffusive_flux2_R::Vector{uEltype} end function ContainerAntidiffusiveFlux2D{uEltype}(capacity::Integer, n_variables, @@ -1278,24 +1282,36 @@ function ContainerAntidiffusiveFlux2D{uEltype}(capacity::Integer, n_variables, nan_uEltype = convert(uEltype, NaN) # Initialize fields with defaults - _antidiffusive_flux1 = fill(nan_uEltype, - n_variables * (n_nodes + 1) * n_nodes * capacity) - antidiffusive_flux1 = unsafe_wrap(Array, pointer(_antidiffusive_flux1), - (n_variables, n_nodes + 1, n_nodes, capacity)) - - _antidiffusive_flux2 = fill(nan_uEltype, - n_variables * n_nodes * (n_nodes + 1) * capacity) - antidiffusive_flux2 = unsafe_wrap(Array, pointer(_antidiffusive_flux2), - (n_variables, n_nodes, n_nodes + 1, capacity)) - - return ContainerAntidiffusiveFlux2D{uEltype}(antidiffusive_flux1, - antidiffusive_flux2, - _antidiffusive_flux1, - _antidiffusive_flux2) + _antidiffusive_flux1_L = fill(nan_uEltype, + n_variables * (n_nodes + 1) * n_nodes * capacity) + antidiffusive_flux1_L = unsafe_wrap(Array, pointer(_antidiffusive_flux1_L), + (n_variables, n_nodes + 1, n_nodes, capacity)) + _antidiffusive_flux1_R = fill(nan_uEltype, + n_variables * (n_nodes + 1) * n_nodes * capacity) + antidiffusive_flux1_R = unsafe_wrap(Array, pointer(_antidiffusive_flux1_R), + (n_variables, n_nodes + 1, n_nodes, capacity)) + + _antidiffusive_flux2_L = fill(nan_uEltype, + n_variables * n_nodes * (n_nodes + 1) * capacity) + antidiffusive_flux2_L = unsafe_wrap(Array, pointer(_antidiffusive_flux2_L), + (n_variables, n_nodes, n_nodes + 1, capacity)) + _antidiffusive_flux2_R = fill(nan_uEltype, + n_variables * n_nodes * (n_nodes + 1) * capacity) + antidiffusive_flux2_R = unsafe_wrap(Array, pointer(_antidiffusive_flux2_R), + (n_variables, n_nodes, n_nodes + 1, capacity)) + + return ContainerAntidiffusiveFlux2D{uEltype}(antidiffusive_flux1_L, + antidiffusive_flux1_R, + antidiffusive_flux2_L, + antidiffusive_flux2_R, + _antidiffusive_flux1_L, + _antidiffusive_flux1_R, + _antidiffusive_flux2_L, + _antidiffusive_flux2_R) end -nvariables(fluxes::ContainerAntidiffusiveFlux2D) = size(fluxes.antidiffusive_flux1, 1) -nnodes(fluxes::ContainerAntidiffusiveFlux2D) = size(fluxes.antidiffusive_flux1, 3) +nvariables(fluxes::ContainerAntidiffusiveFlux2D) = size(fluxes.antidiffusive_flux1_L, 1) +nnodes(fluxes::ContainerAntidiffusiveFlux2D) = size(fluxes.antidiffusive_flux1_L, 3) # Only one-dimensional `Array`s are `resize!`able in Julia. # Hence, we use `Vector`s as internal storage and `resize!` @@ -1306,16 +1322,24 @@ function Base.resize!(fluxes::ContainerAntidiffusiveFlux2D, capacity) n_nodes = nnodes(fluxes) n_variables = nvariables(fluxes) - @unpack _antidiffusive_flux1, _antidiffusive_flux2 = fluxes - - resize!(_antidiffusive_flux1, n_variables * (n_nodes + 1) * n_nodes * capacity) - fluxes.antidiffusive_flux1 = unsafe_wrap(Array, pointer(_antidiffusive_flux1), - (n_variables, n_nodes + 1, n_nodes, - capacity)) - resize!(_antidiffusive_flux2, n_variables * n_nodes * (n_nodes + 1) * capacity) - fluxes.antidiffusive_flux2 = unsafe_wrap(Array, pointer(_antidiffusive_flux2), - (n_variables, n_nodes, n_nodes + 1, - capacity)) + @unpack _antidiffusive_flux1_L, _antidiffusive_flux2_L, _antidiffusive_flux1_R, _antidiffusive_flux2_R = fluxes + + resize!(_antidiffusive_flux1_L, n_variables * (n_nodes + 1) * n_nodes * capacity) + fluxes.antidiffusive_flux1_L = unsafe_wrap(Array, pointer(_antidiffusive_flux1_L), + (n_variables, n_nodes + 1, n_nodes, + capacity)) + resize!(_antidiffusive_flux1_R, n_variables * (n_nodes + 1) * n_nodes * capacity) + fluxes.antidiffusive_flux1_R = unsafe_wrap(Array, pointer(_antidiffusive_flux1_R), + (n_variables, n_nodes + 1, n_nodes, + capacity)) + resize!(_antidiffusive_flux2_L, n_variables * n_nodes * (n_nodes + 1) * capacity) + fluxes.antidiffusive_flux2_L = unsafe_wrap(Array, pointer(_antidiffusive_flux2_L), + (n_variables, n_nodes, n_nodes + 1, + capacity)) + resize!(_antidiffusive_flux2_R, n_variables * n_nodes * (n_nodes + 1) * capacity) + fluxes.antidiffusive_flux2_R = unsafe_wrap(Array, pointer(_antidiffusive_flux2_R), + (n_variables, n_nodes, n_nodes + 1, + capacity)) return nothing end diff --git a/src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl b/src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl index 70ff346740d..97843db7743 100644 --- a/src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl +++ b/src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl @@ -14,20 +14,45 @@ function create_cache(mesh::TreeMesh{2}, equations, A3dp1_x = Array{uEltype, 3} A3dp1_y = Array{uEltype, 3} A3d = Array{uEltype, 3} - - fhat1_threaded = A3dp1_x[A3dp1_x(undef, nvariables(equations), nnodes(dg) + 1, - nnodes(dg)) for _ in 1:Threads.nthreads()] - fhat2_threaded = A3dp1_y[A3dp1_y(undef, nvariables(equations), nnodes(dg), - nnodes(dg) + 1) for _ in 1:Threads.nthreads()] + A4d = Array{uEltype, 4} + + fhat1_L_threaded = A3dp1_x[A3dp1_x(undef, nvariables(equations), nnodes(dg) + 1, + nnodes(dg)) for _ in 1:Threads.nthreads()] + fhat2_L_threaded = A3dp1_y[A3dp1_y(undef, nvariables(equations), nnodes(dg), + nnodes(dg) + 1) for _ in 1:Threads.nthreads()] + fhat1_R_threaded = A3dp1_x[A3dp1_x(undef, nvariables(equations), nnodes(dg) + 1, + nnodes(dg)) for _ in 1:Threads.nthreads()] + fhat2_R_threaded = A3dp1_y[A3dp1_y(undef, nvariables(equations), nnodes(dg), + nnodes(dg) + 1) for _ in 1:Threads.nthreads()] flux_temp_threaded = A3d[A3d(undef, nvariables(equations), nnodes(dg), nnodes(dg)) for _ in 1:Threads.nthreads()] - + fhat_temp_threaded = A3d[A3d(undef, nvariables(equations), nnodes(dg), + nnodes(dg)) + for _ in 1:Threads.nthreads()] antidiffusive_fluxes = Trixi.ContainerAntidiffusiveFlux2D{uEltype}(0, nvariables(equations), nnodes(dg)) - return (; cache..., antidiffusive_fluxes, fhat1_threaded, fhat2_threaded, - flux_temp_threaded) + if have_nonconservative_terms(equations) == true + flux_nonconservative_temp_threaded = A4d[A4d(undef, nvariables(equations), + n_nonconservative_terms(equations), + nnodes(dg), nnodes(dg)) + for _ in 1:Threads.nthreads()] + fhat_nonconservative_temp_threaded = A4d[A4d(undef, nvariables(equations), + n_nonconservative_terms(equations), + nnodes(dg), nnodes(dg)) + for _ in 1:Threads.nthreads()] + phi_threaded = A4d[A4d(undef, nvariables(equations), + n_nonconservative_terms(equations), + nnodes(dg), nnodes(dg)) + for _ in 1:Threads.nthreads()] + cache = (; cache..., flux_nonconservative_temp_threaded, + fhat_nonconservative_temp_threaded, phi_threaded) + end + + return (; cache..., antidiffusive_fluxes, + fhat1_L_threaded, fhat2_L_threaded, fhat1_R_threaded, fhat2_R_threaded, + flux_temp_threaded, fhat_temp_threaded) end function calc_volume_integral!(du, u, @@ -47,19 +72,22 @@ end @inline function subcell_limiting_kernel!(du, u, element, mesh::TreeMesh{2}, - nonconservative_terms::False, equations, + nonconservative_terms, equations, volume_integral, limiter::SubcellLimiterIDP, dg::DGSEM, cache) @unpack inverse_weights = dg.basis @unpack volume_flux_dg, volume_flux_fv = volume_integral # high-order DG fluxes - @unpack fhat1_threaded, fhat2_threaded = cache + @unpack fhat1_L_threaded, fhat1_R_threaded, fhat2_L_threaded, fhat2_R_threaded = cache - fhat1 = fhat1_threaded[Threads.threadid()] - fhat2 = fhat2_threaded[Threads.threadid()] - calcflux_fhat!(fhat1, fhat2, u, mesh, - nonconservative_terms, equations, volume_flux_dg, dg, element, cache) + fhat1_L = fhat1_L_threaded[Threads.threadid()] + fhat1_R = fhat1_R_threaded[Threads.threadid()] + fhat2_L = fhat2_L_threaded[Threads.threadid()] + fhat2_R = fhat2_R_threaded[Threads.threadid()] + calcflux_fhat!(fhat1_L, fhat1_R, fhat2_L, fhat2_R, u, mesh, + nonconservative_terms, equations, volume_flux_dg, dg, element, + cache) # low-order FV fluxes @unpack fstar1_L_threaded, fstar1_R_threaded, fstar2_L_threaded, fstar2_R_threaded = cache @@ -69,12 +97,14 @@ end fstar1_R = fstar1_R_threaded[Threads.threadid()] fstar2_R = fstar2_R_threaded[Threads.threadid()] calcflux_fv!(fstar1_L, fstar1_R, fstar2_L, fstar2_R, u, mesh, - nonconservative_terms, equations, volume_flux_fv, dg, element, cache) + nonconservative_terms, equations, volume_flux_fv, dg, element, + cache) # antidiffusive flux - calcflux_antidiffusive!(fhat1, fhat2, fstar1_L, fstar2_L, u, mesh, - nonconservative_terms, equations, limiter, dg, element, - cache) + calcflux_antidiffusive!(fhat1_L, fhat1_R, fhat2_L, fhat2_R, + fstar1_L, fstar1_R, fstar2_L, fstar2_R, + u, mesh, nonconservative_terms, equations, limiter, dg, + element, cache) # Calculate volume integral contribution of low-order FV flux for j in eachnode(dg), i in eachnode(dg) @@ -93,7 +123,7 @@ end # (**without non-conservative terms**). # # See also `flux_differencing_kernel!`. -@inline function calcflux_fhat!(fhat1, fhat2, u, +@inline function calcflux_fhat!(fhat1_L, fhat1_R, fhat2_L, fhat2_R, u, mesh::TreeMesh{2}, nonconservative_terms::False, equations, volume_flux, dg::DGSEM, element, cache) @@ -132,11 +162,14 @@ end end # FV-form flux `fhat` in x direction - fhat1[:, 1, :] .= zero(eltype(fhat1)) - fhat1[:, nnodes(dg) + 1, :] .= zero(eltype(fhat1)) + fhat1_L[:, 1, :] .= zero(eltype(fhat1_L)) + fhat1_L[:, nnodes(dg) + 1, :] .= zero(eltype(fhat1_L)) + fhat1_R[:, 1, :] .= zero(eltype(fhat1_R)) + fhat1_R[:, nnodes(dg) + 1, :] .= zero(eltype(fhat1_R)) for j in eachnode(dg), i in 1:(nnodes(dg) - 1), v in eachvariable(equations) - fhat1[v, i + 1, j] = fhat1[v, i, j] + weights[i] * flux_temp[v, i, j] + fhat1_L[v, i + 1, j] = fhat1_L[v, i, j] + weights[i] * flux_temp[v, i, j] + fhat1_R[v, i + 1, j] = fhat1_L[v, i + 1, j] end # Split form volume flux in orientation 2: y direction @@ -155,38 +188,278 @@ end end # FV-form flux `fhat` in y direction - fhat2[:, :, 1] .= zero(eltype(fhat2)) - fhat2[:, :, nnodes(dg) + 1] .= zero(eltype(fhat2)) + fhat2_L[:, :, 1] .= zero(eltype(fhat2_L)) + fhat2_L[:, :, nnodes(dg) + 1] .= zero(eltype(fhat2_L)) + fhat2_R[:, :, 1] .= zero(eltype(fhat2_R)) + fhat2_R[:, :, nnodes(dg) + 1] .= zero(eltype(fhat2_R)) for j in 1:(nnodes(dg) - 1), i in eachnode(dg), v in eachvariable(equations) - fhat2[v, i, j + 1] = fhat2[v, i, j] + weights[j] * flux_temp[v, i, j] + fhat2_L[v, i, j + 1] = fhat2_L[v, i, j] + weights[j] * flux_temp[v, i, j] + fhat2_R[v, i, j + 1] = fhat2_L[v, i, j + 1] + end + + return nothing +end + +# Calculate the DG staggered volume fluxes `fhat` in subcell FV-form inside the element +# (**with non-conservative terms**). +# +# See also `flux_differencing_kernel!`. +# +# The calculation of the non-conservative staggered "fluxes" requires non-conservative +# terms that can be written as a product of local and a symmetric contributions. See, e.g., +# +# - Rueda-Ramírez, Gassner (2023). A Flux-Differencing Formula for Split-Form Summation By Parts +# Discretizations of Non-Conservative Systems. https://arxiv.org/pdf/2211.14009.pdf. +# +@inline function calcflux_fhat!(fhat1_L, fhat1_R, fhat2_L, fhat2_R, u, + mesh::TreeMesh{2}, nonconservative_terms::True, + equations, + volume_flux, dg::DGSEM, element, cache) + @unpack weights, derivative_split = dg.basis + @unpack flux_temp_threaded, flux_nonconservative_temp_threaded = cache + @unpack fhat_temp_threaded, fhat_nonconservative_temp_threaded, phi_threaded = cache + + volume_flux_cons, volume_flux_noncons = volume_flux + + flux_temp = flux_temp_threaded[Threads.threadid()] + flux_noncons_temp = flux_nonconservative_temp_threaded[Threads.threadid()] + + fhat_temp = fhat_temp_threaded[Threads.threadid()] + fhat_noncons_temp = fhat_nonconservative_temp_threaded[Threads.threadid()] + phi = phi_threaded[Threads.threadid()] + + # The FV-form fluxes are calculated in a recursive manner, i.e.: + # fhat_(0,1) = w_0 * FVol_0, + # fhat_(j,j+1) = fhat_(j-1,j) + w_j * FVol_j, for j=1,...,N-1, + # with the split form volume fluxes FVol_j = -2 * sum_i=0^N D_ji f*_(j,i). + + # To use the symmetry of the `volume_flux`, the split form volume flux is precalculated + # like in `calc_volume_integral!` for the `VolumeIntegralFluxDifferencing` + # and saved in in `flux_temp`. + + # Split form volume flux in orientation 1: x direction + flux_temp .= zero(eltype(flux_temp)) + flux_noncons_temp .= zero(eltype(flux_noncons_temp)) + + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, j, element) + + # All diagonal entries of `derivative_split` are zero. Thus, we can skip + # the computation of the diagonal terms. In addition, we use the symmetry + # of `volume_flux_cons` and `volume_flux_noncons` to save half of the possible two-point flux + # computations. + for ii in (i + 1):nnodes(dg) + u_node_ii = get_node_vars(u, equations, dg, ii, j, element) + flux1 = volume_flux_cons(u_node, u_node_ii, 1, equations) + multiply_add_to_node_vars!(flux_temp, derivative_split[i, ii], flux1, + equations, dg, i, j) + multiply_add_to_node_vars!(flux_temp, derivative_split[ii, i], flux1, + equations, dg, ii, j) + for noncons in 1:n_nonconservative_terms(equations) + # We multiply by 0.5 because that is done in other parts of Trixi + 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], + flux1_noncons, + equations, dg, noncons, i, j) + multiply_add_to_node_vars!(flux_noncons_temp, + 0.5 * derivative_split[ii, i], + flux1_noncons, + equations, dg, noncons, ii, j) + end + end end + # FV-form flux `fhat` in x direction + fhat1_L[:, 1, :] .= zero(eltype(fhat1_L)) + fhat1_L[:, nnodes(dg) + 1, :] .= zero(eltype(fhat1_L)) + fhat1_R[:, 1, :] .= zero(eltype(fhat1_R)) + fhat1_R[:, nnodes(dg) + 1, :] .= zero(eltype(fhat1_R)) + + fhat_temp[:, 1, :] .= zero(eltype(fhat1_L)) + fhat_noncons_temp[:, :, 1, :] .= zero(eltype(fhat1_L)) + + # Compute local contribution to non-conservative flux + for j in eachnode(dg), i in eachnode(dg) + u_local = get_node_vars(u, equations, dg, i, j, element) + for noncons in 1:n_nonconservative_terms(equations) + set_node_vars!(phi, + volume_flux_noncons(u_local, 1, equations, + NonConservativeLocal(), noncons), + equations, dg, noncons, i, j) + end + end + + for j in eachnode(dg), i in 1:(nnodes(dg) - 1) + # Conservative part + for v in eachvariable(equations) + value = fhat_temp[v, i, j] + weights[i] * flux_temp[v, i, j] + fhat_temp[v, i + 1, j] = value + fhat1_L[v, i + 1, j] = value + fhat1_R[v, i + 1, j] = value + end + # Nonconservative part + for noncons in 1:n_nonconservative_terms(equations), + v in eachvariable(equations) + + value = fhat_noncons_temp[v, noncons, i, j] + + weights[i] * flux_noncons_temp[v, noncons, i, j] + fhat_noncons_temp[v, noncons, i + 1, j] = value + + fhat1_L[v, i + 1, j] = fhat1_L[v, i + 1, j] + phi[v, noncons, i, j] * value + fhat1_R[v, i + 1, j] = fhat1_R[v, i + 1, j] + + phi[v, noncons, i + 1, j] * value + end + end + + # Split form volume flux in orientation 2: y direction + flux_temp .= zero(eltype(flux_temp)) + flux_noncons_temp .= zero(eltype(flux_noncons_temp)) + + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, j, element) + for jj in (j + 1):nnodes(dg) + u_node_jj = get_node_vars(u, equations, dg, i, jj, element) + flux2 = volume_flux_cons(u_node, u_node_jj, 2, equations) + multiply_add_to_node_vars!(flux_temp, derivative_split[j, jj], flux2, + equations, dg, i, j) + multiply_add_to_node_vars!(flux_temp, derivative_split[jj, j], flux2, + equations, dg, i, jj) + for noncons in 1:n_nonconservative_terms(equations) + # We multiply by 0.5 because that is done in other parts of Trixi + flux2_noncons = volume_flux_noncons(u_node, u_node_jj, 2, equations, + NonConservativeSymmetric(), noncons) + multiply_add_to_node_vars!(flux_noncons_temp, + 0.5 * derivative_split[j, jj], + flux2_noncons, + equations, dg, noncons, i, j) + multiply_add_to_node_vars!(flux_noncons_temp, + 0.5 * derivative_split[jj, j], + flux2_noncons, + equations, dg, noncons, i, jj) + end + end + end + + # FV-form flux `fhat` in y direction + fhat2_L[:, :, 1] .= zero(eltype(fhat2_L)) + fhat2_L[:, :, nnodes(dg) + 1] .= zero(eltype(fhat2_L)) + fhat2_R[:, :, 1] .= zero(eltype(fhat2_R)) + fhat2_R[:, :, nnodes(dg) + 1] .= zero(eltype(fhat2_R)) + + fhat_temp[:, :, 1] .= zero(eltype(fhat1_L)) + fhat_noncons_temp[:, :, :, 1] .= zero(eltype(fhat1_L)) + + # Compute local contribution to non-conservative flux + for j in eachnode(dg), i in eachnode(dg) + u_local = get_node_vars(u, equations, dg, i, j, element) + for noncons in 1:n_nonconservative_terms(equations) + set_node_vars!(phi, + volume_flux_noncons(u_local, 2, equations, + NonConservativeLocal(), noncons), + equations, dg, noncons, i, j) + end + end + + for j in 1:(nnodes(dg) - 1), i in eachnode(dg) + # Conservative part + for v in eachvariable(equations) + value = fhat_temp[v, i, j] + weights[j] * flux_temp[v, i, j] + fhat_temp[v, i, j + 1] = value + fhat2_L[v, i, j + 1] = value + fhat2_R[v, i, j + 1] = value + end + # Nonconservative part + for noncons in 1:n_nonconservative_terms(equations), + v in eachvariable(equations) + + value = fhat_noncons_temp[v, noncons, i, j] + + weights[j] * flux_noncons_temp[v, noncons, i, j] + fhat_noncons_temp[v, noncons, i, j + 1] = value + + fhat2_L[v, i, j + 1] = fhat2_L[v, i, j + 1] + phi[v, noncons, i, j] * value + fhat2_R[v, i, j + 1] = fhat2_R[v, i, j + 1] + + phi[v, noncons, i, j + 1] * value + end + end + + return nothing +end + +# Calculate the antidiffusive flux `antidiffusive_flux` as the subtraction between `fhat` and `fstar` for conservative systems. +@inline function calcflux_antidiffusive!(fhat1_L, fhat1_R, fhat2_L, fhat2_R, + fstar1_L, fstar1_R, fstar2_L, fstar2_R, + u, mesh, + nonconservative_terms::False, equations, + limiter::SubcellLimiterIDP, dg, element, cache) + @unpack antidiffusive_flux1_L, antidiffusive_flux2_L, antidiffusive_flux1_R, antidiffusive_flux2_R = cache.antidiffusive_fluxes + + for j in eachnode(dg), i in 2:nnodes(dg) + for v in eachvariable(equations) + antidiffusive_flux1_L[v, i, j, element] = fhat1_L[v, i, j] - + fstar1_L[v, i, j] + antidiffusive_flux1_R[v, i, j, element] = antidiffusive_flux1_L[v, i, j, + element] + end + end + for j in 2:nnodes(dg), i in eachnode(dg) + for v in eachvariable(equations) + antidiffusive_flux2_L[v, i, j, element] = fhat2_L[v, i, j] - + fstar2_L[v, i, j] + antidiffusive_flux2_R[v, i, j, element] = antidiffusive_flux2_L[v, i, j, + element] + end + end + + antidiffusive_flux1_L[:, 1, :, element] .= zero(eltype(antidiffusive_flux1_L)) + antidiffusive_flux1_L[:, nnodes(dg) + 1, :, element] .= zero(eltype(antidiffusive_flux1_L)) + antidiffusive_flux1_R[:, 1, :, element] .= zero(eltype(antidiffusive_flux1_R)) + antidiffusive_flux1_R[:, nnodes(dg) + 1, :, element] .= zero(eltype(antidiffusive_flux1_R)) + + antidiffusive_flux2_L[:, :, 1, element] .= zero(eltype(antidiffusive_flux2_L)) + antidiffusive_flux2_L[:, :, nnodes(dg) + 1, element] .= zero(eltype(antidiffusive_flux2_L)) + antidiffusive_flux2_R[:, :, 1, element] .= zero(eltype(antidiffusive_flux2_R)) + antidiffusive_flux2_R[:, :, nnodes(dg) + 1, element] .= zero(eltype(antidiffusive_flux2_R)) + return nothing end -# Calculate the antidiffusive flux `antidiffusive_flux` as the subtraction between `fhat` and `fstar`. -@inline function calcflux_antidiffusive!(fhat1, fhat2, fstar1, fstar2, u, mesh, - nonconservative_terms, equations, +# Calculate the antidiffusive flux `antidiffusive_flux` as the subtraction between `fhat` and `fstar` for conservative systems. +@inline function calcflux_antidiffusive!(fhat1_L, fhat1_R, fhat2_L, fhat2_R, + fstar1_L, fstar1_R, fstar2_L, fstar2_R, + u, mesh, + nonconservative_terms::True, equations, limiter::SubcellLimiterIDP, dg, element, cache) - @unpack antidiffusive_flux1, antidiffusive_flux2 = cache.antidiffusive_fluxes + @unpack antidiffusive_flux1_L, antidiffusive_flux2_L, antidiffusive_flux1_R, antidiffusive_flux2_R = cache.antidiffusive_fluxes for j in eachnode(dg), i in 2:nnodes(dg) for v in eachvariable(equations) - antidiffusive_flux1[v, i, j, element] = fhat1[v, i, j] - fstar1[v, i, j] + antidiffusive_flux1_L[v, i, j, element] = fhat1_L[v, i, j] - + fstar1_L[v, i, j] + antidiffusive_flux1_R[v, i, j, element] = fhat1_R[v, i, j] - + fstar1_R[v, i, j] end end for j in 2:nnodes(dg), i in eachnode(dg) for v in eachvariable(equations) - antidiffusive_flux2[v, i, j, element] = fhat2[v, i, j] - fstar2[v, i, j] + antidiffusive_flux2_L[v, i, j, element] = fhat2_L[v, i, j] - + fstar2_L[v, i, j] + antidiffusive_flux2_R[v, i, j, element] = fhat2_R[v, i, j] - + fstar2_R[v, i, j] end end - antidiffusive_flux1[:, 1, :, element] .= zero(eltype(antidiffusive_flux1)) - antidiffusive_flux1[:, nnodes(dg) + 1, :, element] .= zero(eltype(antidiffusive_flux1)) + antidiffusive_flux1_L[:, 1, :, element] .= zero(eltype(antidiffusive_flux1_L)) + antidiffusive_flux1_L[:, nnodes(dg) + 1, :, element] .= zero(eltype(antidiffusive_flux1_L)) + antidiffusive_flux1_R[:, 1, :, element] .= zero(eltype(antidiffusive_flux1_R)) + antidiffusive_flux1_R[:, nnodes(dg) + 1, :, element] .= zero(eltype(antidiffusive_flux1_R)) - antidiffusive_flux2[:, :, 1, element] .= zero(eltype(antidiffusive_flux2)) - antidiffusive_flux2[:, :, nnodes(dg) + 1, element] .= zero(eltype(antidiffusive_flux2)) + antidiffusive_flux2_L[:, :, 1, element] .= zero(eltype(antidiffusive_flux2_L)) + antidiffusive_flux2_L[:, :, nnodes(dg) + 1, element] .= zero(eltype(antidiffusive_flux2_L)) + antidiffusive_flux2_R[:, :, 1, element] .= zero(eltype(antidiffusive_flux2_R)) + antidiffusive_flux2_R[:, :, nnodes(dg) + 1, element] .= zero(eltype(antidiffusive_flux2_R)) return nothing end diff --git a/src/solvers/dgsem_tree/subcell_limiters_2d.jl b/src/solvers/dgsem_tree/subcell_limiters_2d.jl index 5e00ab4e903..0a72b79ea3f 100644 --- a/src/solvers/dgsem_tree/subcell_limiters_2d.jl +++ b/src/solvers/dgsem_tree/subcell_limiters_2d.jl @@ -63,7 +63,7 @@ end @inline function idp_positivity!(alpha, limiter, u, dt, semi, variable) mesh, equations, dg, cache = mesh_equations_solver_cache(semi) - (; antidiffusive_flux1, antidiffusive_flux2) = cache.antidiffusive_fluxes + (; antidiffusive_flux1_L, antidiffusive_flux2_L, antidiffusive_flux1_R, antidiffusive_flux2_R) = cache.antidiffusive_fluxes (; inverse_weights) = dg.basis (; positivity_correction_factor) = limiter @@ -91,13 +91,13 @@ end # Calculate Pm # Note: Boundaries of antidiffusive_flux1/2 are constant 0, so they make no difference here. val_flux1_local = inverse_weights[i] * - antidiffusive_flux1[variable, i, j, element] + antidiffusive_flux1_R[variable, i, j, element] val_flux1_local_ip1 = -inverse_weights[i] * - antidiffusive_flux1[variable, i + 1, j, element] + antidiffusive_flux1_L[variable, i + 1, j, element] val_flux2_local = inverse_weights[j] * - antidiffusive_flux2[variable, i, j, element] + antidiffusive_flux2_R[variable, i, j, element] val_flux2_local_jp1 = -inverse_weights[j] * - antidiffusive_flux2[variable, i, j + 1, element] + antidiffusive_flux2_L[variable, i, j + 1, element] Pm = min(0, val_flux1_local) + min(0, val_flux1_local_ip1) + min(0, val_flux2_local) + min(0, val_flux2_local_jp1) diff --git a/src/time_integration/methods_SSP.jl b/src/time_integration/methods_SSP.jl index 733f89c2158..dbb9e51121b 100644 --- a/src/time_integration/methods_SSP.jl +++ b/src/time_integration/methods_SSP.jl @@ -218,6 +218,11 @@ function set_proposed_dt!(integrator::SimpleIntegratorSSP, dt) integrator.dt = dt end +# used by adaptive timestepping algorithms in DiffEq +function get_proposed_dt(integrator::SimpleIntegratorSSP) + return integrator.dt +end + # stop the time integration function terminate!(integrator::SimpleIntegratorSSP) integrator.finalstep = true diff --git a/test/test_tree_2d_mhd.jl b/test/test_tree_2d_mhd.jl index af264561027..bd6a95bba50 100644 --- a/test/test_tree_2d_mhd.jl +++ b/test/test_tree_2d_mhd.jl @@ -328,6 +328,37 @@ end @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 end end + +@trixi_testset "elixir_mhd_shockcapturing_subcell.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_shockcapturing_subcell.jl"), + l2=[2.9974425783503109e-02, + 7.2849646345685956e-02, + 7.2488477174662239e-02, + 0.0000000000000000e+00, + 1.2507971380965512e+00, + 1.8929505145499678e-02, + 1.2218606317164420e-02, + 0.0000000000000000e+00, + 3.0154796910479838e-03], + linf=[3.2147382412340830e-01, + 1.3709471664007811e+00, + 1.3465154685288383e+00, + 0.0000000000000000e+00, + 1.6051257523415284e+01, + 3.0564266749926644e-01, + 2.3908016329805595e-01, + 0.0000000000000000e+00, + 1.3711262178549158e-01], + tspan=(0.0, 0.003)) + # 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)) < 15000 + end +end end end # module From 28500ea8965bd8ecf54ce35166d2ff6bf35ab212 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Tue, 31 Oct 2023 16:03:26 +0100 Subject: [PATCH 147/263] Fix allocs (#1695) * Fix allocs * remove unnecessary code * rerun fmt * format --- src/solvers/dgmulti/dg.jl | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/src/solvers/dgmulti/dg.jl b/src/solvers/dgmulti/dg.jl index 182a486dce5..695260f4b9b 100644 --- a/src/solvers/dgmulti/dg.jl +++ b/src/solvers/dgmulti/dg.jl @@ -465,24 +465,13 @@ function calc_boundary_flux!(cache, t, boundary_conditions::BoundaryConditionPer nothing end -# "lispy tuple programming" instead of for loop for type stability function calc_boundary_flux!(cache, t, boundary_conditions, mesh, have_nonconservative_terms, equations, dg::DGMulti) - - # peel off first boundary condition - calc_single_boundary_flux!(cache, t, first(boundary_conditions), - first(keys(boundary_conditions)), - mesh, have_nonconservative_terms, equations, dg) - - # recurse on the remainder of the boundary conditions - calc_boundary_flux!(cache, t, Base.tail(boundary_conditions), - mesh, have_nonconservative_terms, equations, dg) -end - -# terminate recursion -function calc_boundary_flux!(cache, t, boundary_conditions::NamedTuple{(), Tuple{}}, - mesh, have_nonconservative_terms, equations, dg::DGMulti) - nothing + for (key, value) in zip(keys(boundary_conditions), boundary_conditions) + calc_single_boundary_flux!(cache, t, value, + key, + mesh, have_nonconservative_terms, equations, dg) + end end function calc_single_boundary_flux!(cache, t, boundary_condition, boundary_key, mesh, From abd97b17ed34dd8269bf07e482826e347629811e Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Wed, 1 Nov 2023 15:40:37 +0100 Subject: [PATCH 148/263] Allocation tests dgmulti 2d (#1698) --- test/test_dgmulti_2d.jl | 265 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 264 insertions(+), 1 deletion(-) diff --git a/test/test_dgmulti_2d.jl b/test/test_dgmulti_2d.jl index 8fd00df72ea..892c8ed37f0 100644 --- a/test/test_dgmulti_2d.jl +++ b/test/test_dgmulti_2d.jl @@ -30,6 +30,14 @@ isdir(outdir) && rm(outdir, recursive = true) 0.002062399194485476, 0.004897700392503701, ]) + # 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_weakform.jl (SBP)" begin @@ -49,6 +57,14 @@ end 0.013593978324845324, 0.03270995869587523, ]) + # 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_weakform.jl (Quadrilateral elements)" begin @@ -68,6 +84,14 @@ end 0.0013568139808290969, 0.0032249020004324613, ]) + # 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_weakform.jl (EC) " begin @@ -88,6 +112,14 @@ end 0.01396529873508534, 0.04227683691807904, ]) + # 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_weakform.jl (SBP, EC)" begin @@ -109,6 +141,14 @@ end 0.05321027922608157, 0.13392025411844033, ]) + # 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_weakform.jl (Quadrilateral elements, SBP, EC)" begin @@ -131,6 +171,14 @@ end 0.012674028479251254, 0.02210545278615017, ]) + # 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_bilinear.jl (Bilinear quadrilateral elements, SBP, flux differencing)" begin @@ -147,6 +195,14 @@ end 6.874188052830021e-5, 0.0001912435192696904, ]) + # 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_curved.jl (Quadrilateral elements, SBP, flux differencing)" begin @@ -163,6 +219,14 @@ end 0.00010003778085621029, 0.00036426282101720275, ]) + # 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_curved.jl (Quadrilateral elements, GaussSBP, flux differencing)" begin @@ -181,6 +245,14 @@ end 3.679582619220412e-5, ], rtol=2 * sqrt(eps())) + # 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_curved.jl (Triangular elements, Polynomial, weak formulation)" begin @@ -199,6 +271,14 @@ end 4.032272526011127e-5, 0.00012013725458537294, ]) + # 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_hohqmesh.jl (Quadrilateral elements, SBP, flux differencing)" begin @@ -215,6 +295,14 @@ end 0.0028721569841545502, 0.011125365074589944, ]) + # 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_weakform.jl (convergence)" begin @@ -228,6 +316,14 @@ end 4.128314378397532, 4.081366752807379, ], rtol = 0.05) + # 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_weakform_periodic.jl" begin @@ -245,6 +341,14 @@ end 0.0019373508504538783, 0.004742686826709086, ]) + # 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_triangulate_pkg_mesh.jl" begin @@ -261,6 +365,14 @@ end 2.6180448559287584e-5, 5.5752932611508044e-5, ]) + # 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_kelvin_helmholtz_instability.jl" begin @@ -280,6 +392,14 @@ end 0.1235468309508845, 0.26911424973147735, ]) + # 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_kelvin_helmholtz_instability.jl (Quadrilateral elements, GaussSBP)" begin @@ -300,6 +420,14 @@ end 0.12344140473946856, 0.26978428189564774, ]) + # 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_rayleigh_taylor_instability.jl" begin @@ -318,6 +446,14 @@ end 0.040307056293369226, 0.0852365428206836, ]) + # 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_brown_minion_vortex.jl" begin @@ -335,6 +471,14 @@ end 0.021957154972646383, 0.33773439650806303, ]) + # 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_shockcapturing.jl" begin @@ -352,6 +496,14 @@ end 0.1668441768697189, 0.8572572782118661, ]) + # 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_shockcapturing_curved.jl" begin @@ -369,6 +521,14 @@ end 0.16930148707515688, 0.8587706761131937, ]) + # 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_weakform.jl (FD SBP)" begin @@ -395,6 +555,14 @@ end 0.0016243096040242655, 0.004447503691245913, ]) + # 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_weakform.jl (FD SBP, EC)" begin @@ -423,6 +591,14 @@ end 0.003452046522624652, 0.007677153211004928, ]) + # 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_fdsbp_periodic.jl" begin @@ -439,6 +615,14 @@ end 3.9885950273710336e-6, 8.848583042286862e-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 end @trixi_testset "elixir_euler_fdsbp_periodic.jl (arbitrary reference domain)" begin @@ -456,6 +640,14 @@ end 3.988595024928543e-6, 8.84858303740188e-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 end @trixi_testset "elixir_euler_fdsbp_periodic.jl (arbitrary reference and physical domains)" begin @@ -479,6 +671,14 @@ end 0.5244468027020814, 1.2210130256735705, ]) + # 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_fdsbp_periodic.jl (CGSEM)" begin @@ -503,6 +703,14 @@ end 5.067812786885284e-5, 9.887976803746312e-5, ]) + # 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_mhd_weak_blast_wave.jl (Quad)" begin @@ -518,6 +726,14 @@ end 0.7450328339751362, 0.06357382685763713, 0.0635738268576378, 0.1058830287485999, 0.005740591170062146]) + # 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_mhd_weak_blast_wave.jl (Tri)" begin @@ -533,6 +749,14 @@ end 0.6906308908961734, 0.05349939593012487, 0.05349939593013042, 0.08830587480616725, 0.0029551359803035027]) + # 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_mhd_weak_blast_wave_SBP.jl (Quad)" begin @@ -601,6 +825,14 @@ end 0.0, 0.0002992631411931389, ]) + # 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_source_terms.jl (Quad, SBP)" begin @@ -619,6 +851,14 @@ end 0.12088392994348407, 9.325873406851315e-15, ]) + # 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_source_terms.jl (Tri, SBP)" begin @@ -637,6 +877,14 @@ end 0.5674183379872275, 1.1546319456101628e-14, ]) + # 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_source_terms.jl (Tri, Polynomial)" begin @@ -657,6 +905,14 @@ end 0.06345885709961152, 3.3989933098554914e-5, ]) + # 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_source_terms.jl (Quad, Polynomial)" begin @@ -679,9 +935,16 @@ end 0.010364675200833062, 1.021405182655144e-14, ]) + # 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 @test_nowarn isdir(outdir) && rm(outdir, recursive = true) From c438d34331a69fdbe9bea831d52b9b518949c446 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Wed, 1 Nov 2023 15:41:31 +0100 Subject: [PATCH 149/263] HLLE CEE 2D3D NonCartesian Meshes (#1692) * HLLE CEE 2D3D NonCartesian Meshes * format * hlle via hll * format test * format test * format * do not export hlle * Correct test vals * test values CI * Update src/equations/compressible_euler_2d.jl Co-authored-by: Hendrik Ranocha * Update src/equations/compressible_euler_1d.jl Co-authored-by: Hendrik Ranocha * Update src/equations/compressible_euler_2d.jl Co-authored-by: Hendrik Ranocha * Update src/equations/compressible_euler_3d.jl Co-authored-by: Hendrik Ranocha * Update src/equations/compressible_euler_3d.jl Co-authored-by: Hendrik Ranocha * apply suggestions * additional sentence * Fix typo * typos * correct test vals --------- Co-authored-by: Hendrik Ranocha --- src/equations/compressible_euler_1d.jl | 36 +-------- src/equations/compressible_euler_2d.jl | 92 +++++++++++++++-------- src/equations/compressible_euler_3d.jl | 100 ++++++++++++++++--------- src/equations/numerical_fluxes.jl | 8 ++ test/test_p4est_2d.jl | 26 +++++++ test/test_p4est_3d.jl | 28 +++++++ test/test_tree_1d_euler.jl | 16 ++++ test/test_tree_2d_euler.jl | 26 +++++++ test/test_tree_3d_euler.jl | 28 +++++++ test/test_unit.jl | 18 ++--- 10 files changed, 265 insertions(+), 113 deletions(-) diff --git a/src/equations/compressible_euler_1d.jl b/src/equations/compressible_euler_1d.jl index 9204989e8be..05c38ce791d 100644 --- a/src/equations/compressible_euler_1d.jl +++ b/src/equations/compressible_euler_1d.jl @@ -808,7 +808,7 @@ function flux_hllc(u_ll, u_rr, orientation::Integer, end """ - flux_hlle(u_ll, u_rr, orientation, equations::CompressibleEulerEquations1D) + min_max_speed_einfeldt(u_ll, u_rr, orientation, equations::CompressibleEulerEquations1D) Computes the HLLE (Harten-Lax-van Leer-Einfeldt) flux for the compressible Euler equations. Special estimates of the signal velocites and linearization of the Riemann problem developed @@ -825,8 +825,8 @@ Compactly summarized: Numerical methods for conservation laws and related equations. [Link](https://metaphor.ethz.ch/x/2019/hs/401-4671-00L/literature/mishra_hyperbolic_pdes.pdf) """ -function flux_hlle(u_ll, u_rr, orientation::Integer, - equations::CompressibleEulerEquations1D) +@inline function min_max_speed_einfeldt(u_ll, u_rr, orientation::Integer, + equations::CompressibleEulerEquations1D) # Calculate primitive variables, enthalpy and speed of sound rho_ll, v_ll, p_ll = cons2prim(u_ll, equations) rho_rr, v_rr, p_rr = cons2prim(u_rr, equations) @@ -858,35 +858,7 @@ function flux_hlle(u_ll, u_rr, orientation::Integer, SsL = min(v_roe - c_roe, v_ll - beta * c_ll, zero(v_roe)) SsR = max(v_roe + c_roe, v_rr + beta * c_rr, zero(v_roe)) - if SsL >= 0.0 && SsR > 0.0 - # Positive supersonic speed - f_ll = flux(u_ll, orientation, equations) - - f1 = f_ll[1] - f2 = f_ll[2] - f3 = f_ll[3] - elseif SsR <= 0.0 && SsL < 0.0 - # Negative supersonic speed - f_rr = flux(u_rr, orientation, equations) - - f1 = f_rr[1] - f2 = f_rr[2] - f3 = f_rr[3] - else - # Subsonic case - # Compute left and right fluxes - f_ll = flux(u_ll, orientation, equations) - f_rr = flux(u_rr, orientation, equations) - - f1 = (SsR * f_ll[1] - SsL * f_rr[1] + SsL * SsR * (u_rr[1] - u_ll[1])) / - (SsR - SsL) - f2 = (SsR * f_ll[2] - SsL * f_rr[2] + SsL * SsR * (u_rr[2] - u_ll[2])) / - (SsR - SsL) - f3 = (SsR * f_ll[3] - SsL * f_rr[3] + SsL * SsR * (u_rr[3] - u_ll[3])) / - (SsR - SsL) - end - - return SVector(f1, f2, f3) + return SsL, SsR end @inline function max_abs_speeds(u, equations::CompressibleEulerEquations1D) diff --git a/src/equations/compressible_euler_2d.jl b/src/equations/compressible_euler_2d.jl index 27b92f41953..6c8f2e1e848 100644 --- a/src/equations/compressible_euler_2d.jl +++ b/src/equations/compressible_euler_2d.jl @@ -1253,7 +1253,7 @@ function flux_hllc(u_ll, u_rr, orientation::Integer, end """ - flux_hlle(u_ll, u_rr, orientation, equations::CompressibleEulerEquations2D) + min_max_speed_einfeldt(u_ll, u_rr, orientation, equations::CompressibleEulerEquations2D) Computes the HLLE (Harten-Lax-van Leer-Einfeldt) flux for the compressible Euler equations. Special estimates of the signal velocites and linearization of the Riemann problem developed @@ -1267,8 +1267,8 @@ of the numerical flux. On Godunov-type methods near low densities. [DOI: 10.1016/0021-9991(91)90211-3](https://doi.org/10.1016/0021-9991(91)90211-3) """ -function flux_hlle(u_ll, u_rr, orientation::Integer, - equations::CompressibleEulerEquations2D) +@inline function min_max_speed_einfeldt(u_ll, u_rr, orientation::Integer, + equations::CompressibleEulerEquations2D) # Calculate primitive variables, enthalpy and speed of sound rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations) rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations) @@ -1306,39 +1306,65 @@ function flux_hlle(u_ll, u_rr, orientation::Integer, SsR = max(v2_roe + c_roe, v2_rr + beta * c_rr, zero(v2_roe)) end - if SsL >= 0.0 && SsR > 0.0 - # Positive supersonic speed - f_ll = flux(u_ll, orientation, equations) + return SsL, SsR +end - f1 = f_ll[1] - f2 = f_ll[2] - f3 = f_ll[3] - f4 = f_ll[4] - elseif SsR <= 0.0 && SsL < 0.0 - # Negative supersonic speed - f_rr = flux(u_rr, orientation, equations) +""" + min_max_speed_einfeldt(u_ll, u_rr, normal_direction, equations::CompressibleEulerEquations2D) - f1 = f_rr[1] - f2 = f_rr[2] - f3 = f_rr[3] - f4 = f_rr[4] - else - # Subsonic case - # Compute left and right fluxes - f_ll = flux(u_ll, orientation, equations) - f_rr = flux(u_rr, orientation, equations) - - f1 = (SsR * f_ll[1] - SsL * f_rr[1] + SsL * SsR * (u_rr[1] - u_ll[1])) / - (SsR - SsL) - f2 = (SsR * f_ll[2] - SsL * f_rr[2] + SsL * SsR * (u_rr[2] - u_ll[2])) / - (SsR - SsL) - f3 = (SsR * f_ll[3] - SsL * f_rr[3] + SsL * SsR * (u_rr[3] - u_ll[3])) / - (SsR - SsL) - f4 = (SsR * f_ll[4] - SsL * f_rr[4] + SsL * SsR * (u_rr[4] - u_ll[4])) / - (SsR - SsL) - end +Computes the HLLE (Harten-Lax-van Leer-Einfeldt) flux for the compressible Euler equations. +Special estimates of the signal velocites and linearization of the Riemann problem developed +by Einfeldt to ensure that the internal energy and density remain positive during the computation +of the numerical flux. - return SVector(f1, f2, f3, f4) +- Bernd Einfeldt (1988) + On Godunov-type methods for gas dynamics. + [DOI: 10.1137/0725021](https://doi.org/10.1137/0725021) +- Bernd Einfeldt, Claus-Dieter Munz, Philip L. Roe and Björn Sjögreen (1991) + On Godunov-type methods near low densities. + [DOI: 10.1016/0021-9991(91)90211-3](https://doi.org/10.1016/0021-9991(91)90211-3) +""" +@inline function min_max_speed_einfeldt(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleEulerEquations2D) + # Calculate primitive variables, enthalpy and speed of sound + rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations) + + v_dot_n_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] + v_dot_n_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] + + norm_ = norm(normal_direction) + + # `u_ll[4]` is total energy `rho_e_ll` on the left + H_ll = (u_ll[4] + p_ll) / rho_ll + c_ll = sqrt(equations.gamma * p_ll / rho_ll) * norm_ + + # `u_rr[4]` is total energy `rho_e_rr` on the right + H_rr = (u_rr[4] + p_rr) / rho_rr + c_rr = sqrt(equations.gamma * p_rr / rho_rr) * norm_ + + # Compute Roe averages + sqrt_rho_ll = sqrt(rho_ll) + sqrt_rho_rr = sqrt(rho_rr) + inv_sum_sqrt_rho = inv(sqrt_rho_ll + sqrt_rho_rr) + + v1_roe = (sqrt_rho_ll * v1_ll + sqrt_rho_rr * v1_rr) * inv_sum_sqrt_rho + v2_roe = (sqrt_rho_ll * v2_ll + sqrt_rho_rr * v2_rr) * inv_sum_sqrt_rho + v_roe = v1_roe * normal_direction[1] + v2_roe * normal_direction[2] + v_roe_mag = (v1_roe * normal_direction[1])^2 + (v2_roe * normal_direction[2])^2 + + H_roe = (sqrt_rho_ll * H_ll + sqrt_rho_rr * H_rr) * inv_sum_sqrt_rho + c_roe = sqrt((equations.gamma - 1) * (H_roe - 0.5 * v_roe_mag)) * norm_ + + # Compute convenience constant for positivity preservation, see + # https://doi.org/10.1016/0021-9991(91)90211-3 + beta = sqrt(0.5 * (equations.gamma - 1) / equations.gamma) + + # Estimate the edges of the Riemann fan (with positivity conservation) + SsL = min(v_roe - c_roe, v_dot_n_ll - beta * c_ll, zero(v_roe)) + SsR = max(v_roe + c_roe, v_dot_n_rr + beta * c_rr, zero(v_roe)) + + return SsL, SsR end @inline function max_abs_speeds(u, equations::CompressibleEulerEquations2D) diff --git a/src/equations/compressible_euler_3d.jl b/src/equations/compressible_euler_3d.jl index 7f25bde31fd..fc56f58025b 100644 --- a/src/equations/compressible_euler_3d.jl +++ b/src/equations/compressible_euler_3d.jl @@ -1322,7 +1322,7 @@ function flux_hllc(u_ll, u_rr, orientation::Integer, end """ - flux_hlle(u_ll, u_rr, orientation, equations::CompressibleEulerEquations3D) + min_max_speed_einfeldt(u_ll, u_rr, orientation, equations::CompressibleEulerEquations3D) Computes the HLLE (Harten-Lax-van Leer-Einfeldt) flux for the compressible Euler equations. Special estimates of the signal velocites and linearization of the Riemann problem developed @@ -1336,8 +1336,8 @@ of the numerical flux. On Godunov-type methods near low densities. [DOI: 10.1016/0021-9991(91)90211-3](https://doi.org/10.1016/0021-9991(91)90211-3) """ -function flux_hlle(u_ll, u_rr, orientation::Integer, - equations::CompressibleEulerEquations3D) +@inline function min_max_speed_einfeldt(u_ll, u_rr, orientation::Integer, + equations::CompressibleEulerEquations3D) # Calculate primitive variables, enthalpy and speed of sound rho_ll, v1_ll, v2_ll, v3_ll, p_ll = cons2prim(u_ll, equations) rho_rr, v1_rr, v2_rr, v3_rr, p_rr = cons2prim(u_rr, equations) @@ -1379,43 +1379,69 @@ function flux_hlle(u_ll, u_rr, orientation::Integer, SsR = max(v3_roe + c_roe, v3_rr + beta * c_rr, zero(v3_roe)) end - if SsL >= 0.0 && SsR > 0.0 - # Positive supersonic speed - f_ll = flux(u_ll, orientation, equations) + return SsL, SsR +end - f1 = f_ll[1] - f2 = f_ll[2] - f3 = f_ll[3] - f4 = f_ll[4] - f5 = f_ll[5] - elseif SsR <= 0.0 && SsL < 0.0 - # Negative supersonic speed - f_rr = flux(u_rr, orientation, equations) +""" + min_max_speed_einfeldt(u_ll, u_rr, normal_direction, equations::CompressibleEulerEquations3D) - f1 = f_rr[1] - f2 = f_rr[2] - f3 = f_rr[3] - f4 = f_rr[4] - f5 = f_rr[5] - else - # Subsonic case - # Compute left and right fluxes - f_ll = flux(u_ll, orientation, equations) - f_rr = flux(u_rr, orientation, equations) - - f1 = (SsR * f_ll[1] - SsL * f_rr[1] + SsL * SsR * (u_rr[1] - u_ll[1])) / - (SsR - SsL) - f2 = (SsR * f_ll[2] - SsL * f_rr[2] + SsL * SsR * (u_rr[2] - u_ll[2])) / - (SsR - SsL) - f3 = (SsR * f_ll[3] - SsL * f_rr[3] + SsL * SsR * (u_rr[3] - u_ll[3])) / - (SsR - SsL) - f4 = (SsR * f_ll[4] - SsL * f_rr[4] + SsL * SsR * (u_rr[4] - u_ll[4])) / - (SsR - SsL) - f5 = (SsR * f_ll[5] - SsL * f_rr[5] + SsL * SsR * (u_rr[5] - u_ll[5])) / - (SsR - SsL) - end +Computes the HLLE (Harten-Lax-van Leer-Einfeldt) flux for the compressible Euler equations. +Special estimates of the signal velocites and linearization of the Riemann problem developed +by Einfeldt to ensure that the internal energy and density remain positive during the computation +of the numerical flux. - return SVector(f1, f2, f3, f4, f5) +- Bernd Einfeldt (1988) + On Godunov-type methods for gas dynamics. + [DOI: 10.1137/0725021](https://doi.org/10.1137/0725021) +- Bernd Einfeldt, Claus-Dieter Munz, Philip L. Roe and Björn Sjögreen (1991) + On Godunov-type methods near low densities. + [DOI: 10.1016/0021-9991(91)90211-3](https://doi.org/10.1016/0021-9991(91)90211-3) +""" +@inline function min_max_speed_einfeldt(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleEulerEquations3D) + # Calculate primitive variables, enthalpy and speed of sound + rho_ll, v1_ll, v2_ll, v3_ll, p_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr, v3_rr, p_rr = cons2prim(u_rr, equations) + + v_dot_n_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] + + v3_ll * normal_direction[3] + v_dot_n_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] + + v3_rr * normal_direction[3] + + norm_ = norm(normal_direction) + + # `u_ll[5]` is total energy `rho_e_ll` on the left + H_ll = (u_ll[5] + p_ll) / rho_ll + c_ll = sqrt(equations.gamma * p_ll / rho_ll) * norm_ + + # `u_rr[5]` is total energy `rho_e_rr` on the right + H_rr = (u_rr[5] + p_rr) / rho_rr + c_rr = sqrt(equations.gamma * p_rr / rho_rr) * norm_ + + # Compute Roe averages + sqrt_rho_ll = sqrt(rho_ll) + sqrt_rho_rr = sqrt(rho_rr) + inv_sum_sqrt_rho = inv(sqrt_rho_ll + sqrt_rho_rr) + + v1_roe = (sqrt_rho_ll * v1_ll + sqrt_rho_rr * v1_rr) * inv_sum_sqrt_rho + v2_roe = (sqrt_rho_ll * v2_ll + sqrt_rho_rr * v2_rr) * inv_sum_sqrt_rho + v3_roe = (sqrt_rho_ll * v3_ll + sqrt_rho_rr * v3_rr) * inv_sum_sqrt_rho + v_roe = v1_roe * normal_direction[1] + v2_roe * normal_direction[2] + + v3_roe * normal_direction[3] + v_roe_mag = v1_roe^2 + v2_roe^2 + v3_roe^2 + + H_roe = (sqrt_rho_ll * H_ll + sqrt_rho_rr * H_rr) * inv_sum_sqrt_rho + c_roe = sqrt((equations.gamma - 1) * (H_roe - 0.5 * v_roe_mag)) * norm_ + + # Compute convenience constant for positivity preservation, see + # https://doi.org/10.1016/0021-9991(91)90211-3 + beta = sqrt(0.5 * (equations.gamma - 1) / equations.gamma) + + # Estimate the edges of the Riemann fan (with positivity conservation) + SsL = min(v_roe - c_roe, v_dot_n_ll - beta * c_ll, zero(v_roe)) + SsR = max(v_roe + c_roe, v_dot_n_rr + beta * c_rr, zero(v_roe)) + + return SsL, SsR end @inline function max_abs_speeds(u, equations::CompressibleEulerEquations3D) diff --git a/src/equations/numerical_fluxes.jl b/src/equations/numerical_fluxes.jl index 87010275f2c..71782644b17 100644 --- a/src/equations/numerical_fluxes.jl +++ b/src/equations/numerical_fluxes.jl @@ -304,6 +304,14 @@ See [`FluxHLL`](@ref). """ const flux_hll = FluxHLL() +""" + flux_hlle + +See [`min_max_speed_einfeldt`](@ref). +This is a [`FluxHLL`](@ref)-type two-wave solver with special estimates of the wave speeds. +""" +const flux_hlle = FluxHLL(min_max_speed_einfeldt) + # TODO: TrixiShallowWater: move the chen_noelle flux structure to the new package # An empty version of the `min_max_speed_chen_noelle` function is declared here diff --git a/test/test_p4est_2d.jl b/test/test_p4est_2d.jl index cf7250b246b..546e5bff8a6 100644 --- a/test/test_p4est_2d.jl +++ b/test/test_p4est_2d.jl @@ -200,6 +200,32 @@ end end end +@trixi_testset "elixir_euler_sedov.jl (HLLE)" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov.jl"), + l2=[ + 0.411541263324004, + 0.2558929632770186, + 0.2558929632770193, + 1.298715766843915, + ], + linf=[ + 1.3457201726152221, + 1.3138961427140758, + 1.313896142714079, + 6.293305112638921, + ], + surface_flux=flux_hlle, + tspan=(0.0, 0.3)) + # 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_blast_wave_amr.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blast_wave_amr.jl"), l2=[ diff --git a/test/test_p4est_3d.jl b/test/test_p4est_3d.jl index 63077deb436..346c61c7448 100644 --- a/test/test_p4est_3d.jl +++ b/test/test_p4est_3d.jl @@ -287,6 +287,34 @@ end end end +@trixi_testset "elixir_euler_sedov.jl (HLLE)" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov.jl"), + l2=[ + 0.09946224487902565, + 0.04863386374672001, + 0.048633863746720116, + 0.04863386374672032, + 0.3751015774232693, + ], + linf=[ + 0.789241521871487, + 0.42046970270100276, + 0.42046970270100276, + 0.4204697027010028, + 4.730877375538398, + ], + tspan=(0.0, 0.3), + surface_flux=flux_hlle) + # 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_source_terms_nonconforming_earth.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonconforming_earth.jl"), diff --git a/test/test_tree_1d_euler.jl b/test/test_tree_1d_euler.jl index f01124509cb..62afc5baee3 100644 --- a/test/test_tree_1d_euler.jl +++ b/test/test_tree_1d_euler.jl @@ -281,6 +281,22 @@ end end end +@trixi_testset "elixir_euler_sedov_blast_wave.jl (HLLE)" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov_blast_wave.jl"), + l2=[0.6442208390304879, 0.508817280068289, 0.9482809853033687], + linf=[3.007059066482486, 2.4678899558345506, 2.3952311739389787], + tspan=(0.0, 0.5), + surface_flux=flux_hlle) + # 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_blast_wave_pure_fv.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov_blast_wave_pure_fv.jl"), diff --git a/test/test_tree_2d_euler.jl b/test/test_tree_2d_euler.jl index af7c5d8324c..db36cb7d79f 100644 --- a/test/test_tree_2d_euler.jl +++ b/test/test_tree_2d_euler.jl @@ -422,6 +422,32 @@ end end end +@trixi_testset "elixir_euler_sedov_blast_wave.jl (HLLE)" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov_blast_wave.jl"), + l2=[ + 0.35267161504176747, + 0.17218309138797958, + 0.17218307467125854, + 0.6236143054619037, + ], + linf=[ + 2.77484045816607, + 1.8281111268370718, + 1.8281110470490887, + 6.24263735888126, + ], + tspan=(0.0, 0.5), + surface_flux=flux_hlle) + # 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_blast_wave_neuralnetwork_perssonperaire.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl"), diff --git a/test/test_tree_3d_euler.jl b/test/test_tree_3d_euler.jl index d96dcff3977..02e657e001a 100644 --- a/test/test_tree_3d_euler.jl +++ b/test/test_tree_3d_euler.jl @@ -473,6 +473,34 @@ end @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 end end + +@trixi_testset "elixir_euler_sedov_blast_wave.jl (HLLE)" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov_blast_wave.jl"), + l2=[ + 0.0007871241159752619, + 0.0037168004033428146, + 0.0037168004033428094, + 0.0037168004033428514, + 0.011119869089205635, + ], + linf=[ + 0.13982864363612468, + 0.786004687738243, + 0.786004687738243, + 0.7860046877382431, + 1.7082524045150382, + ], + tspan=(0.0, 0.01), + surface_flux=flux_hlle) + # 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 end # module diff --git a/test/test_unit.jl b/test/test_unit.jl index 5422db7a66d..a73dfab5504 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -911,7 +911,7 @@ end SVector(-1.2, 0.3)] for normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ + @test flux_hlle(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) end @@ -930,18 +930,15 @@ end SVector(-1.2, 0.3, 1.4)] for normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ + @test flux_hlle(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) end end @timed_testset "Consistency check for HLLE flux: SWE" begin - # Test HLL flux with min_max_speed_einfeldt - flux_hll = FluxHLL(min_max_speed_einfeldt) - equations = ShallowWaterEquations1D(gravity_constant = 9.81) u = SVector(1, 0.5, 0.0) - @test flux_hll(u, u, 1, equations) ≈ flux(u, 1, equations) + @test flux_hlle(u, u, 1, equations) ≈ flux(u, 1, equations) equations = ShallowWaterEquations2D(gravity_constant = 9.81) normal_directions = [SVector(1.0, 0.0), @@ -953,18 +950,17 @@ end u = SVector(1, 0.5, 0.5, 0.0) for orientation in orientations - @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hlle(u, u, orientation, equations) ≈ flux(u, orientation, equations) end for normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ + @test flux_hlle(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) end end @timed_testset "Consistency check for HLLE flux: MHD" begin - # Test HLL flux with min_max_speed_einfeldt - flux_hll = FluxHLL(min_max_speed_naive) + # Note: min_max_speed_naive for MHD is essentially min_max_speed_einfeldt equations = IdealGlmMhdEquations1D(1.4) u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1), @@ -1242,7 +1238,7 @@ end u = SVector(1, 0.5, 0.5, 0.0) fluxes = [flux_central, flux_fjordholm_etal, flux_wintermeyer_etal, - flux_hll, FluxHLL(min_max_speed_davis), FluxHLL(min_max_speed_einfeldt)] + flux_hll, FluxHLL(min_max_speed_davis), flux_hlle] end @timed_testset "IdealGlmMhdEquations2D" begin From 08a2e09fe41460c9f15c77cb084e8609c5d39e55 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Nov 2023 06:10:43 +0100 Subject: [PATCH 150/263] Bump crate-ci/typos from 1.16.15 to 1.16.21 (#1700) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.16.15 to 1.16.21. - [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.16.15...v1.16.21) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-type: direct:production update-type: version-update:semver-patch ... 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 eae6d8e0be9..fb71fe45af9 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.16.15 + uses: crate-ci/typos@v1.16.21 From 2ec512c56379294ecb4083c64023e7634d444b7e Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Fri, 3 Nov 2023 10:45:42 +0100 Subject: [PATCH 151/263] Add NumFOCUS + ACTRIX to acknowledgments (#1697) * Add NumFOCUS + ACTRIX to acknowledgments * Try to avoid spaces * Another try to avoid gaps between images * Hopefully fix image alignment in docs * Try new logo formats * Use smaller DUBS logo and add DUBS funding statement * Add markdown-based table for logos in docs * Try another table approach * Hopefully get a layout that finally *works*... * Arrrrrrgggggghhhhh --- README.md | 45 ++++++++++++++++++++++++++------------ docs/src/index.md | 55 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 73 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 673708d8b89..1d52089ae3e 100644 --- a/README.md +++ b/README.md @@ -256,31 +256,48 @@ or [create an issue](https://github.com/trixi-framework/Trixi.jl/issues/new). ## Acknowledgments -

- +

-This project has benefited from funding by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) -under Germany's Excellence Strategy EXC 2044-390685587, Mathematics Münster: -Dynamics-Geometry-Structure. - -This project has benefited from funding by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) -through the research unit FOR 5409 "Structure-Preserving Numerical Methods for Bulk- and -Interface Coupling of Heterogeneous Models (SNuBIC)" (project number 463312734). +This project has benefited from funding by the [Deutsche +Forschungsgemeinschaft](https://www.dfg.de/) (DFG, German Research Foundation) +through the following grants: +* Excellence Strategy EXC 2044-390685587, Mathematics Münster: Dynamics-Geometry-Structure. +* Research unit FOR 5409 "Structure-Preserving Numerical Methods for Bulk- and + Interface Coupling of Heterogeneous Models (SNuBIC)" (project number 463312734). +* Individual grant no. 528753982. -This project has benefited from funding from the European Research Council through the +This project has benefited from funding from the [European Research Council](https://erc.europa.eu) +through the ERC Starting Grant "An Exascale aware and Un-crashable Space-Time-Adaptive Discontinuous Spectral Element Solver for Non-Linear Conservation Laws" (Extreme), ERC grant agreement no. 714487. -This project has benefited from funding from Vetenskapsrådet (VR, Swedish Research Council), Sweden +This project has benefited from funding from [Vetenskapsrådet](https://www.vr.se) +(VR, Swedish Research Council), Sweden through the VR Starting Grant "Shallow water flows including sediment transport and morphodynamics", VR grant agreement 2020-03642 VR. -This project has benefited from funding from the United States National Science Foundation under awards +This project has benefited from funding from the United States +[National Science Foundation](https://www.nsf.gov/) (NSF) under awards DMS-1719818 and DMS-1943186. -This project has benefited from funding from the German Federal Ministry of -Education and Research through the project grant "Adaptive earth system modeling +This project has benefited from funding from the German +[Federal Ministry of Education and Research](https://www.bmbf.de) (BMBF) +through the project grant "Adaptive earth system modeling with significantly reduced computation time for exascale supercomputers (ADAPTEX)" (funding id: 16ME0668K). + +This project has benefited from funding by the +[Daimler und Benz Stiftung](https://www.daimler-benz-stiftung.de) (Daimler and Benz Foundation) +through grant no. 32-10/22. + +Trixi.jl is supported by [NumFOCUS](https://numfocus.org/) as an Affiliated Project. diff --git a/docs/src/index.md b/docs/src/index.md index 9ffaee26c40..fd923348928 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -344,29 +344,58 @@ or [create an issue](https://github.com/trixi-framework/Trixi.jl/issues/new). ## Acknowledgments -![funding-logo](https://user-images.githubusercontent.com/3637659/233821022-84910be7-8649-4999-a0ff-22d5e20f0b90.jpg) - -This project has benefited from funding by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) -under Germany's Excellence Strategy EXC 2044-390685587, Mathematics Münster: -Dynamics-Geometry-Structure. +```@raw html +
+
+
+
+
+
+
+
+``` -This project has benefited from funding by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) -through the research unit FOR 5409 "Structure-Preserving Numerical Methods for Bulk- and -Interface Coupling of Heterogeneous Models (SNuBIC)" (project number 463312734). +This project has benefited from funding by the [Deutsche +Forschungsgemeinschaft](https://www.dfg.de/) (DFG, German Research Foundation) +through the following grants: +* Excellence Strategy EXC 2044-390685587, Mathematics Münster: Dynamics-Geometry-Structure. +* Research unit FOR 5409 "Structure-Preserving Numerical Methods for Bulk- and + Interface Coupling of Heterogeneous Models (SNuBIC)" (project number 463312734). +* Individual grant no. 528753982. -This project has benefited from funding from the European Research Council through the +This project has benefited from funding from the [European Research Council](https://erc.europa.eu) +through the ERC Starting Grant "An Exascale aware and Un-crashable Space-Time-Adaptive Discontinuous Spectral Element Solver for Non-Linear Conservation Laws" (Extreme), ERC grant agreement no. 714487. -This project has benefited from funding from Vetenskapsrådet (VR, Swedish Research Council), Sweden +This project has benefited from funding from [Vetenskapsrådet](https://www.vr.se) +(VR, Swedish Research Council), Sweden through the VR Starting Grant "Shallow water flows including sediment transport and morphodynamics", VR grant agreement 2020-03642 VR. -This project has benefited from funding from the United States National Science Foundation under awards +This project has benefited from funding from the United States +[National Science Foundation](https://www.nsf.gov/) (NSF) under awards DMS-1719818 and DMS-1943186. -This project has benefited from funding from the German Federal Ministry of -Education and Research through the project grant "Adaptive earth system modeling +This project has benefited from funding from the German +[Federal Ministry of Education and Research](https://www.bmbf.de) (BMBF) +through the project grant "Adaptive earth system modeling with significantly reduced computation time for exascale supercomputers (ADAPTEX)" (funding id: 16ME0668K). + +This project has benefited from funding by the +[Daimler und Benz Stiftung](https://www.daimler-benz-stiftung.de) (Daimler and Benz Foundation) +through grant no. 32-10/22. + +Trixi.jl is supported by [NumFOCUS](https://numfocus.org/) as an Affiliated Project. From c79fa4324726b6894317056c3ece2906ccb9c08d Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 3 Nov 2023 13:47:05 +0100 Subject: [PATCH 152/263] format examples (#1531) * format examples * check formatting of examples in CI * update style guide * fix weird formatting * fix formatting of binary operators * format again --- .github/workflows/FormatCheck.yml | 2 +- docs/src/styleguide.md | 18 +- .../dgmulti_1d/elixir_advection_gauss_sbp.jl | 13 +- .../dgmulti_1d/elixir_euler_fdsbp_periodic.jl | 23 +- examples/dgmulti_1d/elixir_euler_flux_diff.jl | 12 +- .../dgmulti_2d/elixir_advection_diffusion.jl | 38 +- .../elixir_advection_diffusion_nonperiodic.jl | 54 +-- .../elixir_advection_diffusion_periodic.jl | 12 +- examples/dgmulti_2d/elixir_euler_bilinear.jl | 29 +- .../elixir_euler_brown_minion_vortex.jl | 32 +- examples/dgmulti_2d/elixir_euler_curved.jl | 22 +- .../dgmulti_2d/elixir_euler_fdsbp_periodic.jl | 23 +- examples/dgmulti_2d/elixir_euler_hohqmesh.jl | 27 +- ...ixir_euler_kelvin_helmholtz_instability.jl | 35 +- ...lixir_euler_rayleigh_taylor_instability.jl | 58 +-- .../dgmulti_2d/elixir_euler_shockcapturing.jl | 27 +- .../elixir_euler_shockcapturing_curved.jl | 31 +- .../elixir_euler_triangulate_pkg_mesh.jl | 12 +- examples/dgmulti_2d/elixir_euler_weakform.jl | 21 +- .../elixir_euler_weakform_periodic.jl | 10 +- .../dgmulti_2d/elixir_mhd_reflective_wall.jl | 93 ++-- .../dgmulti_2d/elixir_mhd_weak_blast_wave.jl | 20 +- .../elixir_mhd_weak_blast_wave_SBP.jl | 17 +- .../elixir_navierstokes_convergence.jl | 300 ++++++------ .../elixir_navierstokes_convergence_curved.jl | 307 +++++++------ .../elixir_navierstokes_lid_driven_cavity.jl | 38 +- .../elixir_shallowwater_source_terms.jl | 19 +- .../elixir_advection_tensor_wedge.jl | 22 +- examples/dgmulti_3d/elixir_euler_curved.jl | 26 +- .../dgmulti_3d/elixir_euler_fdsbp_periodic.jl | 21 +- .../elixir_euler_taylor_green_vortex.jl | 45 +- examples/dgmulti_3d/elixir_euler_weakform.jl | 16 +- .../elixir_euler_weakform_periodic.jl | 10 +- .../elixir_navierstokes_convergence.jl | 401 ++++++++-------- .../elixir_navierstokes_convergence_curved.jl | 409 +++++++++-------- ...elixir_navierstokes_taylor_green_vortex.jl | 50 +- ...ixir_advection_amr_solution_independent.jl | 149 +++--- .../elixir_advection_amr_unstructured_flag.jl | 66 ++- .../p4est_2d_dgsem/elixir_advection_basic.jl | 32 +- ..._advection_diffusion_nonperiodic_curved.jl | 54 +-- .../elixir_advection_diffusion_periodic.jl | 30 +- ...xir_advection_diffusion_periodic_curved.jl | 34 +- .../elixir_advection_extended.jl | 50 +- .../elixir_advection_nonconforming_flag.jl | 55 +-- .../elixir_advection_restart.jl | 10 +- .../elixir_advection_unstructured_flag.jl | 44 +- .../elixir_euler_blast_wave_amr.jl | 96 ++-- .../elixir_euler_double_mach_amr.jl | 140 +++--- .../elixir_euler_forward_step_amr.jl | 152 ++++--- .../elixir_euler_free_stream.jl | 70 +-- examples/p4est_2d_dgsem/elixir_euler_sedov.jl | 79 ++-- .../elixir_euler_shockcapturing_ec.jl | 44 +- ...e_terms_nonconforming_unstructured_flag.jl | 70 +-- .../elixir_euler_supersonic_cylinder.jl | 102 +++-- .../elixir_euler_wall_bc_amr.jl | 82 ++-- .../elixir_eulergravity_convergence.jl | 60 ++- .../elixir_linearizedeuler_gaussian_source.jl | 55 +-- .../p4est_2d_dgsem/elixir_mhd_alfven_wave.jl | 29 +- examples/p4est_2d_dgsem/elixir_mhd_rotor.jl | 126 +++--- .../elixir_navierstokes_convergence.jl | 307 +++++++------ ...ir_navierstokes_convergence_nonperiodic.jl | 308 +++++++------ .../elixir_navierstokes_lid_driven_cavity.jl | 54 ++- .../elixir_shallowwater_source_terms.jl | 31 +- .../p4est_3d_dgsem/elixir_advection_amr.jl | 48 +- ...lixir_advection_amr_unstructured_curved.jl | 103 ++--- .../p4est_3d_dgsem/elixir_advection_basic.jl | 35 +- .../elixir_advection_cubed_sphere.jl | 31 +- .../elixir_advection_nonconforming.jl | 54 +-- .../elixir_advection_restart.jl | 13 +- .../elixir_advection_unstructured_curved.jl | 83 ++-- .../elixir_euler_baroclinic_instability.jl | 370 +++++++-------- ...lixir_euler_circular_wind_nonconforming.jl | 126 +++--- examples/p4est_3d_dgsem/elixir_euler_ec.jl | 81 ++-- .../elixir_euler_free_stream.jl | 104 +++-- .../elixir_euler_free_stream_extruded.jl | 86 ++-- examples/p4est_3d_dgsem/elixir_euler_sedov.jl | 86 ++-- ..._euler_source_terms_nonconforming_earth.jl | 108 +++-- ...terms_nonconforming_unstructured_curved.jl | 107 ++--- .../elixir_euler_source_terms_nonperiodic.jl | 52 +-- ...euler_source_terms_nonperiodic_hohqmesh.jl | 45 +- .../elixir_mhd_alfven_wave_nonconforming.jl | 58 +-- .../elixir_mhd_shockcapturing_amr.jl | 124 ++--- .../elixir_navierstokes_convergence.jl | 420 ++++++++--------- ...elixir_navierstokes_taylor_green_vortex.jl | 70 +-- .../elixir_euler_convergence.jl | 31 +- .../elixir_eulergravity_convergence.jl | 54 +-- .../elixir_eulergravity_jeans_instability.jl | 164 +++---- .../elixir_eulergravity_sedov_blast_wave.jl | 219 ++++----- .../elixir_hypdiff_convergence.jl | 45 +- examples/special_elixirs/elixir_euler_ad.jl | 78 ++-- .../elixir_advection_basic.jl | 24 +- .../elixir_advection_nonperiodic.jl | 35 +- .../elixir_advection_shockcapturing.jl | 81 ++-- .../structured_1d_dgsem/elixir_euler_sedov.jl | 77 ++-- .../elixir_euler_source_terms.jl | 31 +- .../elixir_euler_source_terms_nonperiodic.jl | 39 +- .../elixir_advection_basic.jl | 26 +- .../elixir_advection_coupled.jl | 74 +-- .../elixir_advection_extended.jl | 34 +- .../elixir_advection_free_stream.jl | 41 +- .../elixir_advection_nonperiodic.jl | 32 +- .../elixir_advection_parallelogram.jl | 57 ++- .../elixir_advection_restart.jl | 7 +- .../elixir_advection_rotated.jl | 69 ++- .../elixir_advection_waving_flag.jl | 29 +- .../structured_2d_dgsem/elixir_euler_ec.jl | 38 +- .../elixir_euler_free_stream.jl | 39 +- ...lixir_euler_rayleigh_taylor_instability.jl | 72 ++- .../structured_2d_dgsem/elixir_euler_sedov.jl | 79 ++-- .../elixir_euler_source_terms.jl | 26 +- .../elixir_euler_source_terms_nonperiodic.jl | 41 +- ...elixir_euler_source_terms_parallelogram.jl | 26 +- .../elixir_euler_source_terms_rotated.jl | 105 +++-- .../elixir_euler_source_terms_waving_flag.jl | 30 +- .../elixir_eulerpolytropic_ec.jl | 38 +- .../elixir_hypdiff_harmonic_nonperiodic.jl | 72 ++- .../elixir_hypdiff_nonperiodic.jl | 57 ++- .../elixir_mhd_alfven_wave.jl | 62 +-- examples/structured_2d_dgsem/elixir_mhd_ec.jl | 88 ++-- .../elixir_mhd_ec_shockcapturing.jl | 35 +- .../elixir_shallowwater_conical_island.jl | 75 +-- .../elixir_shallowwater_parabolic_bowl.jl | 80 ++-- .../elixir_shallowwater_source_terms.jl | 31 +- .../elixir_shallowwater_well_balanced.jl | 88 ++-- ...ixir_shallowwater_well_balanced_wet_dry.jl | 163 +++---- .../elixir_advection_basic.jl | 30 +- .../elixir_advection_free_stream.jl | 58 +-- .../elixir_advection_nonperiodic_curved.jl | 72 +-- .../elixir_advection_restart.jl | 13 +- .../structured_3d_dgsem/elixir_euler_ec.jl | 63 +-- .../elixir_euler_free_stream.jl | 69 +-- .../structured_3d_dgsem/elixir_euler_sedov.jl | 88 ++-- .../elixir_euler_source_terms.jl | 28 +- ...r_euler_source_terms_nonperiodic_curved.jl | 85 ++-- .../elixir_mhd_alfven_wave.jl | 37 +- examples/structured_3d_dgsem/elixir_mhd_ec.jl | 67 +-- .../elixir_mhd_ec_shockcapturing.jl | 71 +-- .../elixir_eulergravity_convergence.jl | 39 +- .../t8code_2d_dgsem/elixir_mhd_alfven_wave.jl | 28 +- .../elixir_shallowwater_source_terms.jl | 25 +- .../tree_1d_dgsem/elixir_advection_amr.jl | 47 +- .../elixir_advection_amr_nonperiodic.jl | 53 +-- .../tree_1d_dgsem/elixir_advection_basic.jl | 30 +- .../elixir_advection_diffusion.jl | 68 +-- .../elixir_advection_extended.jl | 40 +- .../elixir_advection_finite_volume.jl | 21 +- .../tree_1d_dgsem/elixir_burgers_basic.jl | 35 +- .../elixir_burgers_linear_stability.jl | 36 +- .../elixir_burgers_rarefaction.jl | 61 ++- .../tree_1d_dgsem/elixir_burgers_shock.jl | 57 ++- .../tree_1d_dgsem/elixir_euler_blast_wave.jl | 77 ++-- ...blast_wave_neuralnetwork_perssonperaire.jl | 89 ++-- ...r_blast_wave_neuralnetwork_rayhesthaven.jl | 89 ++-- .../elixir_euler_convergence_pure_fv.jl | 37 +- .../elixir_euler_density_wave.jl | 30 +- examples/tree_1d_dgsem/elixir_euler_ec.jl | 33 +- .../tree_1d_dgsem/elixir_euler_positivity.jl | 101 ++--- .../elixir_euler_sedov_blast_wave.jl | 100 ++-- .../elixir_euler_sedov_blast_wave_pure_fv.jl | 86 ++-- .../elixir_euler_shockcapturing.jl | 43 +- .../elixir_euler_source_terms.jl | 35 +- .../elixir_euler_source_terms_nonperiodic.jl | 43 +- .../elixir_eulergravity_convergence.jl | 54 ++- .../elixir_eulermulti_convergence_ec.jl | 37 +- .../elixir_eulermulti_convergence_es.jl | 37 +- .../tree_1d_dgsem/elixir_eulermulti_ec.jl | 38 +- .../tree_1d_dgsem/elixir_eulermulti_es.jl | 42 +- ..._eulermulti_two_interacting_blast_waves.jl | 98 ++-- .../elixir_hypdiff_harmonic_nonperiodic.jl | 63 ++- .../elixir_hypdiff_nonperiodic.jl | 38 +- .../tree_1d_dgsem/elixir_mhd_alfven_wave.jl | 45 +- .../elixir_mhd_briowu_shock_tube.jl | 91 ++-- examples/tree_1d_dgsem/elixir_mhd_ec.jl | 35 +- .../elixir_mhd_ryujones_shock_tube.jl | 71 ++- .../elixir_mhd_shu_osher_shock_tube.jl | 128 +++--- .../elixir_mhd_torrilhon_shock_tube.jl | 73 ++- .../elixir_mhdmulti_briowu_shock_tube.jl | 122 ++--- .../elixir_mhdmulti_convergence.jl | 36 +- examples/tree_1d_dgsem/elixir_mhdmulti_ec.jl | 33 +- examples/tree_1d_dgsem/elixir_mhdmulti_es.jl | 37 +- ...lixir_navierstokes_convergence_periodic.jl | 166 +++---- .../elixir_navierstokes_convergence_walls.jl | 212 ++++----- ...ixir_navierstokes_convergence_walls_amr.jl | 226 ++++----- .../elixir_shallowwater_beach.jl | 100 ++-- .../tree_1d_dgsem/elixir_shallowwater_ec.jl | 63 +-- .../elixir_shallowwater_parabolic_bowl.jl | 82 ++-- .../elixir_shallowwater_shock_capturing.jl | 83 ++-- .../elixir_shallowwater_source_terms.jl | 30 +- ...xir_shallowwater_source_terms_dirichlet.jl | 28 +- ...lixir_shallowwater_twolayer_convergence.jl | 32 +- .../elixir_shallowwater_twolayer_dam_break.jl | 71 +-- ...xir_shallowwater_twolayer_well_balanced.jl | 42 +- .../elixir_shallowwater_well_balanced.jl | 57 +-- ..._shallowwater_well_balanced_nonperiodic.jl | 48 +- ...ixir_shallowwater_well_balanced_wet_dry.jl | 141 +++--- .../tree_1d_fdsbp/elixir_advection_upwind.jl | 12 +- .../elixir_advection_upwind_periodic.jl | 12 +- .../tree_1d_fdsbp/elixir_burgers_basic.jl | 40 +- .../elixir_burgers_linear_stability.jl | 39 +- .../tree_1d_fdsbp/elixir_euler_convergence.jl | 40 +- .../elixir_euler_density_wave.jl | 36 +- .../elixir_acoustics_convergence.jl | 31 +- .../tree_2d_dgsem/elixir_acoustics_gauss.jl | 27 +- .../elixir_acoustics_gauss_wall.jl | 40 +- .../elixir_acoustics_gaussian_source.jl | 53 ++- .../elixir_acoustics_monopole.jl | 134 +++--- .../tree_2d_dgsem/elixir_advection_amr.jl | 47 +- .../elixir_advection_amr_coarsen_twice.jl | 69 ++- .../elixir_advection_amr_nonperiodic.jl | 50 +- .../elixir_advection_amr_refine_twice.jl | 69 ++- ...ixir_advection_amr_solution_independent.jl | 141 +++--- .../elixir_advection_amr_visualization.jl | 60 ++- .../tree_2d_dgsem/elixir_advection_basic.jl | 30 +- .../elixir_advection_callbacks.jl | 132 +++--- .../elixir_advection_diffusion.jl | 49 +- .../elixir_advection_diffusion_nonperiodic.jl | 48 +- .../elixir_advection_extended.jl | 40 +- .../tree_2d_dgsem/elixir_advection_mortar.jl | 40 +- .../tree_2d_dgsem/elixir_advection_restart.jl | 10 +- .../elixir_advection_timeintegration.jl | 45 +- .../elixir_euler_astro_jet_amr.jl | 119 +++-- .../tree_2d_dgsem/elixir_euler_blast_wave.jl | 75 ++- .../elixir_euler_blast_wave_amr.jl | 93 ++-- ...ixir_euler_blast_wave_neuralnetwork_cnn.jl | 86 ++-- ...blast_wave_neuralnetwork_perssonperaire.jl | 86 ++-- ...r_blast_wave_neuralnetwork_rayhesthaven.jl | 88 ++-- .../elixir_euler_blast_wave_pure_fv.jl | 63 ++- .../tree_2d_dgsem/elixir_euler_blob_amr.jl | 131 +++--- .../tree_2d_dgsem/elixir_euler_blob_mortar.jl | 119 +++-- .../elixir_euler_colliding_flow.jl | 116 ++--- .../elixir_euler_colliding_flow_amr.jl | 119 +++-- .../elixir_euler_convergence_pure_fv.jl | 28 +- .../elixir_euler_density_wave.jl | 31 +- examples/tree_2d_dgsem/elixir_euler_ec.jl | 37 +- ...ixir_euler_kelvin_helmholtz_instability.jl | 66 +-- ..._euler_kelvin_helmholtz_instability_amr.jl | 88 ++-- ...bility_amr_neuralnetwork_perssonperaire.jl | 124 ++--- ...in_helmholtz_instability_fjordholm_etal.jl | 128 +++--- .../tree_2d_dgsem/elixir_euler_positivity.jl | 104 ++--- .../elixir_euler_sedov_blast_wave.jl | 102 ++--- ...blast_wave_neuralnetwork_perssonperaire.jl | 121 +++-- .../elixir_euler_shockcapturing.jl | 43 +- .../elixir_euler_shockcapturing_subcell.jl | 72 ++- .../elixir_euler_source_terms.jl | 30 +- ...r_euler_source_terms_amr_refine_coarsen.jl | 86 ++-- .../elixir_euler_source_terms_nonperiodic.jl | 47 +- examples/tree_2d_dgsem/elixir_euler_vortex.jl | 98 ++-- .../tree_2d_dgsem/elixir_euler_vortex_amr.jl | 191 ++++---- .../elixir_euler_vortex_mortar.jl | 104 ++--- ...ixir_euler_vortex_mortar_shockcapturing.jl | 114 ++--- .../elixir_euler_vortex_mortar_split.jl | 106 ++--- .../elixir_euler_vortex_shockcapturing.jl | 110 ++--- ..._euleracoustics_co-rotating_vortex_pair.jl | 377 +++++++-------- .../elixir_eulermulti_convergence_ec.jl | 37 +- .../elixir_eulermulti_convergence_es.jl | 37 +- .../tree_2d_dgsem/elixir_eulermulti_ec.jl | 38 +- .../tree_2d_dgsem/elixir_eulermulti_es.jl | 39 +- .../elixir_eulermulti_shock_bubble.jl | 214 ++++----- ...ubble_shockcapturing_subcell_positivity.jl | 199 ++++---- .../tree_2d_dgsem/elixir_hypdiff_godunov.jl | 88 ++-- .../elixir_hypdiff_harmonic_nonperiodic.jl | 76 ++-- .../elixir_hypdiff_lax_friedrichs.jl | 86 ++-- .../elixir_hypdiff_nonperiodic.jl | 45 +- examples/tree_2d_dgsem/elixir_kpp.jl | 73 +-- examples/tree_2d_dgsem/elixir_lbm_constant.jl | 37 +- examples/tree_2d_dgsem/elixir_lbm_couette.jl | 113 +++-- .../elixir_lbm_lid_driven_cavity.jl | 89 ++-- .../elixir_linearizedeuler_convergence.jl | 31 +- .../elixir_linearizedeuler_gauss_wall.jl | 38 +- .../tree_2d_dgsem/elixir_mhd_alfven_wave.jl | 45 +- .../elixir_mhd_alfven_wave_mortar.jl | 49 +- .../tree_2d_dgsem/elixir_mhd_blast_wave.jl | 102 ++--- examples/tree_2d_dgsem/elixir_mhd_ec.jl | 36 +- .../tree_2d_dgsem/elixir_mhd_orszag_tang.jl | 86 ++-- examples/tree_2d_dgsem/elixir_mhd_rotor.jl | 113 +++-- .../elixir_mhd_shockcapturing_subcell.jl | 92 ++-- .../elixir_mhdmulti_convergence.jl | 39 +- examples/tree_2d_dgsem/elixir_mhdmulti_ec.jl | 40 +- examples/tree_2d_dgsem/elixir_mhdmulti_es.jl | 40 +- .../tree_2d_dgsem/elixir_mhdmulti_rotor.jl | 121 +++-- .../elixir_navierstokes_convergence.jl | 315 ++++++------- .../elixir_navierstokes_lid_driven_cavity.jl | 45 +- .../elixir_navierstokes_shearlayer_amr.jl | 71 ++- ...elixir_navierstokes_taylor_green_vortex.jl | 53 +-- .../elixir_shallowwater_conical_island.jl | 75 +-- .../tree_2d_dgsem/elixir_shallowwater_ec.jl | 100 ++-- .../elixir_shallowwater_parabolic_bowl.jl | 83 ++-- .../elixir_shallowwater_source_terms.jl | 30 +- ...xir_shallowwater_source_terms_dirichlet.jl | 29 +- ...lixir_shallowwater_twolayer_convergence.jl | 31 +- ...xir_shallowwater_twolayer_well_balanced.jl | 55 +-- .../elixir_shallowwater_well_balanced.jl | 89 ++-- .../elixir_shallowwater_well_balanced_wall.jl | 89 ++-- ...ixir_shallowwater_well_balanced_wet_dry.jl | 156 ++++--- .../elixir_advection_extended.jl | 28 +- .../tree_2d_fdsbp/elixir_euler_convergence.jl | 41 +- ...ixir_euler_kelvin_helmholtz_instability.jl | 69 ++- examples/tree_2d_fdsbp/elixir_euler_vortex.jl | 102 ++--- .../tree_3d_dgsem/elixir_advection_amr.jl | 46 +- .../tree_3d_dgsem/elixir_advection_basic.jl | 30 +- .../elixir_advection_diffusion_amr.jl | 76 ++-- .../elixir_advection_diffusion_nonperiodic.jl | 52 +-- .../elixir_advection_extended.jl | 40 +- .../tree_3d_dgsem/elixir_advection_mortar.jl | 43 +- .../tree_3d_dgsem/elixir_advection_restart.jl | 8 +- examples/tree_3d_dgsem/elixir_euler_amr.jl | 71 ++- .../tree_3d_dgsem/elixir_euler_blob_amr.jl | 137 +++--- .../tree_3d_dgsem/elixir_euler_convergence.jl | 33 +- .../elixir_euler_convergence_pure_fv.jl | 33 +- .../elixir_euler_density_pulse.jl | 57 ++- examples/tree_3d_dgsem/elixir_euler_ec.jl | 33 +- examples/tree_3d_dgsem/elixir_euler_mortar.jl | 37 +- .../elixir_euler_sedov_blast_wave.jl | 159 ++++--- .../elixir_euler_shockcapturing.jl | 43 +- .../elixir_euler_shockcapturing_amr.jl | 58 ++- .../elixir_euler_source_terms.jl | 33 +- .../elixir_euler_taylor_green_vortex.jl | 61 +-- .../elixir_eulergravity_convergence.jl | 56 ++- .../elixir_hypdiff_lax_friedrichs.jl | 93 ++-- .../elixir_hypdiff_nonperiodic.jl | 49 +- examples/tree_3d_dgsem/elixir_lbm_constant.jl | 37 +- .../elixir_lbm_taylor_green_vortex.jl | 60 ++- .../tree_3d_dgsem/elixir_mhd_alfven_wave.jl | 38 +- .../elixir_mhd_alfven_wave_mortar.jl | 43 +- examples/tree_3d_dgsem/elixir_mhd_ec.jl | 36 +- .../elixir_mhd_ec_shockcapturing.jl | 38 +- .../elixir_navierstokes_convergence.jl | 428 +++++++++--------- ...elixir_navierstokes_taylor_green_vortex.jl | 58 +-- .../elixir_advection_extended.jl | 28 +- .../tree_3d_fdsbp/elixir_euler_convergence.jl | 40 +- .../elixir_euler_taylor_green_vortex.jl | 72 +-- .../elixir_acoustics_gauss_wall.jl | 45 +- .../elixir_advection_basic.jl | 29 +- .../elixir_euler_basic.jl | 43 +- .../unstructured_2d_dgsem/elixir_euler_ec.jl | 31 +- .../elixir_euler_free_stream.jl | 41 +- .../elixir_euler_periodic.jl | 19 +- .../elixir_euler_restart.jl | 13 +- .../elixir_euler_sedov.jl | 78 ++-- .../elixir_euler_wall_bc.jl | 64 +-- .../elixir_mhd_alfven_wave.jl | 49 +- .../unstructured_2d_dgsem/elixir_mhd_ec.jl | 79 ++-- .../elixir_shallowwater_dirichlet.jl | 51 ++- .../elixir_shallowwater_ec.jl | 101 +++-- .../elixir_shallowwater_ec_shockcapturing.jl | 104 +++-- .../elixir_shallowwater_source_terms.jl | 33 +- ...ixir_shallowwater_three_mound_dam_break.jl | 99 ++-- ...lixir_shallowwater_twolayer_convergence.jl | 34 +- .../elixir_shallowwater_twolayer_dam_break.jl | 139 +++--- ...xir_shallowwater_twolayer_well_balanced.jl | 58 +-- ...xir_shallowwater_wall_bc_shockcapturing.jl | 82 ++-- .../elixir_shallowwater_well_balanced.jl | 92 ++-- 352 files changed, 12593 insertions(+), 12638 deletions(-) diff --git a/.github/workflows/FormatCheck.yml b/.github/workflows/FormatCheck.yml index 81d18f4105e..a733cb7cc21 100644 --- a/.github/workflows/FormatCheck.yml +++ b/.github/workflows/FormatCheck.yml @@ -30,7 +30,7 @@ jobs: # format(".") run: | julia -e 'using Pkg; Pkg.add(PackageSpec(name = "JuliaFormatter"))' - julia -e 'using JuliaFormatter; format(["benchmark", "ext", "src", "test", "utils"])' + julia -e 'using JuliaFormatter; format(["benchmark", "examples", "ext", "src", "test", "utils"])' - name: Format check run: | julia -e ' diff --git a/docs/src/styleguide.md b/docs/src/styleguide.md index 60e227204ca..2f28dbfcb17 100644 --- a/docs/src/styleguide.md +++ b/docs/src/styleguide.md @@ -17,11 +17,11 @@ conventions, we apply and enforce automated source code formatting * Maximum line length (strictly): **92**. * Functions that mutate their *input* are named with a trailing `!`. * Functions order their parameters [similar to Julia Base](https://docs.julialang.org/en/v1/manual/style-guide/#Write-functions-with-argument-ordering-similar-to-Julia-Base-1). - * The main modified argument comes first. For example, if the right-hand side `du` is modified, - it should come first. If only the `cache` is modified, e.g., in `prolong2interfaces!` + * The main modified argument comes first. For example, if the right-hand side `du` is modified, + it should come first. If only the `cache` is modified, e.g., in `prolong2interfaces!` and its siblings, put the `cache` first. * Otherwise, use the order `mesh, equations, solver, cache`. - * If something needs to be specified in more detail for dispatch, put the additional argument before the general one + * If something needs to be specified in more detail for dispatch, put the additional argument before the general one that is specified in more detail. For example, we use `have_nonconservative_terms(equations), equations` and `dg.mortar, dg`. * Prefer `for i in ...` to `for i = ...` for better semantic clarity and greater flexibility. @@ -55,7 +55,7 @@ julia -e 'using Pkg; Pkg.add("JuliaFormatter")' ``` You can then recursively format the core Julia files in the Trixi.jl repo by executing ```shell -julia -e 'using JuliaFormatter; format(["benchmark", "ext", "src", "utils"])' +julia -e 'using JuliaFormatter; format(["benchmark", "examples", "ext", "src", "test", "utils"])' ``` from inside the Trixi.jl repository. For convenience, there is also a script you can directly run from your terminal shell, which will automatically install JuliaFormatter in a @@ -67,12 +67,12 @@ You can get more information about using the convenience script by running it wi `--help`/`-h` flag. ### Checking formatting before committing -It can be convenient to check the formatting of source code automatically before each commit. +It can be convenient to check the formatting of source code automatically before each commit. We use git-hooks for it and provide a `pre-commit` script in the `utils` folder. The script uses -[JuliaFormatter.jl](https://github.com/domluna/JuliaFormatter.jl) just like formatting script that -runs over the whole Trixi.jl directory. -You can copy the `pre-commit`-script into `.git/hooks/pre-commit` and it will check your formatting +[JuliaFormatter.jl](https://github.com/domluna/JuliaFormatter.jl) just like formatting script that +runs over the whole Trixi.jl directory. +You can copy the `pre-commit`-script into `.git/hooks/pre-commit` and it will check your formatting before each commit. If errors are found the commit is aborted and you can add the corrections via -```shell +```shell git add -p ``` diff --git a/examples/dgmulti_1d/elixir_advection_gauss_sbp.jl b/examples/dgmulti_1d/elixir_advection_gauss_sbp.jl index d06ed05a621..09d66fe8aea 100644 --- a/examples/dgmulti_1d/elixir_advection_gauss_sbp.jl +++ b/examples/dgmulti_1d/elixir_advection_gauss_sbp.jl @@ -23,8 +23,8 @@ dg = DGMulti(polydeg = 3, cells_per_dimension = (8,) mesh = DGMultiMesh(dg, cells_per_dimension, - coordinates_min=(-1.0,), coordinates_max=(1.0,), - periodicity=true) + coordinates_min = (-1.0,), coordinates_max = (1.0,), + periodicity = true) ############################################################################### # setup the test problem (no source term needed for linear advection) @@ -49,10 +49,10 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() # analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = 100, uEltype = real(dg)) # handles the re-calculation of the maximum Δt after each time step -stepsize_callback = StepsizeCallback(cfl=0.75) +stepsize_callback = StepsizeCallback(cfl = 0.75) # collect all callbacks such that they can be passed to the ODE solver callbacks = CallbackSet(summary_callback, analysis_callback, stepsize_callback) @@ -60,9 +60,8 @@ callbacks = CallbackSet(summary_callback, analysis_callback, stepsize_callback) ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=1.0, save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0, save_everystep = false, callback = callbacks); # Print the timer summary summary_callback() - diff --git a/examples/dgmulti_1d/elixir_euler_fdsbp_periodic.jl b/examples/dgmulti_1d/elixir_euler_fdsbp_periodic.jl index 3566185d110..6abd7118fe3 100644 --- a/examples/dgmulti_1d/elixir_euler_fdsbp_periodic.jl +++ b/examples/dgmulti_1d/elixir_euler_fdsbp_periodic.jl @@ -2,8 +2,10 @@ using Trixi, OrdinaryDiffEq dg = DGMulti(element_type = Line(), - approximation_type = periodic_derivative_operator( - derivative_order=1, accuracy_order=4, xmin=0.0, xmax=1.0, N=50), + approximation_type = periodic_derivative_operator(derivative_order = 1, + accuracy_order = 4, + xmin = 0.0, xmax = 1.0, + N = 50), surface_flux = flux_hll, volume_integral = VolumeIntegralWeakForm()) @@ -11,8 +13,8 @@ equations = CompressibleEulerEquations1D(1.4) initial_condition = initial_condition_convergence_test source_terms = source_terms_convergence_test -mesh = DGMultiMesh(dg, coordinates_min=(-1.0,), - coordinates_max=( 1.0,)) +mesh = DGMultiMesh(dg, coordinates_min = (-1.0,), + coordinates_max = (1.0,)) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg, source_terms = source_terms) @@ -21,15 +23,16 @@ tspan = (0.0, 0.4) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) -stepsize_callback = StepsizeCallback(cfl=1.0) -callbacks = CallbackSet(summary_callback, alive_callback, stepsize_callback, analysis_callback) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) +stepsize_callback = StepsizeCallback(cfl = 1.0) +callbacks = CallbackSet(summary_callback, alive_callback, stepsize_callback, + analysis_callback) ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt = 0.5 * estimate_dt(mesh, dg), save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 0.5 * estimate_dt(mesh, dg), save_everystep = false, callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/dgmulti_1d/elixir_euler_flux_diff.jl b/examples/dgmulti_1d/elixir_euler_flux_diff.jl index 489b23e37b2..56a24d25d07 100644 --- a/examples/dgmulti_1d/elixir_euler_flux_diff.jl +++ b/examples/dgmulti_1d/elixir_euler_flux_diff.jl @@ -13,17 +13,17 @@ source_terms = source_terms_convergence_test cells_per_dimension = (8,) mesh = DGMultiMesh(dg, cells_per_dimension, - coordinates_min=(-1.0,), coordinates_max=(1.0,), periodicity=true) + coordinates_min = (-1.0,), coordinates_max = (1.0,), periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg; - source_terms=source_terms) + source_terms = source_terms) tspan = (0.0, 1.1) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) @@ -31,7 +31,7 @@ callbacks = CallbackSet(summary_callback, ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt = 0.5 * estimate_dt(mesh, dg), save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 0.5 * estimate_dt(mesh, dg), save_everystep = false, callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_advection_diffusion.jl b/examples/dgmulti_2d/elixir_advection_diffusion.jl index 8a79e9700ac..ce7b0e745a4 100644 --- a/examples/dgmulti_2d/elixir_advection_diffusion.jl +++ b/examples/dgmulti_2d/elixir_advection_diffusion.jl @@ -11,48 +11,52 @@ initial_condition_zero(x, t, equations::LinearScalarAdvectionEquation2D) = SVect initial_condition = initial_condition_zero # tag different boundary segments -left(x, tol=50*eps()) = abs(x[1] + 1) < tol -right(x, tol=50*eps()) = abs(x[1] - 1) < tol -bottom(x, tol=50*eps()) = abs(x[2] + 1) < tol -top(x, tol=50*eps()) = abs(x[2] - 1) < tol +left(x, tol = 50 * eps()) = abs(x[1] + 1) < tol +right(x, tol = 50 * eps()) = abs(x[1] - 1) < tol +bottom(x, tol = 50 * eps()) = abs(x[2] + 1) < tol +top(x, tol = 50 * eps()) = abs(x[2] - 1) < tol is_on_boundary = Dict(:left => left, :right => right, :top => top, :bottom => bottom) cells_per_dimension = (16, 16) mesh = DGMultiMesh(dg, cells_per_dimension; is_on_boundary) # BC types -boundary_condition_left = BoundaryConditionDirichlet((x, t, equations) -> SVector(1 + 0.1 * x[2])) +boundary_condition_left = BoundaryConditionDirichlet((x, t, equations) -> SVector(1 + + 0.1 * + x[2])) boundary_condition_zero = BoundaryConditionDirichlet((x, t, equations) -> SVector(0.0)) boundary_condition_neumann_zero = BoundaryConditionNeumann((x, t, equations) -> SVector(0.0)) # define inviscid boundary conditions boundary_conditions = (; :left => boundary_condition_left, - :bottom => boundary_condition_zero, - :top => boundary_condition_do_nothing, - :right => boundary_condition_do_nothing) + :bottom => boundary_condition_zero, + :top => boundary_condition_do_nothing, + :right => boundary_condition_do_nothing) # define viscous boundary conditions boundary_conditions_parabolic = (; :left => boundary_condition_left, - :bottom => boundary_condition_zero, - :top => boundary_condition_zero, - :right => boundary_condition_neumann_zero) + :bottom => boundary_condition_zero, + :top => boundary_condition_zero, + :right => boundary_condition_neumann_zero) -semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, dg; - boundary_conditions=(boundary_conditions, boundary_conditions_parabolic)) +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, dg; + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic)) tspan = (0.0, 1.5) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, alive_callback) ############################################################################### # run the simulation time_int_tol = 1e-6 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl b/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl index 7e87d9f097d..d2f11f18507 100644 --- a/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl +++ b/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl @@ -16,61 +16,63 @@ equations_parabolic = LaplaceDiffusion2D(diffusivity(), equations) # to numerical partial differential equations. # [DOI](https://doi.org/10.1007/978-3-319-41640-3_6). function initial_condition_erikkson_johnson(x, t, equations) - l = 4 - epsilon = diffusivity() # Note: this requires epsilon < 0.6 due to the sqrt - lambda_1 = (-1 + sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) - lambda_2 = (-1 - sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) - r1 = (1 + sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) - s1 = (1 - sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) - u = exp(-l * t) * (exp(lambda_1 * x[1]) - exp(lambda_2 * x[1])) + - cos(pi * x[2]) * (exp(s1 * x[1]) - exp(r1 * x[1])) / (exp(-s1) - exp(-r1)) - return SVector{1}(u) + l = 4 + epsilon = diffusivity() # Note: this requires epsilon < 0.6 due to the sqrt + lambda_1 = (-1 + sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + lambda_2 = (-1 - sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + r1 = (1 + sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + s1 = (1 - sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + u = exp(-l * t) * (exp(lambda_1 * x[1]) - exp(lambda_2 * x[1])) + + cos(pi * x[2]) * (exp(s1 * x[1]) - exp(r1 * x[1])) / (exp(-s1) - exp(-r1)) + return SVector{1}(u) end initial_condition = initial_condition_erikkson_johnson # tag different boundary segments -left(x, tol=50*eps()) = abs(x[1] + 1) < tol -right(x, tol=50*eps()) = abs(x[1]) < tol -bottom(x, tol=50*eps()) = abs(x[2] + 0.5) < tol -top(x, tol=50*eps()) = abs(x[2] - 0.5) < tol -entire_boundary(x, tol=50*eps()) = true +left(x, tol = 50 * eps()) = abs(x[1] + 1) < tol +right(x, tol = 50 * eps()) = abs(x[1]) < tol +bottom(x, tol = 50 * eps()) = abs(x[2] + 0.5) < tol +top(x, tol = 50 * eps()) = abs(x[2] - 0.5) < tol +entire_boundary(x, tol = 50 * eps()) = true is_on_boundary = Dict(:left => left, :right => right, :top => top, :bottom => bottom, :entire_boundary => entire_boundary) cells_per_dimension = (16, 16) mesh = DGMultiMesh(dg, cells_per_dimension; - coordinates_min=(-1.0, -0.5), - coordinates_max=(0.0, 0.5), + coordinates_min = (-1.0, -0.5), + coordinates_max = (0.0, 0.5), is_on_boundary) # BC types boundary_condition = BoundaryConditionDirichlet(initial_condition) # define inviscid boundary conditions, enforce "do nothing" boundary condition at the outflow -boundary_conditions = (; :left => boundary_condition, - :top => boundary_condition, - :bottom => boundary_condition, - :right => boundary_condition_do_nothing) +boundary_conditions = (; :left => boundary_condition, + :top => boundary_condition, + :bottom => boundary_condition, + :right => boundary_condition_do_nothing) # define viscous boundary conditions boundary_conditions_parabolic = (; :entire_boundary => boundary_condition) -semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, dg; - boundary_conditions=(boundary_conditions, boundary_conditions_parabolic)) +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, dg; + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic)) tspan = (0.0, 1.5) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, alive_callback) ############################################################################### # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_advection_diffusion_periodic.jl b/examples/dgmulti_2d/elixir_advection_diffusion_periodic.jl index 76512f1e39f..c498e5468d3 100644 --- a/examples/dgmulti_2d/elixir_advection_diffusion_periodic.jl +++ b/examples/dgmulti_2d/elixir_advection_diffusion_periodic.jl @@ -8,12 +8,12 @@ equations = LinearScalarAdvectionEquation2D(0.0, 0.0) equations_parabolic = LaplaceDiffusion2D(5.0e-1, equations) function initial_condition_sharp_gaussian(x, t, equations::LinearScalarAdvectionEquation2D) - return SVector(exp(-100 * (x[1]^2 + x[2]^2))) + return SVector(exp(-100 * (x[1]^2 + x[2]^2))) end initial_condition = initial_condition_sharp_gaussian cells_per_dimension = (16, 16) -mesh = DGMultiMesh(dg, cells_per_dimension, periodicity=true) +mesh = DGMultiMesh(dg, cells_per_dimension, periodicity = true) semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, dg) @@ -21,16 +21,16 @@ tspan = (0.0, 0.1) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation time_int_tol = 1e-6 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - dt = time_int_tol, ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + dt = time_int_tol, ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_euler_bilinear.jl b/examples/dgmulti_2d/elixir_euler_bilinear.jl index bdd582610ea..cd498bf39b8 100644 --- a/examples/dgmulti_2d/elixir_euler_bilinear.jl +++ b/examples/dgmulti_2d/elixir_euler_bilinear.jl @@ -10,27 +10,28 @@ initial_condition = initial_condition_convergence_test source_terms = source_terms_convergence_test # example where we tag two separate boundary segments of the mesh -top_boundary(x, tol=50*eps()) = abs(x[2]-1) top_boundary, :rest => rest_of_boundary) function mapping(xi, eta) - x = xi + 0.1 * sin(pi * xi) * sin(pi * eta) - y = eta + 0.1 * sin(pi * xi) * sin(pi * eta) - return SVector(x, y) + x = xi + 0.1 * sin(pi * xi) * sin(pi * eta) + y = eta + 0.1 * sin(pi * xi) * sin(pi * eta) + return SVector(x, y) end cells_per_dimension = (16, 16) -vertex_coordinates, EToV = StartUpDG.uniform_mesh(dg.basis.element_type, cells_per_dimension...) +vertex_coordinates, EToV = StartUpDG.uniform_mesh(dg.basis.element_type, + cells_per_dimension...) for i in eachindex(vertex_coordinates[1]) - vx, vy = getindex.(vertex_coordinates, i) - setindex!.(vertex_coordinates, mapping(vx, vy), i) + vx, vy = getindex.(vertex_coordinates, i) + setindex!.(vertex_coordinates, mapping(vx, vy), i) end -mesh = DGMultiMesh(dg, vertex_coordinates, EToV, is_on_boundary=is_on_boundary) +mesh = DGMultiMesh(dg, vertex_coordinates, EToV, is_on_boundary = is_on_boundary) boundary_condition_convergence_test = BoundaryConditionDirichlet(initial_condition) boundary_conditions = (; :top => boundary_condition_convergence_test, - :rest => boundary_condition_convergence_test) + :rest => boundary_condition_convergence_test) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg, source_terms = source_terms, @@ -40,15 +41,15 @@ tspan = (0.0, 0.4) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-6, reltol=1.0e-6, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-6, reltol = 1.0e-6, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_euler_brown_minion_vortex.jl b/examples/dgmulti_2d/elixir_euler_brown_minion_vortex.jl index 4bb05c0b062..e7830c4736b 100644 --- a/examples/dgmulti_2d/elixir_euler_brown_minion_vortex.jl +++ b/examples/dgmulti_2d/elixir_euler_brown_minion_vortex.jl @@ -1,6 +1,6 @@ using Trixi, OrdinaryDiffEq -dg = DGMulti(polydeg=4, element_type = Quad(), approximation_type = Polynomial(), +dg = DGMulti(polydeg = 4, element_type = Quad(), approximation_type = Polynomial(), surface_integral = SurfaceIntegralWeakForm(FluxLaxFriedrichs()), volume_integral = VolumeIntegralFluxDifferencing(flux_ranocha)) @@ -16,38 +16,38 @@ incompressible version. [DOI: 10.1006/jcph.1995.1205](https://doi.org/10.1006/jcph.1995.1205) """ function initial_condition_BM_vortex(x, t, equations::CompressibleEulerEquations2D) - pbar = 9.0 / equations.gamma - delta = 0.05 - epsilon = 30 - H = (x[2] < 0) ? tanh(epsilon * (x[2] + 0.25)) : tanh(epsilon * (0.25 - x[2])) - rho = 1.0 - v1 = H - v2 = delta * cos(2.0 * pi * x[1]) - p = pbar - return prim2cons(SVector(rho, v1, v2, p), equations) + pbar = 9.0 / equations.gamma + delta = 0.05 + epsilon = 30 + H = (x[2] < 0) ? tanh(epsilon * (x[2] + 0.25)) : tanh(epsilon * (0.25 - x[2])) + rho = 1.0 + v1 = H + v2 = delta * cos(2.0 * pi * x[1]) + p = pbar + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_BM_vortex cells_per_dimension = (16, 16) mesh = DGMultiMesh(dg, cells_per_dimension, - coordinates_min=(-0.5, -0.5), coordinates_max=(0.5, 0.5), - periodicity=true) + coordinates_min = (-0.5, -0.5), coordinates_max = (0.5, 0.5), + periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg) tspan = (0.0, 1.0) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) ############################################################################### # run the simulation tol = 1.0e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=tol, reltol=tol, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = tol, reltol = tol, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_euler_curved.jl b/examples/dgmulti_2d/elixir_euler_curved.jl index 39e3a0a0360..48662f4b12b 100644 --- a/examples/dgmulti_2d/elixir_euler_curved.jl +++ b/examples/dgmulti_2d/elixir_euler_curved.jl @@ -10,21 +10,21 @@ initial_condition = initial_condition_convergence_test source_terms = source_terms_convergence_test # example where we tag two separate boundary segments of the mesh -top_boundary(x, tol=50*eps()) = abs(x[2]-1) top_boundary, :rest => rest_of_boundary) function mapping(xi, eta) - x = xi + 0.1 * sin(pi * xi) * sin(pi * eta) - y = eta + 0.1 * sin(pi * xi) * sin(pi * eta) - return SVector(x, y) + x = xi + 0.1 * sin(pi * xi) * sin(pi * eta) + y = eta + 0.1 * sin(pi * xi) * sin(pi * eta) + return SVector(x, y) end cells_per_dimension = (16, 16) -mesh = DGMultiMesh(dg, cells_per_dimension, mapping, is_on_boundary=is_on_boundary) +mesh = DGMultiMesh(dg, cells_per_dimension, mapping, is_on_boundary = is_on_boundary) boundary_condition_convergence_test = BoundaryConditionDirichlet(initial_condition) boundary_conditions = (; :top => boundary_condition_convergence_test, - :rest => boundary_condition_convergence_test) + :rest => boundary_condition_convergence_test) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg, source_terms = source_terms, @@ -34,16 +34,16 @@ tspan = (0.0, 0.4) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation alg = RDPK3SpFSAL49() -sol = solve(ode, alg; abstol=1.0e-6, reltol=1.0e-6, - ode_default_options()..., callback=callbacks); +sol = solve(ode, alg; abstol = 1.0e-6, reltol = 1.0e-6, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_euler_fdsbp_periodic.jl b/examples/dgmulti_2d/elixir_euler_fdsbp_periodic.jl index d41ca2c5b34..3a73089b566 100644 --- a/examples/dgmulti_2d/elixir_euler_fdsbp_periodic.jl +++ b/examples/dgmulti_2d/elixir_euler_fdsbp_periodic.jl @@ -2,8 +2,10 @@ using Trixi, OrdinaryDiffEq dg = DGMulti(element_type = Quad(), - approximation_type = periodic_derivative_operator( - derivative_order=1, accuracy_order=4, xmin=0.0, xmax=1.0, N=50), + approximation_type = periodic_derivative_operator(derivative_order = 1, + accuracy_order = 4, + xmin = 0.0, xmax = 1.0, + N = 50), surface_flux = flux_hll, volume_integral = VolumeIntegralWeakForm()) @@ -11,8 +13,8 @@ equations = CompressibleEulerEquations2D(1.4) initial_condition = initial_condition_convergence_test source_terms = source_terms_convergence_test -mesh = DGMultiMesh(dg, coordinates_min=(-1.0, -1.0), - coordinates_max=( 1.0, 1.0)) +mesh = DGMultiMesh(dg, coordinates_min = (-1.0, -1.0), + coordinates_max = (1.0, 1.0)) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg, source_terms = source_terms) @@ -21,15 +23,16 @@ tspan = (0.0, 0.4) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) -stepsize_callback = StepsizeCallback(cfl=1.0) -callbacks = CallbackSet(summary_callback, alive_callback, stepsize_callback, analysis_callback) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) +stepsize_callback = StepsizeCallback(cfl = 1.0) +callbacks = CallbackSet(summary_callback, alive_callback, stepsize_callback, + analysis_callback) ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt = 0.5 * estimate_dt(mesh, dg), save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 0.5 * estimate_dt(mesh, dg), save_everystep = false, callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_euler_hohqmesh.jl b/examples/dgmulti_2d/elixir_euler_hohqmesh.jl index b9a24dc2450..f534b5bc8ad 100644 --- a/examples/dgmulti_2d/elixir_euler_hohqmesh.jl +++ b/examples/dgmulti_2d/elixir_euler_hohqmesh.jl @@ -15,11 +15,11 @@ initial_condition = initial_condition_convergence_test source_terms = source_terms_convergence_test boundary_condition_convergence_test = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = (; :Slant => boundary_condition_convergence_test, - :Bezier => boundary_condition_convergence_test, - :Right => boundary_condition_convergence_test, - :Bottom => boundary_condition_convergence_test, - :Top => boundary_condition_convergence_test ) +boundary_conditions = (; :Slant => boundary_condition_convergence_test, + :Bezier => boundary_condition_convergence_test, + :Right => boundary_condition_convergence_test, + :Bottom => boundary_condition_convergence_test, + :Top => boundary_condition_convergence_test) ############################################################################### # Get the DG approximation space @@ -32,8 +32,9 @@ dg = DGMulti(polydeg = 8, element_type = Quad(), approximation_type = SBP(), # Get the curved quad mesh from a file (downloads the file if not available locally) default_mesh_file = joinpath(@__DIR__, "mesh_trixi_unstructured_mesh_docs.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/52056f1487853fab63b7f4ed7f171c80/raw/9d573387dfdbb8bce2a55db7246f4207663ac07f/mesh_trixi_unstructured_mesh_docs.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/52056f1487853fab63b7f4ed7f171c80/raw/9d573387dfdbb8bce2a55db7246f4207663ac07f/mesh_trixi_unstructured_mesh_docs.mesh", + default_mesh_file) mesh_file = default_mesh_file mesh = DGMultiMesh(dg, mesh_file) @@ -42,8 +43,8 @@ mesh = DGMultiMesh(dg, mesh_file) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg, - source_terms=source_terms, - boundary_conditions=boundary_conditions) + source_terms = source_terms, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -54,9 +55,9 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -66,7 +67,7 @@ callbacks = CallbackSet(summary_callback, # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - dt = time_int_tol, ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + dt = time_int_tol, ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_euler_kelvin_helmholtz_instability.jl b/examples/dgmulti_2d/elixir_euler_kelvin_helmholtz_instability.jl index 39e98d1a2c5..14de0bf0e8b 100644 --- a/examples/dgmulti_2d/elixir_euler_kelvin_helmholtz_instability.jl +++ b/examples/dgmulti_2d/elixir_euler_kelvin_helmholtz_instability.jl @@ -15,23 +15,24 @@ A version of the classical Kelvin-Helmholtz instability based on of the Euler Equations [arXiv: 2102.06017](https://arxiv.org/abs/2102.06017) """ -function initial_condition_kelvin_helmholtz_instability(x, t, equations::CompressibleEulerEquations2D) - # change discontinuity to tanh - # typical resolution 128^2, 256^2 - # domain size is [-1,+1]^2 - slope = 15 - amplitude = 0.02 - B = tanh(slope * x[2] + 7.5) - tanh(slope * x[2] - 7.5) - rho = 0.5 + 0.75 * B - v1 = 0.5 * (B - 1) - v2 = 0.1 * sin(2 * pi * x[1]) - p = 1.0 - return prim2cons(SVector(rho, v1, v2, p), equations) +function initial_condition_kelvin_helmholtz_instability(x, t, + equations::CompressibleEulerEquations2D) + # change discontinuity to tanh + # typical resolution 128^2, 256^2 + # domain size is [-1,+1]^2 + slope = 15 + amplitude = 0.02 + B = tanh(slope * x[2] + 7.5) - tanh(slope * x[2] - 7.5) + rho = 0.5 + 0.75 * B + v1 = 0.5 * (B - 1) + v2 = 0.1 * sin(2 * pi * x[1]) + p = 1.0 + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_kelvin_helmholtz_instability cells_per_dimension = (32, 32) -mesh = DGMultiMesh(dg, cells_per_dimension; periodicity=true) +mesh = DGMultiMesh(dg, cells_per_dimension; periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg) @@ -39,9 +40,9 @@ tspan = (0.0, 1.0) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) @@ -49,7 +50,7 @@ callbacks = CallbackSet(summary_callback, ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt = estimate_dt(mesh, dg), save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = estimate_dt(mesh, dg), save_everystep = false, callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_euler_rayleigh_taylor_instability.jl b/examples/dgmulti_2d/elixir_euler_rayleigh_taylor_instability.jl index f5adc7bf83c..49c8b28eaf8 100644 --- a/examples/dgmulti_2d/elixir_euler_rayleigh_taylor_instability.jl +++ b/examples/dgmulti_2d/elixir_euler_rayleigh_taylor_instability.jl @@ -29,34 +29,34 @@ defined below. """ @inline function initial_condition_rayleigh_taylor_instability(x, t, equations::CompressibleEulerEquations2D, - slope=1000) - tol = 1e2*eps() - - if x[2] < 0.5 - p = 2*x[2] + 1 - else - p = x[2] + 3/2 - end - - # smooth the discontinuity to avoid ambiguity at element interfaces - smoothed_heaviside(x, left, right) = left + 0.5*(1 + tanh(slope * x)) * (right-left) - rho = smoothed_heaviside(x[2] - 0.5, 2.0, 1.0) - - c = sqrt(equations.gamma * p / rho) - # the velocity is multiplied by sin(pi*y)^6 as in Remacle et al. 2003 to ensure that the - # initial condition satisfies reflective boundary conditions at the top/bottom boundaries. - v = -0.025 * c * cos(8*pi*x[1]) * sin(pi*x[2])^6 - u = 0.0 - - return prim2cons(SVector(rho, u, v, p), equations) + slope = 1000) + tol = 1e2 * eps() + + if x[2] < 0.5 + p = 2 * x[2] + 1 + else + p = x[2] + 3 / 2 + end + + # smooth the discontinuity to avoid ambiguity at element interfaces + smoothed_heaviside(x, left, right) = left + 0.5 * (1 + tanh(slope * x)) * (right - left) + rho = smoothed_heaviside(x[2] - 0.5, 2.0, 1.0) + + c = sqrt(equations.gamma * p / rho) + # the velocity is multiplied by sin(pi*y)^6 as in Remacle et al. 2003 to ensure that the + # initial condition satisfies reflective boundary conditions at the top/bottom boundaries. + v = -0.025 * c * cos(8 * pi * x[1]) * sin(pi * x[2])^6 + u = 0.0 + + return prim2cons(SVector(rho, u, v, p), equations) end @inline function source_terms_rayleigh_taylor_instability(u, x, t, equations::CompressibleEulerEquations2D) - g = 1.0 - rho, rho_v1, rho_v2, rho_e = u + g = 1.0 + rho, rho_v1, rho_v2, rho_e = u - return SVector(0.0, 0.0, g*rho, g*rho_v2) + return SVector(0.0, 0.0, g * rho, g * rho_v2) end # numerical parameters @@ -67,8 +67,8 @@ dg = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = Polynomial num_elements = 16 cells_per_dimension = (num_elements, 4 * num_elements) mesh = DGMultiMesh(dg, cells_per_dimension, - coordinates_min=(0.0, 0.0), coordinates_max=(0.25, 1.0), - periodicity=(true, false)) + coordinates_min = (0.0, 0.0), coordinates_max = (0.25, 1.0), + periodicity = (true, false)) initial_condition = initial_condition_rayleigh_taylor_instability boundary_conditions = (; :entire_boundary => boundary_condition_slip_wall) @@ -86,9 +86,9 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -97,7 +97,7 @@ callbacks = CallbackSet(summary_callback, ############################################################################### # run the simulation -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-6, reltol=1.0e-6, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-6, reltol = 1.0e-6, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_euler_shockcapturing.jl b/examples/dgmulti_2d/elixir_euler_shockcapturing.jl index 4b2a408c757..36494b268d6 100644 --- a/examples/dgmulti_2d/elixir_euler_shockcapturing.jl +++ b/examples/dgmulti_2d/elixir_euler_shockcapturing.jl @@ -10,25 +10,25 @@ equations = CompressibleEulerEquations2D(1.4) initial_condition = initial_condition_weak_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_ranocha +volume_flux = flux_ranocha polydeg = 3 -basis = DGMultiBasis(Quad(), polydeg, approximation_type=GaussSBP()) +basis = DGMultiBasis(Quad(), polydeg, approximation_type = GaussSBP()) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) dg = DGMulti(basis, surface_integral = SurfaceIntegralWeakForm(surface_flux), volume_integral = volume_integral) cells_per_dimension = (8, 8) -mesh = DGMultiMesh(dg, cells_per_dimension, periodicity=true) +mesh = DGMultiMesh(dg, cells_per_dimension, periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg) @@ -36,16 +36,15 @@ tspan = (0.0, 0.15) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-6, reltol=1.0e-6, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-6, reltol = 1.0e-6, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary - diff --git a/examples/dgmulti_2d/elixir_euler_shockcapturing_curved.jl b/examples/dgmulti_2d/elixir_euler_shockcapturing_curved.jl index dad898b99b6..5e8d9e6c8e4 100644 --- a/examples/dgmulti_2d/elixir_euler_shockcapturing_curved.jl +++ b/examples/dgmulti_2d/elixir_euler_shockcapturing_curved.jl @@ -10,27 +10,27 @@ equations = CompressibleEulerEquations2D(1.4) initial_condition = initial_condition_weak_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_ranocha +volume_flux = flux_ranocha polydeg = 3 -basis = DGMultiBasis(Quad(), polydeg, approximation_type=GaussSBP()) +basis = DGMultiBasis(Quad(), polydeg, approximation_type = GaussSBP()) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) dg = DGMulti(basis, surface_integral = SurfaceIntegralWeakForm(surface_flux), volume_integral = volume_integral) function mapping(xi, eta) - x = xi + 0.1 * sin(pi * xi) * sin(pi * eta) - y = eta + 0.1 * sin(pi * xi) * sin(pi * eta) - return SVector(x, y) + x = xi + 0.1 * sin(pi * xi) * sin(pi * eta) + y = eta + 0.1 * sin(pi * xi) * sin(pi * eta) + return SVector(x, y) end cells_per_dimension = (16, 16) mesh = DGMultiMesh(dg, cells_per_dimension, mapping) @@ -41,16 +41,15 @@ tspan = (0.0, 0.15) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-6, reltol=1.0e-6, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-6, reltol = 1.0e-6, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary - diff --git a/examples/dgmulti_2d/elixir_euler_triangulate_pkg_mesh.jl b/examples/dgmulti_2d/elixir_euler_triangulate_pkg_mesh.jl index c10b5e46a14..53661af259a 100644 --- a/examples/dgmulti_2d/elixir_euler_triangulate_pkg_mesh.jl +++ b/examples/dgmulti_2d/elixir_euler_triangulate_pkg_mesh.jl @@ -13,11 +13,11 @@ meshIO = StartUpDG.triangulate_domain(StartUpDG.RectangularDomainWithHole()) # the pre-defined Triangulate geometry in StartUpDG has integer boundary tags. this routine # assigns boundary faces based on these integer boundary tags. -mesh = DGMultiMesh(dg, meshIO, Dict(:outer_boundary=>1, :inner_boundary=>2)) +mesh = DGMultiMesh(dg, meshIO, Dict(:outer_boundary => 1, :inner_boundary => 2)) boundary_condition_convergence_test = BoundaryConditionDirichlet(initial_condition) boundary_conditions = (; :outer_boundary => boundary_condition_convergence_test, - :inner_boundary => boundary_condition_convergence_test) + :inner_boundary => boundary_condition_convergence_test) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg, source_terms = source_terms, @@ -27,14 +27,14 @@ tspan = (0.0, 0.2) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt = 0.5 * estimate_dt(mesh, dg), save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 0.5 * estimate_dt(mesh, dg), save_everystep = false, callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_euler_weakform.jl b/examples/dgmulti_2d/elixir_euler_weakform.jl index 486a30b37f1..ecf5e94a86b 100644 --- a/examples/dgmulti_2d/elixir_euler_weakform.jl +++ b/examples/dgmulti_2d/elixir_euler_weakform.jl @@ -10,16 +10,16 @@ initial_condition = initial_condition_convergence_test source_terms = source_terms_convergence_test # example where we tag two separate boundary segments of the mesh -top_boundary(x, tol=50*eps()) = abs(x[2]-1) top_boundary, :rest => rest_of_boundary) cells_per_dimension = (8, 8) -mesh = DGMultiMesh(dg, cells_per_dimension, is_on_boundary=is_on_boundary) +mesh = DGMultiMesh(dg, cells_per_dimension, is_on_boundary = is_on_boundary) boundary_condition_convergence_test = BoundaryConditionDirichlet(initial_condition) boundary_conditions = (; :top => boundary_condition_convergence_test, - :rest => boundary_condition_convergence_test) + :rest => boundary_condition_convergence_test) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg, source_terms = source_terms, @@ -29,15 +29,16 @@ tspan = (0.0, 0.4) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) -stepsize_callback = StepsizeCallback(cfl=1.5) -callbacks = CallbackSet(summary_callback, alive_callback, stepsize_callback, analysis_callback) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) +stepsize_callback = StepsizeCallback(cfl = 1.5) +callbacks = CallbackSet(summary_callback, alive_callback, stepsize_callback, + analysis_callback) ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt = 0.5 * estimate_dt(mesh, dg), save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 0.5 * estimate_dt(mesh, dg), save_everystep = false, callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_euler_weakform_periodic.jl b/examples/dgmulti_2d/elixir_euler_weakform_periodic.jl index c4c83fff642..307bf5cbf4a 100644 --- a/examples/dgmulti_2d/elixir_euler_weakform_periodic.jl +++ b/examples/dgmulti_2d/elixir_euler_weakform_periodic.jl @@ -10,7 +10,7 @@ initial_condition = initial_condition_convergence_test source_terms = source_terms_convergence_test cells_per_dimension = (4, 4) -mesh = DGMultiMesh(dg, cells_per_dimension, periodicity=true) +mesh = DGMultiMesh(dg, cells_per_dimension, periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg, source_terms = source_terms) @@ -18,14 +18,14 @@ tspan = (0.0, 0.4) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt = 0.5 * estimate_dt(mesh, dg), save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 0.5 * estimate_dt(mesh, dg), save_everystep = false, callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_mhd_reflective_wall.jl b/examples/dgmulti_2d/elixir_mhd_reflective_wall.jl index a1351cf8244..11670288526 100644 --- a/examples/dgmulti_2d/elixir_mhd_reflective_wall.jl +++ b/examples/dgmulti_2d/elixir_mhd_reflective_wall.jl @@ -8,70 +8,72 @@ using LinearAlgebra: norm, dot # for use in the MHD boundary condition equations = IdealGlmMhdEquations2D(1.4) function initial_condition_perturbation(x, t, equations::IdealGlmMhdEquations2D) - # pressure perturbation in a vertically magnetized field on the domain [-1, 1]^2 + # pressure perturbation in a vertically magnetized field on the domain [-1, 1]^2 - r2 = (x[1] + 0.25)^2 + (x[2] + 0.25)^2 + r2 = (x[1] + 0.25)^2 + (x[2] + 0.25)^2 - rho = 1.0 - v1 = 0.0 - v2 = 0.0 - v3 = 0.0 - p = 1 + 0.5 * exp(-100 * r2) + rho = 1.0 + v1 = 0.0 + v2 = 0.0 + v3 = 0.0 + p = 1 + 0.5 * exp(-100 * r2) - # the pressure and magnetic field are chosen to be strongly - # magnetized, such that p / ||B||^2 ≈ 0.01. - B1 = 0.0 - B2 = 40.0 / sqrt(4.0 * pi) - B3 = 0.0 + # the pressure and magnetic field are chosen to be strongly + # magnetized, such that p / ||B||^2 ≈ 0.01. + B1 = 0.0 + B2 = 40.0 / sqrt(4.0 * pi) + B3 = 0.0 - psi = 0.0 - return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3, psi), equations) + psi = 0.0 + return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3, psi), equations) end initial_condition = initial_condition_perturbation surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell) -volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) +volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -solver = DGMulti(polydeg=3, element_type = Quad(), approximation_type = GaussSBP(), +solver = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = GaussSBP(), surface_integral = SurfaceIntegralWeakForm(surface_flux), volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) -x_neg(x, tol=50*eps()) = abs(x[1] + 1) < tol -x_pos(x, tol=50*eps()) = abs(x[1] - 1) < tol -y_neg(x, tol=50*eps()) = abs(x[2] + 1) < tol -y_pos(x, tol=50*eps()) = abs(x[2] - 1) < tol +x_neg(x, tol = 50 * eps()) = abs(x[1] + 1) < tol +x_pos(x, tol = 50 * eps()) = abs(x[1] - 1) < tol +y_neg(x, tol = 50 * eps()) = abs(x[2] + 1) < tol +y_pos(x, tol = 50 * eps()) = abs(x[2] - 1) < tol is_on_boundary = Dict(:x_neg => x_neg, :x_pos => x_pos, :y_neg => y_neg, :y_pos => y_pos) cells_per_dimension = (16, 16) -mesh = DGMultiMesh(solver, cells_per_dimension; periodicity=(false, false), is_on_boundary) +mesh = DGMultiMesh(solver, cells_per_dimension; periodicity = (false, false), + is_on_boundary) # Create a "reflective-like" boundary condition by mirroring the velocity but leaving the magnetic field alone. # Note that this boundary condition is probably not entropy stable. -function boundary_condition_velocity_slip_wall(u_inner, normal_direction::AbstractVector, x, t, - surface_flux_function, equations::IdealGlmMhdEquations2D) +function boundary_condition_velocity_slip_wall(u_inner, normal_direction::AbstractVector, + x, t, surface_flux_function, + equations::IdealGlmMhdEquations2D) - # Normalize the vector without using `normalize` since we need to multiply by the `norm_` later - norm_ = norm(normal_direction) - normal = normal_direction / norm_ + # Normalize the vector without using `normalize` since we need to multiply by the `norm_` later + norm_ = norm(normal_direction) + normal = normal_direction / norm_ - # compute the primitive variables - rho, v1, v2, v3, p, B1, B2, B3, psi = cons2prim(u_inner, equations) + # compute the primitive variables + rho, v1, v2, v3, p, B1, B2, B3, psi = cons2prim(u_inner, equations) - v_normal = dot(normal, SVector(v1, v2)) - u_mirror = prim2cons(SVector(rho, v1 - 2 * v_normal * normal[1], - v2 - 2 * v_normal * normal[2], - v3, p, B1, B2, B3, psi), equations) + v_normal = dot(normal, SVector(v1, v2)) + u_mirror = prim2cons(SVector(rho, v1 - 2 * v_normal * normal[1], + v2 - 2 * v_normal * normal[2], + v3, p, B1, B2, B3, psi), equations) - return surface_flux_function(u_inner, u_mirror, normal, equations) * norm_ + return surface_flux_function(u_inner, u_mirror, normal, equations) * norm_ end -boundary_conditions = (; x_neg=boundary_condition_velocity_slip_wall, - x_pos=boundary_condition_velocity_slip_wall, - y_neg=boundary_condition_do_nothing, - y_pos=BoundaryConditionDirichlet(initial_condition)) +boundary_conditions = (; x_neg = boundary_condition_velocity_slip_wall, + x_pos = boundary_condition_velocity_slip_wall, + y_neg = boundary_condition_do_nothing, + y_pos = BoundaryConditionDirichlet(initial_condition)) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver; - boundary_conditions=boundary_conditions) + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -82,12 +84,13 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(solver)) -alive_callback = AliveCallback(alive_interval=10) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + uEltype = real(solver)) +alive_callback = AliveCallback(alive_interval = 10) cfl = 0.5 -stepsize_callback = StepsizeCallback(cfl=cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -98,8 +101,8 @@ callbacks = CallbackSet(summary_callback, ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=1e-5, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1e-5, # 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/dgmulti_2d/elixir_mhd_weak_blast_wave.jl b/examples/dgmulti_2d/elixir_mhd_weak_blast_wave.jl index bf5045ce8b0..663301e189f 100644 --- a/examples/dgmulti_2d/elixir_mhd_weak_blast_wave.jl +++ b/examples/dgmulti_2d/elixir_mhd_weak_blast_wave.jl @@ -11,14 +11,14 @@ initial_condition = initial_condition_weak_blast_wave surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell) volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -dg = DGMulti(polydeg=3, element_type = Quad(), approximation_type = Polynomial(), +dg = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = Polynomial(), surface_integral = SurfaceIntegralWeakForm(surface_flux), volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) cells_per_dimension = (16, 16) mesh = DGMultiMesh(dg, cells_per_dimension, - coordinates_min=(-2.0, -2.0), coordinates_max=(2.0, 2.0), - periodicity=true) + coordinates_min = (-2.0, -2.0), coordinates_max = (2.0, 2.0), + periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg) ############################################################################### @@ -30,13 +30,13 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) +alive_callback = AliveCallback(analysis_interval = analysis_interval) cfl = 1.0 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -47,8 +47,8 @@ callbacks = CallbackSet(summary_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); +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/dgmulti_2d/elixir_mhd_weak_blast_wave_SBP.jl b/examples/dgmulti_2d/elixir_mhd_weak_blast_wave_SBP.jl index 9c8dfcb3801..3dc070a7296 100644 --- a/examples/dgmulti_2d/elixir_mhd_weak_blast_wave_SBP.jl +++ b/examples/dgmulti_2d/elixir_mhd_weak_blast_wave_SBP.jl @@ -15,13 +15,13 @@ initial_condition = initial_condition_weak_blast_wave surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell) volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -dg = DGMulti(polydeg=3, element_type = Quad(), approximation_type = SBP(), +dg = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = SBP(), surface_integral = SurfaceIntegralWeakForm(surface_flux), volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) mesh = DGMultiMesh(dg, cells_per_dimension, - coordinates_min=(-2.0, -2.0), coordinates_max=(2.0, 2.0), - periodicity=true) + coordinates_min = (-2.0, -2.0), coordinates_max = (2.0, 2.0), + periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg) ############################################################################### @@ -33,8 +33,8 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) +alive_callback = AliveCallback(analysis_interval = analysis_interval) # See comment above and https://github.com/trixi-framework/Trixi.jl/issues/881 # DGMulti uses a conservative timestep estimate, so we can use a large CFL here. @@ -46,8 +46,7 @@ alive_callback = AliveCallback(analysis_interval=analysis_interval) callbacks = CallbackSet(summary_callback, analysis_callback, #stepsize_callback, - alive_callback, - #=glm_speed_callback=#) + alive_callback) #=glm_speed_callback=# ############################################################################### # run the simulation @@ -56,7 +55,7 @@ callbacks = CallbackSet(summary_callback, # 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); -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-8, reltol=1.0e-8, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-8, reltol = 1.0e-8, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_navierstokes_convergence.jl b/examples/dgmulti_2d/elixir_navierstokes_convergence.jl index 23c9c2e8ed4..38cf3d7984b 100644 --- a/examples/dgmulti_2d/elixir_navierstokes_convergence.jl +++ b/examples/dgmulti_2d/elixir_navierstokes_convergence.jl @@ -10,169 +10,180 @@ mu() = 0.01 equations = CompressibleEulerEquations2D(1.4) # Note: If you change the Navier-Stokes parameters here, also change them in the initial condition # I really do not like this structure but it should work for now -equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu=mu(), Prandtl=prandtl_number(), - gradient_variables=GradientVariablesPrimitive()) +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu = mu(), + Prandtl = prandtl_number(), + gradient_variables = GradientVariablesPrimitive()) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux dg = DGMulti(polydeg = 3, element_type = Tri(), approximation_type = Polynomial(), surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), volume_integral = VolumeIntegralWeakForm()) -top_bottom(x, tol=50*eps()) = abs(abs(x[2]) - 1) < tol +top_bottom(x, tol = 50 * eps()) = abs(abs(x[2]) - 1) < tol is_on_boundary = Dict(:top_bottom => top_bottom) cells_per_dimension = (16, 16) -mesh = DGMultiMesh(dg, cells_per_dimension; periodicity=(true, false), is_on_boundary) +mesh = DGMultiMesh(dg, cells_per_dimension; periodicity = (true, false), is_on_boundary) # Note: the initial condition cannot be specialized to `CompressibleNavierStokesDiffusion2D` # since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesDiffusion2D`) # and by the initial condition (which passes in `CompressibleEulerEquations2D`). # This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) function initial_condition_navier_stokes_convergence_test(x, t, equations) - # Amplitude and shift - A = 0.5 - c = 2.0 + # Amplitude and shift + A = 0.5 + c = 2.0 - # convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_t = pi * t + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t - rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) - v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0)) ) * cos(pi_t) - v2 = v1 - p = rho^2 + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0))) * cos(pi_t) + v2 = v1 + p = rho^2 - return prim2cons(SVector(rho, v1, v2, p), equations) + return prim2cons(SVector(rho, v1, v2, p), equations) end @inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) - y = x[2] - - # TODO: parabolic - # we currently need to hardcode these parameters until we fix the "combined equation" issue - # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 - inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = prandtl_number() - mu_ = mu() - - # Same settings as in `initial_condition` - # Amplitude and shift - A = 0.5 - c = 2.0 - - # convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_t = pi * t - - # compute the manufactured solution and all necessary derivatives - rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) - rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) - rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) - rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) - rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) - rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) - - v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) - v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_y = sin(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) - v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_xy = pi * cos(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) - v1_yy = (sin(pi_x) * ( 2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) - - A * A * log(y + 2.0) * exp(-A * (y - 1.0)) - - (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) - v2 = v1 - v2_t = v1_t - v2_x = v1_x - v2_y = v1_y - v2_xx = v1_xx - v2_xy = v1_xy - v2_yy = v1_yy - - p = rho * rho - p_t = 2.0 * rho * rho_t - p_x = 2.0 * rho * rho_x - p_y = 2.0 * rho * rho_y - p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x - p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y - - # Note this simplifies slightly because the ansatz assumes that v1 = v2 - E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) - E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t - E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x - E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y - - # Some convenience constants - T_const = equations.gamma * inv_gamma_minus_one / Pr - inv_rho_cubed = 1.0 / (rho^3) - - # compute the source terms - # density equation - du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y - - # x-momentum equation - du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 - + 2.0 * rho * v1 * v1_x - + rho_y * v1 * v2 - + rho * v1_y * v2 - + rho * v1 * v2_y - # stress tensor from x-direction - - 4.0 / 3.0 * v1_xx * mu_ - + 2.0 / 3.0 * v2_xy * mu_ - - v1_yy * mu_ - - v2_xy * mu_ ) - # y-momentum equation - du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 - + rho * v1_x * v2 - + rho * v1 * v2_x - + rho_y * v2^2 - + 2.0 * rho * v2 * v2_y - # stress tensor from y-direction - - v1_xy * mu_ - - v2_xx * mu_ - - 4.0 / 3.0 * v2_yy * mu_ - + 2.0 / 3.0 * v1_xy * mu_ ) - # total energy equation - du4 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) - + v2_y * (E + p) + v2 * (E_y + p_y) - # stress tensor and temperature gradient terms from x-direction - - 4.0 / 3.0 * v1_xx * v1 * mu_ - + 2.0 / 3.0 * v2_xy * v1 * mu_ - - 4.0 / 3.0 * v1_x * v1_x * mu_ - + 2.0 / 3.0 * v2_y * v1_x * mu_ - - v1_xy * v2 * mu_ - - v2_xx * v2 * mu_ - - v1_y * v2_x * mu_ - - v2_x * v2_x * mu_ - - T_const * inv_rho_cubed * ( p_xx * rho * rho - - 2.0 * p_x * rho * rho_x - + 2.0 * p * rho_x * rho_x - - p * rho * rho_xx ) * mu_ - # stress tensor and temperature gradient terms from y-direction - - v1_yy * v1 * mu_ - - v2_xy * v1 * mu_ - - v1_y * v1_y * mu_ - - v2_x * v1_y * mu_ - - 4.0 / 3.0 * v2_yy * v2 * mu_ - + 2.0 / 3.0 * v1_xy * v2 * mu_ - - 4.0 / 3.0 * v2_y * v2_y * mu_ - + 2.0 / 3.0 * v1_x * v2_y * mu_ - - T_const * inv_rho_cubed * ( p_yy * rho * rho - - 2.0 * p_y * rho * rho_y - + 2.0 * p * rho_y * rho_y - - p * rho * rho_yy ) * mu_ ) - - return SVector(du1, du2, du3, du4) + y = x[2] + + # TODO: parabolic + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + mu_ = mu() + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) + rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) + rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) + rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + + v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) + v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_y = sin(pi_x) * + (A * log(y + 2.0) * exp(-A * (y - 1.0)) + + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_xy = pi * cos(pi_x) * + (A * log(y + 2.0) * exp(-A * (y - 1.0)) + + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_yy = (sin(pi_x) * + (2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) - + A * A * log(y + 2.0) * exp(-A * (y - 1.0)) - + (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_xx = v1_xx + v2_xy = v1_xy + v2_yy = v1_yy + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y + + # Note this simplifies slightly because the ansatz assumes that v1 = v2 + E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) + E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x + E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one / Pr + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y + + # x-momentum equation + du2 = (rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y - + # stress tensor from x-direction + 4.0 / 3.0 * v1_xx * mu_ + + 2.0 / 3.0 * v2_xy * mu_ - + v1_yy * mu_ - + v2_xy * mu_) + # y-momentum equation + du3 = (rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y - + # stress tensor from y-direction + v1_xy * mu_ - + v2_xx * mu_ - + 4.0 / 3.0 * v2_yy * mu_ + + 2.0 / 3.0 * v1_xy * mu_) + # total energy equation + du4 = (E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) - + # stress tensor and temperature gradient terms from x-direction + 4.0 / 3.0 * v1_xx * v1 * mu_ + + 2.0 / 3.0 * v2_xy * v1 * mu_ - + 4.0 / 3.0 * v1_x * v1_x * mu_ + + 2.0 / 3.0 * v2_y * v1_x * mu_ - + v1_xy * v2 * mu_ - + v2_xx * v2 * mu_ - + v1_y * v2_x * mu_ - + v2_x * v2_x * mu_ - + T_const * inv_rho_cubed * + (p_xx * rho * rho - + 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x - + p * rho * rho_xx) * mu_ - + # stress tensor and temperature gradient terms from y-direction + v1_yy * v1 * mu_ - + v2_xy * v1 * mu_ - + v1_y * v1_y * mu_ - + v2_x * v1_y * mu_ - + 4.0 / 3.0 * v2_yy * v2 * mu_ + + 2.0 / 3.0 * v1_xy * v2 * mu_ - + 4.0 / 3.0 * v2_y * v2_y * mu_ + + 2.0 / 3.0 * v1_x * v2_y * mu_ - + T_const * inv_rho_cubed * + (p_yy * rho * rho - + 2.0 * p_y * rho * rho_y + + 2.0 * p * rho_y * rho_y - + p * rho * rho_yy) * mu_) + + return SVector(du1, du2, du3, du4) end initial_condition = initial_condition_navier_stokes_convergence_test # BC types -velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:3]) +velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, + t, + equations)[2:3]) heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) -boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, heat_bc_top_bottom) +boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, + heat_bc_top_bottom) # define inviscid boundary conditions boundary_conditions = (; :top_bottom => boundary_condition_slip_wall) @@ -180,10 +191,11 @@ boundary_conditions = (; :top_bottom => boundary_condition_slip_wall) # define viscous boundary conditions boundary_conditions_parabolic = (; :top_bottom => boundary_condition_top_bottom) -semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, dg; - boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), - source_terms=source_terms_navier_stokes_convergence_test) - +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, dg; + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic), + source_terms = source_terms_navier_stokes_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -193,15 +205,15 @@ tspan = (0.0, 0.5) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, alive_callback) ############################################################################### # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_navierstokes_convergence_curved.jl b/examples/dgmulti_2d/elixir_navierstokes_convergence_curved.jl index 86b5ae64348..87ffd0e0995 100644 --- a/examples/dgmulti_2d/elixir_navierstokes_convergence_curved.jl +++ b/examples/dgmulti_2d/elixir_navierstokes_convergence_curved.jl @@ -10,24 +10,26 @@ mu() = 0.01 equations = CompressibleEulerEquations2D(1.4) # Note: If you change the Navier-Stokes parameters here, also change them in the initial condition # I really do not like this structure but it should work for now -equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu=mu(), Prandtl=prandtl_number(), - gradient_variables=GradientVariablesPrimitive()) +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu = mu(), + Prandtl = prandtl_number(), + gradient_variables = GradientVariablesPrimitive()) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux dg = DGMulti(polydeg = 3, element_type = Tri(), approximation_type = Polynomial(), surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), volume_integral = VolumeIntegralWeakForm()) -top_bottom(x, tol=50*eps()) = abs(abs(x[2]) - 1) < tol +top_bottom(x, tol = 50 * eps()) = abs(abs(x[2]) - 1) < tol is_on_boundary = Dict(:top_bottom => top_bottom) function mapping(xi, eta) - x = xi + 0.1 * sin(pi * xi) * sin(pi * eta) - y = eta + 0.1 * sin(pi * xi) * sin(pi * eta) - return SVector(x, y) + x = xi + 0.1 * sin(pi * xi) * sin(pi * eta) + y = eta + 0.1 * sin(pi * xi) * sin(pi * eta) + return SVector(x, y) end cells_per_dimension = (16, 16) -mesh = DGMultiMesh(dg, cells_per_dimension, mapping; periodicity=(true, false), is_on_boundary) +mesh = DGMultiMesh(dg, cells_per_dimension, mapping; periodicity = (true, false), + is_on_boundary) # This initial condition is taken from `examples/dgmulti_2d/elixir_navierstokes_convergence.jl` @@ -36,150 +38,160 @@ mesh = DGMultiMesh(dg, cells_per_dimension, mapping; periodicity=(true, false), # and by the initial condition (which passes in `CompressibleEulerEquations2D`). # This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) function initial_condition_navier_stokes_convergence_test(x, t, equations) - # Amplitude and shift - A = 0.5 - c = 2.0 + # Amplitude and shift + A = 0.5 + c = 2.0 - # convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_t = pi * t + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t - rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) - v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0)) ) * cos(pi_t) - v2 = v1 - p = rho^2 + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0))) * cos(pi_t) + v2 = v1 + p = rho^2 - return prim2cons(SVector(rho, v1, v2, p), equations) + return prim2cons(SVector(rho, v1, v2, p), equations) end @inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) - y = x[2] - - # TODO: parabolic - # we currently need to hardcode these parameters until we fix the "combined equation" issue - # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 - inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = prandtl_number() - mu_ = mu() - - # Same settings as in `initial_condition` - # Amplitude and shift - A = 0.5 - c = 2.0 - - # convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_t = pi * t - - # compute the manufactured solution and all necessary derivatives - rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) - rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) - rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) - rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) - rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) - rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) - - v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) - v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_y = sin(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) - v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_xy = pi * cos(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) - v1_yy = (sin(pi_x) * ( 2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) - - A * A * log(y + 2.0) * exp(-A * (y - 1.0)) - - (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) - v2 = v1 - v2_t = v1_t - v2_x = v1_x - v2_y = v1_y - v2_xx = v1_xx - v2_xy = v1_xy - v2_yy = v1_yy - - p = rho * rho - p_t = 2.0 * rho * rho_t - p_x = 2.0 * rho * rho_x - p_y = 2.0 * rho * rho_y - p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x - p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y - - # Note this simplifies slightly because the ansatz assumes that v1 = v2 - E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) - E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t - E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x - E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y - - # Some convenience constants - T_const = equations.gamma * inv_gamma_minus_one / Pr - inv_rho_cubed = 1.0 / (rho^3) - - # compute the source terms - # density equation - du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y - - # x-momentum equation - du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 - + 2.0 * rho * v1 * v1_x - + rho_y * v1 * v2 - + rho * v1_y * v2 - + rho * v1 * v2_y - # stress tensor from x-direction - - 4.0 / 3.0 * v1_xx * mu_ - + 2.0 / 3.0 * v2_xy * mu_ - - v1_yy * mu_ - - v2_xy * mu_ ) - # y-momentum equation - du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 - + rho * v1_x * v2 - + rho * v1 * v2_x - + rho_y * v2^2 - + 2.0 * rho * v2 * v2_y - # stress tensor from y-direction - - v1_xy * mu_ - - v2_xx * mu_ - - 4.0 / 3.0 * v2_yy * mu_ - + 2.0 / 3.0 * v1_xy * mu_ ) - # total energy equation - du4 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) - + v2_y * (E + p) + v2 * (E_y + p_y) - # stress tensor and temperature gradient terms from x-direction - - 4.0 / 3.0 * v1_xx * v1 * mu_ - + 2.0 / 3.0 * v2_xy * v1 * mu_ - - 4.0 / 3.0 * v1_x * v1_x * mu_ - + 2.0 / 3.0 * v2_y * v1_x * mu_ - - v1_xy * v2 * mu_ - - v2_xx * v2 * mu_ - - v1_y * v2_x * mu_ - - v2_x * v2_x * mu_ - - T_const * inv_rho_cubed * ( p_xx * rho * rho - - 2.0 * p_x * rho * rho_x - + 2.0 * p * rho_x * rho_x - - p * rho * rho_xx ) * mu_ - # stress tensor and temperature gradient terms from y-direction - - v1_yy * v1 * mu_ - - v2_xy * v1 * mu_ - - v1_y * v1_y * mu_ - - v2_x * v1_y * mu_ - - 4.0 / 3.0 * v2_yy * v2 * mu_ - + 2.0 / 3.0 * v1_xy * v2 * mu_ - - 4.0 / 3.0 * v2_y * v2_y * mu_ - + 2.0 / 3.0 * v1_x * v2_y * mu_ - - T_const * inv_rho_cubed * ( p_yy * rho * rho - - 2.0 * p_y * rho * rho_y - + 2.0 * p * rho_y * rho_y - - p * rho * rho_yy ) * mu_ ) - - return SVector(du1, du2, du3, du4) + y = x[2] + + # TODO: parabolic + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + mu_ = mu() + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) + rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) + rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) + rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + + v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) + v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_y = sin(pi_x) * + (A * log(y + 2.0) * exp(-A * (y - 1.0)) + + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_xy = pi * cos(pi_x) * + (A * log(y + 2.0) * exp(-A * (y - 1.0)) + + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_yy = (sin(pi_x) * + (2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) - + A * A * log(y + 2.0) * exp(-A * (y - 1.0)) - + (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_xx = v1_xx + v2_xy = v1_xy + v2_yy = v1_yy + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y + + # Note this simplifies slightly because the ansatz assumes that v1 = v2 + E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) + E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x + E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one / Pr + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y + + # x-momentum equation + du2 = (rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y - + # stress tensor from x-direction + 4.0 / 3.0 * v1_xx * mu_ + + 2.0 / 3.0 * v2_xy * mu_ - + v1_yy * mu_ - + v2_xy * mu_) + # y-momentum equation + du3 = (rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y - + # stress tensor from y-direction + v1_xy * mu_ - + v2_xx * mu_ - + 4.0 / 3.0 * v2_yy * mu_ + + 2.0 / 3.0 * v1_xy * mu_) + # total energy equation + du4 = (E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) - + # stress tensor and temperature gradient terms from x-direction + 4.0 / 3.0 * v1_xx * v1 * mu_ + + 2.0 / 3.0 * v2_xy * v1 * mu_ - + 4.0 / 3.0 * v1_x * v1_x * mu_ + + 2.0 / 3.0 * v2_y * v1_x * mu_ - + v1_xy * v2 * mu_ - + v2_xx * v2 * mu_ - + v1_y * v2_x * mu_ - + v2_x * v2_x * mu_ - + T_const * inv_rho_cubed * + (p_xx * rho * rho - + 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x - + p * rho * rho_xx) * mu_ - + # stress tensor and temperature gradient terms from y-direction + v1_yy * v1 * mu_ - + v2_xy * v1 * mu_ - + v1_y * v1_y * mu_ - + v2_x * v1_y * mu_ - + 4.0 / 3.0 * v2_yy * v2 * mu_ + + 2.0 / 3.0 * v1_xy * v2 * mu_ - + 4.0 / 3.0 * v2_y * v2_y * mu_ + + 2.0 / 3.0 * v1_x * v2_y * mu_ - + T_const * inv_rho_cubed * + (p_yy * rho * rho - + 2.0 * p_y * rho * rho_y + + 2.0 * p * rho_y * rho_y - + p * rho * rho_yy) * mu_) + + return SVector(du1, du2, du3, du4) end initial_condition = initial_condition_navier_stokes_convergence_test # BC types -velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:3]) +velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, + t, + equations)[2:3]) heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) -boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, heat_bc_top_bottom) +boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, + heat_bc_top_bottom) # define inviscid boundary conditions boundary_conditions = (; :top_bottom => boundary_condition_slip_wall) @@ -187,10 +199,11 @@ boundary_conditions = (; :top_bottom => boundary_condition_slip_wall) # define viscous boundary conditions boundary_conditions_parabolic = (; :top_bottom => boundary_condition_top_bottom) -semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, dg; - boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), - source_terms=source_terms_navier_stokes_convergence_test) - +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, dg; + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic), + source_terms = source_terms_navier_stokes_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -200,15 +213,15 @@ tspan = (0.0, 0.5) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, alive_callback) ############################################################################### # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_navierstokes_lid_driven_cavity.jl b/examples/dgmulti_2d/elixir_navierstokes_lid_driven_cavity.jl index 97b779ebaf9..7c55cbf0ccf 100644 --- a/examples/dgmulti_2d/elixir_navierstokes_lid_driven_cavity.jl +++ b/examples/dgmulti_2d/elixir_navierstokes_lid_driven_cavity.jl @@ -9,28 +9,27 @@ prandtl_number() = 0.72 mu() = 0.001 equations = CompressibleEulerEquations2D(1.4) -equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu=mu(), - Prandtl=prandtl_number()) - +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu = mu(), + Prandtl = prandtl_number()) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux dg = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = GaussSBP(), surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), volume_integral = VolumeIntegralFluxDifferencing(flux_ranocha)) -top(x, tol=50*eps()) = abs(x[2] - 1) < tol -rest_of_boundary(x, tol=50*eps()) = !top(x, tol) +top(x, tol = 50 * eps()) = abs(x[2] - 1) < tol +rest_of_boundary(x, tol = 50 * eps()) = !top(x, tol) is_on_boundary = Dict(:top => top, :rest_of_boundary => rest_of_boundary) cells_per_dimension = (16, 16) mesh = DGMultiMesh(dg, cells_per_dimension; is_on_boundary) function initial_condition_cavity(x, t, equations::CompressibleEulerEquations2D) - Ma = 0.1 - rho = 1.0 - u, v = 0.0, 0.0 - p = 1.0 / (Ma^2 * equations.gamma) - return prim2cons(SVector(rho, u, v, p), equations) + Ma = 0.1 + rho = 1.0 + u, v = 0.0, 0.0 + p = 1.0 / (Ma^2 * equations.gamma) + return prim2cons(SVector(rho, u, v, p), equations) end initial_condition = initial_condition_cavity @@ -43,15 +42,16 @@ boundary_condition_cavity = BoundaryConditionNavierStokesWall(velocity_bc_cavity # define inviscid boundary conditions boundary_conditions = (; :top => boundary_condition_slip_wall, - :rest_of_boundary => boundary_condition_slip_wall) + :rest_of_boundary => boundary_condition_slip_wall) # define viscous boundary conditions boundary_conditions_parabolic = (; :top => boundary_condition_lid, - :rest_of_boundary => boundary_condition_cavity) - -semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, dg; - boundary_conditions=(boundary_conditions, boundary_conditions_parabolic)) + :rest_of_boundary => boundary_condition_cavity) +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, dg; + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic)) ############################################################################### # ODE solvers, callbacks etc. @@ -61,15 +61,15 @@ tspan = (0.0, 10.0) ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, alive_callback) ############################################################################### # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_shallowwater_source_terms.jl b/examples/dgmulti_2d/elixir_shallowwater_source_terms.jl index 3551c863ff2..f7120d8091b 100644 --- a/examples/dgmulti_2d/elixir_shallowwater_source_terms.jl +++ b/examples/dgmulti_2d/elixir_shallowwater_source_terms.jl @@ -4,24 +4,23 @@ using Trixi ############################################################################### # semidiscretization of the shallow water equations -equations = ShallowWaterEquations2D(gravity_constant=9.81) +equations = ShallowWaterEquations2D(gravity_constant = 9.81) initial_condition = initial_condition_convergence_test volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) surface_flux = (flux_lax_friedrichs, flux_nonconservative_fjordholm_etal) -dg = DGMulti(polydeg=3, element_type = Quad(), approximation_type = SBP(), +dg = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = SBP(), surface_integral = SurfaceIntegralWeakForm(surface_flux), volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) cells_per_dimension = (8, 8) mesh = DGMultiMesh(dg, cells_per_dimension, - coordinates_min=(0.0, 0.0), coordinates_max=(sqrt(2), sqrt(2)), - periodicity=true) - + coordinates_min = (0.0, 0.0), coordinates_max = (sqrt(2), sqrt(2)), + periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg; - source_terms=source_terms_convergence_test) + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -32,8 +31,8 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) +alive_callback = AliveCallback(analysis_interval = analysis_interval) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -42,7 +41,7 @@ callbacks = CallbackSet(summary_callback, ############################################################################### # run the simulation -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-7, reltol=1.0e-7, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-7, reltol = 1.0e-7, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/dgmulti_3d/elixir_advection_tensor_wedge.jl b/examples/dgmulti_3d/elixir_advection_tensor_wedge.jl index 4f43f2571a3..e877e602547 100644 --- a/examples/dgmulti_3d/elixir_advection_tensor_wedge.jl +++ b/examples/dgmulti_3d/elixir_advection_tensor_wedge.jl @@ -16,17 +16,15 @@ dg = DGMulti(element_type = Wedge(), surface_flux = flux_lax_friedrichs, polydeg = tensor_polydeg) - cells_per_dimension = (8, 8, 8) -mesh = DGMultiMesh(dg, +mesh = DGMultiMesh(dg, cells_per_dimension, - coordinates_min = (-1.0, -1.0, -1.0), + coordinates_min = (-1.0, -1.0, -1.0), coordinates_max = (1.0, 1.0, 1.0), periodicity = true) - semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg, - boundary_conditions=boundary_condition_periodic) + boundary_conditions = boundary_condition_periodic) ############################################################################### # ODE solvers, callbacks etc. @@ -37,20 +35,20 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) # The StepsizeCallback handles the re-calculation of the maximum Δt after each time step -stepsize_callback = StepsizeCallback(cfl=1.0) - -callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, stepsize_callback) +stepsize_callback = StepsizeCallback(cfl = 1.0) +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, + stepsize_callback) ############################################################################### # run the simulation sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, - save_everystep=false, callback=callbacks); + save_everystep = false, callback = callbacks); -summary_callback() # print the timer summary \ No newline at end of file +summary_callback() # print the timer summary diff --git a/examples/dgmulti_3d/elixir_euler_curved.jl b/examples/dgmulti_3d/elixir_euler_curved.jl index d8c4df5dd64..67c84b50974 100644 --- a/examples/dgmulti_3d/elixir_euler_curved.jl +++ b/examples/dgmulti_3d/elixir_euler_curved.jl @@ -1,7 +1,7 @@ using Trixi, OrdinaryDiffEq -dg = DGMulti(polydeg = 3, element_type = Hex(), approximation_type=SBP(), +dg = DGMulti(polydeg = 3, element_type = Hex(), approximation_type = SBP(), surface_integral = SurfaceIntegralWeakForm(flux_hll), volume_integral = VolumeIntegralFluxDifferencing(flux_ranocha)) @@ -10,22 +10,22 @@ initial_condition = initial_condition_convergence_test source_terms = source_terms_convergence_test # example where we tag two separate boundary segments of the mesh -top_boundary(x, tol=50*eps()) = abs(x[2] - 1) < tol -rest_of_boundary(x, tol=50*eps()) = !top_boundary(x, tol) +top_boundary(x, tol = 50 * eps()) = abs(x[2] - 1) < tol +rest_of_boundary(x, tol = 50 * eps()) = !top_boundary(x, tol) is_on_boundary = Dict(:top => top_boundary, :rest => rest_of_boundary) function mapping(xi, eta, zeta) - x = xi + 0.1 * sin(pi * xi) * sin(pi * eta) - y = eta + 0.1 * sin(pi * xi) * sin(pi * eta) - z = zeta + 0.1 * sin(pi * xi) * sin(pi * eta) - return SVector(x, y, z) + x = xi + 0.1 * sin(pi * xi) * sin(pi * eta) + y = eta + 0.1 * sin(pi * xi) * sin(pi * eta) + z = zeta + 0.1 * sin(pi * xi) * sin(pi * eta) + return SVector(x, y, z) end cells_per_dimension = (4, 4, 4) -mesh = DGMultiMesh(dg, cells_per_dimension, mapping, is_on_boundary=is_on_boundary) +mesh = DGMultiMesh(dg, cells_per_dimension, mapping, is_on_boundary = is_on_boundary) boundary_condition_convergence_test = BoundaryConditionDirichlet(initial_condition) boundary_conditions = (; :top => boundary_condition_convergence_test, - :rest => boundary_condition_convergence_test) + :rest => boundary_condition_convergence_test) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg, source_terms = source_terms, @@ -35,14 +35,14 @@ tspan = (0.0, 0.1) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt = 0.5 * estimate_dt(mesh, dg), save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 0.5 * estimate_dt(mesh, dg), save_everystep = false, callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/dgmulti_3d/elixir_euler_fdsbp_periodic.jl b/examples/dgmulti_3d/elixir_euler_fdsbp_periodic.jl index 35f7aee8795..0eb38674689 100644 --- a/examples/dgmulti_3d/elixir_euler_fdsbp_periodic.jl +++ b/examples/dgmulti_3d/elixir_euler_fdsbp_periodic.jl @@ -10,19 +10,20 @@ equations = CompressibleEulerEquations3D(1.4) initial_condition = initial_condition_convergence_test source_terms = source_terms_convergence_test -volume_flux = flux_ranocha +volume_flux = flux_ranocha solver = DGMulti(element_type = Hex(), - approximation_type = periodic_derivative_operator( - derivative_order=1, accuracy_order=4, xmin=0.0, xmax=1.0, N=20), + approximation_type = periodic_derivative_operator(derivative_order = 1, + accuracy_order = 4, + xmin = 0.0, xmax = 1.0, + N = 20), surface_flux = flux_lax_friedrichs, volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) -mesh = DGMultiMesh(solver, coordinates_min=(-1.0, -1.0, -1.0), - coordinates_max=( 1.0, 1.0, 1.0)) +mesh = DGMultiMesh(solver, coordinates_min = (-1.0, -1.0, -1.0), + coordinates_max = (1.0, 1.0, 1.0)) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver; - source_terms=source_terms) - + source_terms = source_terms) ############################################################################### # ODE solvers, callbacks etc. @@ -33,14 +34,14 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(solver)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + uEltype = real(solver)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) - ############################################################################### # run the simulation diff --git a/examples/dgmulti_3d/elixir_euler_taylor_green_vortex.jl b/examples/dgmulti_3d/elixir_euler_taylor_green_vortex.jl index 253d2486468..fea43ad4d26 100644 --- a/examples/dgmulti_3d/elixir_euler_taylor_green_vortex.jl +++ b/examples/dgmulti_3d/elixir_euler_taylor_green_vortex.jl @@ -12,35 +12,38 @@ equations = CompressibleEulerEquations3D(1.4) The classical inviscid Taylor-Green vortex. """ -function initial_condition_taylor_green_vortex(x, t, equations::CompressibleEulerEquations3D) - A = 1.0 # magnitude of speed - Ms = 0.1 # maximum Mach number - - rho = 1.0 - v1 = A * sin(x[1]) * cos(x[2]) * cos(x[3]) - v2 = -A * cos(x[1]) * sin(x[2]) * cos(x[3]) - v3 = 0.0 - p = (A / Ms)^2 * rho / equations.gamma # scaling to get Ms - p = p + 1.0/16.0 * A^2 * rho * (cos(2*x[1])*cos(2*x[3]) + 2*cos(2*x[2]) + 2*cos(2*x[1]) + cos(2*x[2])*cos(2*x[3])) - - return prim2cons(SVector(rho, v1, v2, v3, p), equations) +function initial_condition_taylor_green_vortex(x, t, + equations::CompressibleEulerEquations3D) + A = 1.0 # magnitude of speed + Ms = 0.1 # maximum Mach number + + rho = 1.0 + v1 = A * sin(x[1]) * cos(x[2]) * cos(x[3]) + v2 = -A * cos(x[1]) * sin(x[2]) * cos(x[3]) + v3 = 0.0 + p = (A / Ms)^2 * rho / equations.gamma # scaling to get Ms + p = p + + 1.0 / 16.0 * A^2 * rho * + (cos(2 * x[1]) * cos(2 * x[3]) + 2 * cos(2 * x[2]) + 2 * cos(2 * x[1]) + + cos(2 * x[2]) * cos(2 * x[3])) + + return prim2cons(SVector(rho, v1, v2, v3, p), equations) end initial_condition = initial_condition_taylor_green_vortex -volume_flux = flux_ranocha +volume_flux = flux_ranocha surface_flux = flux_lax_friedrichs solver = DGMulti(polydeg = 3, element_type = Hex(), approximation_type = Polynomial(), - surface_integral= SurfaceIntegralWeakForm(surface_flux), - volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + surface_integral = SurfaceIntegralWeakForm(surface_flux), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) cells_per_dimension = (8, 8, 8) mesh = DGMultiMesh(solver, cells_per_dimension, - coordinates_min=(-pi, -pi, -pi), coordinates_max=(pi, pi, pi), - periodicity=true) + coordinates_min = (-pi, -pi, -pi), coordinates_max = (pi, pi, pi), + periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -50,14 +53,14 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(solver)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + uEltype = real(solver)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) - ############################################################################### # run the simulation diff --git a/examples/dgmulti_3d/elixir_euler_weakform.jl b/examples/dgmulti_3d/elixir_euler_weakform.jl index b167377af51..6e06b35c4f6 100644 --- a/examples/dgmulti_3d/elixir_euler_weakform.jl +++ b/examples/dgmulti_3d/elixir_euler_weakform.jl @@ -10,16 +10,16 @@ initial_condition = initial_condition_convergence_test source_terms = source_terms_convergence_test # example where we tag two separate boundary segments of the mesh -top_boundary(x, tol=50*eps()) = abs(x[2] - 1) < tol -rest_of_boundary(x, tol=50*eps()) = !top_boundary(x, tol) +top_boundary(x, tol = 50 * eps()) = abs(x[2] - 1) < tol +rest_of_boundary(x, tol = 50 * eps()) = !top_boundary(x, tol) is_on_boundary = Dict(:top => top_boundary, :rest => rest_of_boundary) cells_per_dimension = (4, 4, 4) -mesh = DGMultiMesh(dg, cells_per_dimension, is_on_boundary=is_on_boundary) +mesh = DGMultiMesh(dg, cells_per_dimension, is_on_boundary = is_on_boundary) boundary_condition_convergence_test = BoundaryConditionDirichlet(initial_condition) boundary_conditions = (; :top => boundary_condition_convergence_test, - :rest => boundary_condition_convergence_test) + :rest => boundary_condition_convergence_test) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg, source_terms = source_terms, @@ -29,14 +29,14 @@ tspan = (0.0, 0.1) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt = 0.5 * estimate_dt(mesh, dg), save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 0.5 * estimate_dt(mesh, dg), save_everystep = false, callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/dgmulti_3d/elixir_euler_weakform_periodic.jl b/examples/dgmulti_3d/elixir_euler_weakform_periodic.jl index 6b17d4bba65..bc963a3a2fd 100644 --- a/examples/dgmulti_3d/elixir_euler_weakform_periodic.jl +++ b/examples/dgmulti_3d/elixir_euler_weakform_periodic.jl @@ -10,7 +10,7 @@ initial_condition = initial_condition_convergence_test source_terms = source_terms_convergence_test cells_per_dimension = (4, 4, 4) -mesh = DGMultiMesh(dg, cells_per_dimension, periodicity=true) +mesh = DGMultiMesh(dg, cells_per_dimension, periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg, source_terms = source_terms) @@ -19,14 +19,14 @@ tspan = (0.0, 0.1) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt = 0.5 * estimate_dt(mesh, dg), save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 0.5 * estimate_dt(mesh, dg), save_everystep = false, callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/dgmulti_3d/elixir_navierstokes_convergence.jl b/examples/dgmulti_3d/elixir_navierstokes_convergence.jl index 9a237b2d2fc..5fa0ad7ce60 100644 --- a/examples/dgmulti_3d/elixir_navierstokes_convergence.jl +++ b/examples/dgmulti_3d/elixir_navierstokes_convergence.jl @@ -8,219 +8,225 @@ prandtl_number() = 0.72 mu() = 0.01 equations = CompressibleEulerEquations3D(1.4) -equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu=mu(), Prandtl=prandtl_number(), - gradient_variables=GradientVariablesPrimitive()) +equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu = mu(), + Prandtl = prandtl_number(), + gradient_variables = GradientVariablesPrimitive()) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux dg = DGMulti(polydeg = 3, element_type = Hex(), approximation_type = Polynomial(), surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), volume_integral = VolumeIntegralWeakForm()) -top_bottom(x, tol=50*eps()) = abs(abs(x[2]) - 1) < tol +top_bottom(x, tol = 50 * eps()) = abs(abs(x[2]) - 1) < tol is_on_boundary = Dict(:top_bottom => top_bottom) cells_per_dimension = (8, 8, 8) -mesh = DGMultiMesh(dg, cells_per_dimension; periodicity=(true, false, true), is_on_boundary) +mesh = DGMultiMesh(dg, cells_per_dimension; periodicity = (true, false, true), + is_on_boundary) # Note: the initial condition cannot be specialized to `CompressibleNavierStokesDiffusion3D` # since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesDiffusion3D`) # and by the initial condition (which passes in `CompressibleEulerEquations3D`). # This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) function initial_condition_navier_stokes_convergence_test(x, t, equations) - # Constants. OBS! Must match those in `source_terms_navier_stokes_convergence_test` - c = 2.0 - A1 = 0.5 - A2 = 1.0 - A3 = 0.5 - - # Convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_z = pi * x[3] - pi_t = 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.0) * (1.0 - exp(-A3 * (x[2] - 1.0))) * sin(pi_z) * cos(pi_t) - v2 = v1 - v3 = v1 - p = rho^2 - - return prim2cons(SVector(rho, v1, v2, v3, p), equations) + # Constants. OBS! Must match those in `source_terms_navier_stokes_convergence_test` + c = 2.0 + A1 = 0.5 + A2 = 1.0 + A3 = 0.5 + + # Convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_z = pi * x[3] + pi_t = 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.0) * (1.0 - exp(-A3 * (x[2] - 1.0))) * sin(pi_z) * + cos(pi_t) + v2 = v1 + v3 = v1 + p = rho^2 + + return prim2cons(SVector(rho, v1, v2, v3, p), equations) end @inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) - # TODO: parabolic - # we currently need to hardcode these parameters until we fix the "combined equation" issue - # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 - inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = prandtl_number() - mu_ = mu() - - # Constants. OBS! Must match those in `initial_condition_navier_stokes_convergence_test` - c = 2.0 - A1 = 0.5 - A2 = 1.0 - A3 = 0.5 - - # Convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_z = pi * x[3] - pi_t = pi * t - - # Define auxiliary functions for the strange function of the y variable - # to make expressions easier to read - g = log(x[2] + 2.0) * (1.0 - exp(-A3 * (x[2] - 1.0))) - g_y = ( A3 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0)) - + (1.0 - exp(-A3 * (x[2] - 1.0))) / (x[2] + 2.0) ) - g_yy = ( 2.0 * A3 * exp(-A3 * (x[2] - 1.0)) / (x[2] + 2.0) - - (1.0 - exp(-A3 * (x[2] - 1.0))) / ((x[2] + 2.0)^2) - - A3^2 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0)) ) - - # Density and its derivatives - rho = c + A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t) - rho_t = -pi * A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * sin(pi_t) - rho_x = pi * A1 * cos(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t) - rho_y = -pi * A1 * sin(pi_x) * sin(pi_y) * sin(pi_z) * cos(pi_t) - rho_z = pi * A1 * sin(pi_x) * cos(pi_y) * cos(pi_z) * cos(pi_t) - rho_xx = -pi^2 * (rho - c) - rho_yy = -pi^2 * (rho - c) - rho_zz = -pi^2 * (rho - c) - - # Velocities and their derivatives - # v1 terms - v1 = A2 * sin(pi_x) * g * sin(pi_z) * cos(pi_t) - v1_t = -pi * A2 * sin(pi_x) * g * sin(pi_z) * sin(pi_t) - v1_x = pi * A2 * cos(pi_x) * g * sin(pi_z) * cos(pi_t) - v1_y = A2 * sin(pi_x) * g_y * sin(pi_z) * cos(pi_t) - v1_z = pi * A2 * sin(pi_x) * g * cos(pi_z) * cos(pi_t) - v1_xx = -pi^2 * v1 - v1_yy = A2 * sin(pi_x) * g_yy * sin(pi_z) * cos(pi_t) - v1_zz = -pi^2 * v1 - v1_xy = pi * A2 * cos(pi_x) * g_y * sin(pi_z) * cos(pi_t) - v1_xz = pi^2 * A2 * cos(pi_x) * g * cos(pi_z) * cos(pi_t) - v1_yz = pi * A2 * sin(pi_x) * g_y * cos(pi_z) * cos(pi_t) - # v2 terms (simplifies from ansatz) - v2 = v1 - v2_t = v1_t - v2_x = v1_x - v2_y = v1_y - v2_z = v1_z - v2_xx = v1_xx - v2_yy = v1_yy - v2_zz = v1_zz - v2_xy = v1_xy - v2_yz = v1_yz - # v3 terms (simplifies from ansatz) - v3 = v1 - v3_t = v1_t - v3_x = v1_x - v3_y = v1_y - v3_z = v1_z - v3_xx = v1_xx - v3_yy = v1_yy - v3_zz = v1_zz - v3_xz = v1_xz - v3_yz = v1_yz - - # Pressure and its derivatives - p = rho^2 - p_t = 2.0 * rho * rho_t - p_x = 2.0 * rho * rho_x - p_y = 2.0 * rho * rho_y - p_z = 2.0 * rho * rho_z - - # Total energy and its derivatives; simiplifies from ansatz that v2 = v1 and v3 = v1 - E = p * inv_gamma_minus_one + 1.5 * rho * v1^2 - E_t = p_t * inv_gamma_minus_one + 1.5 * rho_t * v1^2 + 3.0 * rho * v1 * v1_t - E_x = p_x * inv_gamma_minus_one + 1.5 * rho_x * v1^2 + 3.0 * rho * v1 * v1_x - E_y = p_y * inv_gamma_minus_one + 1.5 * rho_y * v1^2 + 3.0 * rho * v1 * v1_y - E_z = p_z * inv_gamma_minus_one + 1.5 * rho_z * v1^2 + 3.0 * rho * v1 * v1_z - - # Divergence of Fick's law ∇⋅∇q = kappa ∇⋅∇T; simplifies because p = rho², so T = p/rho = rho - kappa = equations.gamma * inv_gamma_minus_one / Pr - q_xx = kappa * rho_xx # kappa T_xx - q_yy = kappa * rho_yy # kappa T_yy - q_zz = kappa * rho_zz # kappa T_zz - - # Stress tensor and its derivatives (exploit symmetry) - tau11 = 4.0 / 3.0 * v1_x - 2.0 / 3.0 * (v2_y + v3_z) - tau12 = v1_y + v2_x - tau13 = v1_z + v3_x - tau22 = 4.0 / 3.0 * v2_y - 2.0 / 3.0 * (v1_x + v3_z) - tau23 = v2_z + v3_y - tau33 = 4.0 / 3.0 * v3_z - 2.0 / 3.0 * (v1_x + v2_y) - - tau11_x = 4.0 / 3.0 * v1_xx - 2.0 / 3.0 * (v2_xy + v3_xz) - tau12_x = v1_xy + v2_xx - tau13_x = v1_xz + v3_xx - - tau12_y = v1_yy + v2_xy - tau22_y = 4.0 / 3.0 * v2_yy - 2.0 / 3.0 * (v1_xy + v3_yz) - tau23_y = v2_yz + v3_yy - - tau13_z = v1_zz + v3_xz - tau23_z = v2_zz + v3_yz - tau33_z = 4.0 / 3.0 * v3_zz - 2.0 / 3.0 * (v1_xz + v2_yz) - - # Compute the source terms - # Density equation - du1 = ( rho_t + rho_x * v1 + rho * v1_x - + rho_y * v2 + rho * v2_y - + rho_z * v3 + rho * v3_z ) - # x-momentum equation - du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 - + 2.0 * rho * v1 * v1_x - + rho_y * v1 * v2 - + rho * v1_y * v2 - + rho * v1 * v2_y - + rho_z * v1 * v3 - + rho * v1_z * v3 - + rho * v1 * v3_z - - mu_ * (tau11_x + tau12_y + tau13_z) ) - # y-momentum equation - du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 - + rho * v1_x * v2 - + rho * v1 * v2_x - + rho_y * v2^2 - + 2.0 * rho * v2 * v2_y - + rho_z * v2 * v3 - + rho * v2_z * v3 - + rho * v2 * v3_z - - mu_ * (tau12_x + tau22_y + tau23_z) ) - # z-momentum equation - du4 = ( rho_t * v3 + rho * v3_t + p_z + rho_x * v1 * v3 - + rho * v1_x * v3 - + rho * v1 * v3_x - + rho_y * v2 * v3 - + rho * v2_y * v3 - + rho * v2 * v3_y - + rho_z * v3^2 - + 2.0 * rho * v3 * v3_z - - mu_ * (tau13_x + tau23_y + tau33_z) ) - # Total energy equation - du5 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) - + v2_y * (E + p) + v2 * (E_y + p_y) - + v3_z * (E + p) + v3 * (E_z + p_z) - # stress tensor and temperature gradient from x-direction - - mu_ * ( q_xx + v1_x * tau11 + v2_x * tau12 + v3_x * tau13 - + v1 * tau11_x + v2 * tau12_x + v3 * tau13_x) - # stress tensor and temperature gradient terms from y-direction - - mu_ * ( q_yy + v1_y * tau12 + v2_y * tau22 + v3_y * tau23 - + v1 * tau12_y + v2 * tau22_y + v3 * tau23_y) - # stress tensor and temperature gradient terms from z-direction - - mu_ * ( q_zz + v1_z * tau13 + v2_z * tau23 + v3_z * tau33 - + v1 * tau13_z + v2 * tau23_z + v3 * tau33_z) ) - - return SVector(du1, du2, du3, du4, du5) + # TODO: parabolic + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + mu_ = mu() + + # Constants. OBS! Must match those in `initial_condition_navier_stokes_convergence_test` + c = 2.0 + A1 = 0.5 + A2 = 1.0 + A3 = 0.5 + + # Convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_z = pi * x[3] + pi_t = pi * t + + # Define auxiliary functions for the strange function of the y variable + # to make expressions easier to read + g = log(x[2] + 2.0) * (1.0 - exp(-A3 * (x[2] - 1.0))) + g_y = (A3 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0)) + + (1.0 - exp(-A3 * (x[2] - 1.0))) / (x[2] + 2.0)) + g_yy = (2.0 * A3 * exp(-A3 * (x[2] - 1.0)) / (x[2] + 2.0) - + (1.0 - exp(-A3 * (x[2] - 1.0))) / ((x[2] + 2.0)^2) - + A3^2 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0))) + + # Density and its derivatives + rho = c + A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t) + rho_t = -pi * A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * sin(pi_t) + rho_x = pi * A1 * cos(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t) + rho_y = -pi * A1 * sin(pi_x) * sin(pi_y) * sin(pi_z) * cos(pi_t) + rho_z = pi * A1 * sin(pi_x) * cos(pi_y) * cos(pi_z) * cos(pi_t) + rho_xx = -pi^2 * (rho - c) + rho_yy = -pi^2 * (rho - c) + rho_zz = -pi^2 * (rho - c) + + # Velocities and their derivatives + # v1 terms + v1 = A2 * sin(pi_x) * g * sin(pi_z) * cos(pi_t) + v1_t = -pi * A2 * sin(pi_x) * g * sin(pi_z) * sin(pi_t) + v1_x = pi * A2 * cos(pi_x) * g * sin(pi_z) * cos(pi_t) + v1_y = A2 * sin(pi_x) * g_y * sin(pi_z) * cos(pi_t) + v1_z = pi * A2 * sin(pi_x) * g * cos(pi_z) * cos(pi_t) + v1_xx = -pi^2 * v1 + v1_yy = A2 * sin(pi_x) * g_yy * sin(pi_z) * cos(pi_t) + v1_zz = -pi^2 * v1 + v1_xy = pi * A2 * cos(pi_x) * g_y * sin(pi_z) * cos(pi_t) + v1_xz = pi^2 * A2 * cos(pi_x) * g * cos(pi_z) * cos(pi_t) + v1_yz = pi * A2 * sin(pi_x) * g_y * cos(pi_z) * cos(pi_t) + # v2 terms (simplifies from ansatz) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_z = v1_z + v2_xx = v1_xx + v2_yy = v1_yy + v2_zz = v1_zz + v2_xy = v1_xy + v2_yz = v1_yz + # v3 terms (simplifies from ansatz) + v3 = v1 + v3_t = v1_t + v3_x = v1_x + v3_y = v1_y + v3_z = v1_z + v3_xx = v1_xx + v3_yy = v1_yy + v3_zz = v1_zz + v3_xz = v1_xz + v3_yz = v1_yz + + # Pressure and its derivatives + p = rho^2 + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_z = 2.0 * rho * rho_z + + # Total energy and its derivatives; simiplifies from ansatz that v2 = v1 and v3 = v1 + E = p * inv_gamma_minus_one + 1.5 * rho * v1^2 + E_t = p_t * inv_gamma_minus_one + 1.5 * rho_t * v1^2 + 3.0 * rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + 1.5 * rho_x * v1^2 + 3.0 * rho * v1 * v1_x + E_y = p_y * inv_gamma_minus_one + 1.5 * rho_y * v1^2 + 3.0 * rho * v1 * v1_y + E_z = p_z * inv_gamma_minus_one + 1.5 * rho_z * v1^2 + 3.0 * rho * v1 * v1_z + + # Divergence of Fick's law ∇⋅∇q = kappa ∇⋅∇T; simplifies because p = rho², so T = p/rho = rho + kappa = equations.gamma * inv_gamma_minus_one / Pr + q_xx = kappa * rho_xx # kappa T_xx + q_yy = kappa * rho_yy # kappa T_yy + q_zz = kappa * rho_zz # kappa T_zz + + # Stress tensor and its derivatives (exploit symmetry) + tau11 = 4.0 / 3.0 * v1_x - 2.0 / 3.0 * (v2_y + v3_z) + tau12 = v1_y + v2_x + tau13 = v1_z + v3_x + tau22 = 4.0 / 3.0 * v2_y - 2.0 / 3.0 * (v1_x + v3_z) + tau23 = v2_z + v3_y + tau33 = 4.0 / 3.0 * v3_z - 2.0 / 3.0 * (v1_x + v2_y) + + tau11_x = 4.0 / 3.0 * v1_xx - 2.0 / 3.0 * (v2_xy + v3_xz) + tau12_x = v1_xy + v2_xx + tau13_x = v1_xz + v3_xx + + tau12_y = v1_yy + v2_xy + tau22_y = 4.0 / 3.0 * v2_yy - 2.0 / 3.0 * (v1_xy + v3_yz) + tau23_y = v2_yz + v3_yy + + tau13_z = v1_zz + v3_xz + tau23_z = v2_zz + v3_yz + tau33_z = 4.0 / 3.0 * v3_zz - 2.0 / 3.0 * (v1_xz + v2_yz) + + # Compute the source terms + # Density equation + du1 = (rho_t + rho_x * v1 + rho * v1_x + + rho_y * v2 + rho * v2_y + + rho_z * v3 + rho * v3_z) + # x-momentum equation + du2 = (rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y + + rho_z * v1 * v3 + + rho * v1_z * v3 + + rho * v1 * v3_z - + mu_ * (tau11_x + tau12_y + tau13_z)) + # y-momentum equation + du3 = (rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y + + rho_z * v2 * v3 + + rho * v2_z * v3 + + rho * v2 * v3_z - + mu_ * (tau12_x + tau22_y + tau23_z)) + # z-momentum equation + du4 = (rho_t * v3 + rho * v3_t + p_z + rho_x * v1 * v3 + + rho * v1_x * v3 + + rho * v1 * v3_x + + rho_y * v2 * v3 + + rho * v2_y * v3 + + rho * v2 * v3_y + + rho_z * v3^2 + + 2.0 * rho * v3 * v3_z - + mu_ * (tau13_x + tau23_y + tau33_z)) + # Total energy equation + du5 = (E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) + + v3_z * (E + p) + v3 * (E_z + p_z) - + # stress tensor and temperature gradient from x-direction + mu_ * (q_xx + v1_x * tau11 + v2_x * tau12 + v3_x * tau13 + + v1 * tau11_x + v2 * tau12_x + v3 * tau13_x) - + # stress tensor and temperature gradient terms from y-direction + mu_ * (q_yy + v1_y * tau12 + v2_y * tau22 + v3_y * tau23 + + v1 * tau12_y + v2 * tau22_y + v3 * tau23_y) - + # stress tensor and temperature gradient terms from z-direction + mu_ * (q_zz + v1_z * tau13 + v2_z * tau23 + v3_z * tau33 + + v1 * tau13_z + v2 * tau23_z + v3 * tau33_z)) + + return SVector(du1, du2, du3, du4, du5) end initial_condition = initial_condition_navier_stokes_convergence_test # BC types -velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:4]) +velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, + t, + equations)[2:4]) heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) -boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, heat_bc_top_bottom) +boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, + heat_bc_top_bottom) # define inviscid boundary conditions boundary_conditions = (; :top_bottom => boundary_condition_slip_wall) @@ -228,10 +234,11 @@ boundary_conditions = (; :top_bottom => boundary_condition_slip_wall) # define viscous boundary conditions boundary_conditions_parabolic = (; :top_bottom => boundary_condition_top_bottom) -semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, dg; - boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), - source_terms=source_terms_navier_stokes_convergence_test) - +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, dg; + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic), + source_terms = source_terms_navier_stokes_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -241,15 +248,15 @@ tspan = (0.0, 1.0) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary diff --git a/examples/dgmulti_3d/elixir_navierstokes_convergence_curved.jl b/examples/dgmulti_3d/elixir_navierstokes_convergence_curved.jl index c14d6620803..c58d78d2581 100644 --- a/examples/dgmulti_3d/elixir_navierstokes_convergence_curved.jl +++ b/examples/dgmulti_3d/elixir_navierstokes_convergence_curved.jl @@ -8,25 +8,27 @@ prandtl_number() = 0.72 mu() = 0.01 equations = CompressibleEulerEquations3D(1.4) -equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu=mu(), Prandtl=prandtl_number(), - gradient_variables=GradientVariablesPrimitive()) +equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu = mu(), + Prandtl = prandtl_number(), + gradient_variables = GradientVariablesPrimitive()) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux dg = DGMulti(polydeg = 3, element_type = Hex(), approximation_type = Polynomial(), surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), volume_integral = VolumeIntegralWeakForm()) -top_bottom(x, tol=50*eps()) = abs(abs(x[2]) - 1) < tol +top_bottom(x, tol = 50 * eps()) = abs(abs(x[2]) - 1) < tol is_on_boundary = Dict(:top_bottom => top_bottom) function mapping(xi, eta, zeta) - x = xi + 0.1 * sin(pi * xi) * sin(pi * eta) - y = eta + 0.1 * sin(pi * xi) * sin(pi * eta) - z = zeta + 0.1 * sin(pi * xi) * sin(pi * eta) - return SVector(x, y, z) + x = xi + 0.1 * sin(pi * xi) * sin(pi * eta) + y = eta + 0.1 * sin(pi * xi) * sin(pi * eta) + z = zeta + 0.1 * sin(pi * xi) * sin(pi * eta) + return SVector(x, y, z) end cells_per_dimension = (8, 8, 8) -mesh = DGMultiMesh(dg, cells_per_dimension, mapping; periodicity=(true, false, true), is_on_boundary) +mesh = DGMultiMesh(dg, cells_per_dimension, mapping; periodicity = (true, false, true), + is_on_boundary) # This initial condition is taken from `examples/dgmulti_3d/elixir_navierstokes_convergence.jl` @@ -35,200 +37,204 @@ mesh = DGMultiMesh(dg, cells_per_dimension, mapping; periodicity=(true, false, t # and by the initial condition (which passes in `CompressibleEulerEquations3D`). # This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) function initial_condition_navier_stokes_convergence_test(x, t, equations) - # Constants. OBS! Must match those in `source_terms_navier_stokes_convergence_test` - c = 2.0 - A1 = 0.5 - A2 = 1.0 - A3 = 0.5 - - # Convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_z = pi * x[3] - pi_t = 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.0) * (1.0 - exp(-A3 * (x[2] - 1.0))) * sin(pi_z) * cos(pi_t) - v2 = v1 - v3 = v1 - p = rho^2 - - return prim2cons(SVector(rho, v1, v2, v3, p), equations) + # Constants. OBS! Must match those in `source_terms_navier_stokes_convergence_test` + c = 2.0 + A1 = 0.5 + A2 = 1.0 + A3 = 0.5 + + # Convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_z = pi * x[3] + pi_t = 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.0) * (1.0 - exp(-A3 * (x[2] - 1.0))) * sin(pi_z) * + cos(pi_t) + v2 = v1 + v3 = v1 + p = rho^2 + + return prim2cons(SVector(rho, v1, v2, v3, p), equations) end @inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) - # TODO: parabolic - # we currently need to hardcode these parameters until we fix the "combined equation" issue - # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 - inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = prandtl_number() - mu_ = mu() - - # Constants. OBS! Must match those in `initial_condition_navier_stokes_convergence_test` - c = 2.0 - A1 = 0.5 - A2 = 1.0 - A3 = 0.5 - - # Convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_z = pi * x[3] - pi_t = pi * t - - # Define auxiliary functions for the strange function of the y variable - # to make expressions easier to read - g = log(x[2] + 2.0) * (1.0 - exp(-A3 * (x[2] - 1.0))) - g_y = ( A3 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0)) - + (1.0 - exp(-A3 * (x[2] - 1.0))) / (x[2] + 2.0) ) - g_yy = ( 2.0 * A3 * exp(-A3 * (x[2] - 1.0)) / (x[2] + 2.0) - - (1.0 - exp(-A3 * (x[2] - 1.0))) / ((x[2] + 2.0)^2) - - A3^2 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0)) ) - - # Density and its derivatives - rho = c + A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t) - rho_t = -pi * A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * sin(pi_t) - rho_x = pi * A1 * cos(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t) - rho_y = -pi * A1 * sin(pi_x) * sin(pi_y) * sin(pi_z) * cos(pi_t) - rho_z = pi * A1 * sin(pi_x) * cos(pi_y) * cos(pi_z) * cos(pi_t) - rho_xx = -pi^2 * (rho - c) - rho_yy = -pi^2 * (rho - c) - rho_zz = -pi^2 * (rho - c) - - # Velocities and their derivatives - # v1 terms - v1 = A2 * sin(pi_x) * g * sin(pi_z) * cos(pi_t) - v1_t = -pi * A2 * sin(pi_x) * g * sin(pi_z) * sin(pi_t) - v1_x = pi * A2 * cos(pi_x) * g * sin(pi_z) * cos(pi_t) - v1_y = A2 * sin(pi_x) * g_y * sin(pi_z) * cos(pi_t) - v1_z = pi * A2 * sin(pi_x) * g * cos(pi_z) * cos(pi_t) - v1_xx = -pi^2 * v1 - v1_yy = A2 * sin(pi_x) * g_yy * sin(pi_z) * cos(pi_t) - v1_zz = -pi^2 * v1 - v1_xy = pi * A2 * cos(pi_x) * g_y * sin(pi_z) * cos(pi_t) - v1_xz = pi^2 * A2 * cos(pi_x) * g * cos(pi_z) * cos(pi_t) - v1_yz = pi * A2 * sin(pi_x) * g_y * cos(pi_z) * cos(pi_t) - # v2 terms (simplifies from ansatz) - v2 = v1 - v2_t = v1_t - v2_x = v1_x - v2_y = v1_y - v2_z = v1_z - v2_xx = v1_xx - v2_yy = v1_yy - v2_zz = v1_zz - v2_xy = v1_xy - v2_yz = v1_yz - # v3 terms (simplifies from ansatz) - v3 = v1 - v3_t = v1_t - v3_x = v1_x - v3_y = v1_y - v3_z = v1_z - v3_xx = v1_xx - v3_yy = v1_yy - v3_zz = v1_zz - v3_xz = v1_xz - v3_yz = v1_yz - - # Pressure and its derivatives - p = rho^2 - p_t = 2.0 * rho * rho_t - p_x = 2.0 * rho * rho_x - p_y = 2.0 * rho * rho_y - p_z = 2.0 * rho * rho_z - - # Total energy and its derivatives; simiplifies from ansatz that v2 = v1 and v3 = v1 - E = p * inv_gamma_minus_one + 1.5 * rho * v1^2 - E_t = p_t * inv_gamma_minus_one + 1.5 * rho_t * v1^2 + 3.0 * rho * v1 * v1_t - E_x = p_x * inv_gamma_minus_one + 1.5 * rho_x * v1^2 + 3.0 * rho * v1 * v1_x - E_y = p_y * inv_gamma_minus_one + 1.5 * rho_y * v1^2 + 3.0 * rho * v1 * v1_y - E_z = p_z * inv_gamma_minus_one + 1.5 * rho_z * v1^2 + 3.0 * rho * v1 * v1_z - - # Divergence of Fick's law ∇⋅∇q = kappa ∇⋅∇T; simplifies because p = rho², so T = p/rho = rho - kappa = equations.gamma * inv_gamma_minus_one / Pr - q_xx = kappa * rho_xx # kappa T_xx - q_yy = kappa * rho_yy # kappa T_yy - q_zz = kappa * rho_zz # kappa T_zz - - # Stress tensor and its derivatives (exploit symmetry) - tau11 = 4.0 / 3.0 * v1_x - 2.0 / 3.0 * (v2_y + v3_z) - tau12 = v1_y + v2_x - tau13 = v1_z + v3_x - tau22 = 4.0 / 3.0 * v2_y - 2.0 / 3.0 * (v1_x + v3_z) - tau23 = v2_z + v3_y - tau33 = 4.0 / 3.0 * v3_z - 2.0 / 3.0 * (v1_x + v2_y) - - tau11_x = 4.0 / 3.0 * v1_xx - 2.0 / 3.0 * (v2_xy + v3_xz) - tau12_x = v1_xy + v2_xx - tau13_x = v1_xz + v3_xx - - tau12_y = v1_yy + v2_xy - tau22_y = 4.0 / 3.0 * v2_yy - 2.0 / 3.0 * (v1_xy + v3_yz) - tau23_y = v2_yz + v3_yy - - tau13_z = v1_zz + v3_xz - tau23_z = v2_zz + v3_yz - tau33_z = 4.0 / 3.0 * v3_zz - 2.0 / 3.0 * (v1_xz + v2_yz) - - # Compute the source terms - # Density equation - du1 = ( rho_t + rho_x * v1 + rho * v1_x - + rho_y * v2 + rho * v2_y - + rho_z * v3 + rho * v3_z ) - # x-momentum equation - du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 - + 2.0 * rho * v1 * v1_x - + rho_y * v1 * v2 - + rho * v1_y * v2 - + rho * v1 * v2_y - + rho_z * v1 * v3 - + rho * v1_z * v3 - + rho * v1 * v3_z - - mu_ * (tau11_x + tau12_y + tau13_z) ) - # y-momentum equation - du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 - + rho * v1_x * v2 - + rho * v1 * v2_x - + rho_y * v2^2 - + 2.0 * rho * v2 * v2_y - + rho_z * v2 * v3 - + rho * v2_z * v3 - + rho * v2 * v3_z - - mu_ * (tau12_x + tau22_y + tau23_z) ) - # z-momentum equation - du4 = ( rho_t * v3 + rho * v3_t + p_z + rho_x * v1 * v3 - + rho * v1_x * v3 - + rho * v1 * v3_x - + rho_y * v2 * v3 - + rho * v2_y * v3 - + rho * v2 * v3_y - + rho_z * v3^2 - + 2.0 * rho * v3 * v3_z - - mu_ * (tau13_x + tau23_y + tau33_z) ) - # Total energy equation - du5 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) - + v2_y * (E + p) + v2 * (E_y + p_y) - + v3_z * (E + p) + v3 * (E_z + p_z) - # stress tensor and temperature gradient from x-direction - - mu_ * ( q_xx + v1_x * tau11 + v2_x * tau12 + v3_x * tau13 - + v1 * tau11_x + v2 * tau12_x + v3 * tau13_x) - # stress tensor and temperature gradient terms from y-direction - - mu_ * ( q_yy + v1_y * tau12 + v2_y * tau22 + v3_y * tau23 - + v1 * tau12_y + v2 * tau22_y + v3 * tau23_y) - # stress tensor and temperature gradient terms from z-direction - - mu_ * ( q_zz + v1_z * tau13 + v2_z * tau23 + v3_z * tau33 - + v1 * tau13_z + v2 * tau23_z + v3 * tau33_z) ) - - return SVector(du1, du2, du3, du4, du5) + # TODO: parabolic + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + mu_ = mu() + + # Constants. OBS! Must match those in `initial_condition_navier_stokes_convergence_test` + c = 2.0 + A1 = 0.5 + A2 = 1.0 + A3 = 0.5 + + # Convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_z = pi * x[3] + pi_t = pi * t + + # Define auxiliary functions for the strange function of the y variable + # to make expressions easier to read + g = log(x[2] + 2.0) * (1.0 - exp(-A3 * (x[2] - 1.0))) + g_y = (A3 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0)) + + (1.0 - exp(-A3 * (x[2] - 1.0))) / (x[2] + 2.0)) + g_yy = (2.0 * A3 * exp(-A3 * (x[2] - 1.0)) / (x[2] + 2.0) - + (1.0 - exp(-A3 * (x[2] - 1.0))) / ((x[2] + 2.0)^2) - + A3^2 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0))) + + # Density and its derivatives + rho = c + A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t) + rho_t = -pi * A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * sin(pi_t) + rho_x = pi * A1 * cos(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t) + rho_y = -pi * A1 * sin(pi_x) * sin(pi_y) * sin(pi_z) * cos(pi_t) + rho_z = pi * A1 * sin(pi_x) * cos(pi_y) * cos(pi_z) * cos(pi_t) + rho_xx = -pi^2 * (rho - c) + rho_yy = -pi^2 * (rho - c) + rho_zz = -pi^2 * (rho - c) + + # Velocities and their derivatives + # v1 terms + v1 = A2 * sin(pi_x) * g * sin(pi_z) * cos(pi_t) + v1_t = -pi * A2 * sin(pi_x) * g * sin(pi_z) * sin(pi_t) + v1_x = pi * A2 * cos(pi_x) * g * sin(pi_z) * cos(pi_t) + v1_y = A2 * sin(pi_x) * g_y * sin(pi_z) * cos(pi_t) + v1_z = pi * A2 * sin(pi_x) * g * cos(pi_z) * cos(pi_t) + v1_xx = -pi^2 * v1 + v1_yy = A2 * sin(pi_x) * g_yy * sin(pi_z) * cos(pi_t) + v1_zz = -pi^2 * v1 + v1_xy = pi * A2 * cos(pi_x) * g_y * sin(pi_z) * cos(pi_t) + v1_xz = pi^2 * A2 * cos(pi_x) * g * cos(pi_z) * cos(pi_t) + v1_yz = pi * A2 * sin(pi_x) * g_y * cos(pi_z) * cos(pi_t) + # v2 terms (simplifies from ansatz) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_z = v1_z + v2_xx = v1_xx + v2_yy = v1_yy + v2_zz = v1_zz + v2_xy = v1_xy + v2_yz = v1_yz + # v3 terms (simplifies from ansatz) + v3 = v1 + v3_t = v1_t + v3_x = v1_x + v3_y = v1_y + v3_z = v1_z + v3_xx = v1_xx + v3_yy = v1_yy + v3_zz = v1_zz + v3_xz = v1_xz + v3_yz = v1_yz + + # Pressure and its derivatives + p = rho^2 + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_z = 2.0 * rho * rho_z + + # Total energy and its derivatives; simiplifies from ansatz that v2 = v1 and v3 = v1 + E = p * inv_gamma_minus_one + 1.5 * rho * v1^2 + E_t = p_t * inv_gamma_minus_one + 1.5 * rho_t * v1^2 + 3.0 * rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + 1.5 * rho_x * v1^2 + 3.0 * rho * v1 * v1_x + E_y = p_y * inv_gamma_minus_one + 1.5 * rho_y * v1^2 + 3.0 * rho * v1 * v1_y + E_z = p_z * inv_gamma_minus_one + 1.5 * rho_z * v1^2 + 3.0 * rho * v1 * v1_z + + # Divergence of Fick's law ∇⋅∇q = kappa ∇⋅∇T; simplifies because p = rho², so T = p/rho = rho + kappa = equations.gamma * inv_gamma_minus_one / Pr + q_xx = kappa * rho_xx # kappa T_xx + q_yy = kappa * rho_yy # kappa T_yy + q_zz = kappa * rho_zz # kappa T_zz + + # Stress tensor and its derivatives (exploit symmetry) + tau11 = 4.0 / 3.0 * v1_x - 2.0 / 3.0 * (v2_y + v3_z) + tau12 = v1_y + v2_x + tau13 = v1_z + v3_x + tau22 = 4.0 / 3.0 * v2_y - 2.0 / 3.0 * (v1_x + v3_z) + tau23 = v2_z + v3_y + tau33 = 4.0 / 3.0 * v3_z - 2.0 / 3.0 * (v1_x + v2_y) + + tau11_x = 4.0 / 3.0 * v1_xx - 2.0 / 3.0 * (v2_xy + v3_xz) + tau12_x = v1_xy + v2_xx + tau13_x = v1_xz + v3_xx + + tau12_y = v1_yy + v2_xy + tau22_y = 4.0 / 3.0 * v2_yy - 2.0 / 3.0 * (v1_xy + v3_yz) + tau23_y = v2_yz + v3_yy + + tau13_z = v1_zz + v3_xz + tau23_z = v2_zz + v3_yz + tau33_z = 4.0 / 3.0 * v3_zz - 2.0 / 3.0 * (v1_xz + v2_yz) + + # Compute the source terms + # Density equation + du1 = (rho_t + rho_x * v1 + rho * v1_x + + rho_y * v2 + rho * v2_y + + rho_z * v3 + rho * v3_z) + # x-momentum equation + du2 = (rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y + + rho_z * v1 * v3 + + rho * v1_z * v3 + + rho * v1 * v3_z - + mu_ * (tau11_x + tau12_y + tau13_z)) + # y-momentum equation + du3 = (rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y + + rho_z * v2 * v3 + + rho * v2_z * v3 + + rho * v2 * v3_z - + mu_ * (tau12_x + tau22_y + tau23_z)) + # z-momentum equation + du4 = (rho_t * v3 + rho * v3_t + p_z + rho_x * v1 * v3 + + rho * v1_x * v3 + + rho * v1 * v3_x + + rho_y * v2 * v3 + + rho * v2_y * v3 + + rho * v2 * v3_y + + rho_z * v3^2 + + 2.0 * rho * v3 * v3_z - + mu_ * (tau13_x + tau23_y + tau33_z)) + # Total energy equation + du5 = (E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) + + v3_z * (E + p) + v3 * (E_z + p_z) - + # stress tensor and temperature gradient from x-direction + mu_ * (q_xx + v1_x * tau11 + v2_x * tau12 + v3_x * tau13 + + v1 * tau11_x + v2 * tau12_x + v3 * tau13_x) - + # stress tensor and temperature gradient terms from y-direction + mu_ * (q_yy + v1_y * tau12 + v2_y * tau22 + v3_y * tau23 + + v1 * tau12_y + v2 * tau22_y + v3 * tau23_y) - + # stress tensor and temperature gradient terms from z-direction + mu_ * (q_zz + v1_z * tau13 + v2_z * tau23 + v3_z * tau33 + + v1 * tau13_z + v2 * tau23_z + v3 * tau33_z)) + + return SVector(du1, du2, du3, du4, du5) end initial_condition = initial_condition_navier_stokes_convergence_test # BC types -velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:4]) +velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, + t, + equations)[2:4]) heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) -boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, heat_bc_top_bottom) +boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, + heat_bc_top_bottom) # define inviscid boundary conditions boundary_conditions = (; :top_bottom => boundary_condition_slip_wall) @@ -236,10 +242,11 @@ boundary_conditions = (; :top_bottom => boundary_condition_slip_wall) # define viscous boundary conditions boundary_conditions_parabolic = (; :top_bottom => boundary_condition_top_bottom) -semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, dg; - boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), - source_terms=source_terms_navier_stokes_convergence_test) - +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, dg; + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic), + source_terms = source_terms_navier_stokes_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -249,15 +256,15 @@ tspan = (0.0, 1.0) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary diff --git a/examples/dgmulti_3d/elixir_navierstokes_taylor_green_vortex.jl b/examples/dgmulti_3d/elixir_navierstokes_taylor_green_vortex.jl index 7953838afeb..dedd8267a3b 100644 --- a/examples/dgmulti_3d/elixir_navierstokes_taylor_green_vortex.jl +++ b/examples/dgmulti_3d/elixir_navierstokes_taylor_green_vortex.jl @@ -10,26 +10,30 @@ prandtl_number() = 0.72 mu() = 6.25e-4 # equivalent to Re = 1600 equations = CompressibleEulerEquations3D(1.4) -equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu=mu(), - Prandtl=prandtl_number()) +equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu = mu(), + Prandtl = prandtl_number()) """ initial_condition_taylor_green_vortex(x, t, equations::CompressibleEulerEquations3D) The classical inviscid Taylor-Green vortex. """ -function initial_condition_taylor_green_vortex(x, t, equations::CompressibleEulerEquations3D) - A = 1.0 # magnitude of speed - Ms = 0.1 # maximum Mach number - - rho = 1.0 - v1 = A * sin(x[1]) * cos(x[2]) * cos(x[3]) - v2 = -A * cos(x[1]) * sin(x[2]) * cos(x[3]) - v3 = 0.0 - p = (A / Ms)^2 * rho / equations.gamma # scaling to get Ms - p = p + 1.0/16.0 * A^2 * rho * (cos(2*x[1])*cos(2*x[3]) + 2*cos(2*x[2]) + 2*cos(2*x[1]) + cos(2*x[2])*cos(2*x[3])) - - return prim2cons(SVector(rho, v1, v2, v3, p), equations) +function initial_condition_taylor_green_vortex(x, t, + equations::CompressibleEulerEquations3D) + A = 1.0 # magnitude of speed + Ms = 0.1 # maximum Mach number + + rho = 1.0 + v1 = A * sin(x[1]) * cos(x[2]) * cos(x[3]) + v2 = -A * cos(x[1]) * sin(x[2]) * cos(x[3]) + v3 = 0.0 + p = (A / Ms)^2 * rho / equations.gamma # scaling to get Ms + p = p + + 1.0 / 16.0 * A^2 * rho * + (cos(2 * x[1]) * cos(2 * x[3]) + 2 * cos(2 * x[2]) + 2 * cos(2 * x[1]) + + cos(2 * x[2]) * cos(2 * x[3])) + + return prim2cons(SVector(rho, v1, v2, v3, p), equations) end initial_condition = initial_condition_taylor_green_vortex @@ -39,11 +43,11 @@ dg = DGMulti(polydeg = 3, element_type = Hex(), approximation_type = GaussSBP(), volume_integral = VolumeIntegralFluxDifferencing(flux_ranocha)) coordinates_min = (-1.0, -1.0, -1.0) .* pi -coordinates_max = ( 1.0, 1.0, 1.0) .* pi +coordinates_max = (1.0, 1.0, 1.0) .* pi cells_per_dimension = (8, 8, 8) mesh = DGMultiMesh(dg, cells_per_dimension; coordinates_min, coordinates_max, - periodicity=(true, true, true)) + periodicity = (true, true, true)) semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, dg) @@ -55,18 +59,18 @@ tspan = (0.0, 10.0) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg), - extra_analysis_integrals=(energy_kinetic, - energy_internal, - enstrophy)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg), + extra_analysis_integrals = (energy_kinetic, + energy_internal, + enstrophy)) callbacks = CallbackSet(summary_callback, alive_callback) ############################################################################### # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary diff --git a/examples/p4est_2d_dgsem/elixir_advection_amr_solution_independent.jl b/examples/p4est_2d_dgsem/elixir_advection_amr_solution_independent.jl index 841a080947e..5a2537be4e6 100644 --- a/examples/p4est_2d_dgsem/elixir_advection_amr_solution_independent.jl +++ b/examples/p4est_2d_dgsem/elixir_advection_amr_solution_independent.jl @@ -7,74 +7,73 @@ module TrixiExtension using Trixi -struct IndicatorSolutionIndependent{Cache<:NamedTuple} <: Trixi.AbstractIndicator - cache::Cache +struct IndicatorSolutionIndependent{Cache <: NamedTuple} <: Trixi.AbstractIndicator + cache::Cache end function IndicatorSolutionIndependent(semi) - basis = semi.solver.basis - alpha = Vector{real(basis)}() - cache = (; semi.mesh, alpha) - return IndicatorSolutionIndependent{typeof(cache)}(cache) + basis = semi.solver.basis + alpha = Vector{real(basis)}() + cache = (; semi.mesh, alpha) + return IndicatorSolutionIndependent{typeof(cache)}(cache) end -function (indicator::IndicatorSolutionIndependent)(u::AbstractArray{<:Any,4}, +function (indicator::IndicatorSolutionIndependent)(u::AbstractArray{<:Any, 4}, mesh, equations, dg, cache; t, kwargs...) - - mesh = indicator.cache.mesh - alpha = indicator.cache.alpha - resize!(alpha, nelements(dg, cache)) - - #Predict the theoretical center. - advection_velocity = (0.2, -0.7) - center = t.*advection_velocity - - inner_distance = 1 - outer_distance = 1.85 - - #Iterate over all elements - for element in 1:length(alpha) - # Calculate periodic distance between cell and center. - # This requires an uncurved mesh! - coordinates = SVector(0.5 * (cache.elements.node_coordinates[1, 1, 1, element] + - cache.elements.node_coordinates[1, end, 1, element]), - 0.5 * (cache.elements.node_coordinates[2, 1, 1, element] + - cache.elements.node_coordinates[2, 1, end, element])) - - #The geometric shape of the amr should be preserved when the base_level is increased. - #This is done by looking at the original coordinates of each cell. - cell_coordinates = original_coordinates(coordinates, 5/8) - cell_distance = periodic_distance_2d(cell_coordinates, center, 10) - if cell_distance < (inner_distance+outer_distance)/2 - cell_coordinates = original_coordinates(coordinates, 5/16) - cell_distance = periodic_distance_2d(cell_coordinates, center, 10) + mesh = indicator.cache.mesh + alpha = indicator.cache.alpha + resize!(alpha, nelements(dg, cache)) + + #Predict the theoretical center. + advection_velocity = (0.2, -0.7) + center = t .* advection_velocity + + inner_distance = 1 + outer_distance = 1.85 + + #Iterate over all elements + for element in 1:length(alpha) + # Calculate periodic distance between cell and center. + # This requires an uncurved mesh! + coordinates = SVector(0.5 * (cache.elements.node_coordinates[1, 1, 1, element] + + cache.elements.node_coordinates[1, end, 1, element]), + 0.5 * (cache.elements.node_coordinates[2, 1, 1, element] + + cache.elements.node_coordinates[2, 1, end, element])) + + #The geometric shape of the amr should be preserved when the base_level is increased. + #This is done by looking at the original coordinates of each cell. + cell_coordinates = original_coordinates(coordinates, 5 / 8) + cell_distance = periodic_distance_2d(cell_coordinates, center, 10) + if cell_distance < (inner_distance + outer_distance) / 2 + cell_coordinates = original_coordinates(coordinates, 5 / 16) + cell_distance = periodic_distance_2d(cell_coordinates, center, 10) + end + + #Set alpha according to cells position inside the circles. + target_level = (cell_distance < inner_distance) + (cell_distance < outer_distance) + alpha[element] = target_level / 2 end - - #Set alpha according to cells position inside the circles. - target_level = (cell_distance < inner_distance) + (cell_distance < outer_distance) - alpha[element] = target_level/2 - end - return alpha + return alpha end # For periodic domains, distance between two points must take into account # periodic extensions of the domain function periodic_distance_2d(coordinates, center, domain_length) - dx = coordinates .- center - dx_shifted = abs.(dx .% domain_length) - dx_periodic = min.(dx_shifted, domain_length .- dx_shifted) - return sqrt(sum(dx_periodic.^2)) + dx = coordinates .- center + dx_shifted = abs.(dx .% domain_length) + dx_periodic = min.(dx_shifted, domain_length .- dx_shifted) + return sqrt(sum(dx_periodic .^ 2)) end #This takes a cells coordinates and transforms them into the coordinates of a parent-cell it originally refined from. #It does it so that the parent-cell has given cell_length. function original_coordinates(coordinates, cell_length) - offset = coordinates .% cell_length - offset_sign = sign.(offset) - border = coordinates - offset - center = border + (offset_sign .* cell_length/2) - return center + offset = coordinates .% cell_length + offset_sign = sign.(offset) + border = coordinates - offset + center = border + (offset_sign .* cell_length / 2) + return center end end # module TrixiExtension @@ -88,21 +87,19 @@ equations = LinearScalarAdvectionEquation2D(advection_velocity) initial_condition = initial_condition_gauss -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-5.0, -5.0) -coordinates_max = ( 5.0, 5.0) +coordinates_max = (5.0, 5.0) trees_per_dimension = (1, 1) -mesh = P4estMesh(trees_per_dimension, polydeg=3, - coordinates_min=coordinates_min, coordinates_max=coordinates_max, - initial_refinement_level=4) - +mesh = P4estMesh(trees_per_dimension, polydeg = 3, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + initial_refinement_level = 4) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -112,38 +109,38 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -amr_controller = ControllerThreeLevel(semi, TrixiExtension.IndicatorSolutionIndependent(semi), - base_level=4, - med_level=5, med_threshold=0.1, - max_level=6, max_threshold=0.6) +amr_controller = ControllerThreeLevel(semi, + TrixiExtension.IndicatorSolutionIndependent(semi), + base_level = 4, + med_level = 5, med_threshold = 0.1, + max_level = 6, max_threshold = 0.6) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) 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); +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/p4est_2d_dgsem/elixir_advection_amr_unstructured_flag.jl b/examples/p4est_2d_dgsem/elixir_advection_amr_unstructured_flag.jl index 7e6d99c83b1..0a50b3644f0 100644 --- a/examples/p4est_2d_dgsem/elixir_advection_amr_unstructured_flag.jl +++ b/examples/p4est_2d_dgsem/elixir_advection_amr_unstructured_flag.jl @@ -12,18 +12,16 @@ equations = LinearScalarAdvectionEquation2D(advection_velocity) initial_condition = initial_condition_gauss boundary_condition = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = Dict( - :all => boundary_condition -) +boundary_conditions = Dict(:all => boundary_condition) -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) # Deformed rectangle that looks like a waving flag, # lower and upper faces are sinus curves, left and right are vertical lines. f1(s) = SVector(-5.0, 5 * s - 5.0) -f2(s) = SVector( 5.0, 5 * s + 5.0) +f2(s) = SVector(5.0, 5 * s + 5.0) f3(s) = SVector(5 * s, -5.0 + 5 * sin(0.5 * pi * s)) -f4(s) = SVector(5 * s, 5.0 + 5 * sin(0.5 * pi * s)) +f4(s) = SVector(5 * s, 5.0 + 5 * sin(0.5 * pi * s)) faces = (f1, f2, f3, f4) # This creates a mapping that transforms [-1, 1]^2 to the domain with the faces defined above. @@ -34,17 +32,16 @@ mapping_flag = Trixi.transfinite_mapping(faces) # Unstructured mesh with 24 cells of the square domain [-1, 1]^n mesh_file = joinpath(@__DIR__, "square_unstructured_2.inp") -isfile(mesh_file) || download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", - mesh_file) - -mesh = P4estMesh{2}(mesh_file, polydeg=3, - mapping=mapping_flag, - initial_refinement_level=1) +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", + mesh_file) +mesh = P4estMesh{2}(mesh_file, polydeg = 3, + mapping = mapping_flag, + initial_refinement_level = 1) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -55,41 +52,40 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable=first), - base_level=1, - med_level=2, med_threshold=0.1, - max_level=3, max_threshold=0.6) +amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first), + base_level = 1, + med_level = 2, med_threshold = 0.1, + max_level = 3, max_threshold = 0.6) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=0.7) +stepsize_callback = StepsizeCallback(cfl = 0.7) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_restart, save_solution, amr_callback, stepsize_callback); - ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=1, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1, # 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/p4est_2d_dgsem/elixir_advection_basic.jl b/examples/p4est_2d_dgsem/elixir_advection_basic.jl index 0b2de85da48..ed235bf839c 100644 --- a/examples/p4est_2d_dgsem/elixir_advection_basic.jl +++ b/examples/p4est_2d_dgsem/elixir_advection_basic.jl @@ -11,21 +11,21 @@ advection_velocity = (0.2, -0.7) 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) -coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) +coordinates_max = (1.0, 1.0) # maximum coordinates (max(x), max(y)) trees_per_dimension = (8, 8) # Create P4estMesh with 8 x 8 trees and 16 x 16 elements -mesh = P4estMesh(trees_per_dimension, polydeg=3, - coordinates_min=coordinates_min, coordinates_max=coordinates_max, - initial_refinement_level=1) +mesh = P4estMesh(trees_per_dimension, polydeg = 3, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + initial_refinement_level = 1) # A semidiscretization collects data structures and functions for the spatial discretization -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, solver) - +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, + solver) ############################################################################### # ODE solvers, callbacks etc. @@ -38,26 +38,26 @@ ode = semidiscretize(semi, (0.0, 1.0)); summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +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.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) # 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) - +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/p4est_2d_dgsem/elixir_advection_diffusion_nonperiodic_curved.jl b/examples/p4est_2d_dgsem/elixir_advection_diffusion_nonperiodic_curved.jl index 55682f73fce..5497f13aa65 100644 --- a/examples/p4est_2d_dgsem/elixir_advection_diffusion_nonperiodic_curved.jl +++ b/examples/p4est_2d_dgsem/elixir_advection_diffusion_nonperiodic_curved.jl @@ -16,15 +16,15 @@ equations_parabolic = LaplaceDiffusion2D(diffusivity(), equations) # to numerical partial differential equations. # [DOI](https://doi.org/10.1007/978-3-319-41640-3_6). function initial_condition_eriksson_johnson(x, t, equations) - l = 4 - epsilon = diffusivity() # TODO: this requires epsilon < .6 due to sqrt - lambda_1 = (-1 + sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) - lambda_2 = (-1 - sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) - r1 = (1 + sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) - s1 = (1 - sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) - u = exp(-l * t) * (exp(lambda_1 * x[1]) - exp(lambda_2 * x[1])) + - cos(pi * x[2]) * (exp(s1 * x[1]) - exp(r1 * x[1])) / (exp(-s1) - exp(-r1)) - return SVector{1}(u) + l = 4 + epsilon = diffusivity() # TODO: this requires epsilon < .6 due to sqrt + lambda_1 = (-1 + sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + lambda_2 = (-1 - sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + r1 = (1 + sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + s1 = (1 - sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + u = exp(-l * t) * (exp(lambda_1 * x[1]) - exp(lambda_2 * x[1])) + + cos(pi * x[2]) * (exp(s1 * x[1]) - exp(r1 * x[1])) / (exp(-s1) - exp(-r1)) + return SVector{1}(u) end initial_condition = initial_condition_eriksson_johnson @@ -33,34 +33,35 @@ boundary_conditions = Dict(:x_neg => BoundaryConditionDirichlet(initial_conditio :y_pos => BoundaryConditionDirichlet(initial_condition), :x_pos => boundary_condition_do_nothing) -boundary_conditions_parabolic = Dict(:x_neg => BoundaryConditionDirichlet(initial_condition), - :x_pos => BoundaryConditionDirichlet(initial_condition), - :y_neg => BoundaryConditionDirichlet(initial_condition), +boundary_conditions_parabolic = Dict(:x_neg => BoundaryConditionDirichlet(initial_condition), + :x_pos => BoundaryConditionDirichlet(initial_condition), + :y_neg => BoundaryConditionDirichlet(initial_condition), :y_pos => BoundaryConditionDirichlet(initial_condition)) # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) -coordinates_min = (-1.0, -0.5) -coordinates_max = ( 0.0, 0.5) +coordinates_min = (-1.0, -0.5) +coordinates_max = (0.0, 0.5) # This maps the domain [-1, 1]^2 to [-1, 0] x [-0.5, 0.5] while also # introducing a curved warping to interior nodes. function mapping(xi, eta) - x = xi + 0.1 * sin(pi * xi) * sin(pi * eta) + x = xi + 0.1 * sin(pi * xi) * sin(pi * eta) y = eta + 0.1 * sin(pi * xi) * sin(pi * eta) return SVector(0.5 * (1 + x) - 1, 0.5 * y) -end +end trees_per_dimension = (4, 4) mesh = P4estMesh(trees_per_dimension, - polydeg=3, initial_refinement_level=2, - mapping=mapping, periodicity=(false, false)) + polydeg = 3, initial_refinement_level = 2, + mapping = mapping, periodicity = (false, false)) # A semidiscretization collects data structures and functions for the spatial discretization -semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver, - boundary_conditions = (boundary_conditions, boundary_conditions_parabolic)) - +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver, + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic)) ############################################################################### # ODE solvers, callbacks etc. @@ -75,22 +76,21 @@ summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) # The AliveCallback prints short status information in regular intervals -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) - ############################################################################### # run the simulation # OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks time_int_tol = 1.0e-11 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) # Print the timer summary summary_callback() diff --git a/examples/p4est_2d_dgsem/elixir_advection_diffusion_periodic.jl b/examples/p4est_2d_dgsem/elixir_advection_diffusion_periodic.jl index 1cd075e84ea..0b5129e3c0f 100644 --- a/examples/p4est_2d_dgsem/elixir_advection_diffusion_periodic.jl +++ b/examples/p4est_2d_dgsem/elixir_advection_diffusion_periodic.jl @@ -9,19 +9,21 @@ advection_velocity = (1.0, 0.0) equations = LinearScalarAdvectionEquation2D(advection_velocity) equations_parabolic = LaplaceDiffusion2D(diffusivity(), equations) -function x_trans_periodic(x, domain_length=SVector(2 * pi), center=SVector(0.0)) +function x_trans_periodic(x, domain_length = SVector(2 * pi), center = SVector(0.0)) x_normalized = x .- center x_shifted = x_normalized .% domain_length - x_offset = ((x_shifted .< -0.5 * domain_length) - (x_shifted .> 0.5 * domain_length)) .* domain_length + x_offset = ((x_shifted .< -0.5 * domain_length) - (x_shifted .> 0.5 * domain_length)) .* + domain_length return center + x_shifted + x_offset end # Define initial condition (copied from "examples/tree_1d_dgsem/elixir_advection_diffusion.jl") -function initial_condition_diffusive_convergence_test(x, t, equation::LinearScalarAdvectionEquation2D) +function initial_condition_diffusive_convergence_test(x, t, + equation::LinearScalarAdvectionEquation2D) # Store translated coordinate for easy use of exact solution # Assumes that advection_velocity[2] = 0 (effectively that we are solving a 1D equation) x_trans = x_trans_periodic(x[1] - equation.advection_velocity[1] * t) - + nu = diffusivity() c = 0.0 A = 1.0 @@ -32,23 +34,22 @@ end initial_condition = initial_condition_diffusive_convergence_test # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-pi, -pi) # minimum coordinates (min(x), min(y)) -coordinates_max = ( pi, pi) # maximum coordinates (max(x), max(y)) +coordinates_max = (pi, pi) # maximum coordinates (max(x), max(y)) trees_per_dimension = (4, 4) mesh = P4estMesh(trees_per_dimension, - polydeg=3, initial_refinement_level=2, - coordinates_min=coordinates_min, coordinates_max=coordinates_max, - periodicity=true) + polydeg = 3, initial_refinement_level = 2, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + periodicity = true) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -62,22 +63,21 @@ summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) # The AliveCallback prints short status information in regular intervals -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) - ############################################################################### # run the simulation # OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks time_int_tol = 1.0e-11 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) # Print the timer summary summary_callback() diff --git a/examples/p4est_2d_dgsem/elixir_advection_diffusion_periodic_curved.jl b/examples/p4est_2d_dgsem/elixir_advection_diffusion_periodic_curved.jl index b438fb8a29c..130def37997 100644 --- a/examples/p4est_2d_dgsem/elixir_advection_diffusion_periodic_curved.jl +++ b/examples/p4est_2d_dgsem/elixir_advection_diffusion_periodic_curved.jl @@ -9,19 +9,21 @@ advection_velocity = (1.0, 0.0) equations = LinearScalarAdvectionEquation2D(advection_velocity) equations_parabolic = LaplaceDiffusion2D(diffusivity(), equations) -function x_trans_periodic(x, domain_length=SVector(2 * pi), center=SVector(0.0)) +function x_trans_periodic(x, domain_length = SVector(2 * pi), center = SVector(0.0)) x_normalized = x .- center x_shifted = x_normalized .% domain_length - x_offset = ((x_shifted .< -0.5 * domain_length) - (x_shifted .> 0.5 * domain_length)) .* domain_length + x_offset = ((x_shifted .< -0.5 * domain_length) - (x_shifted .> 0.5 * domain_length)) .* + domain_length return center + x_shifted + x_offset end # Define initial condition (copied from "examples/tree_1d_dgsem/elixir_advection_diffusion.jl") -function initial_condition_diffusive_convergence_test(x, t, equation::LinearScalarAdvectionEquation2D) +function initial_condition_diffusive_convergence_test(x, t, + equation::LinearScalarAdvectionEquation2D) # Store translated coordinate for easy use of exact solution # Assumes that advection_velocity[2] = 0 (effectively that we are solving a 1D equation) x_trans = x_trans_periodic(x[1] - equation.advection_velocity[1] * t) - + nu = diffusivity() c = 0.0 A = 1.0 @@ -32,28 +34,27 @@ end initial_condition = initial_condition_diffusive_convergence_test # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) # This maps the domain [-1, 1]^2 to [-pi, pi]^2 while also # introducing a curved warping to interior nodes. function mapping(xi, eta) - x = xi + 0.1 * sin(pi * xi) * sin(pi * eta) - y = eta + 0.1 * sin(pi * xi) * sin(pi * eta) - return pi * SVector(x, y) + x = xi + 0.1 * sin(pi * xi) * sin(pi * eta) + y = eta + 0.1 * sin(pi * xi) * sin(pi * eta) + return pi * SVector(x, y) end trees_per_dimension = (4, 4) mesh = P4estMesh(trees_per_dimension, - polydeg=3, initial_refinement_level=2, - mapping=mapping, - periodicity=true) + polydeg = 3, initial_refinement_level = 2, + mapping = mapping, + periodicity = true) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -67,22 +68,21 @@ summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) # The AliveCallback prints short status information in regular intervals -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) - ############################################################################### # run the simulation # OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks time_int_tol = 1.0e-11 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) # Print the timer summary summary_callback() diff --git a/examples/p4est_2d_dgsem/elixir_advection_extended.jl b/examples/p4est_2d_dgsem/elixir_advection_extended.jl index 6d8e7030ac0..66a5b7e0f5b 100644 --- a/examples/p4est_2d_dgsem/elixir_advection_extended.jl +++ b/examples/p4est_2d_dgsem/elixir_advection_extended.jl @@ -12,31 +12,28 @@ initial_condition = initial_condition_convergence_test # BCs must be passed as Dict boundary_condition = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = Dict( - :x_neg => boundary_condition, - :x_pos => boundary_condition, - :y_neg => boundary_condition, - :y_pos => boundary_condition -) +boundary_conditions = Dict(:x_neg => boundary_condition, + :x_pos => boundary_condition, + :y_neg => boundary_condition, + :y_pos => boundary_condition) # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) # The initial condition is 2-periodic coordinates_min = (-1.5, 1.3) # minimum coordinates (min(x), min(y)) -coordinates_max = ( 0.5, 5.3) # maximum coordinates (max(x), max(y)) +coordinates_max = (0.5, 5.3) # maximum coordinates (max(x), max(y)) trees_per_dimension = (19, 37) # Create curved mesh with 19 x 37 elements -mesh = P4estMesh(trees_per_dimension, polydeg=3, - coordinates_min=coordinates_min, coordinates_max=coordinates_max, - periodicity=false) +mesh = P4estMesh(trees_per_dimension, polydeg = 3, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + periodicity = false) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -51,24 +48,24 @@ summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy, energy_total)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy, energy_total)) # The AliveCallback prints short status information in regular intervals -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) # The SaveRestartCallback allows to save a file from which a Trixi.jl simulation can be restarted -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) # The SaveSolutionCallback allows to save the solution to a file in regular intervals -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) # The StepsizeCallback handles the re-calculation of the maximum Δt after each time step -stepsize_callback = StepsizeCallback(cfl=1.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver callbacks = CallbackSet(summary_callback, @@ -76,14 +73,13 @@ callbacks = CallbackSet(summary_callback, save_restart, 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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/p4est_2d_dgsem/elixir_advection_nonconforming_flag.jl b/examples/p4est_2d_dgsem/elixir_advection_nonconforming_flag.jl index 0e6e314ebd7..b47b0d61192 100644 --- a/examples/p4est_2d_dgsem/elixir_advection_nonconforming_flag.jl +++ b/examples/p4est_2d_dgsem/elixir_advection_nonconforming_flag.jl @@ -2,7 +2,6 @@ using OrdinaryDiffEq using Trixi - ############################################################################### # semidiscretization of the linear advection equation @@ -10,42 +9,44 @@ advection_velocity = (0.2, -0.7) equations = LinearScalarAdvectionEquation2D(advection_velocity) # Create DG solver with polynomial degree = 4 and (local) Lax-Friedrichs/Rusanov flux as surface flux -solver = DGSEM(polydeg=4, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 4, surface_flux = flux_lax_friedrichs) # Deformed rectangle that looks like a waving flag, # lower and upper faces are sinus curves, left and right are vertical lines. f1(s) = SVector(-1.0, s - 1.0) -f2(s) = SVector( 1.0, s + 1.0) +f2(s) = SVector(1.0, s + 1.0) f3(s) = SVector(s, -1.0 + sin(0.5 * pi * s)) -f4(s) = SVector(s, 1.0 + sin(0.5 * pi * s)) +f4(s) = SVector(s, 1.0 + sin(0.5 * pi * s)) # Create P4estMesh with 3 x 2 trees and 6 x 4 elements, # approximate the geometry with a smaller polydeg for testing. trees_per_dimension = (3, 2) -mesh = P4estMesh(trees_per_dimension, polydeg=3, - faces=(f1, f2, f3, f4), - initial_refinement_level=1) +mesh = P4estMesh(trees_per_dimension, polydeg = 3, + faces = (f1, f2, f3, f4), + initial_refinement_level = 1) # Refine bottom left quadrant of each tree to level 4 function refine_fn(p4est, which_tree, quadrant) - quadrant_obj = unsafe_load(quadrant) - if quadrant_obj.x == 0 && quadrant_obj.y == 0 && quadrant_obj.level < 4 - # return true (refine) - return Cint(1) - else - # return false (don't refine) - return Cint(0) - end + quadrant_obj = unsafe_load(quadrant) + if quadrant_obj.x == 0 && quadrant_obj.y == 0 && quadrant_obj.level < 4 + # return true (refine) + return Cint(1) + else + # return false (don't refine) + return Cint(0) + end end # Refine recursively until each bottom left quadrant of a tree has level 4 # The mesh will be rebalanced before the simulation starts -refine_fn_c = @cfunction(refine_fn, Cint, (Ptr{Trixi.p4est_t}, Ptr{Trixi.p4est_topidx_t}, Ptr{Trixi.p4est_quadrant_t})) +refine_fn_c = @cfunction(refine_fn, Cint, + (Ptr{Trixi.p4est_t}, Ptr{Trixi.p4est_topidx_t}, + Ptr{Trixi.p4est_quadrant_t})) Trixi.refine_p4est!(mesh.p4est, true, refine_fn_c, C_NULL) # A semidiscretization collects data structures and functions for the spatial discretization -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, solver) - +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, + solver) ############################################################################### # ODE solvers, callbacks etc. @@ -58,26 +59,26 @@ ode = semidiscretize(semi, (0.0, 0.2)); summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +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.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) # 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) - +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/p4est_2d_dgsem/elixir_advection_restart.jl b/examples/p4est_2d_dgsem/elixir_advection_restart.jl index 52917616a6a..4f43e122ab3 100644 --- a/examples/p4est_2d_dgsem/elixir_advection_restart.jl +++ b/examples/p4est_2d_dgsem/elixir_advection_restart.jl @@ -10,7 +10,6 @@ restart_file = "restart_000021.h5" trixi_include(@__MODULE__, joinpath(@__DIR__, elixir_file)) - ############################################################################### # adapt the parameters that have changed compared to "elixir_advection_extended.jl" @@ -21,7 +20,7 @@ restart_filename = joinpath("out", restart_file) mesh = load_mesh(restart_filename) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) + boundary_conditions = boundary_conditions) tspan = (load_time(restart_filename), 2.0) dt = load_dt(restart_filename) @@ -30,14 +29,13 @@ ode = semidiscretize(semi, tspan, restart_filename); # Do not overwrite the initial snapshot written by elixir_advection_extended.jl. save_solution.condition.save_initial_solution = false -integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=dt, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +integrator = init(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); # Get the last time index and work with that. load_timestep!(integrator, restart_filename) - ############################################################################### # run the simulation diff --git a/examples/p4est_2d_dgsem/elixir_advection_unstructured_flag.jl b/examples/p4est_2d_dgsem/elixir_advection_unstructured_flag.jl index 9f5b813639f..37fcc547f60 100644 --- a/examples/p4est_2d_dgsem/elixir_advection_unstructured_flag.jl +++ b/examples/p4est_2d_dgsem/elixir_advection_unstructured_flag.jl @@ -3,7 +3,6 @@ using Downloads: download using OrdinaryDiffEq using Trixi - ############################################################################### # semidiscretization of the linear advection equation @@ -13,19 +12,17 @@ equations = LinearScalarAdvectionEquation2D(advection_velocity) initial_condition = initial_condition_convergence_test boundary_condition = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = Dict( - :all => boundary_condition -) +boundary_conditions = Dict(:all => boundary_condition) # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) # Deformed rectangle that looks like a waving flag, # lower and upper faces are sinus curves, left and right are vertical lines. f1(s) = SVector(-1.0, s - 1.0) -f2(s) = SVector( 1.0, s + 1.0) +f2(s) = SVector(1.0, s + 1.0) f3(s) = SVector(s, -1.0 + sin(0.5 * pi * s)) -f4(s) = SVector(s, 1.0 + sin(0.5 * pi * s)) +f4(s) = SVector(s, 1.0 + sin(0.5 * pi * s)) faces = (f1, f2, f3, f4) Trixi.validate_faces(faces) @@ -33,16 +30,17 @@ mapping_flag = Trixi.transfinite_mapping(faces) # Unstructured mesh with 24 cells of the square domain [-1, 1]^n mesh_file = joinpath(@__DIR__, "square_unstructured_2.inp") -isfile(mesh_file) || download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", - mesh_file) +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", + mesh_file) -mesh = P4estMesh{2}(mesh_file, polydeg=3, - mapping=mapping_flag, - initial_refinement_level=2) +mesh = P4estMesh{2}(mesh_file, polydeg = 3, + mapping = mapping_flag, + initial_refinement_level = 2) # A semidiscretization collects data structures and functions for the spatial discretization -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions=boundary_conditions) - +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -56,26 +54,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +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.4) +stepsize_callback = StepsizeCallback(cfl = 1.4) # 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) - +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/p4est_2d_dgsem/elixir_euler_blast_wave_amr.jl b/examples/p4est_2d_dgsem/elixir_euler_blast_wave_amr.jl index e3f33fb0d28..0ca4fdc2eb7 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_blast_wave_amr.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_blast_wave_amr.jl @@ -17,49 +17,48 @@ A medium blast wave taken from [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) """ function initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations2D) - # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" - # 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) - phi = atan(y_norm, x_norm) - sin_phi, cos_phi = sincos(phi) - - # 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 - p = r > 0.5 ? 1.0E-3 : 1.245 - - return prim2cons(SVector(rho, v1, v2, p), equations) + # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" + # 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) + phi = atan(y_norm, x_norm) + sin_phi, cos_phi = sincos(phi) + + # 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 + p = r > 0.5 ? 1.0E-3 : 1.245 + + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_ranocha +volume_flux = flux_ranocha basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) # Unstructured mesh with 48 cells of the square domain [-1, 1]^n mesh_file = joinpath(@__DIR__, "square_unstructured_1.inp") -isfile(mesh_file) || download("https://gist.githubusercontent.com/efaulhaber/a075f8ec39a67fa9fad8f6f84342cbca/raw/a7206a02ed3a5d3cadacd8d9694ac154f9151db7/square_unstructured_1.inp", - mesh_file) +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/a075f8ec39a67fa9fad8f6f84342cbca/raw/a7206a02ed3a5d3cadacd8d9694ac154f9151db7/square_unstructured_1.inp", + mesh_file) -mesh = P4estMesh{2}(mesh_file, polydeg=3, initial_refinement_level=1) +mesh = P4estMesh{2}(mesh_file, polydeg = 3, initial_refinement_level = 1) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=Dict( - :all => BoundaryConditionDirichlet(initial_condition) - )) + boundary_conditions = Dict(:all => BoundaryConditionDirichlet(initial_condition))) ############################################################################### # ODE solvers, callbacks etc. @@ -70,40 +69,39 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = density_pressure) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=1, - max_level =3, max_threshold=0.01) + base_level = 1, + max_level = 3, max_threshold = 0.01) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=0.9) +stepsize_callback = StepsizeCallback(cfl = 0.9) 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); +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/p4est_2d_dgsem/elixir_euler_double_mach_amr.jl b/examples/p4est_2d_dgsem/elixir_euler_double_mach_amr.jl index 70a0e10c296..92928146d7b 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_double_mach_amr.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_double_mach_amr.jl @@ -21,64 +21,66 @@ See Section IV c on the paper below for details. The Numerical Simulation of Two-Dimensional Fluid Flows with Strong Shocks. [DOI: 10.1016/0021-9991(84)90142-6](https://doi.org/10.1016/0021-9991(84)90142-6) """ -@inline function initial_condition_double_mach_reflection(x, t, equations::CompressibleEulerEquations2D) - - if x[1] < 1 / 6 + (x[2] + 20 * t) / sqrt(3) - phi = pi / 6 - sin_phi, cos_phi = sincos(phi) - - rho = 8.0 - v1 = 8.25 * cos_phi - v2 = -8.25 * sin_phi - p = 116.5 - else - rho = 1.4 - v1 = 0.0 - v2 = 0.0 - p = 1.0 - end - - prim = SVector(rho, v1, v2, p) - return prim2cons(prim, equations) +@inline function initial_condition_double_mach_reflection(x, t, + equations::CompressibleEulerEquations2D) + if x[1] < 1 / 6 + (x[2] + 20 * t) / sqrt(3) + phi = pi / 6 + sin_phi, cos_phi = sincos(phi) + + rho = 8.0 + v1 = 8.25 * cos_phi + v2 = -8.25 * sin_phi + p = 116.5 + else + rho = 1.4 + v1 = 0.0 + v2 = 0.0 + p = 1.0 + end + + prim = SVector(rho, v1, v2, p) + return prim2cons(prim, equations) end initial_condition = initial_condition_double_mach_reflection - boundary_condition_inflow = BoundaryConditionDirichlet(initial_condition_double_mach_reflection) # Supersonic outflow boundary condition. Solution is taken entirely from the internal state. # See `examples/p4est_2d_dgsem/elixir_euler_forward_step_amr.jl` for complete documentation. @inline function boundary_condition_outflow(u_inner, normal_direction::AbstractVector, x, t, - surface_flux_function, equations::CompressibleEulerEquations2D) - # NOTE: Only for the supersonic outflow is this strategy valid - # Calculate the boundary flux entirely from the internal solution state - return flux(u_inner, normal_direction, equations) + surface_flux_function, + equations::CompressibleEulerEquations2D) + # NOTE: Only for the supersonic outflow is this strategy valid + # Calculate the boundary flux entirely from the internal solution state + return flux(u_inner, normal_direction, equations) end # Special mixed boundary condition type for the :Bottom of the domain. # It is Dirichlet when x < 1/6 and a slip wall when x >= 1/6 -@inline function boundary_condition_mixed_dirichlet_wall(u_inner, normal_direction::AbstractVector, +@inline function boundary_condition_mixed_dirichlet_wall(u_inner, + normal_direction::AbstractVector, x, t, surface_flux_function, equations::CompressibleEulerEquations2D) - if x[1] < 1 / 6 - # From the BoundaryConditionDirichlet - # get the external value of the solution - u_boundary = initial_condition_double_mach_reflection(x, t, equations) - # Calculate boundary flux - flux = surface_flux_function(u_inner, u_boundary, normal_direction, equations) - else # x[1] >= 1 / 6 - # Use the free slip wall BC otherwise - flux = boundary_condition_slip_wall(u_inner, normal_direction, x, t, surface_flux_function, equations) - end - - return flux + if x[1] < 1 / 6 + # From the BoundaryConditionDirichlet + # get the external value of the solution + u_boundary = initial_condition_double_mach_reflection(x, t, equations) + # Calculate boundary flux + flux = surface_flux_function(u_inner, u_boundary, normal_direction, equations) + else # x[1] >= 1 / 6 + # Use the free slip wall BC otherwise + flux = boundary_condition_slip_wall(u_inner, normal_direction, x, t, + surface_flux_function, equations) + end + + return flux end -boundary_conditions = Dict( :Bottom => boundary_condition_mixed_dirichlet_wall, - :Top => boundary_condition_inflow, - :Right => boundary_condition_outflow, - :Left => boundary_condition_inflow ) +boundary_conditions = Dict(:Bottom => boundary_condition_mixed_dirichlet_wall, + :Top => boundary_condition_inflow, + :Right => boundary_condition_outflow, + :Left => boundary_condition_inflow) volume_flux = flux_ranocha surface_flux = flux_lax_friedrichs @@ -86,25 +88,27 @@ surface_flux = flux_lax_friedrichs polydeg = 4 basis = LobattoLegendreBasis(polydeg) shock_indicator = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = density_pressure) volume_integral = VolumeIntegralShockCapturingHG(shock_indicator; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) -solver = DGSEM(polydeg=polydeg, surface_flux=surface_flux, volume_integral=volume_integral) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral) # Get the unstructured quad mesh from a file (downloads the file if not available locally) default_mesh_file = joinpath(@__DIR__, "abaqus_double_mach.inp") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/a0806ef0d03cf5ea221af523167b6e32/raw/61ed0eb017eb432d996ed119a52fb041fe363e8c/abaqus_double_mach.inp", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/a0806ef0d03cf5ea221af523167b6e32/raw/61ed0eb017eb432d996ed119a52fb041fe363e8c/abaqus_double_mach.inp", + default_mesh_file) mesh_file = default_mesh_file mesh = P4estMesh{2}(mesh_file) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -115,27 +119,27 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -amr_indicator = IndicatorLöhner(semi, variable=Trixi.density) +amr_indicator = IndicatorLöhner(semi, variable = Trixi.density) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=0, - med_level=3, med_threshold=0.05, - max_level=6, max_threshold=0.1) + base_level = 0, + med_level = 3, med_threshold = 0.05, + max_level = 6, max_threshold = 0.1) amr_callback = AMRCallback(semi, amr_controller, - interval=1, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 1, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -143,11 +147,11 @@ callbacks = CallbackSet(summary_callback, amr_callback) # positivity limiter necessary for this example with strong shocks -stage_limiter! = PositivityPreservingLimiterZhangShu(thresholds=(5.0e-6, 5.0e-6), - variables=(Trixi.density, pressure)) +stage_limiter! = PositivityPreservingLimiterZhangShu(thresholds = (5.0e-6, 5.0e-6), + variables = (Trixi.density, pressure)) ############################################################################### # run the simulation sol = solve(ode, SSPRK43(stage_limiter!); - ode_default_options()..., callback=callbacks); + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/p4est_2d_dgsem/elixir_euler_forward_step_amr.jl b/examples/p4est_2d_dgsem/elixir_euler_forward_step_amr.jl index 667834ea108..0ec9fc222f2 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_forward_step_amr.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_forward_step_amr.jl @@ -20,19 +20,18 @@ See Section IV b on the paper below for details. [DOI: 10.1016/0021-9991(84)90142-6](https://doi.org/10.1016/0021-9991(84)90142-6) """ @inline function initial_condition_mach3_flow(x, t, equations::CompressibleEulerEquations2D) - # set the freestream flow parameters - rho_freestream = 1.4 - v1 = 3.0 - v2 = 0.0 - p_freestream = 1.0 - - prim = SVector(rho_freestream, v1, v2, p_freestream) - return prim2cons(prim, equations) + # set the freestream flow parameters + rho_freestream = 1.4 + v1 = 3.0 + v2 = 0.0 + p_freestream = 1.0 + + prim = SVector(rho_freestream, v1, v2, p_freestream) + return prim2cons(prim, equations) end initial_condition = initial_condition_mach3_flow - boundary_condition_inflow = BoundaryConditionDirichlet(initial_condition_mach3_flow) # Outflow boundary condition. @@ -46,46 +45,47 @@ boundary_condition_inflow = BoundaryConditionDirichlet(initial_condition_mach3_f # Inflow/Outflow Boundary Conditions with Application to FUN3D. # [NASA TM 20110022658](https://ntrs.nasa.gov/citations/20110022658) @inline function boundary_condition_outflow(u_inner, normal_direction::AbstractVector, x, t, - surface_flux_function, equations::CompressibleEulerEquations2D) - # # This would be for the general case where we need to check the magnitude of the local Mach number - # norm_ = norm(normal_direction) - # # Normalize the vector without using `normalize` since we need to multiply by the `norm_` later - # normal = normal_direction / norm_ - - # # Rotate the internal solution state - # u_local = Trixi.rotate_to_x(u_inner, normal, equations) - - # # Compute the primitive variables - # rho_local, v_normal, v_tangent, p_local = cons2prim(u_local, equations) - - # # Compute local Mach number - # a_local = sqrt( equations.gamma * p_local / rho_local ) - # Mach_local = abs( v_normal / a_local ) - # if Mach_local <= 1.0 - # p_local = # Set to the external reference pressure value (somehow? maybe stored in `equations`) - # end - - # # Create the `u_surface` solution state where the local pressure is possibly set from an external value - # prim = SVector(rho_local, v_normal, v_tangent, p_local) - # u_boundary = prim2cons(prim, equations) - # u_surface = Trixi.rotate_from_x(u_boundary, normal, equations) - - # Compute the flux using the appropriate mixture of internal / external solution states - # flux = Trixi.flux(u_surface, normal_direction, equations) - - # NOTE: Only for the supersonic outflow is this strategy valid - # Calculate the boundary flux entirely from the internal solution state - flux = Trixi.flux(u_inner, normal_direction, equations) - - return flux + surface_flux_function, + equations::CompressibleEulerEquations2D) + # # This would be for the general case where we need to check the magnitude of the local Mach number + # norm_ = norm(normal_direction) + # # Normalize the vector without using `normalize` since we need to multiply by the `norm_` later + # normal = normal_direction / norm_ + + # # Rotate the internal solution state + # u_local = Trixi.rotate_to_x(u_inner, normal, equations) + + # # Compute the primitive variables + # rho_local, v_normal, v_tangent, p_local = cons2prim(u_local, equations) + + # # Compute local Mach number + # a_local = sqrt( equations.gamma * p_local / rho_local ) + # Mach_local = abs( v_normal / a_local ) + # if Mach_local <= 1.0 + # p_local = # Set to the external reference pressure value (somehow? maybe stored in `equations`) + # end + + # # Create the `u_surface` solution state where the local pressure is possibly set from an external value + # prim = SVector(rho_local, v_normal, v_tangent, p_local) + # u_boundary = prim2cons(prim, equations) + # u_surface = Trixi.rotate_from_x(u_boundary, normal, equations) + + # Compute the flux using the appropriate mixture of internal / external solution states + # flux = Trixi.flux(u_surface, normal_direction, equations) + + # NOTE: Only for the supersonic outflow is this strategy valid + # Calculate the boundary flux entirely from the internal solution state + flux = Trixi.flux(u_inner, normal_direction, equations) + + return flux end -boundary_conditions = Dict( :Bottom => boundary_condition_slip_wall, - :Step_Front => boundary_condition_slip_wall, - :Step_Top => boundary_condition_slip_wall, - :Top => boundary_condition_slip_wall, - :Right => boundary_condition_outflow, - :Left => boundary_condition_inflow ) +boundary_conditions = Dict(:Bottom => boundary_condition_slip_wall, + :Step_Front => boundary_condition_slip_wall, + :Step_Top => boundary_condition_slip_wall, + :Top => boundary_condition_slip_wall, + :Right => boundary_condition_outflow, + :Left => boundary_condition_inflow) volume_flux = flux_ranocha surface_flux = flux_lax_friedrichs @@ -93,25 +93,27 @@ surface_flux = flux_lax_friedrichs polydeg = 4 basis = LobattoLegendreBasis(polydeg) shock_indicator = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = density_pressure) volume_integral = VolumeIntegralShockCapturingHG(shock_indicator; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) -solver = DGSEM(polydeg=polydeg, surface_flux=surface_flux, volume_integral=volume_integral) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral) # Get the unstructured quad mesh from a file (downloads the file if not available locally) default_mesh_file = joinpath(@__DIR__, "abaqus_forward_step.inp") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/b346ee6aa5446687f128eab8b37d52a7/raw/cd1e1d43bebd8d2631a07caec45585ec8456ca4c/abaqus_forward_step.inp", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/b346ee6aa5446687f128eab8b37d52a7/raw/cd1e1d43bebd8d2631a07caec45585ec8456ca4c/abaqus_forward_step.inp", + default_mesh_file) mesh_file = default_mesh_file mesh = P4estMesh{2}(mesh_file) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -122,27 +124,27 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=2000, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 2000, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -amr_indicator = IndicatorLöhner(semi, variable=Trixi.density) +amr_indicator = IndicatorLöhner(semi, variable = Trixi.density) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=0, - med_level=2, med_threshold=0.05, - max_level=5, max_threshold=0.1) + base_level = 0, + med_level = 2, med_threshold = 0.05, + max_level = 5, max_threshold = 0.1) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -150,12 +152,12 @@ callbacks = CallbackSet(summary_callback, amr_callback) # positivity limiter necessary for this example with strong shocks -stage_limiter! = PositivityPreservingLimiterZhangShu(thresholds=(5.0e-6, 5.0e-6), - variables=(Trixi.density, pressure)) +stage_limiter! = PositivityPreservingLimiterZhangShu(thresholds = (5.0e-6, 5.0e-6), + variables = (Trixi.density, pressure)) ############################################################################### # run the simulation sol = solve(ode, SSPRK43(stage_limiter!); - maxiters=999999, ode_default_options()..., - callback=callbacks); + maxiters = 999999, ode_default_options()..., + callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/p4est_2d_dgsem/elixir_euler_free_stream.jl b/examples/p4est_2d_dgsem/elixir_euler_free_stream.jl index e88baa2223d..38307a7d781 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_free_stream.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_free_stream.jl @@ -10,21 +10,21 @@ equations = CompressibleEulerEquations2D(1.4) initial_condition = initial_condition_constant -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) # Mapping as described in https://arxiv.org/abs/2012.12040 but reduced to 2D function mapping(xi_, eta_) - # Transform input variables between -1 and 1 onto [0,3] - xi = 1.5 * xi_ + 1.5 - eta = 1.5 * eta_ + 1.5 + # Transform input variables between -1 and 1 onto [0,3] + xi = 1.5 * xi_ + 1.5 + eta = 1.5 * eta_ + 1.5 - y = eta + 3/8 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3)) + y = eta + 3 / 8 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3)) - x = xi + 3/8 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3)) + x = xi + 3 / 8 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3)) - return SVector(x, y) + return SVector(x, y) end ############################################################################### @@ -32,34 +32,34 @@ end # Unstructured mesh with 48 cells of the square domain [-1, 1]^n mesh_file = joinpath(@__DIR__, "square_unstructured_1.inp") -isfile(mesh_file) || download("https://gist.githubusercontent.com/efaulhaber/a075f8ec39a67fa9fad8f6f84342cbca/raw/a7206a02ed3a5d3cadacd8d9694ac154f9151db7/square_unstructured_1.inp", - mesh_file) +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/a075f8ec39a67fa9fad8f6f84342cbca/raw/a7206a02ed3a5d3cadacd8d9694ac154f9151db7/square_unstructured_1.inp", + mesh_file) # Map the unstructured mesh with the mapping above -mesh = P4estMesh{2}(mesh_file, polydeg=3, mapping=mapping, initial_refinement_level=1) +mesh = P4estMesh{2}(mesh_file, polydeg = 3, mapping = mapping, initial_refinement_level = 1) # Refine bottom left quadrant of each tree to level 2 function refine_fn(p4est, which_tree, quadrant) - quadrant_obj = unsafe_load(quadrant) - if quadrant_obj.x == 0 && quadrant_obj.y == 0 && quadrant_obj.level < 3 - # return true (refine) - return Cint(1) - else - # return false (don't refine) - return Cint(0) - end + quadrant_obj = unsafe_load(quadrant) + if quadrant_obj.x == 0 && quadrant_obj.y == 0 && quadrant_obj.level < 3 + # return true (refine) + return Cint(1) + else + # return false (don't refine) + return Cint(0) + end end # Refine recursively until each bottom left quadrant of a tree has level 2. # The mesh will be rebalanced before the simulation starts. -refine_fn_c = @cfunction(refine_fn, Cint, (Ptr{Trixi.p4est_t}, Ptr{Trixi.p4est_topidx_t}, Ptr{Trixi.p4est_quadrant_t})) +refine_fn_c = @cfunction(refine_fn, Cint, + (Ptr{Trixi.p4est_t}, Ptr{Trixi.p4est_topidx_t}, + Ptr{Trixi.p4est_quadrant_t})) Trixi.refine_p4est!(mesh.p4est, true, refine_fn_c, C_NULL) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=Dict( - :all => BoundaryConditionDirichlet(initial_condition) - )) - + boundary_conditions = Dict(:all => BoundaryConditionDirichlet(initial_condition))) ############################################################################### # ODE solvers, callbacks etc. @@ -70,16 +70,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=2.0) +stepsize_callback = StepsizeCallback(cfl = 2.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -89,7 +89,7 @@ callbacks = CallbackSet(summary_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); +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/p4est_2d_dgsem/elixir_euler_sedov.jl b/examples/p4est_2d_dgsem/elixir_euler_sedov.jl index d5d8e0c78bf..539ddb45395 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_sedov.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_sedov.jl @@ -14,25 +14,25 @@ The Sedov blast wave setup based on Flash - https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_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) - - # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 - r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) - E = 1.0 - p0_inner = 3 * (equations.gamma - 1) * E / (3 * pi * r0^2) - p0_outer = 1.0e-5 # = true Sedov setup - - # Calculate primitive variables - rho = 1.0 - v1 = 0.0 - v2 = 0.0 - p = r > r0 ? p0_outer : p0_inner - - return prim2cons(SVector(rho, v1, v2, p), equations) + # 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) + + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 + r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) + E = 1.0 + p0_inner = 3 * (equations.gamma - 1) * E / (3 * pi * r0^2) + p0_outer = 1.0e-5 # = true Sedov setup + + # Calculate primitive variables + rho = 1.0 + 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_sedov_blast_wave @@ -43,26 +43,27 @@ 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) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) -solver = DGSEM(polydeg=polydeg, surface_flux=surface_flux, volume_integral=volume_integral) +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral) ############################################################################### coordinates_min = (-1.0, -1.0) -coordinates_max = ( 1.0, 1.0) +coordinates_max = (1.0, 1.0) 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) + polydeg = 4, initial_refinement_level = 2, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -75,15 +76,15 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 300 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=300, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 300, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -94,7 +95,7 @@ callbacks = CallbackSet(summary_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); +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/p4est_2d_dgsem/elixir_euler_shockcapturing_ec.jl b/examples/p4est_2d_dgsem/elixir_euler_shockcapturing_ec.jl index 6ef551c486f..0cb18526f8d 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_shockcapturing_ec.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_shockcapturing_ec.jl @@ -14,30 +14,30 @@ 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) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) -solver = DGSEM(polydeg=polydeg, surface_flux=surface_flux, volume_integral=volume_integral) +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral) ############################################################################### coordinates_min = (-1.0, -1.0) -coordinates_max = ( 1.0, 1.0) +coordinates_max = (1.0, 1.0) 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) + polydeg = 4, initial_refinement_level = 2, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -47,16 +47,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -66,7 +66,7 @@ callbacks = CallbackSet(summary_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); +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/p4est_2d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_flag.jl b/examples/p4est_2d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_flag.jl index d9a322b065a..09d018309a6 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_flag.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_flag.jl @@ -14,18 +14,16 @@ source_terms = source_terms_convergence_test # BCs must be passed as Dict boundary_condition = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = Dict( - :all => boundary_condition -) +boundary_conditions = Dict(:all => boundary_condition) -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) # Deformed rectangle that looks like a waving flag, # lower and upper faces are sinus curves, left and right are vertical lines. f1(s) = SVector(-1.0, s - 1.0) -f2(s) = SVector( 1.0, s + 1.0) +f2(s) = SVector(1.0, s + 1.0) f3(s) = SVector(s, -1.0 + sin(0.5 * pi * s)) -f4(s) = SVector(s, 1.0 + sin(0.5 * pi * s)) +f4(s) = SVector(s, 1.0 + sin(0.5 * pi * s)) faces = (f1, f2, f3, f4) Trixi.validate_faces(faces) @@ -34,34 +32,36 @@ mapping_flag = Trixi.transfinite_mapping(faces) # Get the uncurved mesh from a file (downloads the file if not available locally) # Unstructured mesh with 24 cells of the square domain [-1, 1]^n mesh_file = joinpath(@__DIR__, "square_unstructured_2.inp") -isfile(mesh_file) || download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", - mesh_file) +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", + mesh_file) -mesh = P4estMesh{2}(mesh_file, polydeg=3, - mapping=mapping_flag, - initial_refinement_level=1) +mesh = P4estMesh{2}(mesh_file, polydeg = 3, + mapping = mapping_flag, + initial_refinement_level = 1) # Refine bottom left quadrant of each tree to level 2 function refine_fn(p4est, which_tree, quadrant) - quadrant_obj = unsafe_load(quadrant) - if quadrant_obj.x == 0 && quadrant_obj.y == 0 && quadrant_obj.level < 2 - # return true (refine) - return Cint(1) - else - # return false (don't refine) - return Cint(0) - end + quadrant_obj = unsafe_load(quadrant) + if quadrant_obj.x == 0 && quadrant_obj.y == 0 && quadrant_obj.level < 2 + # return true (refine) + return Cint(1) + else + # return false (don't refine) + return Cint(0) + end end # Refine recursively until each bottom left quadrant of a tree has level 2 # The mesh will be rebalanced before the simulation starts -refine_fn_c = @cfunction(refine_fn, Cint, (Ptr{Trixi.p4est_t}, Ptr{Trixi.p4est_topidx_t}, Ptr{Trixi.p4est_quadrant_t})) +refine_fn_c = @cfunction(refine_fn, Cint, + (Ptr{Trixi.p4est_t}, Ptr{Trixi.p4est_topidx_t}, + Ptr{Trixi.p4est_quadrant_t})) Trixi.refine_p4est!(mesh.p4est, true, refine_fn_c, C_NULL) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms, - boundary_conditions=boundary_conditions) - + source_terms = source_terms, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -72,19 +72,19 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -93,7 +93,7 @@ callbacks = CallbackSet(summary_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); +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/p4est_2d_dgsem/elixir_euler_supersonic_cylinder.jl b/examples/p4est_2d_dgsem/elixir_euler_supersonic_cylinder.jl index 366be700f9f..36c5624ba97 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_supersonic_cylinder.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_supersonic_cylinder.jl @@ -23,14 +23,14 @@ using Trixi equations = CompressibleEulerEquations2D(1.4) @inline function initial_condition_mach3_flow(x, t, equations::CompressibleEulerEquations2D) - # set the freestream flow parameters - rho_freestream = 1.4 - v1 = 3.0 - v2 = 0.0 - p_freestream = 1.0 - - prim = SVector(rho_freestream, v1, v2, p_freestream) - return prim2cons(prim, equations) + # set the freestream flow parameters + rho_freestream = 1.4 + v1 = 3.0 + v2 = 0.0 + p_freestream = 1.0 + + prim = SVector(rho_freestream, v1, v2, p_freestream) + return prim2cons(prim, equations) end initial_condition = initial_condition_mach3_flow @@ -38,30 +38,32 @@ initial_condition = initial_condition_mach3_flow # Supersonic inflow boundary condition. # Calculate the boundary flux entirely from the external solution state, i.e., set # external solution state values for everything entering the domain. -@inline function boundary_condition_supersonic_inflow(u_inner, normal_direction::AbstractVector, x, t, - surface_flux_function, equations::CompressibleEulerEquations2D) - u_boundary = initial_condition_mach3_flow(x, t, equations) - flux = Trixi.flux(u_boundary, normal_direction, equations) - - return flux +@inline function boundary_condition_supersonic_inflow(u_inner, + normal_direction::AbstractVector, + x, t, surface_flux_function, + equations::CompressibleEulerEquations2D) + u_boundary = initial_condition_mach3_flow(x, t, equations) + flux = Trixi.flux(u_boundary, normal_direction, equations) + + return flux end - # Supersonic outflow boundary condition. # Calculate the boundary flux entirely from the internal solution state. Analogous to supersonic inflow # except all the solution state values are set from the internal solution as everything leaves the domain @inline function boundary_condition_outflow(u_inner, normal_direction::AbstractVector, x, t, - surface_flux_function, equations::CompressibleEulerEquations2D) - flux = Trixi.flux(u_inner, normal_direction, equations) + surface_flux_function, + equations::CompressibleEulerEquations2D) + flux = Trixi.flux(u_inner, normal_direction, equations) - return flux + return flux end -boundary_conditions = Dict( :Bottom => boundary_condition_slip_wall, - :Circle => boundary_condition_slip_wall, - :Top => boundary_condition_slip_wall, - :Right => boundary_condition_outflow, - :Left => boundary_condition_supersonic_inflow ) +boundary_conditions = Dict(:Bottom => boundary_condition_slip_wall, + :Circle => boundary_condition_slip_wall, + :Top => boundary_condition_slip_wall, + :Right => boundary_condition_outflow, + :Left => boundary_condition_supersonic_inflow) volume_flux = flux_ranocha_turbo surface_flux = flux_lax_friedrichs @@ -69,25 +71,27 @@ surface_flux = flux_lax_friedrichs polydeg = 3 basis = LobattoLegendreBasis(polydeg) shock_indicator = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = density_pressure) volume_integral = VolumeIntegralShockCapturingHG(shock_indicator; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) -solver = DGSEM(polydeg=polydeg, surface_flux=surface_flux, volume_integral=volume_integral) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral) # Get the unstructured quad mesh from a file (downloads the file if not available locally) default_mesh_file = joinpath(@__DIR__, "abaqus_cylinder_in_channel.inp") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/a08f78f6b185b63c3baeff911a63f628/raw/addac716ea0541f588b9d2bd3f92f643eb27b88f/abaqus_cylinder_in_channel.inp", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/a08f78f6b185b63c3baeff911a63f628/raw/addac716ea0541f588b9d2bd3f92f643eb27b88f/abaqus_cylinder_in_channel.inp", + default_mesh_file) mesh_file = default_mesh_file mesh = P4estMesh{2}(mesh_file) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers @@ -100,26 +104,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -amr_indicator = IndicatorLöhner(semi, variable=Trixi.density) +amr_indicator = IndicatorLöhner(semi, variable = Trixi.density) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=0, - med_level=3, med_threshold=0.05, - max_level=5, max_threshold=0.1) + base_level = 0, + med_level = 3, med_threshold = 0.05, + max_level = 5, max_threshold = 0.1) amr_callback = AMRCallback(semi, amr_controller, - interval=1, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 1, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -128,11 +132,11 @@ callbacks = CallbackSet(summary_callback, # positivity limiter necessary for this example with strong shocks. Very sensitive # to the order of the limiter variables, pressure must come first. -stage_limiter! = PositivityPreservingLimiterZhangShu(thresholds=(5.0e-7, 1.0e-6), - variables=(pressure, Trixi.density)) +stage_limiter! = PositivityPreservingLimiterZhangShu(thresholds = (5.0e-7, 1.0e-6), + variables = (pressure, Trixi.density)) ############################################################################### # run the simulation sol = solve(ode, SSPRK43(stage_limiter!); - ode_default_options()..., callback=callbacks); + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/p4est_2d_dgsem/elixir_euler_wall_bc_amr.jl b/examples/p4est_2d_dgsem/elixir_euler_wall_bc_amr.jl index 7c7896ce372..8b8d05bade8 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_wall_bc_amr.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_wall_bc_amr.jl @@ -9,45 +9,46 @@ using Trixi equations = CompressibleEulerEquations2D(1.4) @inline function uniform_flow_state(x, t, equations::CompressibleEulerEquations2D) - # set the freestream flow parameters - rho_freestream = 1.0 - u_freestream = 0.3 - p_freestream = inv(equations.gamma) - - theta = pi / 90.0 # analogous with a two degree angle of attack - si, co = sincos(theta) - v1 = u_freestream * co - v2 = u_freestream * si - - prim = SVector(rho_freestream, v1, v2, p_freestream) - return prim2cons(prim, equations) + # set the freestream flow parameters + rho_freestream = 1.0 + u_freestream = 0.3 + p_freestream = inv(equations.gamma) + + theta = pi / 90.0 # analogous with a two degree angle of attack + si, co = sincos(theta) + v1 = u_freestream * co + v2 = u_freestream * si + + prim = SVector(rho_freestream, v1, v2, p_freestream) + return prim2cons(prim, equations) end initial_condition = uniform_flow_state boundary_condition_uniform_flow = BoundaryConditionDirichlet(uniform_flow_state) -boundary_conditions = Dict( :Body => boundary_condition_uniform_flow, - :Button1 => boundary_condition_slip_wall, - :Button2 => boundary_condition_slip_wall, - :Eye1 => boundary_condition_slip_wall, - :Eye2 => boundary_condition_slip_wall, - :Smile => boundary_condition_slip_wall, - :Bowtie => boundary_condition_slip_wall ) +boundary_conditions = Dict(:Body => boundary_condition_uniform_flow, + :Button1 => boundary_condition_slip_wall, + :Button2 => boundary_condition_slip_wall, + :Eye1 => boundary_condition_slip_wall, + :Eye2 => boundary_condition_slip_wall, + :Smile => boundary_condition_slip_wall, + :Bowtie => boundary_condition_slip_wall) volume_flux = flux_ranocha -solver = DGSEM(polydeg=5, surface_flux=flux_lax_friedrichs, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 5, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) # Get the unstructured quad mesh from a file (downloads the file if not available locally) default_mesh_file = joinpath(@__DIR__, "abaqus_gingerbread_man.inp") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/0e9e990a04b5105d1d2e3096a6e41272/raw/0d924b1d7e7d3cc1070a6cc22fe1d501687aa6dd/abaqus_gingerbread_man.inp", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/0e9e990a04b5105d1d2e3096a6e41272/raw/0d924b1d7e7d3cc1070a6cc22fe1d501687aa6dd/abaqus_gingerbread_man.inp", + default_mesh_file) mesh_file = default_mesh_file mesh = P4estMesh{2}(mesh_file) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -58,36 +59,35 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -amr_indicator = IndicatorLöhner(semi, variable=density) +amr_indicator = IndicatorLöhner(semi, variable = density) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=0, - med_level=1, med_threshold=0.05, - max_level=3, max_threshold=0.1) + base_level = 0, + med_level = 1, med_threshold = 0.05, + max_level = 3, max_threshold = 0.1) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, amr_callback) - ############################################################################### # run the simulation -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-7, reltol=1.0e-7, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-7, reltol = 1.0e-7, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/p4est_2d_dgsem/elixir_eulergravity_convergence.jl b/examples/p4est_2d_dgsem/elixir_eulergravity_convergence.jl index b34c73d2a4e..d55a59ca5ce 100644 --- a/examples/p4est_2d_dgsem/elixir_eulergravity_convergence.jl +++ b/examples/p4est_2d_dgsem/elixir_eulergravity_convergence.jl @@ -2,10 +2,8 @@ using OrdinaryDiffEq using Trixi - initial_condition = initial_condition_eoc_test_coupled_euler_gravity - ############################################################################### # semidiscretization of the compressible Euler equations gamma = 2.0 @@ -18,13 +16,13 @@ coordinates_min = (0.0, 0.0) coordinates_max = (2.0, 2.0) trees_per_dimension = (1, 1) -mesh = P4estMesh(trees_per_dimension, polydeg=1, - coordinates_min=coordinates_min, coordinates_max=coordinates_max, - initial_refinement_level=2) - -semi_euler = SemidiscretizationHyperbolic(mesh, equations_euler, initial_condition, solver_euler, - source_terms=source_terms_eoc_test_coupled_euler_gravity) +mesh = P4estMesh(trees_per_dimension, polydeg = 1, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + initial_refinement_level = 2) +semi_euler = SemidiscretizationHyperbolic(mesh, equations_euler, initial_condition, + solver_euler, + source_terms = source_terms_eoc_test_coupled_euler_gravity) ############################################################################### # semidiscretization of the hyperbolic diffusion equations @@ -32,24 +30,23 @@ equations_gravity = HyperbolicDiffusionEquations2D() solver_gravity = DGSEM(polydeg, flux_lax_friedrichs) -semi_gravity = SemidiscretizationHyperbolic(mesh, equations_gravity, initial_condition, solver_gravity, - source_terms=source_terms_harmonic) - +semi_gravity = SemidiscretizationHyperbolic(mesh, equations_gravity, initial_condition, + solver_gravity, + source_terms = source_terms_harmonic) ############################################################################### # combining both semidiscretizations for Euler + self-gravity -parameters = ParametersEulerGravity(background_density=2.0, # aka rho0 +parameters = ParametersEulerGravity(background_density = 2.0, # aka rho0 # rho0 is (ab)used to add a "+8π" term to the source terms # for the manufactured solution - gravitational_constant=1.0, # aka G - cfl=1.1, - resid_tol=1.0e-10, - n_iterations_max=1000, - timestep_gravity=timestep_gravity_erk52_3Sstar!) + gravitational_constant = 1.0, # aka G + cfl = 1.1, + resid_tol = 1.0e-10, + n_iterations_max = 1000, + timestep_gravity = timestep_gravity_erk52_3Sstar!) semi = SemidiscretizationEulerGravity(semi_euler, semi_gravity, parameters) - ############################################################################### # ODE solvers, callbacks etc. tspan = (0.0, 0.5) @@ -57,31 +54,30 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) -save_solution = SaveSolutionCallback(interval=10, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 10, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) analysis_interval = 100 -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -analysis_callback = AnalysisCallback(semi_euler, interval=analysis_interval, - save_analysis=true) +analysis_callback = AnalysisCallback(semi_euler, interval = analysis_interval, + save_analysis = true) callbacks = CallbackSet(summary_callback, stepsize_callback, save_restart, save_solution, analysis_callback, alive_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); +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 println("Number of gravity subcycles: ", semi.gravity_counter.ncalls_since_readout) diff --git a/examples/p4est_2d_dgsem/elixir_linearizedeuler_gaussian_source.jl b/examples/p4est_2d_dgsem/elixir_linearizedeuler_gaussian_source.jl index ba2ec827778..364e0296449 100644 --- a/examples/p4est_2d_dgsem/elixir_linearizedeuler_gaussian_source.jl +++ b/examples/p4est_2d_dgsem/elixir_linearizedeuler_gaussian_source.jl @@ -8,20 +8,22 @@ using Trixi # Oscillating Gaussian-shaped source terms function source_terms_gauss(u, x, t, equations::LinearizedEulerEquations2D) - r = 0.1 - A = 1.0 - f = 2.0 + r = 0.1 + A = 1.0 + f = 2.0 - # Velocity sources - s2 = 0.0 - s3 = 0.0 - # Density and pressure source - s1 = s4 = exp(-(x[1]^2 + x[2]^2) / (2 * r^2)) * A * sin(2 * pi * f * t) + # Velocity sources + s2 = 0.0 + s3 = 0.0 + # Density and pressure source + s1 = s4 = exp(-(x[1]^2 + x[2]^2) / (2 * r^2)) * A * sin(2 * pi * f * t) - return SVector(s1, s2, s3, s4) + return SVector(s1, s2, s3, s4) end -initial_condition_zero(x, t, equations::LinearizedEulerEquations2D) = SVector(0.0, 0.0, 0.0, 0.0) +function initial_condition_zero(x, t, equations::LinearizedEulerEquations2D) + SVector(0.0, 0.0, 0.0, 0.0) +end ############################################################################### # semidiscretization of the linearized Euler equations @@ -30,28 +32,27 @@ initial_condition_zero(x, t, equations::LinearizedEulerEquations2D) = SVector(0. c = cospi(2 * 30.0 / 360.0) s = sinpi(2 * 30.0 / 360.0) rot_mat = Trixi.SMatrix{2, 2}([c -s; s c]) -mapping(xi, eta) = rot_mat * SVector(3.0*xi, 3.0*eta) +mapping(xi, eta) = rot_mat * SVector(3.0 * xi, 3.0 * eta) # Mean density and speed of sound are slightly off from 1.0 to allow proper verification of # curved LEE implementation using this elixir (some things in the LEE cancel if both are 1.0) -equations = LinearizedEulerEquations2D(v_mean_global=Tuple(rot_mat * SVector(-0.5, 0.25)), - c_mean_global=1.02, rho_mean_global=1.01) +equations = LinearizedEulerEquations2D(v_mean_global = Tuple(rot_mat * SVector(-0.5, 0.25)), + c_mean_global = 1.02, rho_mean_global = 1.01) initial_condition = initial_condition_zero # Create DG solver with polynomial degree = 3 and upwind flux as surface flux -solver = DGSEM(polydeg=3, surface_flux=flux_godunov) +solver = DGSEM(polydeg = 3, surface_flux = flux_godunov) # Create a uniformly refined mesh with periodic boundaries trees_per_dimension = (4, 4) -mesh = P4estMesh(trees_per_dimension, polydeg=1, - mapping=mapping, - periodicity=true, initial_refinement_level=2) +mesh = P4estMesh(trees_per_dimension, polydeg = 1, + mapping = mapping, + periodicity = true, initial_refinement_level = 2) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_gauss) - + source_terms = source_terms_gauss) ############################################################################### # ODE solvers, callbacks etc. @@ -65,25 +66,25 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +analysis_callback = AnalysisCallback(semi, interval = 100) # The SaveSolutionCallback allows to save the solution to a file in regular intervals -save_solution = SaveSolutionCallback(interval=100) +save_solution = SaveSolutionCallback(interval = 100) # The StepsizeCallback handles the re-calculation of the maximum Δt after each time step -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) # 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) - +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/p4est_2d_dgsem/elixir_mhd_alfven_wave.jl b/examples/p4est_2d_dgsem/elixir_mhd_alfven_wave.jl index 66bce781f60..93db7bfdbaf 100644 --- a/examples/p4est_2d_dgsem/elixir_mhd_alfven_wave.jl +++ b/examples/p4est_2d_dgsem/elixir_mhd_alfven_wave.jl @@ -2,28 +2,27 @@ using OrdinaryDiffEq using Trixi - ############################################################################### # semidiscretization of the compressible ideal GLM-MHD equations -gamma = 5/3 +gamma = 5 / 3 equations = IdealGlmMhdEquations2D(gamma) initial_condition = initial_condition_convergence_test # Get the DG approximation space volume_flux = (flux_central, flux_nonconservative_powell) -solver = DGSEM(polydeg=4, surface_flux=(flux_hll, flux_nonconservative_powell), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 4, surface_flux = (flux_hll, flux_nonconservative_powell), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) -coordinates_min = (0.0 , 0.0 ) +coordinates_min = (0.0, 0.0) coordinates_max = (sqrt(2.0), sqrt(2.0)) trees_per_dimension = (8, 8) mesh = P4estMesh(trees_per_dimension, - polydeg=3, initial_refinement_level=0, - coordinates_min=coordinates_min, coordinates_max=coordinates_max, - periodicity=true) + polydeg = 3, initial_refinement_level = 0, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -36,14 +35,14 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) cfl = 0.9 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -54,7 +53,7 @@ callbacks = CallbackSet(summary_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); +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/p4est_2d_dgsem/elixir_mhd_rotor.jl b/examples/p4est_2d_dgsem/elixir_mhd_rotor.jl index 58915a8f6a7..380db487356 100644 --- a/examples/p4est_2d_dgsem/elixir_mhd_rotor.jl +++ b/examples/p4est_2d_dgsem/elixir_mhd_rotor.jl @@ -16,74 +16,74 @@ The classical MHD rotor test case. Here, the setup is taken from [doi: 10.1365/s13291-018-0178-9](https://doi.org/10.1365/s13291-018-0178-9) """ function initial_condition_rotor(x, t, equations::IdealGlmMhdEquations2D) - # setup taken from Derigs et al. DMV article (2018) - # domain must be [0, 1] x [0, 1], γ = 1.4 - dx = x[1] - 0.5 - dy = x[2] - 0.5 - r = sqrt(dx^2 + dy^2) - f = (0.115 - r)/0.015 - if r <= 0.1 - rho = 10.0 - v1 = -20.0*dy - v2 = 20.0*dx - elseif r >= 0.115 - rho = 1.0 - v1 = 0.0 - v2 = 0.0 - else - rho = 1.0 + 9.0*f - v1 = -20.0*f*dy - v2 = 20.0*f*dx - end - v3 = 0.0 - p = 1.0 - B1 = 5.0/sqrt(4.0*pi) - B2 = 0.0 - B3 = 0.0 - psi = 0.0 - return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3, psi), equations) + # setup taken from Derigs et al. DMV article (2018) + # domain must be [0, 1] x [0, 1], γ = 1.4 + dx = x[1] - 0.5 + dy = x[2] - 0.5 + r = sqrt(dx^2 + dy^2) + f = (0.115 - r) / 0.015 + if r <= 0.1 + rho = 10.0 + v1 = -20.0 * dy + v2 = 20.0 * dx + elseif r >= 0.115 + rho = 1.0 + v1 = 0.0 + v2 = 0.0 + else + rho = 1.0 + 9.0 * f + v1 = -20.0 * f * dy + v2 = 20.0 * f * dx + end + v3 = 0.0 + p = 1.0 + B1 = 5.0 / sqrt(4.0 * pi) + B2 = 0.0 + B3 = 0.0 + psi = 0.0 + return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3, psi), equations) end initial_condition = initial_condition_rotor surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell) -volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) +volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) polydeg = 4 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) # Affine type mapping to take the [-1,1]^2 domain from the mesh file # and put it onto the rotor domain [0,1]^2 and then warp it with a mapping # as described in https://arxiv.org/abs/2012.12040 function mapping_twist(xi, eta) - y = 0.5 * (eta + 1.0) + 0.05 * cos(1.5 * pi * (2.0 * xi - 1.0)) * cos(0.5 * pi * (2.0 * eta - 1.0)) - x = 0.5 * (xi + 1.0) + 0.05 * cos(0.5 * pi * (2.0 * xi - 1.0)) * cos(2.0 * pi * y) - return SVector(x, y) + y = 0.5 * (eta + 1.0) + + 0.05 * cos(1.5 * pi * (2.0 * xi - 1.0)) * cos(0.5 * pi * (2.0 * eta - 1.0)) + x = 0.5 * (xi + 1.0) + 0.05 * cos(0.5 * pi * (2.0 * xi - 1.0)) * cos(2.0 * pi * y) + return SVector(x, y) end - mesh_file = joinpath(@__DIR__, "square_unstructured_2.inp") -isfile(mesh_file) || download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", - mesh_file) +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", + mesh_file) mesh = P4estMesh{2}(mesh_file, - polydeg=4, - mapping=mapping_twist, - initial_refinement_level=1) + polydeg = 4, + mapping = mapping_twist, + initial_refinement_level = 1) boundary_condition = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = Dict( :all => boundary_condition ) +boundary_conditions = Dict(:all => boundary_condition) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -94,31 +94,31 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorLöhner(semi, - variable=density_pressure) + variable = density_pressure) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=1, - med_level =3, med_threshold=0.05, - max_level =5, max_threshold=0.1) + base_level = 1, + med_level = 3, med_threshold = 0.05, + max_level = 5, max_threshold = 0.1) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) cfl = 0.5 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -131,7 +131,7 @@ callbacks = CallbackSet(summary_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); +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/p4est_2d_dgsem/elixir_navierstokes_convergence.jl b/examples/p4est_2d_dgsem/elixir_navierstokes_convergence.jl index b0c6086ad63..7aa14e25750 100644 --- a/examples/p4est_2d_dgsem/elixir_navierstokes_convergence.jl +++ b/examples/p4est_2d_dgsem/elixir_navierstokes_convergence.jl @@ -8,174 +8,182 @@ prandtl_number() = 0.72 mu() = 0.01 equations = CompressibleEulerEquations2D(1.4) -equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu=mu(), Prandtl=prandtl_number(), - gradient_variables=GradientVariablesPrimitive()) +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu = mu(), + Prandtl = prandtl_number(), + gradient_variables = GradientVariablesPrimitive()) # 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, - volume_integral=VolumeIntegralWeakForm()) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralWeakForm()) coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) -coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) +coordinates_max = (1.0, 1.0) # maximum coordinates (max(x), max(y)) trees_per_dimension = (4, 4) mesh = P4estMesh(trees_per_dimension, - polydeg=3, initial_refinement_level=2, - coordinates_min=coordinates_min, coordinates_max=coordinates_max, - periodicity=(true, false)) + polydeg = 3, initial_refinement_level = 2, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + periodicity = (true, false)) # Note: the initial condition cannot be specialized to `CompressibleNavierStokesDiffusion2D` # since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesDiffusion2D`) # and by the initial condition (which passes in `CompressibleEulerEquations2D`). # This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) function initial_condition_navier_stokes_convergence_test(x, t, equations) - # Amplitude and shift - A = 0.5 - c = 2.0 + # Amplitude and shift + A = 0.5 + c = 2.0 - # convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_t = pi * t + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t - rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) - v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0)) ) * cos(pi_t) - v2 = v1 - p = rho^2 + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0))) * cos(pi_t) + v2 = v1 + p = rho^2 - return prim2cons(SVector(rho, v1, v2, p), equations) + return prim2cons(SVector(rho, v1, v2, p), equations) end @inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) - y = x[2] - - # TODO: parabolic - # we currently need to hardcode these parameters until we fix the "combined equation" issue - # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 - inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = prandtl_number() - mu_ = mu() - - # Same settings as in `initial_condition` - # Amplitude and shift - A = 0.5 - c = 2.0 - - # convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_t = pi * t - - # compute the manufactured solution and all necessary derivatives - rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) - rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) - rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) - rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) - rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) - rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) - - v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) - v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_y = sin(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) - v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_xy = pi * cos(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) - v1_yy = (sin(pi_x) * ( 2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) - - A * A * log(y + 2.0) * exp(-A * (y - 1.0)) - - (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) - v2 = v1 - v2_t = v1_t - v2_x = v1_x - v2_y = v1_y - v2_xx = v1_xx - v2_xy = v1_xy - v2_yy = v1_yy - - p = rho * rho - p_t = 2.0 * rho * rho_t - p_x = 2.0 * rho * rho_x - p_y = 2.0 * rho * rho_y - p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x - p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y - - # Note this simplifies slightly because the ansatz assumes that v1 = v2 - E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) - E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t - E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x - E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y - - # Some convenience constants - T_const = equations.gamma * inv_gamma_minus_one / Pr - inv_rho_cubed = 1.0 / (rho^3) - - # compute the source terms - # density equation - du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y - - # x-momentum equation - du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 - + 2.0 * rho * v1 * v1_x - + rho_y * v1 * v2 - + rho * v1_y * v2 - + rho * v1 * v2_y - # stress tensor from x-direction - - 4.0 / 3.0 * v1_xx * mu_ - + 2.0 / 3.0 * v2_xy * mu_ - - v1_yy * mu_ - - v2_xy * mu_ ) - # y-momentum equation - du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 - + rho * v1_x * v2 - + rho * v1 * v2_x - + rho_y * v2^2 - + 2.0 * rho * v2 * v2_y - # stress tensor from y-direction - - v1_xy * mu_ - - v2_xx * mu_ - - 4.0 / 3.0 * v2_yy * mu_ - + 2.0 / 3.0 * v1_xy * mu_ ) - # total energy equation - du4 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) - + v2_y * (E + p) + v2 * (E_y + p_y) - # stress tensor and temperature gradient terms from x-direction - - 4.0 / 3.0 * v1_xx * v1 * mu_ - + 2.0 / 3.0 * v2_xy * v1 * mu_ - - 4.0 / 3.0 * v1_x * v1_x * mu_ - + 2.0 / 3.0 * v2_y * v1_x * mu_ - - v1_xy * v2 * mu_ - - v2_xx * v2 * mu_ - - v1_y * v2_x * mu_ - - v2_x * v2_x * mu_ - - T_const * inv_rho_cubed * ( p_xx * rho * rho - - 2.0 * p_x * rho * rho_x - + 2.0 * p * rho_x * rho_x - - p * rho * rho_xx ) * mu_ - # stress tensor and temperature gradient terms from y-direction - - v1_yy * v1 * mu_ - - v2_xy * v1 * mu_ - - v1_y * v1_y * mu_ - - v2_x * v1_y * mu_ - - 4.0 / 3.0 * v2_yy * v2 * mu_ - + 2.0 / 3.0 * v1_xy * v2 * mu_ - - 4.0 / 3.0 * v2_y * v2_y * mu_ - + 2.0 / 3.0 * v1_x * v2_y * mu_ - - T_const * inv_rho_cubed * ( p_yy * rho * rho - - 2.0 * p_y * rho * rho_y - + 2.0 * p * rho_y * rho_y - - p * rho * rho_yy ) * mu_ ) - - return SVector(du1, du2, du3, du4) + y = x[2] + + # TODO: parabolic + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + mu_ = mu() + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) + rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) + rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) + rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + + v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) + v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_y = sin(pi_x) * + (A * log(y + 2.0) * exp(-A * (y - 1.0)) + + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_xy = pi * cos(pi_x) * + (A * log(y + 2.0) * exp(-A * (y - 1.0)) + + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_yy = (sin(pi_x) * + (2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) - + A * A * log(y + 2.0) * exp(-A * (y - 1.0)) - + (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_xx = v1_xx + v2_xy = v1_xy + v2_yy = v1_yy + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y + + # Note this simplifies slightly because the ansatz assumes that v1 = v2 + E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) + E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x + E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one / Pr + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y + + # x-momentum equation + du2 = (rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y - + # stress tensor from x-direction + 4.0 / 3.0 * v1_xx * mu_ + + 2.0 / 3.0 * v2_xy * mu_ - + v1_yy * mu_ - + v2_xy * mu_) + # y-momentum equation + du3 = (rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y - + # stress tensor from y-direction + v1_xy * mu_ - + v2_xx * mu_ - + 4.0 / 3.0 * v2_yy * mu_ + + 2.0 / 3.0 * v1_xy * mu_) + # total energy equation + du4 = (E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) - + # stress tensor and temperature gradient terms from x-direction + 4.0 / 3.0 * v1_xx * v1 * mu_ + + 2.0 / 3.0 * v2_xy * v1 * mu_ - + 4.0 / 3.0 * v1_x * v1_x * mu_ + + 2.0 / 3.0 * v2_y * v1_x * mu_ - + v1_xy * v2 * mu_ - + v2_xx * v2 * mu_ - + v1_y * v2_x * mu_ - + v2_x * v2_x * mu_ - + T_const * inv_rho_cubed * + (p_xx * rho * rho - + 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x - + p * rho * rho_xx) * mu_ - + # stress tensor and temperature gradient terms from y-direction + v1_yy * v1 * mu_ - + v2_xy * v1 * mu_ - + v1_y * v1_y * mu_ - + 4.0 / 3.0 * v2_yy * v2 * mu_ + + 2.0 / 3.0 * v1_xy * v2 * mu_ - + 4.0 / 3.0 * v2_y * v2_y * mu_ + + 2.0 / 3.0 * v1_x * v2_y * mu_ - + T_const * inv_rho_cubed * + (p_yy * rho * rho - + 2.0 * p_y * rho * rho_y + + 2.0 * p * rho_y * rho_y - + p * rho * rho_yy) * mu_) + + return SVector(du1, du2, du3, du4) end initial_condition = initial_condition_navier_stokes_convergence_test # BC types velocity_bc_top_bottom = NoSlip() do x, t, equations - u = initial_condition_navier_stokes_convergence_test(x, t, equations) - return SVector(u[2], u[3]) + u = initial_condition_navier_stokes_convergence_test(x, t, equations) + return SVector(u[2], u[3]) end heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) -boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, heat_bc_top_bottom) +boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, + heat_bc_top_bottom) # define inviscid boundary conditions boundary_conditions = Dict(:y_neg => boundary_condition_slip_wall, @@ -185,9 +193,11 @@ boundary_conditions = Dict(:y_neg => boundary_condition_slip_wall, boundary_conditions_parabolic = Dict(:y_neg => boundary_condition_top_bottom, :y_pos => boundary_condition_top_bottom) -semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; - boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), - source_terms=source_terms_navier_stokes_convergence_test) +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic), + source_terms = source_terms_navier_stokes_convergence_test) # ############################################################################### # # ODE solvers, callbacks etc. @@ -197,16 +207,15 @@ tspan = (0.0, 0.5) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, dt = 1e-5, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary - diff --git a/examples/p4est_2d_dgsem/elixir_navierstokes_convergence_nonperiodic.jl b/examples/p4est_2d_dgsem/elixir_navierstokes_convergence_nonperiodic.jl index 935f132ba4b..b4177fe8538 100644 --- a/examples/p4est_2d_dgsem/elixir_navierstokes_convergence_nonperiodic.jl +++ b/examples/p4est_2d_dgsem/elixir_navierstokes_convergence_nonperiodic.jl @@ -8,171 +8,182 @@ prandtl_number() = 0.72 mu() = 0.01 equations = CompressibleEulerEquations2D(1.4) -equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu=mu(), Prandtl=prandtl_number(), - gradient_variables=GradientVariablesPrimitive()) +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu = mu(), + Prandtl = prandtl_number(), + gradient_variables = GradientVariablesPrimitive()) # 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, - volume_integral=VolumeIntegralWeakForm()) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralWeakForm()) coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) -coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) +coordinates_max = (1.0, 1.0) # maximum coordinates (max(x), max(y)) trees_per_dimension = (4, 4) mesh = P4estMesh(trees_per_dimension, - polydeg=3, initial_refinement_level=2, - coordinates_min=coordinates_min, coordinates_max=coordinates_max, - periodicity=(false, false)) + polydeg = 3, initial_refinement_level = 2, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + periodicity = (false, false)) # Note: the initial condition cannot be specialized to `CompressibleNavierStokesDiffusion2D` # since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesDiffusion2D`) # and by the initial condition (which passes in `CompressibleEulerEquations2D`). # This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) function initial_condition_navier_stokes_convergence_test(x, t, equations) - # Amplitude and shift - A = 0.5 - c = 2.0 + # Amplitude and shift + A = 0.5 + c = 2.0 - # convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_t = pi * t + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t - rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) - v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0)) ) * cos(pi_t) - v2 = v1 - p = rho^2 + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0))) * cos(pi_t) + v2 = v1 + p = rho^2 - return prim2cons(SVector(rho, v1, v2, p), equations) + return prim2cons(SVector(rho, v1, v2, p), equations) end @inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) - y = x[2] - - # TODO: parabolic - # we currently need to hardcode these parameters until we fix the "combined equation" issue - # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 - inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = prandtl_number() - mu_ = mu() - - # Same settings as in `initial_condition` - # Amplitude and shift - A = 0.5 - c = 2.0 - - # convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_t = pi * t - - # compute the manufactured solution and all necessary derivatives - rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) - rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) - rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) - rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) - rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) - rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) - - v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) - v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_y = sin(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) - v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_xy = pi * cos(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) - v1_yy = (sin(pi_x) * ( 2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) - - A * A * log(y + 2.0) * exp(-A * (y - 1.0)) - - (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) - v2 = v1 - v2_t = v1_t - v2_x = v1_x - v2_y = v1_y - v2_xx = v1_xx - v2_xy = v1_xy - v2_yy = v1_yy - - p = rho * rho - p_t = 2.0 * rho * rho_t - p_x = 2.0 * rho * rho_x - p_y = 2.0 * rho * rho_y - p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x - p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y - - # Note this simplifies slightly because the ansatz assumes that v1 = v2 - E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) - E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t - E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x - E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y - - # Some convenience constants - T_const = equations.gamma * inv_gamma_minus_one / Pr - inv_rho_cubed = 1.0 / (rho^3) - - # compute the source terms - # density equation - du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y - - # x-momentum equation - du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 - + 2.0 * rho * v1 * v1_x - + rho_y * v1 * v2 - + rho * v1_y * v2 - + rho * v1 * v2_y - # stress tensor from x-direction - - 4.0 / 3.0 * v1_xx * mu_ - + 2.0 / 3.0 * v2_xy * mu_ - - v1_yy * mu_ - - v2_xy * mu_ ) - # y-momentum equation - du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 - + rho * v1_x * v2 - + rho * v1 * v2_x - + rho_y * v2^2 - + 2.0 * rho * v2 * v2_y - # stress tensor from y-direction - - v1_xy * mu_ - - v2_xx * mu_ - - 4.0 / 3.0 * v2_yy * mu_ - + 2.0 / 3.0 * v1_xy * mu_ ) - # total energy equation - du4 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) - + v2_y * (E + p) + v2 * (E_y + p_y) - # stress tensor and temperature gradient terms from x-direction - - 4.0 / 3.0 * v1_xx * v1 * mu_ - + 2.0 / 3.0 * v2_xy * v1 * mu_ - - 4.0 / 3.0 * v1_x * v1_x * mu_ - + 2.0 / 3.0 * v2_y * v1_x * mu_ - - v1_xy * v2 * mu_ - - v2_xx * v2 * mu_ - - v1_y * v2_x * mu_ - - v2_x * v2_x * mu_ - - T_const * inv_rho_cubed * ( p_xx * rho * rho - - 2.0 * p_x * rho * rho_x - + 2.0 * p * rho_x * rho_x - - p * rho * rho_xx ) * mu_ - # stress tensor and temperature gradient terms from y-direction - - v1_yy * v1 * mu_ - - v2_xy * v1 * mu_ - - v1_y * v1_y * mu_ - - v2_x * v1_y * mu_ - - 4.0 / 3.0 * v2_yy * v2 * mu_ - + 2.0 / 3.0 * v1_xy * v2 * mu_ - - 4.0 / 3.0 * v2_y * v2_y * mu_ - + 2.0 / 3.0 * v1_x * v2_y * mu_ - - T_const * inv_rho_cubed * ( p_yy * rho * rho - - 2.0 * p_y * rho * rho_y - + 2.0 * p * rho_y * rho_y - - p * rho * rho_yy ) * mu_ ) - - return SVector(du1, du2, du3, du4) + y = x[2] + + # TODO: parabolic + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + mu_ = mu() + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) + rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) + rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) + rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + + v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) + v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_y = sin(pi_x) * + (A * log(y + 2.0) * exp(-A * (y - 1.0)) + + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_xy = pi * cos(pi_x) * + (A * log(y + 2.0) * exp(-A * (y - 1.0)) + + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_yy = (sin(pi_x) * + (2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) - + A * A * log(y + 2.0) * exp(-A * (y - 1.0)) - + (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_xx = v1_xx + v2_xy = v1_xy + v2_yy = v1_yy + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y + + # Note this simplifies slightly because the ansatz assumes that v1 = v2 + E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) + E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x + E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one / Pr + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y + + # x-momentum equation + du2 = (rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y - + # stress tensor from x-direction + 4.0 / 3.0 * v1_xx * mu_ + + 2.0 / 3.0 * v2_xy * mu_ - + v1_yy * mu_ - + v2_xy * mu_) + # y-momentum equation + du3 = (rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y - + # stress tensor from y-direction + v1_xy * mu_ - + v2_xx * mu_ - + 4.0 / 3.0 * v2_yy * mu_ + + 2.0 / 3.0 * v1_xy * mu_) + # total energy equation + du4 = (E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) - + # stress tensor and temperature gradient terms from x-direction + 4.0 / 3.0 * v1_xx * v1 * mu_ + + 2.0 / 3.0 * v2_xy * v1 * mu_ - + 4.0 / 3.0 * v1_x * v1_x * mu_ + + 2.0 / 3.0 * v2_y * v1_x * mu_ - + v1_xy * v2 * mu_ - + v2_xx * v2 * mu_ - + v1_y * v2_x * mu_ - + v2_x * v2_x * mu_ - + T_const * inv_rho_cubed * + (p_xx * rho * rho - + 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x - + p * rho * rho_xx) * mu_ - + # stress tensor and temperature gradient terms from y-direction + v1_yy * v1 * mu_ - + v2_xy * v1 * mu_ - + v1_y * v1_y * mu_ - + v2_x * v1_y * mu_ - + 4.0 / 3.0 * v2_yy * v2 * mu_ + + 2.0 / 3.0 * v1_xy * v2 * mu_ - + 4.0 / 3.0 * v2_y * v2_y * mu_ + + 2.0 / 3.0 * v1_x * v2_y * mu_ - + T_const * inv_rho_cubed * + (p_yy * rho * rho - + 2.0 * p_y * rho * rho_y + + 2.0 * p * rho_y * rho_y - + p * rho * rho_yy) * mu_) + + return SVector(du1, du2, du3, du4) end initial_condition = initial_condition_navier_stokes_convergence_test # BC types -velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:3]) +velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, + t, + equations)[2:3]) heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) -boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, heat_bc_top_bottom) +boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, + heat_bc_top_bottom) boundary_condition_left_right = BoundaryConditionDirichlet(initial_condition_navier_stokes_convergence_test) @@ -188,9 +199,11 @@ boundary_conditions_parabolic = Dict(:x_neg => boundary_condition_left_right, :y_neg => boundary_condition_top_bottom, :y_pos => boundary_condition_top_bottom) -semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; - boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), - source_terms=source_terms_navier_stokes_convergence_test) +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic), + source_terms = source_terms_navier_stokes_convergence_test) # ############################################################################### # # ODE solvers, callbacks etc. @@ -200,16 +213,15 @@ tspan = (0.0, 0.5) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, dt = 1e-5, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary - diff --git a/examples/p4est_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl b/examples/p4est_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl index 051f4defe54..e6566edb18a 100644 --- a/examples/p4est_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl +++ b/examples/p4est_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl @@ -9,28 +9,28 @@ prandtl_number() = 0.72 mu() = 0.001 equations = CompressibleEulerEquations2D(1.4) -equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu=mu(), - Prandtl=prandtl_number()) +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu = mu(), + Prandtl = prandtl_number()) # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) -coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) +coordinates_max = (1.0, 1.0) # maximum coordinates (max(x), max(y)) # Create a uniformly refined mesh trees_per_dimension = (4, 4) mesh = P4estMesh(trees_per_dimension, - polydeg=3, initial_refinement_level=2, - coordinates_min=coordinates_min, coordinates_max=coordinates_max, - periodicity=(false, false)) + polydeg = 3, initial_refinement_level = 2, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + periodicity = (false, false)) function initial_condition_cavity(x, t, equations::CompressibleEulerEquations2D) - Ma = 0.1 - rho = 1.0 - u, v = 0.0, 0.0 - p = 1.0 / (Ma^2 * equations.gamma) - return prim2cons(SVector(rho, u, v, p), equations) + Ma = 0.1 + rho = 1.0 + u, v = 0.0, 0.0 + p = 1.0 / (Ma^2 * equations.gamma) + return prim2cons(SVector(rho, u, v, p), equations) end initial_condition = initial_condition_cavity @@ -42,21 +42,21 @@ boundary_condition_lid = BoundaryConditionNavierStokesWall(velocity_bc_lid, heat boundary_condition_cavity = BoundaryConditionNavierStokesWall(velocity_bc_cavity, heat_bc) # define periodic boundary conditions everywhere -boundary_conditions = Dict( :x_neg => boundary_condition_slip_wall, - :y_neg => boundary_condition_slip_wall, - :y_pos => boundary_condition_slip_wall, - :x_pos => boundary_condition_slip_wall) +boundary_conditions = Dict(:x_neg => boundary_condition_slip_wall, + :y_neg => boundary_condition_slip_wall, + :y_pos => boundary_condition_slip_wall, + :x_pos => boundary_condition_slip_wall) -boundary_conditions_parabolic = Dict( :x_neg => boundary_condition_cavity, - :y_neg => boundary_condition_cavity, - :y_pos => boundary_condition_lid, - :x_pos => boundary_condition_cavity) +boundary_conditions_parabolic = Dict(:x_neg => boundary_condition_cavity, + :y_neg => boundary_condition_cavity, + :y_pos => boundary_condition_lid, + :x_pos => boundary_condition_cavity) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; - boundary_conditions=(boundary_conditions, - boundary_conditions_parabolic)) + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic)) ############################################################################### # ODE solvers, callbacks etc. @@ -66,17 +66,15 @@ tspan = (0.0, 25.0) ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=100) +alive_callback = AliveCallback(alive_interval = 100) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) callbacks = CallbackSet(summary_callback, alive_callback) ############################################################################### # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary - - diff --git a/examples/p4est_2d_dgsem/elixir_shallowwater_source_terms.jl b/examples/p4est_2d_dgsem/elixir_shallowwater_source_terms.jl index b185a8ce39d..c7922fd3b75 100644 --- a/examples/p4est_2d_dgsem/elixir_shallowwater_source_terms.jl +++ b/examples/p4est_2d_dgsem/elixir_shallowwater_source_terms.jl @@ -5,17 +5,17 @@ using Trixi ############################################################################### # semidiscretization of the shallow water equations -equations = ShallowWaterEquations2D(gravity_constant=9.81) +equations = ShallowWaterEquations2D(gravity_constant = 9.81) initial_condition = initial_condition_convergence_test # MMS EOC test - ############################################################################### # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -solver = DGSEM(polydeg=3, surface_flux=(flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, + surface_flux = (flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the P4estMesh and setup a periodic mesh @@ -25,14 +25,13 @@ coordinates_max = (sqrt(2.0), sqrt(2.0)) # maximum coordinates (max(x), max(y)) # Create P4estMesh with 8 x 8 trees and 16 x 16 elements trees_per_dimension = (8, 8) -mesh = P4estMesh(trees_per_dimension, polydeg=3, - coordinates_min=coordinates_min, coordinates_max=coordinates_max, - initial_refinement_level=1) +mesh = P4estMesh(trees_per_dimension, polydeg = 3, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + initial_refinement_level = 1) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -44,13 +43,13 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 500 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=200, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 200, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) @@ -58,6 +57,6 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav # run the simulation # use a Runge-Kutta method with automatic (error based) time step size control -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-8, reltol=1.0e-8, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-8, reltol = 1.0e-8, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/p4est_3d_dgsem/elixir_advection_amr.jl b/examples/p4est_3d_dgsem/elixir_advection_amr.jl index 0473fd2b23a..d56ecc233ff 100644 --- a/examples/p4est_3d_dgsem/elixir_advection_amr.jl +++ b/examples/p4est_3d_dgsem/elixir_advection_amr.jl @@ -11,23 +11,21 @@ advection_velocity = (0.2, -0.7, 0.5) equations = LinearScalarAdvectionEquation3D(advection_velocity) initial_condition = initial_condition_gauss -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-5.0, -5.0, -5.0) -coordinates_max = ( 5.0, 5.0, 5.0) +coordinates_max = (5.0, 5.0, 5.0) trees_per_dimension = (1, 1, 1) # Note that it is not necessary to use mesh polydeg lower than the solver polydeg # on a Cartesian mesh. # See https://doi.org/10.1007/s10915-018-00897-9, Section 6. -mesh = P4estMesh(trees_per_dimension, polydeg=1, - coordinates_min=coordinates_min, coordinates_max=coordinates_max, - initial_refinement_level=4) - +mesh = P4estMesh(trees_per_dimension, polydeg = 1, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + initial_refinement_level = 4) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -37,26 +35,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable=first), - base_level=4, - med_level=5, med_threshold=0.1, - max_level=6, max_threshold=0.6) +amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first), + base_level = 4, + med_level = 5, med_threshold = 0.1, + max_level = 6, max_threshold = 0.6) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.2) +stepsize_callback = StepsizeCallback(cfl = 1.2) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -68,7 +66,7 @@ callbacks = CallbackSet(summary_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); +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/p4est_3d_dgsem/elixir_advection_amr_unstructured_curved.jl b/examples/p4est_3d_dgsem/elixir_advection_amr_unstructured_curved.jl index fb87c361c18..cd280cf5bf6 100644 --- a/examples/p4est_3d_dgsem/elixir_advection_amr_unstructured_curved.jl +++ b/examples/p4est_3d_dgsem/elixir_advection_amr_unstructured_curved.jl @@ -12,54 +12,55 @@ equations = LinearScalarAdvectionEquation3D(advection_velocity) # Solver with polydeg=4 to ensure free stream preservation (FSP) on non-conforming meshes. # The polydeg of the solver must be at least twice as big as the polydeg of the mesh. # See https://doi.org/10.1007/s10915-018-00897-9, Section 6. -solver = DGSEM(polydeg=4, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 4, surface_flux = flux_lax_friedrichs) initial_condition = initial_condition_gauss boundary_condition = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = Dict( - :all => boundary_condition -) +boundary_conditions = Dict(:all => boundary_condition) # Mapping as described in https://arxiv.org/abs/2012.12040 but with less warping. # The mapping will be interpolated at tree level, and then refined without changing # the geometry interpolant. The original mapping applied to this unstructured mesh # causes some Jacobians to be negative, which makes the mesh invalid. function mapping(xi, eta, zeta) - # Don't transform input variables between -1 and 1 onto [0,3] to obtain curved boundaries - # xi = 1.5 * xi_ + 1.5 - # eta = 1.5 * eta_ + 1.5 - # zeta = 1.5 * zeta_ + 1.5 - - y = eta + 1/4 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - x = xi + 1/4 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - z = zeta + 1/4 * (cos(0.5 * pi * (2 * x - 3)/3) * - cos(pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - # Transform the weird deformed cube to be approximately the size of [-5,5]^3 to match IC - return SVector(5 * x, 5 * y, 5 * z) + # Don't transform input variables between -1 and 1 onto [0,3] to obtain curved boundaries + # xi = 1.5 * xi_ + 1.5 + # eta = 1.5 * eta_ + 1.5 + # zeta = 1.5 * zeta_ + 1.5 + + y = eta + + 1 / 4 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + x = xi + + 1 / 4 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + z = zeta + + 1 / 4 * (cos(0.5 * pi * (2 * x - 3) / 3) * + cos(pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + # Transform the weird deformed cube to be approximately the size of [-5,5]^3 to match IC + return SVector(5 * x, 5 * y, 5 * z) end # Unstructured mesh with 48 cells of the cube domain [-1, 1]^3 mesh_file = joinpath(@__DIR__, "cube_unstructured_2.inp") -isfile(mesh_file) || download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", - mesh_file) +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", + mesh_file) # Mesh polydeg of 2 (half the solver polydeg) to ensure FSP (see above). -mesh = P4estMesh{3}(mesh_file, polydeg=2, - mapping=mapping, - initial_refinement_level=1) - - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions=boundary_conditions) +mesh = P4estMesh{3}(mesh_file, polydeg = 2, + mapping = mapping, + initial_refinement_level = 1) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -70,29 +71,29 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable=first), - base_level=1, - med_level=2, med_threshold=0.1, - max_level=3, max_threshold=0.6) +amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first), + base_level = 1, + med_level = 2, med_threshold = 0.1, + max_level = 3, max_threshold = 0.6) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.2) +stepsize_callback = StepsizeCallback(cfl = 1.2) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -105,7 +106,7 @@ callbacks = CallbackSet(summary_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); +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/p4est_3d_dgsem/elixir_advection_basic.jl b/examples/p4est_3d_dgsem/elixir_advection_basic.jl index a165d1ff132..02ffa5c7aff 100644 --- a/examples/p4est_3d_dgsem/elixir_advection_basic.jl +++ b/examples/p4est_3d_dgsem/elixir_advection_basic.jl @@ -11,19 +11,20 @@ advection_velocity = (0.2, -0.7, 0.5) equations = LinearScalarAdvectionEquation3D(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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -1.0, -1.0) # minimum coordinates (min(x), min(y), min(z)) -coordinates_max = ( 1.0, 1.0, 1.0) # maximum coordinates (max(x), max(y), max(z)) +coordinates_max = (1.0, 1.0, 1.0) # maximum coordinates (max(x), max(y), max(z)) # Create P4estMesh with 8 x 8 x 8 elements (note `refinement_level=1`) trees_per_dimension = (4, 4, 4) -mesh = P4estMesh(trees_per_dimension, polydeg=3, - coordinates_min=coordinates_min, coordinates_max=coordinates_max, - initial_refinement_level=1) +mesh = P4estMesh(trees_per_dimension, polydeg = 3, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + initial_refinement_level = 1) # A semidiscretization collects data structures and functions for the spatial discretization -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, solver) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, + solver) ############################################################################### # ODE solvers, callbacks etc. @@ -37,30 +38,30 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +analysis_callback = AnalysisCallback(semi, interval = 100) # The SaveRestartCallback allows to save a file from which a Trixi.jl simulation can be restarted -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) # The SaveSolutionCallback allows to save the solution to a file in regular intervals -save_solution = SaveSolutionCallback(interval=100, - solution_variables=cons2prim) +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.2) +stepsize_callback = StepsizeCallback(cfl = 1.2) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver -callbacks = CallbackSet(summary_callback, analysis_callback, save_restart, save_solution, stepsize_callback) - +callbacks = CallbackSet(summary_callback, analysis_callback, save_restart, 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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/p4est_3d_dgsem/elixir_advection_cubed_sphere.jl b/examples/p4est_3d_dgsem/elixir_advection_cubed_sphere.jl index 07a8b36bb4c..cd641ca4af7 100644 --- a/examples/p4est_3d_dgsem/elixir_advection_cubed_sphere.jl +++ b/examples/p4est_3d_dgsem/elixir_advection_cubed_sphere.jl @@ -9,21 +9,20 @@ advection_velocity = (0.2, -0.7, 0.5) equations = LinearScalarAdvectionEquation3D(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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) initial_condition = initial_condition_convergence_test boundary_condition = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = Dict( - :inside => boundary_condition, - :outside => boundary_condition, -) +boundary_conditions = Dict(:inside => boundary_condition, + :outside => boundary_condition) mesh = Trixi.P4estMeshCubedSphere(5, 3, 0.5, 0.5, - polydeg=3, initial_refinement_level=0) + polydeg = 3, initial_refinement_level = 0) # A semidiscretization collects data structures and functions for the spatial discretization -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions=boundary_conditions) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -37,26 +36,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +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.2) +stepsize_callback = StepsizeCallback(cfl = 1.2) # 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) - +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/p4est_3d_dgsem/elixir_advection_nonconforming.jl b/examples/p4est_3d_dgsem/elixir_advection_nonconforming.jl index 93ff17c7842..34b0e95834d 100644 --- a/examples/p4est_3d_dgsem/elixir_advection_nonconforming.jl +++ b/examples/p4est_3d_dgsem/elixir_advection_nonconforming.jl @@ -2,7 +2,6 @@ using OrdinaryDiffEq using Trixi - ############################################################################### # semidiscretization of the linear advection equation @@ -10,39 +9,42 @@ advection_velocity = (0.2, -0.7, 0.5) equations = LinearScalarAdvectionEquation3D(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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -1.0, -1.0) # minimum coordinates (min(x), min(y), min(z)) -coordinates_max = ( 1.0, 1.0, 1.0) # maximum coordinates (max(x), max(y), max(z)) +coordinates_max = (1.0, 1.0, 1.0) # maximum coordinates (max(x), max(y), max(z)) trees_per_dimension = (1, 1, 1) # Note that it is not necessary to use mesh polydeg lower than the solver polydeg # on a Cartesian mesh. # See https://doi.org/10.1007/s10915-018-00897-9, Section 6. -mesh = P4estMesh(trees_per_dimension, polydeg=3, - coordinates_min=coordinates_min, coordinates_max=coordinates_max, - initial_refinement_level=2) +mesh = P4estMesh(trees_per_dimension, polydeg = 3, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + initial_refinement_level = 2) # Refine bottom left quadrant of each tree to level 3 function refine_fn(p8est, which_tree, quadrant) - quadrant_obj = unsafe_load(quadrant) - if quadrant_obj.x == 0 && quadrant_obj.y == 0 && quadrant_obj.z == 0 && quadrant_obj.level < 3 - # return true (refine) - return Cint(1) - else - # return false (don't refine) - return Cint(0) - end + quadrant_obj = unsafe_load(quadrant) + if quadrant_obj.x == 0 && quadrant_obj.y == 0 && quadrant_obj.z == 0 && + quadrant_obj.level < 3 + # return true (refine) + return Cint(1) + else + # return false (don't refine) + return Cint(0) + end end # Refine recursively until each bottom left quadrant of a tree has level 3 # The mesh will be rebalanced before the simulation starts -refine_fn_c = @cfunction(refine_fn, Cint, (Ptr{Trixi.p8est_t}, Ptr{Trixi.p4est_topidx_t}, Ptr{Trixi.p8est_quadrant_t})) +refine_fn_c = @cfunction(refine_fn, Cint, + (Ptr{Trixi.p8est_t}, Ptr{Trixi.p4est_topidx_t}, + Ptr{Trixi.p8est_quadrant_t})) Trixi.refine_p4est!(mesh.p4est, true, refine_fn_c, C_NULL) # A semidiscretization collects data structures and functions for the spatial discretization -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, solver) - +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, + solver) ############################################################################### # ODE solvers, callbacks etc. @@ -56,26 +58,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +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.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) # 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) - +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/p4est_3d_dgsem/elixir_advection_restart.jl b/examples/p4est_3d_dgsem/elixir_advection_restart.jl index 26d10cf8826..cd97d69d692 100644 --- a/examples/p4est_3d_dgsem/elixir_advection_restart.jl +++ b/examples/p4est_3d_dgsem/elixir_advection_restart.jl @@ -6,8 +6,7 @@ using Trixi # create a restart file trixi_include(@__MODULE__, joinpath(@__DIR__, "elixir_advection_basic.jl"), - trees_per_dimension=(2, 2, 2)) - + trees_per_dimension = (2, 2, 2)) ############################################################################### # adapt the parameters that have changed compared to "elixir_advection_extended.jl" @@ -18,7 +17,8 @@ trixi_include(@__MODULE__, joinpath(@__DIR__, "elixir_advection_basic.jl"), restart_filename = joinpath("out", "restart_000010.h5") mesh = load_mesh(restart_filename) -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, solver) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, + solver) tspan = (load_time(restart_filename), 2.0) dt = load_dt(restart_filename) @@ -27,14 +27,13 @@ ode = semidiscretize(semi, tspan, restart_filename); # Do not overwrite the initial snapshot written by elixir_advection_extended.jl. save_solution.condition.save_initial_solution = false -integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=dt, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +integrator = init(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); # Get the last time index and work with that. load_timestep!(integrator, restart_filename) - ############################################################################### # run the simulation diff --git a/examples/p4est_3d_dgsem/elixir_advection_unstructured_curved.jl b/examples/p4est_3d_dgsem/elixir_advection_unstructured_curved.jl index 85fd0b9a2cf..6df9ac0b16a 100644 --- a/examples/p4est_3d_dgsem/elixir_advection_unstructured_curved.jl +++ b/examples/p4est_3d_dgsem/elixir_advection_unstructured_curved.jl @@ -10,51 +10,54 @@ advection_velocity = (0.2, -0.7, 0.5) equations = LinearScalarAdvectionEquation3D(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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) initial_condition = initial_condition_convergence_test boundary_condition = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = Dict( - :all => boundary_condition -) +boundary_conditions = Dict(:all => boundary_condition) # Mapping as described in https://arxiv.org/abs/2012.12040 but with less warping. # The mapping will be interpolated at tree level, and then refined without changing # the geometry interpolant. The original mapping applied to this unstructured mesh # causes some Jacobians to be negative, which makes the mesh invalid. function mapping(xi, eta, zeta) - # Don't transform input variables between -1 and 1 onto [0,3] to obtain curved boundaries - # xi = 1.5 * xi_ + 1.5 - # eta = 1.5 * eta_ + 1.5 - # zeta = 1.5 * zeta_ + 1.5 - - y = eta + 1/6 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - x = xi + 1/6 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - z = zeta + 1/6 * (cos(0.5 * pi * (2 * x - 3)/3) * - cos(pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - return SVector(x, y, z) + # Don't transform input variables between -1 and 1 onto [0,3] to obtain curved boundaries + # xi = 1.5 * xi_ + 1.5 + # eta = 1.5 * eta_ + 1.5 + # zeta = 1.5 * zeta_ + 1.5 + + y = eta + + 1 / 6 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + x = xi + + 1 / 6 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + z = zeta + + 1 / 6 * (cos(0.5 * pi * (2 * x - 3) / 3) * + cos(pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + return SVector(x, y, z) end # Unstructured mesh with 68 cells of the cube domain [-1, 1]^3 mesh_file = joinpath(@__DIR__, "cube_unstructured_1.inp") -isfile(mesh_file) || download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", - mesh_file) +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", + mesh_file) -mesh = P4estMesh{3}(mesh_file, polydeg=3, - mapping=mapping, - initial_refinement_level=2) +mesh = P4estMesh{3}(mesh_file, polydeg = 3, + mapping = mapping, + initial_refinement_level = 2) # A semidiscretization collects data structures and functions for the spatial discretization -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions=boundary_conditions) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -68,32 +71,32 @@ summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) # The SaveRestartCallback allows to save a file from which a Trixi.jl simulation can be restarted -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) # The SaveSolutionCallback allows to save the solution to a file in regular intervals -save_solution = SaveSolutionCallback(interval=100, - solution_variables=cons2prim) +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.2) +stepsize_callback = StepsizeCallback(cfl = 1.2) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver -callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_restart, save_solution, stepsize_callback) - +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_restart, + 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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/p4est_3d_dgsem/elixir_euler_baroclinic_instability.jl b/examples/p4est_3d_dgsem/elixir_euler_baroclinic_instability.jl index 27c8ceb130c..0274a89aec7 100644 --- a/examples/p4est_3d_dgsem/elixir_euler_baroclinic_instability.jl +++ b/examples/p4est_3d_dgsem/elixir_euler_baroclinic_instability.jl @@ -22,190 +22,194 @@ equations = CompressibleEulerEquations3D(gamma) # Initial condition for an idealized baroclinic instability test # https://doi.org/10.1002/qj.2241, Section 3.2 and Appendix A -function initial_condition_baroclinic_instability(x, t, equations::CompressibleEulerEquations3D) - lon, lat, r = cartesian_to_sphere(x) - radius_earth = 6.371229e6 - # Make sure that the r is not smaller than radius_earth - z = max(r - radius_earth, 0.0) +function initial_condition_baroclinic_instability(x, t, + equations::CompressibleEulerEquations3D) + lon, lat, r = cartesian_to_sphere(x) + radius_earth = 6.371229e6 + # Make sure that the r is not smaller than radius_earth + z = max(r - radius_earth, 0.0) - # Unperturbed basic state - rho, u, p = basic_state_baroclinic_instability_longitudinal_velocity(lon, lat, z) + # Unperturbed basic state + rho, u, p = basic_state_baroclinic_instability_longitudinal_velocity(lon, lat, z) - # Stream function type perturbation - u_perturbation, v_perturbation = perturbation_stream_function(lon, lat, z) + # Stream function type perturbation + u_perturbation, v_perturbation = perturbation_stream_function(lon, lat, z) - u += u_perturbation - v = v_perturbation + u += u_perturbation + v = v_perturbation - # Convert spherical velocity to Cartesian - v1 = -sin(lon) * u - sin(lat) * cos(lon) * v - v2 = cos(lon) * u - sin(lat) * sin(lon) * v - v3 = cos(lat) * v + # Convert spherical velocity to Cartesian + v1 = -sin(lon) * u - sin(lat) * cos(lon) * v + v2 = cos(lon) * u - sin(lat) * sin(lon) * v + v3 = cos(lat) * v - return prim2cons(SVector(rho, v1, v2, v3, p), equations) + return prim2cons(SVector(rho, v1, v2, v3, p), equations) end # Steady state for RHS correction below function steady_state_baroclinic_instability(x, t, equations::CompressibleEulerEquations3D) - lon, lat, r = cartesian_to_sphere(x) - radius_earth = 6.371229e6 - # Make sure that the r is not smaller than radius_earth - z = max(r - radius_earth, 0.0) + lon, lat, r = cartesian_to_sphere(x) + radius_earth = 6.371229e6 + # Make sure that the r is not smaller than radius_earth + z = max(r - radius_earth, 0.0) - # Unperturbed basic state - rho, u, p = basic_state_baroclinic_instability_longitudinal_velocity(lon, lat, z) + # Unperturbed basic state + rho, u, p = basic_state_baroclinic_instability_longitudinal_velocity(lon, lat, z) - # Convert spherical velocity to Cartesian - v1 = -sin(lon) * u - v2 = cos(lon) * u - v3 = 0.0 + # Convert spherical velocity to Cartesian + v1 = -sin(lon) * u + v2 = cos(lon) * u + v3 = 0.0 - return prim2cons(SVector(rho, v1, v2, v3, p), equations) + return prim2cons(SVector(rho, v1, v2, v3, p), equations) end function cartesian_to_sphere(x) - r = norm(x) - lambda = atan(x[2], x[1]) - if lambda < 0 - lambda += 2 * pi - end - phi = asin(x[3] / r) - - return lambda, phi, r + r = norm(x) + lambda = atan(x[2], x[1]) + if lambda < 0 + lambda += 2 * pi + end + phi = asin(x[3] / r) + + return lambda, phi, r end # Unperturbed balanced steady-state. # Returns primitive variables with only the velocity in longitudinal direction (rho, u, p). # The other velocity components are zero. function basic_state_baroclinic_instability_longitudinal_velocity(lon, lat, z) - # Parameters from Table 1 in the paper - # Corresponding names in the paper are commented - radius_earth = 6.371229e6 # a - half_width_parameter = 2 # b - gravitational_acceleration = 9.80616 # g - k = 3 # k - surface_pressure = 1e5 # p₀ - gas_constant = 287 # R - surface_equatorial_temperature = 310.0 # T₀ᴱ - surface_polar_temperature = 240.0 # T₀ᴾ - lapse_rate = 0.005 # Γ - angular_velocity = 7.29212e-5 # Ω - - # Distance to the center of the Earth - r = z + radius_earth - - # In the paper: T₀ - temperature0 = 0.5 * (surface_equatorial_temperature + surface_polar_temperature) - # In the paper: A, B, C, H - const_a = 1 / lapse_rate - const_b = (temperature0 - surface_polar_temperature) / - (temperature0 * surface_polar_temperature) - const_c = 0.5 * (k + 2) * (surface_equatorial_temperature - surface_polar_temperature) / - (surface_equatorial_temperature * surface_polar_temperature) - const_h = gas_constant * temperature0 / gravitational_acceleration - - # In the paper: (r - a) / bH - scaled_z = z / (half_width_parameter * const_h) - - # Temporary variables - temp1 = exp(lapse_rate/temperature0 * z) - temp2 = exp(-scaled_z^2) - - # In the paper: ̃τ₁, ̃τ₂ - tau1 = const_a * lapse_rate / temperature0 * temp1 + const_b * (1 - 2 * scaled_z^2) * temp2 - tau2 = const_c * (1 - 2 * scaled_z^2) * temp2 - - # In the paper: ∫τ₁(r') dr', ∫τ₂(r') dr' - inttau1 = const_a * (temp1 - 1) + const_b * z * temp2 - inttau2 = const_c * z * temp2 - - # Temporary variables - temp3 = r/radius_earth * cos(lat) - temp4 = temp3^k - k/(k + 2) * temp3^(k+2) - - # In the paper: T - temperature = 1 / ((r/radius_earth)^2 * (tau1 - tau2 * temp4)) - - # In the paper: U, u (zonal wind, first component of spherical velocity) - big_u = gravitational_acceleration/radius_earth * k * temperature * inttau2 * (temp3^(k-1) - temp3^(k+1)) - temp5 = radius_earth * cos(lat) - u = -angular_velocity * temp5 + sqrt(angular_velocity^2 * temp5^2 + temp5 * big_u) - - # Hydrostatic pressure - p = surface_pressure * exp(-gravitational_acceleration/gas_constant * (inttau1 - inttau2 * temp4)) - - # Density (via ideal gas law) - rho = p / (gas_constant * temperature) - - return rho, u, p + # Parameters from Table 1 in the paper + # Corresponding names in the paper are commented + radius_earth = 6.371229e6 # a + half_width_parameter = 2 # b + gravitational_acceleration = 9.80616 # g + k = 3 # k + surface_pressure = 1e5 # p₀ + gas_constant = 287 # R + surface_equatorial_temperature = 310.0 # T₀ᴱ + surface_polar_temperature = 240.0 # T₀ᴾ + lapse_rate = 0.005 # Γ + angular_velocity = 7.29212e-5 # Ω + + # Distance to the center of the Earth + r = z + radius_earth + + # In the paper: T₀ + temperature0 = 0.5 * (surface_equatorial_temperature + surface_polar_temperature) + # In the paper: A, B, C, H + const_a = 1 / lapse_rate + const_b = (temperature0 - surface_polar_temperature) / + (temperature0 * surface_polar_temperature) + const_c = 0.5 * (k + 2) * (surface_equatorial_temperature - surface_polar_temperature) / + (surface_equatorial_temperature * surface_polar_temperature) + const_h = gas_constant * temperature0 / gravitational_acceleration + + # In the paper: (r - a) / bH + scaled_z = z / (half_width_parameter * const_h) + + # Temporary variables + temp1 = exp(lapse_rate / temperature0 * z) + temp2 = exp(-scaled_z^2) + + # In the paper: ̃τ₁, ̃τ₂ + tau1 = const_a * lapse_rate / temperature0 * temp1 + + const_b * (1 - 2 * scaled_z^2) * temp2 + tau2 = const_c * (1 - 2 * scaled_z^2) * temp2 + + # In the paper: ∫τ₁(r') dr', ∫τ₂(r') dr' + inttau1 = const_a * (temp1 - 1) + const_b * z * temp2 + inttau2 = const_c * z * temp2 + + # Temporary variables + temp3 = r / radius_earth * cos(lat) + temp4 = temp3^k - k / (k + 2) * temp3^(k + 2) + + # In the paper: T + temperature = 1 / ((r / radius_earth)^2 * (tau1 - tau2 * temp4)) + + # In the paper: U, u (zonal wind, first component of spherical velocity) + big_u = gravitational_acceleration / radius_earth * k * temperature * inttau2 * + (temp3^(k - 1) - temp3^(k + 1)) + temp5 = radius_earth * cos(lat) + u = -angular_velocity * temp5 + sqrt(angular_velocity^2 * temp5^2 + temp5 * big_u) + + # Hydrostatic pressure + p = surface_pressure * + exp(-gravitational_acceleration / gas_constant * (inttau1 - inttau2 * temp4)) + + # Density (via ideal gas law) + rho = p / (gas_constant * temperature) + + return rho, u, p end # Perturbation as in Equations 25 and 26 of the paper (analytical derivative) function perturbation_stream_function(lon, lat, z) - # Parameters from Table 1 in the paper - # Corresponding names in the paper are commented - perturbation_radius = 1/6 # d₀ / a - perturbed_wind_amplitude = 1.0 # Vₚ - perturbation_lon = pi/9 # Longitude of perturbation location - perturbation_lat = 2 * pi/9 # Latitude of perturbation location - pertz = 15000 # Perturbation height cap - - # Great circle distance (d in the paper) divided by a (radius of the Earth) - # because we never actually need d without dividing by a - great_circle_distance_by_a = acos(sin(perturbation_lat) * sin(lat) + - cos(perturbation_lat) * cos(lat) * - cos(lon - perturbation_lon)) - - # In the first case, the vertical taper function is per definition zero. - # In the second case, the stream function is per definition zero. - if z > pertz || great_circle_distance_by_a > perturbation_radius - return 0.0, 0.0 - end - - # Vertical tapering of stream function - perttaper = 1.0 - 3 * z^2 / pertz^2 + 2 * z^3 / pertz^3 - - # sin/cos(pi * d / (2 * d_0)) in the paper - sin_, cos_ = sincos(0.5 * pi * great_circle_distance_by_a / perturbation_radius) - - # Common factor for both u and v - factor = 16 / (3 * sqrt(3)) * perturbed_wind_amplitude * perttaper * cos_^3 * sin_ - - u_perturbation = -factor * (-sin(perturbation_lat) * cos(lat) + - cos(perturbation_lat) * sin(lat) * cos(lon - perturbation_lon) - ) / sin(great_circle_distance_by_a) - - v_perturbation = factor * cos(perturbation_lat) * sin(lon - perturbation_lon) / - sin(great_circle_distance_by_a) - - return u_perturbation, v_perturbation -end + # Parameters from Table 1 in the paper + # Corresponding names in the paper are commented + perturbation_radius = 1 / 6 # d₀ / a + perturbed_wind_amplitude = 1.0 # Vₚ + perturbation_lon = pi / 9 # Longitude of perturbation location + perturbation_lat = 2 * pi / 9 # Latitude of perturbation location + pertz = 15000 # Perturbation height cap + + # Great circle distance (d in the paper) divided by a (radius of the Earth) + # because we never actually need d without dividing by a + great_circle_distance_by_a = acos(sin(perturbation_lat) * sin(lat) + + cos(perturbation_lat) * cos(lat) * + cos(lon - perturbation_lon)) + + # In the first case, the vertical taper function is per definition zero. + # In the second case, the stream function is per definition zero. + if z > pertz || great_circle_distance_by_a > perturbation_radius + return 0.0, 0.0 + end + + # Vertical tapering of stream function + perttaper = 1.0 - 3 * z^2 / pertz^2 + 2 * z^3 / pertz^3 + + # sin/cos(pi * d / (2 * d_0)) in the paper + sin_, cos_ = sincos(0.5 * pi * great_circle_distance_by_a / perturbation_radius) + # Common factor for both u and v + factor = 16 / (3 * sqrt(3)) * perturbed_wind_amplitude * perttaper * cos_^3 * sin_ -@inline function source_terms_baroclinic_instability(u, x, t, equations::CompressibleEulerEquations3D) - radius_earth = 6.371229e6 # a - gravitational_acceleration = 9.80616 # g - angular_velocity = 7.29212e-5 # Ω + u_perturbation = -factor * (-sin(perturbation_lat) * cos(lat) + + cos(perturbation_lat) * sin(lat) * cos(lon - perturbation_lon)) / + sin(great_circle_distance_by_a) - r = norm(x) - # Make sure that r is not smaller than radius_earth - z = max(r - radius_earth, 0.0) - r = z + radius_earth + v_perturbation = factor * cos(perturbation_lat) * sin(lon - perturbation_lon) / + sin(great_circle_distance_by_a) - du1 = zero(eltype(u)) + return u_perturbation, v_perturbation +end + +@inline function source_terms_baroclinic_instability(u, x, t, + equations::CompressibleEulerEquations3D) + radius_earth = 6.371229e6 # a + gravitational_acceleration = 9.80616 # g + angular_velocity = 7.29212e-5 # Ω + + r = norm(x) + # Make sure that r is not smaller than radius_earth + z = max(r - radius_earth, 0.0) + r = z + radius_earth - # Gravity term - temp = -gravitational_acceleration * radius_earth^2 / r^3 - du2 = temp * u[1] * x[1] - du3 = temp * u[1] * x[2] - du4 = temp * u[1] * x[3] - du5 = temp * (u[2] * x[1] + u[3] * x[2] + u[4] * x[3]) + du1 = zero(eltype(u)) - # Coriolis term, -2Ω × ρv = -2 * angular_velocity * (0, 0, 1) × u[2:4] - du2 -= -2 * angular_velocity * u[3] - du3 -= 2 * angular_velocity * u[2] + # Gravity term + temp = -gravitational_acceleration * radius_earth^2 / r^3 + du2 = temp * u[1] * x[1] + du3 = temp * u[1] * x[2] + du4 = temp * u[1] * x[3] + du5 = temp * (u[2] * x[1] + u[3] * x[2] + u[4] * x[3]) - return SVector(du1, du2, du3, du4, du5) + # Coriolis term, -2Ω × ρv = -2 * angular_velocity * (0, 0, 1) × u[2:4] + du2 -= -2 * angular_velocity * u[3] + du3 -= 2 * angular_velocity * u[2] + + return SVector(du1, du2, du3, du4, du5) end ############################################################################### @@ -213,26 +217,24 @@ end initial_condition = initial_condition_baroclinic_instability -boundary_conditions = Dict( - :inside => boundary_condition_slip_wall, - :outside => boundary_condition_slip_wall, -) +boundary_conditions = Dict(:inside => boundary_condition_slip_wall, + :outside => boundary_condition_slip_wall) # This is a good estimate for the speed of sound in this example. # Other values between 300 and 400 should work as well. surface_flux = FluxLMARS(340) -volume_flux = flux_kennedy_gruber -solver = DGSEM(polydeg=5, surface_flux=surface_flux, volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +volume_flux = flux_kennedy_gruber +solver = DGSEM(polydeg = 5, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) # For optimal results, use (16, 8) here trees_per_cube_face = (8, 4) mesh = Trixi.P4estMeshCubedSphere(trees_per_cube_face..., 6.371229e6, 30000.0, - polydeg=5, initial_refinement_level=0) + polydeg = 5, initial_refinement_level = 0) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_baroclinic_instability, - boundary_conditions=boundary_conditions) - + source_terms = source_terms_baroclinic_instability, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -250,20 +252,20 @@ tspan = (0.0, 10 * 24 * 60 * 60.0) # time in seconds for 10 days u_steady_state = compute_coefficients(steady_state_baroclinic_instability, tspan[1], semi) # Use a `let` block for performance (otherwise du_steady_state will be a global variable) let du_steady_state = similar(u_steady_state) - # Save RHS of the steady state - Trixi.rhs!(du_steady_state, u_steady_state, semi, tspan[1]) - - global function corrected_rhs!(du, u, semi, t) - # Normal RHS evaluation - Trixi.rhs!(du, u, semi, t) - # Correct by subtracting the steady-state RHS - Trixi.@trixi_timeit Trixi.timer() "rhs correction" begin - # Use Trixi.@threaded for threaded performance - Trixi.@threaded for i in eachindex(du) - du[i] -= du_steady_state[i] - end + # Save RHS of the steady state + Trixi.rhs!(du_steady_state, u_steady_state, semi, tspan[1]) + + global function corrected_rhs!(du, u, semi, t) + # Normal RHS evaluation + Trixi.rhs!(du, u, semi, t) + # Correct by subtracting the steady-state RHS + Trixi.@trixi_timeit Trixi.timer() "rhs correction" begin + # Use Trixi.@threaded for threaded performance + Trixi.@threaded for i in eachindex(du) + du[i] -= du_steady_state[i] + end + end end - end end u0 = compute_coefficients(tspan[1], semi) ode = ODEProblem(corrected_rhs!, u0, tspan, semi) @@ -271,27 +273,27 @@ ode = ODEProblem(corrected_rhs!, u0, tspan, semi) summary_callback = SummaryCallback() analysis_interval = 5000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=5000, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 5000, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) - ############################################################################### # run the simulation # Use a Runge-Kutta method with automatic (error based) time step size control # Enable threading of the RK method for better performance on multiple threads -sol = solve(ode, RDPK3SpFSAL49(thread=OrdinaryDiffEq.True()); abstol=1.0e-6, reltol=1.0e-6, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(thread = OrdinaryDiffEq.True()); abstol = 1.0e-6, + reltol = 1.0e-6, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/p4est_3d_dgsem/elixir_euler_circular_wind_nonconforming.jl b/examples/p4est_3d_dgsem/elixir_euler_circular_wind_nonconforming.jl index 63e937620f0..34a43a5b534 100644 --- a/examples/p4est_3d_dgsem/elixir_euler_circular_wind_nonconforming.jl +++ b/examples/p4est_3d_dgsem/elixir_euler_circular_wind_nonconforming.jl @@ -14,78 +14,77 @@ using LinearAlgebra gamma = 1.4 equations = CompressibleEulerEquations3D(gamma) - function initial_condition_circular_wind(x, t, equations::CompressibleEulerEquations3D) - radius_earth = 6.371229e6 - p = 1e5 - rho = 1.0 - v1 = -10 * x[2] / radius_earth - v2 = 10 * x[1] / radius_earth - v3 = 0.0 - - return prim2cons(SVector(rho, v1, v2, v3, p), equations) + radius_earth = 6.371229e6 + p = 1e5 + rho = 1.0 + v1 = -10 * x[2] / radius_earth + v2 = 10 * x[1] / radius_earth + v3 = 0.0 + + return prim2cons(SVector(rho, v1, v2, v3, p), equations) end -@inline function source_terms_circular_wind(u, x, t, equations::CompressibleEulerEquations3D) - radius_earth = 6.371229e6 - rho = 1.0 +@inline function source_terms_circular_wind(u, x, t, + equations::CompressibleEulerEquations3D) + radius_earth = 6.371229e6 + rho = 1.0 - du1 = 0.0 - du2 = -rho * (10 / radius_earth) * (10 * x[1] / radius_earth) - du3 = -rho * (10 / radius_earth) * (10 * x[2] / radius_earth) - du4 = 0.0 - du5 = 0.0 + du1 = 0.0 + du2 = -rho * (10 / radius_earth) * (10 * x[1] / radius_earth) + du3 = -rho * (10 / radius_earth) * (10 * x[2] / radius_earth) + du4 = 0.0 + du5 = 0.0 - return SVector(du1, du2, du3, du4, du5) + return SVector(du1, du2, du3, du4, du5) end - -function indicator_test(u::AbstractArray{<:Any,5}, +function indicator_test(u::AbstractArray{<:Any, 5}, mesh, equations, dg::DGSEM, cache; kwargs...) - alpha = zeros(Int, nelements(dg, cache)) - - for element in eachelement(dg, cache) - for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg) - x = Trixi.get_node_coords(cache.elements.node_coordinates, equations, dg, i, j, k, element) - lambda, phi, r = cart_to_sphere(x) - if 0.22 < lambda < 3.3 && 0.45 < phi < 1.3 - alpha[element] = 1 - end + alpha = zeros(Int, nelements(dg, cache)) + + for element in eachelement(dg, cache) + for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg) + x = Trixi.get_node_coords(cache.elements.node_coordinates, equations, dg, i, j, + k, element) + lambda, phi, r = cart_to_sphere(x) + if 0.22 < lambda < 3.3 && 0.45 < phi < 1.3 + alpha[element] = 1 + end + end end - end - return alpha + return alpha end function cart_to_sphere(x) - r = norm(x) - lambda = atan(x[2], x[1]) - if lambda < 0 - lambda += 2 * pi - end - phi = asin(x[3] / r) - - return lambda, phi, r + r = norm(x) + lambda = atan(x[2], x[1]) + if lambda < 0 + lambda += 2 * pi + end + phi = asin(x[3] / r) + + return lambda, phi, r end -function Trixi.get_element_variables!(element_variables, indicator::typeof(indicator_test), ::AMRCallback) - return nothing +function Trixi.get_element_variables!(element_variables, indicator::typeof(indicator_test), + ::AMRCallback) + return nothing end initial_condition = initial_condition_circular_wind -boundary_conditions = Dict( - :inside => boundary_condition_slip_wall, - :outside => boundary_condition_slip_wall -) +boundary_conditions = Dict(:inside => boundary_condition_slip_wall, + :outside => boundary_condition_slip_wall) # The speed of sound in this example is 374 m/s. surface_flux = FluxLMARS(374) # Note that a free stream is not preserved if N < 2 * N_geo, where N is the # polydeg of the solver and N_geo is the polydeg of the mesh. # However, the FSP error is negligible in this example. -solver = DGSEM(polydeg=4, surface_flux=surface_flux) +solver = DGSEM(polydeg = 4, surface_flux = surface_flux) # Other mesh configurations to run this simulation on. # The cylinder allows to use a structured mesh, the face of the cubed sphere @@ -113,12 +112,11 @@ solver = DGSEM(polydeg=4, surface_flux=surface_flux) trees_per_cube_face = (6, 2) mesh = Trixi.P4estMeshCubedSphere(trees_per_cube_face..., 6.371229e6, 30000.0, - polydeg=4, initial_refinement_level=0) + polydeg = 4, initial_refinement_level = 0) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_circular_wind, - boundary_conditions=boundary_conditions) - + source_terms = source_terms_circular_wind, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -129,22 +127,22 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 5000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=5000, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 5000, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_controller = ControllerThreeLevel(semi, indicator_test, - base_level=0, - max_level=1, max_threshold=0.6) + base_level = 0, + max_level = 1, max_threshold = 0.6) amr_callback = AMRCallback(semi, amr_controller, - interval=0, # Only initial refinement - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 0, # Only initial refinement + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -152,13 +150,13 @@ callbacks = CallbackSet(summary_callback, save_solution, amr_callback) - ############################################################################### # run the simulation # Use a Runge-Kutta method with automatic (error based) time step size control # Enable threading of the RK method for better performance on multiple threads -sol = solve(ode, RDPK3SpFSAL49(thread=OrdinaryDiffEq.True()); abstol=1.0e-6, reltol=1.0e-6, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(thread = OrdinaryDiffEq.True()); abstol = 1.0e-6, + reltol = 1.0e-6, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/p4est_3d_dgsem/elixir_euler_ec.jl b/examples/p4est_3d_dgsem/elixir_euler_ec.jl index 463a26fca53..d9d774a7ffc 100644 --- a/examples/p4est_3d_dgsem/elixir_euler_ec.jl +++ b/examples/p4est_3d_dgsem/elixir_euler_ec.jl @@ -6,56 +6,59 @@ using Trixi ############################################################################### # semidiscretization of the compressible Euler equations -equations = CompressibleEulerEquations3D(5/3) +equations = CompressibleEulerEquations3D(5 / 3) initial_condition = initial_condition_weak_blast_wave -boundary_conditions = Dict( - :all => boundary_condition_slip_wall -) +boundary_conditions = Dict(:all => boundary_condition_slip_wall) # Get the DG approximation space volume_flux = flux_ranocha -solver = DGSEM(polydeg=5, surface_flux=flux_ranocha, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 5, surface_flux = flux_ranocha, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) # Get the curved quad mesh from a file # Mapping as described in https://arxiv.org/abs/2012.12040 function mapping(xi_, eta_, zeta_) - # Transform input variables between -1 and 1 onto [0,3] - xi = 1.5 * xi_ + 1.5 - eta = 1.5 * eta_ + 1.5 - zeta = 1.5 * zeta_ + 1.5 - - y = eta + 3/8 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - x = xi + 3/8 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - z = zeta + 3/8 * (cos(0.5 * pi * (2 * x - 3)/3) * - cos(pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - return SVector(x, y, z) + # Transform input variables between -1 and 1 onto [0,3] + xi = 1.5 * xi_ + 1.5 + eta = 1.5 * eta_ + 1.5 + zeta = 1.5 * zeta_ + 1.5 + + y = eta + + 3 / 8 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + x = xi + + 3 / 8 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + z = zeta + + 3 / 8 * (cos(0.5 * pi * (2 * x - 3) / 3) * + cos(pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + return SVector(x, y, z) end # Unstructured mesh with 48 cells of the cube domain [-1, 1]^3 mesh_file = joinpath(@__DIR__, "cube_unstructured_2.inp") -isfile(mesh_file) || download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", - mesh_file) +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", + mesh_file) -mesh = P4estMesh{3}(mesh_file, polydeg=5, - mapping=mapping, - initial_refinement_level=0) +mesh = P4estMesh{3}(mesh_file, polydeg = 5, + mapping = mapping, + initial_refinement_level = 0) # create the semidiscretization object -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions=boundary_conditions) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -66,15 +69,15 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -85,7 +88,7 @@ callbacks = CallbackSet(summary_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); +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/p4est_3d_dgsem/elixir_euler_free_stream.jl b/examples/p4est_3d_dgsem/elixir_euler_free_stream.jl index 3450adfe861..24a781ca59e 100644 --- a/examples/p4est_3d_dgsem/elixir_euler_free_stream.jl +++ b/examples/p4est_3d_dgsem/elixir_euler_free_stream.jl @@ -10,70 +10,75 @@ equations = CompressibleEulerEquations3D(1.4) initial_condition = initial_condition_constant -boundary_conditions = Dict( - :all => BoundaryConditionDirichlet(initial_condition) -) +boundary_conditions = Dict(:all => BoundaryConditionDirichlet(initial_condition)) # Solver with polydeg=4 to ensure free stream preservation (FSP) on non-conforming meshes. # The polydeg of the solver must be at least twice as big as the polydeg of the mesh. # See https://doi.org/10.1007/s10915-018-00897-9, Section 6. -solver = DGSEM(polydeg=4, surface_flux=flux_lax_friedrichs, - volume_integral=VolumeIntegralWeakForm()) +solver = DGSEM(polydeg = 4, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralWeakForm()) # Mapping as described in https://arxiv.org/abs/2012.12040 but with less warping. # The mapping will be interpolated at tree level, and then refined without changing # the geometry interpolant. This can yield problematic geometries if the unrefined mesh # is not fine enough. function mapping(xi_, eta_, zeta_) - # Transform input variables between -1 and 1 onto [0,3] - xi = 1.5 * xi_ + 1.5 - eta = 1.5 * eta_ + 1.5 - zeta = 1.5 * zeta_ + 1.5 - - y = eta + 1/6 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - x = xi + 1/6 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - z = zeta + 1/6 * (cos(0.5 * pi * (2 * x - 3)/3) * - cos(pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - return SVector(x, y, z) + # Transform input variables between -1 and 1 onto [0,3] + xi = 1.5 * xi_ + 1.5 + eta = 1.5 * eta_ + 1.5 + zeta = 1.5 * zeta_ + 1.5 + + y = eta + + 1 / 6 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + x = xi + + 1 / 6 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + z = zeta + + 1 / 6 * (cos(0.5 * pi * (2 * x - 3) / 3) * + cos(pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + return SVector(x, y, z) end # Unstructured mesh with 68 cells of the cube domain [-1, 1]^3 mesh_file = joinpath(@__DIR__, "cube_unstructured_1.inp") -isfile(mesh_file) || download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", - mesh_file) +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", + mesh_file) # Mesh polydeg of 2 (half the solver polydeg) to ensure FSP (see above). -mesh = P4estMesh{3}(mesh_file, polydeg=2, - mapping=mapping, - initial_refinement_level=0) +mesh = P4estMesh{3}(mesh_file, polydeg = 2, + mapping = mapping, + initial_refinement_level = 0) # Refine bottom left quadrant of each second tree to level 2 function refine_fn(p8est, which_tree, quadrant) - quadrant_obj = unsafe_load(quadrant) - if iseven(convert(Int, which_tree)) && quadrant_obj.x == 0 && quadrant_obj.y == 0 && quadrant_obj.z == 0 && quadrant_obj.level < 2 - # return true (refine) - return Cint(1) - else - # return false (don't refine) - return Cint(0) - end + quadrant_obj = unsafe_load(quadrant) + if iseven(convert(Int, which_tree)) && quadrant_obj.x == 0 && quadrant_obj.y == 0 && + quadrant_obj.z == 0 && quadrant_obj.level < 2 + # return true (refine) + return Cint(1) + else + # return false (don't refine) + return Cint(0) + end end # Refine recursively until each bottom left quadrant of every second tree has level 2. # The mesh will be rebalanced before the simulation starts. -refine_fn_c = @cfunction(refine_fn, Cint, (Ptr{Trixi.p8est_t}, Ptr{Trixi.p4est_topidx_t}, Ptr{Trixi.p8est_quadrant_t})) +refine_fn_c = @cfunction(refine_fn, Cint, + (Ptr{Trixi.p8est_t}, Ptr{Trixi.p4est_topidx_t}, + Ptr{Trixi.p8est_quadrant_t})) Trixi.refine_p4est!(mesh.p4est, true, refine_fn_c, C_NULL) -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions=boundary_conditions) - +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -84,27 +89,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.2) +stepsize_callback = StepsizeCallback(cfl = 1.2) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/p4est_3d_dgsem/elixir_euler_free_stream_extruded.jl b/examples/p4est_3d_dgsem/elixir_euler_free_stream_extruded.jl index 630a269b4a1..f56fe3a429d 100644 --- a/examples/p4est_3d_dgsem/elixir_euler_free_stream_extruded.jl +++ b/examples/p4est_3d_dgsem/elixir_euler_free_stream_extruded.jl @@ -10,12 +10,10 @@ equations = CompressibleEulerEquations3D(1.4) initial_condition = initial_condition_constant -boundary_conditions = Dict( - :all => BoundaryConditionDirichlet(initial_condition) -) +boundary_conditions = Dict(:all => BoundaryConditionDirichlet(initial_condition)) -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs, - volume_integral=VolumeIntegralWeakForm()) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralWeakForm()) # Mapping as described in https://arxiv.org/abs/2012.12040 but reduced to 2D. # This particular mesh is unstructured in the yz-plane, but extruded in x-direction. @@ -23,47 +21,52 @@ solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs, # in x-direction to ensure free stream preservation on a non-conforming mesh. # See https://doi.org/10.1007/s10915-018-00897-9, Section 6. function mapping(xi, eta_, zeta_) - # Transform input variables between -1 and 1 onto [0,3] - eta = 1.5 * eta_ + 1.5 - zeta = 1.5 * zeta_ + 1.5 + # Transform input variables between -1 and 1 onto [0,3] + eta = 1.5 * eta_ + 1.5 + zeta = 1.5 * zeta_ + 1.5 - z = zeta + 1/6 * (cos(1.5 * pi * (2 * eta - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) + z = zeta + + 1 / 6 * (cos(1.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) - y = eta + 1/6 * (cos(0.5 * pi * (2 * eta - 3)/3) * - cos(2 * pi * (2 * z - 3)/3)) + y = eta + 1 / 6 * (cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(2 * pi * (2 * z - 3) / 3)) - return SVector(xi, y, z) + return SVector(xi, y, z) end # Unstructured mesh with 48 cells of the cube domain [-1, 1]^3 mesh_file = joinpath(@__DIR__, "cube_unstructured_2.inp") -isfile(mesh_file) || download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", - mesh_file) +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", + mesh_file) -mesh = P4estMesh{3}(mesh_file, polydeg=3, - mapping=mapping, - initial_refinement_level=0) +mesh = P4estMesh{3}(mesh_file, polydeg = 3, + mapping = mapping, + initial_refinement_level = 0) # Refine quadrants in y-direction of each tree at one edge to level 2 function refine_fn(p8est, which_tree, quadrant) - quadrant_obj = unsafe_load(quadrant) - if convert(Int, which_tree) < 4 && quadrant_obj.x == 0 && quadrant_obj.y == 0 && quadrant_obj.level < 2 - # return true (refine) - return Cint(1) - else - # return false (don't refine) - return Cint(0) - end + quadrant_obj = unsafe_load(quadrant) + if convert(Int, which_tree) < 4 && quadrant_obj.x == 0 && quadrant_obj.y == 0 && + quadrant_obj.level < 2 + # return true (refine) + return Cint(1) + else + # return false (don't refine) + return Cint(0) + end end # Refine recursively until each desired quadrant has level 2. # The mesh will be rebalanced before the simulation starts. -refine_fn_c = @cfunction(refine_fn, Cint, (Ptr{Trixi.p8est_t}, Ptr{Trixi.p4est_topidx_t}, Ptr{Trixi.p8est_quadrant_t})) +refine_fn_c = @cfunction(refine_fn, Cint, + (Ptr{Trixi.p8est_t}, Ptr{Trixi.p4est_topidx_t}, + Ptr{Trixi.p8est_quadrant_t})) Trixi.refine_p4est!(mesh.p4est, true, refine_fn_c, C_NULL) -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions=boundary_conditions) - +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -74,30 +77,29 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.2) +stepsize_callback = StepsizeCallback(cfl = 1.2) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_restart, save_solution, stepsize_callback) - ############################################################################### # run the simulation -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); +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 diff --git a/examples/p4est_3d_dgsem/elixir_euler_sedov.jl b/examples/p4est_3d_dgsem/elixir_euler_sedov.jl index 6fa285b5565..8df95a3cc21 100644 --- a/examples/p4est_3d_dgsem/elixir_euler_sedov.jl +++ b/examples/p4est_3d_dgsem/elixir_euler_sedov.jl @@ -14,28 +14,29 @@ The Sedov blast wave setup based on Flash - https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 with smaller strength of the initial discontinuity. """ -function initial_condition_medium_sedov_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) - - # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 - r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) - E = 1.0 - p0_inner = 3 * (equations.gamma - 1) * E / (4 * pi * r0^2) - p0_outer = 1.0e-3 - - # Calculate primitive variables - rho = 1.0 - 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) +function initial_condition_medium_sedov_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) + + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 + r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) + E = 1.0 + p0_inner = 3 * (equations.gamma - 1) * E / (4 * pi * r0^2) + p0_outer = 1.0e-3 + + # Calculate primitive variables + rho = 1.0 + 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_medium_sedov_blast_wave @@ -45,24 +46,25 @@ volume_flux = flux_ranocha polydeg = 5 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=1.0, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) -solver = DGSEM(polydeg=polydeg, surface_flux=surface_flux, volume_integral=volume_integral) +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral) coordinates_min = (-1.0, -1.0, -1.0) -coordinates_max = ( 1.0, 1.0, 1.0) +coordinates_max = (1.0, 1.0, 1.0) trees_per_dimension = (4, 4, 4) mesh = P4estMesh(trees_per_dimension, - polydeg=4, initial_refinement_level=0, - coordinates_min=coordinates_min, coordinates_max=coordinates_max, - periodicity=true) + polydeg = 4, initial_refinement_level = 0, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + periodicity = true) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -76,15 +78,15 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -95,7 +97,7 @@ callbacks = CallbackSet(summary_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); +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/p4est_3d_dgsem/elixir_euler_source_terms_nonconforming_earth.jl b/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonconforming_earth.jl index c5e349934a2..28a300cd681 100644 --- a/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonconforming_earth.jl +++ b/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonconforming_earth.jl @@ -11,68 +11,68 @@ using LinearAlgebra gamma = 1.4 equations = CompressibleEulerEquations3D(gamma) +function initial_condition_convergence_test_sphere(x, t, + equations::CompressibleEulerEquations3D) + x_scaled = x / 6.371229e6 + t_scaled = t / 6.371229e6 -function initial_condition_convergence_test_sphere(x, t, equations::CompressibleEulerEquations3D) - x_scaled = x / 6.371229e6 - t_scaled = t / 6.371229e6 - - return initial_condition_convergence_test(x_scaled, t_scaled, equations) + return initial_condition_convergence_test(x_scaled, t_scaled, equations) end -@inline function source_terms_convergence_test_sphere(u, x, t, equations::CompressibleEulerEquations3D) - x_scaled = x / 6.371229e6 - t_scaled = t / 6.371229e6 +@inline function source_terms_convergence_test_sphere(u, x, t, + equations::CompressibleEulerEquations3D) + x_scaled = x / 6.371229e6 + t_scaled = t / 6.371229e6 - return source_terms_convergence_test(u, x_scaled, t_scaled, equations) / 6.371229e6 + return source_terms_convergence_test(u, x_scaled, t_scaled, equations) / 6.371229e6 end - -function indicator_test(u::AbstractArray{<:Any,5}, +function indicator_test(u::AbstractArray{<:Any, 5}, mesh, equations, dg::DGSEM, cache; kwargs...) - alpha = zeros(Int, nelements(dg, cache)) - - for element in eachelement(dg, cache) - for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg) - x = Trixi.get_node_coords(cache.elements.node_coordinates, equations, dg, i, j, k, element) - lambda, phi, r = cart_to_sphere(x) - if 0.22 < lambda < 3.3 && 0.45 < phi < 1.3 - alpha[element] = 1 - end + alpha = zeros(Int, nelements(dg, cache)) + + for element in eachelement(dg, cache) + for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg) + x = Trixi.get_node_coords(cache.elements.node_coordinates, equations, dg, i, j, + k, element) + lambda, phi, r = cart_to_sphere(x) + if 0.22 < lambda < 3.3 && 0.45 < phi < 1.3 + alpha[element] = 1 + end + end end - end - return alpha + return alpha end function cart_to_sphere(x) - r = norm(x) - lambda = atan(x[2], x[1]) - if lambda < 0 - lambda += 2 * pi - end - phi = asin(x[3] / r) - - return lambda, phi, r + r = norm(x) + lambda = atan(x[2], x[1]) + if lambda < 0 + lambda += 2 * pi + end + phi = asin(x[3] / r) + + return lambda, phi, r end -function Trixi.get_element_variables!(element_variables, indicator::typeof(indicator_test), ::AMRCallback) - return nothing +function Trixi.get_element_variables!(element_variables, indicator::typeof(indicator_test), + ::AMRCallback) + return nothing end initial_condition = initial_condition_convergence_test_sphere boundary_condition = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = Dict( - :inside => boundary_condition, - :outside => boundary_condition -) +boundary_conditions = Dict(:inside => boundary_condition, + :outside => boundary_condition) surface_flux = flux_hll # Note that a free stream is not preserved if N < 2 * N_geo, where N is the # polydeg of the solver and N_geo is the polydeg of the mesh. # However, the FSP error is negligible in this example. -solver = DGSEM(polydeg=4, surface_flux=surface_flux) +solver = DGSEM(polydeg = 4, surface_flux = surface_flux) # For performance reasons, only one face of the cubed sphere can be used: @@ -87,12 +87,11 @@ solver = DGSEM(polydeg=4, surface_flux=surface_flux) trees_per_cube_face = (6, 2) mesh = Trixi.P4estMeshCubedSphere(trees_per_cube_face..., 6.371229e6, 30000.0, - polydeg=4, initial_refinement_level=0) + polydeg = 4, initial_refinement_level = 0) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test_sphere, - boundary_conditions=boundary_conditions) - + source_terms = source_terms_convergence_test_sphere, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -103,22 +102,22 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_controller = ControllerThreeLevel(semi, indicator_test, - base_level=0, - max_level=1, max_threshold=0.6) + base_level = 0, + max_level = 1, max_threshold = 0.6) amr_callback = AMRCallback(semi, amr_controller, - interval=0, # Only initial refinement - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 0, # Only initial refinement + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -126,12 +125,11 @@ callbacks = CallbackSet(summary_callback, save_solution, amr_callback) - ############################################################################### # run the simulation # Use a Runge-Kutta method with automatic (error based) time step size control -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-6, reltol=1.0e-6, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-6, reltol = 1.0e-6, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_curved.jl b/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_curved.jl index dd394091758..0de22eaea40 100644 --- a/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_curved.jl +++ b/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_curved.jl @@ -11,73 +11,77 @@ equations = CompressibleEulerEquations3D(1.4) initial_condition = initial_condition_convergence_test boundary_condition = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = Dict( - :all => boundary_condition -) +boundary_conditions = Dict(:all => boundary_condition) # Solver with polydeg=4 to ensure free stream preservation (FSP) on non-conforming meshes. # The polydeg of the solver must be at least twice as big as the polydeg of the mesh. # See https://doi.org/10.1007/s10915-018-00897-9, Section 6. -solver = DGSEM(polydeg=4, surface_flux=flux_lax_friedrichs, - volume_integral=VolumeIntegralWeakForm()) +solver = DGSEM(polydeg = 4, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralWeakForm()) # Mapping as described in https://arxiv.org/abs/2012.12040 but with less warping. # The mapping will be interpolated at tree level, and then refined without changing # the geometry interpolant. The original mapping applied to this unstructured mesh # causes some Jacobians to be negative, which makes the mesh invalid. function mapping(xi, eta, zeta) - # Don't transform input variables between -1 and 1 onto [0,3] to obtain curved boundaries - # xi = 1.5 * xi_ + 1.5 - # eta = 1.5 * eta_ + 1.5 - # zeta = 1.5 * zeta_ + 1.5 - - y = eta + 1/6 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - x = xi + 1/6 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - z = zeta + 1/6 * (cos(0.5 * pi * (2 * x - 3)/3) * - cos(pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - # Transform the weird deformed cube to be approximately the cube [0,2]^3 - return SVector(x + 1, y + 1, z + 1) + # Don't transform input variables between -1 and 1 onto [0,3] to obtain curved boundaries + # xi = 1.5 * xi_ + 1.5 + # eta = 1.5 * eta_ + 1.5 + # zeta = 1.5 * zeta_ + 1.5 + + y = eta + + 1 / 6 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + x = xi + + 1 / 6 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + z = zeta + + 1 / 6 * (cos(0.5 * pi * (2 * x - 3) / 3) * + cos(pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + # Transform the weird deformed cube to be approximately the cube [0,2]^3 + return SVector(x + 1, y + 1, z + 1) end # Unstructured mesh with 68 cells of the cube domain [-1, 1]^3 mesh_file = joinpath(@__DIR__, "cube_unstructured_1.inp") -isfile(mesh_file) || download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", - mesh_file) +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", + mesh_file) # Mesh polydeg of 2 (half the solver polydeg) to ensure FSP (see above). -mesh = P4estMesh{3}(mesh_file, polydeg=2, - mapping=mapping, - initial_refinement_level=0) +mesh = P4estMesh{3}(mesh_file, polydeg = 2, + mapping = mapping, + initial_refinement_level = 0) # Refine bottom left quadrant of each tree to level 2 function refine_fn(p8est, which_tree, quadrant) - quadrant_obj = unsafe_load(quadrant) - if quadrant_obj.x == 0 && quadrant_obj.y == 0 && quadrant_obj.z == 0 && quadrant_obj.level < 2 - # return true (refine) - return Cint(1) - else - # return false (don't refine) - return Cint(0) - end + quadrant_obj = unsafe_load(quadrant) + if quadrant_obj.x == 0 && quadrant_obj.y == 0 && quadrant_obj.z == 0 && + quadrant_obj.level < 2 + # return true (refine) + return Cint(1) + else + # return false (don't refine) + return Cint(0) + end end # Refine recursively until each bottom left quadrant of a tree has level 2 # The mesh will be rebalanced before the simulation starts -refine_fn_c = @cfunction(refine_fn, Cint, (Ptr{Trixi.p8est_t}, Ptr{Trixi.p4est_topidx_t}, Ptr{Trixi.p8est_quadrant_t})) +refine_fn_c = @cfunction(refine_fn, Cint, + (Ptr{Trixi.p8est_t}, Ptr{Trixi.p4est_topidx_t}, + Ptr{Trixi.p8est_quadrant_t})) Trixi.refine_p4est!(mesh.p4est, true, refine_fn_c, C_NULL) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test, - boundary_conditions=boundary_conditions) - + source_terms = source_terms_convergence_test, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -88,27 +92,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.6) +stepsize_callback = StepsizeCallback(cfl = 0.6) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/p4est_3d_dgsem/elixir_euler_source_terms_nonperiodic.jl b/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonperiodic.jl index cd796c33e47..fc5e4da3ceb 100644 --- a/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonperiodic.jl +++ b/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonperiodic.jl @@ -10,31 +10,28 @@ equations = CompressibleEulerEquations3D(1.4) initial_condition = initial_condition_convergence_test boundary_condition = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = Dict( - :x_neg => boundary_condition, - :x_pos => boundary_condition, - :y_neg => boundary_condition, - :y_pos => boundary_condition, - :z_neg => boundary_condition, - :z_pos => boundary_condition -) - -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs, - volume_integral=VolumeIntegralWeakForm()) +boundary_conditions = Dict(:x_neg => boundary_condition, + :x_pos => boundary_condition, + :y_neg => boundary_condition, + :y_pos => boundary_condition, + :z_neg => boundary_condition, + :z_pos => boundary_condition) + +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralWeakForm()) coordinates_min = (0.0, 0.0, 0.0) coordinates_max = (2.0, 2.0, 2.0) trees_per_dimension = (2, 2, 2) -mesh = P4estMesh(trees_per_dimension, polydeg=1, - coordinates_min=coordinates_min, coordinates_max=coordinates_max, - periodicity=false, initial_refinement_level=1) +mesh = P4estMesh(trees_per_dimension, polydeg = 1, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + periodicity = false, initial_refinement_level = 1) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test, - boundary_conditions=boundary_conditions) - + source_terms = source_terms_convergence_test, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -45,27 +42,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.6) +stepsize_callback = StepsizeCallback(cfl = 0.6) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/p4est_3d_dgsem/elixir_euler_source_terms_nonperiodic_hohqmesh.jl b/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonperiodic_hohqmesh.jl index ff101bea8aa..0fa3a28fe8b 100644 --- a/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonperiodic_hohqmesh.jl +++ b/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonperiodic_hohqmesh.jl @@ -11,25 +11,25 @@ equations = CompressibleEulerEquations3D(1.4) initial_condition = initial_condition_convergence_test boundary_condition = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = Dict( :Bottom => boundary_condition, - :Top => boundary_condition, - :Circle => boundary_condition, - :Cut => boundary_condition ) +boundary_conditions = Dict(:Bottom => boundary_condition, + :Top => boundary_condition, + :Circle => boundary_condition, + :Cut => boundary_condition) -solver = DGSEM(polydeg=4, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 4, surface_flux = flux_lax_friedrichs) # Unstructured 3D half circle mesh from HOHQMesh default_mesh_file = joinpath(@__DIR__, "abaqus_half_circle_3d.inp") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/11461efbfb02c42e06aca338b3d0b645/raw/81deeb1ebc4945952c30af5bb75fe222a18d975c/abaqus_half_circle_3d.inp", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/11461efbfb02c42e06aca338b3d0b645/raw/81deeb1ebc4945952c30af5bb75fe222a18d975c/abaqus_half_circle_3d.inp", + default_mesh_file) mesh_file = default_mesh_file -mesh = P4estMesh{3}(mesh_file, initial_refinement_level=0) +mesh = P4estMesh{3}(mesh_file, initial_refinement_level = 0) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test, - boundary_conditions=boundary_conditions) - + source_terms = source_terms_convergence_test, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -40,17 +40,17 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=50, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 50, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -58,12 +58,11 @@ callbacks = CallbackSet(summary_callback, save_solution, stepsize_callback); - ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=1, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1, # 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/p4est_3d_dgsem/elixir_mhd_alfven_wave_nonconforming.jl b/examples/p4est_3d_dgsem/elixir_mhd_alfven_wave_nonconforming.jl index 8fe96ae3dec..6a62368ef99 100644 --- a/examples/p4est_3d_dgsem/elixir_mhd_alfven_wave_nonconforming.jl +++ b/examples/p4est_3d_dgsem/elixir_mhd_alfven_wave_nonconforming.jl @@ -5,40 +5,43 @@ using Trixi ############################################################################### # semidiscretization of the compressible ideal GLM-MHD equations -equations = IdealGlmMhdEquations3D(5/3) +equations = IdealGlmMhdEquations3D(5 / 3) initial_condition = initial_condition_convergence_test volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -solver = DGSEM(polydeg=3, surface_flux=(flux_hll, flux_nonconservative_powell), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = (flux_hll, flux_nonconservative_powell), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-1.0, -1.0, -1.0) -coordinates_max = ( 1.0, 1.0, 1.0) +coordinates_max = (1.0, 1.0, 1.0) # Create P4estMesh with 2 x 2 x 2 trees trees_per_dimension = (2, 2, 2) mesh = P4estMesh(trees_per_dimension, - polydeg=3, initial_refinement_level=2, - coordinates_min=coordinates_min, coordinates_max=coordinates_max, - periodicity=true) + polydeg = 3, initial_refinement_level = 2, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + periodicity = true) # OBS! Workaround to add a refinement patch after mesh is constructed # Refine bottom left quadrant of each tree to level 4 function refine_fn(p8est, which_tree, quadrant) - quadrant_obj = unsafe_load(quadrant) - if quadrant_obj.x == 0 && quadrant_obj.y == 0 && quadrant_obj.z == 0 && quadrant_obj.level < 4 - # return true (refine) - return Cint(1) - else - # return false (don't refine) - return Cint(0) - end + quadrant_obj = unsafe_load(quadrant) + if quadrant_obj.x == 0 && quadrant_obj.y == 0 && quadrant_obj.z == 0 && + quadrant_obj.level < 4 + # return true (refine) + return Cint(1) + else + # return false (don't refine) + return Cint(0) + end end # Refine recursively until each bottom left quadrant of a tree has level 4 # The mesh will be rebalanced before the simulation starts -refine_fn_c = @cfunction(refine_fn, Cint, (Ptr{Trixi.p8est_t}, Ptr{Trixi.p4est_topidx_t}, Ptr{Trixi.p8est_quadrant_t})) +refine_fn_c = @cfunction(refine_fn, Cint, + (Ptr{Trixi.p8est_t}, Ptr{Trixi.p4est_topidx_t}, + Ptr{Trixi.p8est_quadrant_t})) Trixi.refine_p4est!(mesh.p4est, true, refine_fn_c, C_NULL) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -52,18 +55,18 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) cfl = 1.0 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -71,11 +74,10 @@ callbacks = CallbackSet(summary_callback, stepsize_callback, glm_speed_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); +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/p4est_3d_dgsem/elixir_mhd_shockcapturing_amr.jl b/examples/p4est_3d_dgsem/elixir_mhd_shockcapturing_amr.jl index fc95d427abb..3941a40b2e4 100644 --- a/examples/p4est_3d_dgsem/elixir_mhd_shockcapturing_amr.jl +++ b/examples/p4est_3d_dgsem/elixir_mhd_shockcapturing_amr.jl @@ -17,71 +17,74 @@ Weak magnetic blast wave setup taken from Section 6.1 of the paper: [doi: 10.1016/j.jcp.2021.110580](https://doi.org/10.1016/j.jcp.2021.110580) """ function initial_condition_blast_wave(x, t, equations::IdealGlmMhdEquations3D) - # Center of the blast wave is selected for the domain [0, 3]^3 - inicenter = (1.5, 1.5, 1.5) - 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) - - delta_0 = 0.1 - r_0 = 0.3 - lambda = exp(5.0 / delta_0 * (r - r_0)) - - prim_inner = SVector(1.2, 0.1, 0.0, 0.1, 0.9, 1.0, 1.0, 1.0, 0.0) - prim_outer = SVector(1.2, 0.2, -0.4, 0.2, 0.3, 1.0, 1.0, 1.0, 0.0) - prim_vars = (prim_inner + lambda * prim_outer) / (1.0 + lambda) - - return prim2cons(prim_vars, equations) + # Center of the blast wave is selected for the domain [0, 3]^3 + inicenter = (1.5, 1.5, 1.5) + 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) + + delta_0 = 0.1 + r_0 = 0.3 + lambda = exp(5.0 / delta_0 * (r - r_0)) + + prim_inner = SVector(1.2, 0.1, 0.0, 0.1, 0.9, 1.0, 1.0, 1.0, 0.0) + prim_outer = SVector(1.2, 0.2, -0.4, 0.2, 0.3, 1.0, 1.0, 1.0, 0.0) + prim_vars = (prim_inner + lambda * prim_outer) / (1.0 + lambda) + + return prim2cons(prim_vars, equations) end initial_condition = initial_condition_blast_wave surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell) -volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) +volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) polydeg = 3 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral) # Mapping as described in https://arxiv.org/abs/2012.12040 but with slightly less warping. # The mapping will be interpolated at tree level, and then refined without changing # the geometry interpolant. function mapping(xi_, eta_, zeta_) - # Transform input variables between -1 and 1 onto [0,3] - xi = 1.5 * xi_ + 1.5 - eta = 1.5 * eta_ + 1.5 - zeta = 1.5 * zeta_ + 1.5 - - y = eta + 3/11 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - x = xi + 3/11 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - z = zeta + 3/11 * (cos(0.5 * pi * (2 * x - 3)/3) * - cos(pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - return SVector(x, y, z) + # Transform input variables between -1 and 1 onto [0,3] + xi = 1.5 * xi_ + 1.5 + eta = 1.5 * eta_ + 1.5 + zeta = 1.5 * zeta_ + 1.5 + + y = eta + + 3 / 11 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + x = xi + + 3 / 11 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + z = zeta + + 3 / 11 * (cos(0.5 * pi * (2 * x - 3) / 3) * + cos(pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + return SVector(x, y, z) end trees_per_dimension = (2, 2, 2) mesh = P4estMesh(trees_per_dimension, - polydeg=3, - mapping=mapping, - initial_refinement_level=2, - periodicity=true) + polydeg = 3, + mapping = mapping, + initial_refinement_level = 2, + periodicity = true) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -95,24 +98,24 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) amr_indicator = IndicatorLöhner(semi, - variable=density_pressure) + variable = density_pressure) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=2, - max_level =4, max_threshold=0.15) + base_level = 2, + max_level = 4, max_threshold = 0.15) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) cfl = 1.4 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -121,11 +124,10 @@ callbacks = CallbackSet(summary_callback, stepsize_callback, glm_speed_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); +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/p4est_3d_dgsem/elixir_navierstokes_convergence.jl b/examples/p4est_3d_dgsem/elixir_navierstokes_convergence.jl index 0109e58dfb3..c640b255b05 100644 --- a/examples/p4est_3d_dgsem/elixir_navierstokes_convergence.jl +++ b/examples/p4est_3d_dgsem/elixir_navierstokes_convergence.jl @@ -8,240 +8,241 @@ prandtl_number() = 0.72 mu() = 0.01 equations = CompressibleEulerEquations3D(1.4) -equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu=mu(), Prandtl=prandtl_number(), - gradient_variables=GradientVariablesPrimitive()) +equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu = mu(), + Prandtl = prandtl_number(), + gradient_variables = GradientVariablesPrimitive()) # 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, - volume_integral=VolumeIntegralWeakForm()) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralWeakForm()) coordinates_min = (-1.0, -1.0, -1.0) # minimum coordinates (min(x), min(y), min(z)) -coordinates_max = ( 1.0, 1.0, 1.0) # maximum coordinates (max(x), max(y), max(z)) +coordinates_max = (1.0, 1.0, 1.0) # maximum coordinates (max(x), max(y), max(z)) trees_per_dimension = (2, 2, 2) -mesh = P4estMesh(trees_per_dimension, polydeg=3, - coordinates_min=coordinates_min, coordinates_max=coordinates_max, - periodicity=(true, false, true), initial_refinement_level=2) +mesh = P4estMesh(trees_per_dimension, polydeg = 3, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + periodicity = (true, false, true), initial_refinement_level = 2) # Note: the initial condition cannot be specialized to `CompressibleNavierStokesDiffusion3D` # since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesDiffusion3D`) # and by the initial condition (which passes in `CompressibleEulerEquations3D`). # This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) function initial_condition_navier_stokes_convergence_test(x, t, equations) - # Constants. OBS! Must match those in `source_terms_navier_stokes_convergence_test` - c = 2.0 - A1 = 0.5 - A2 = 1.0 - A3 = 0.5 - - # Convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_z = pi * x[3] - pi_t = 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.0) * (1.0 - exp(-A3 * (x[2] - 1.0))) * sin(pi_z) * cos(pi_t) - v2 = v1 - v3 = v1 - p = rho^2 - - return prim2cons(SVector(rho, v1, v2, v3, p), equations) + # Constants. OBS! Must match those in `source_terms_navier_stokes_convergence_test` + c = 2.0 + A1 = 0.5 + A2 = 1.0 + A3 = 0.5 + + # Convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_z = pi * x[3] + pi_t = 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.0) * (1.0 - exp(-A3 * (x[2] - 1.0))) * sin(pi_z) * + cos(pi_t) + v2 = v1 + v3 = v1 + p = rho^2 + + return prim2cons(SVector(rho, v1, v2, v3, p), equations) end @inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) - # TODO: parabolic - # we currently need to hardcode these parameters until we fix the "combined equation" issue - # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 - inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = prandtl_number() - mu_ = mu() - - # Constants. OBS! Must match those in `initial_condition_navier_stokes_convergence_test` - c = 2.0 - A1 = 0.5 - A2 = 1.0 - A3 = 0.5 - - # Convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_z = pi * x[3] - pi_t = pi * t - - # Define auxiliary functions for the strange function of the y variable - # to make expressions easier to read - g = log(x[2] + 2.0) * (1.0 - exp(-A3 * (x[2] - 1.0))) - g_y = ( A3 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0)) - + (1.0 - exp(-A3 * (x[2] - 1.0))) / (x[2] + 2.0) ) - g_yy = ( 2.0 * A3 * exp(-A3 * (x[2] - 1.0)) / (x[2] + 2.0) - - (1.0 - exp(-A3 * (x[2] - 1.0))) / ((x[2] + 2.0)^2) - - A3^2 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0)) ) - - # Density and its derivatives - rho = c + A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t) - rho_t = -pi * A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * sin(pi_t) - rho_x = pi * A1 * cos(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t) - rho_y = -pi * A1 * sin(pi_x) * sin(pi_y) * sin(pi_z) * cos(pi_t) - rho_z = pi * A1 * sin(pi_x) * cos(pi_y) * cos(pi_z) * cos(pi_t) - rho_xx = -pi^2 * (rho - c) - rho_yy = -pi^2 * (rho - c) - rho_zz = -pi^2 * (rho - c) - - # Velocities and their derivatives - # v1 terms - v1 = A2 * sin(pi_x) * g * sin(pi_z) * cos(pi_t) - v1_t = -pi * A2 * sin(pi_x) * g * sin(pi_z) * sin(pi_t) - v1_x = pi * A2 * cos(pi_x) * g * sin(pi_z) * cos(pi_t) - v1_y = A2 * sin(pi_x) * g_y * sin(pi_z) * cos(pi_t) - v1_z = pi * A2 * sin(pi_x) * g * cos(pi_z) * cos(pi_t) - v1_xx = -pi^2 * v1 - v1_yy = A2 * sin(pi_x) * g_yy * sin(pi_z) * cos(pi_t) - v1_zz = -pi^2 * v1 - v1_xy = pi * A2 * cos(pi_x) * g_y * sin(pi_z) * cos(pi_t) - v1_xz = pi^2 * A2 * cos(pi_x) * g * cos(pi_z) * cos(pi_t) - v1_yz = pi * A2 * sin(pi_x) * g_y * cos(pi_z) * cos(pi_t) - # v2 terms (simplifies from ansatz) - v2 = v1 - v2_t = v1_t - v2_x = v1_x - v2_y = v1_y - v2_z = v1_z - v2_xx = v1_xx - v2_yy = v1_yy - v2_zz = v1_zz - v2_xy = v1_xy - v2_yz = v1_yz - # v3 terms (simplifies from ansatz) - v3 = v1 - v3_t = v1_t - v3_x = v1_x - v3_y = v1_y - v3_z = v1_z - v3_xx = v1_xx - v3_yy = v1_yy - v3_zz = v1_zz - v3_xz = v1_xz - v3_yz = v1_yz - - # Pressure and its derivatives - p = rho^2 - p_t = 2.0 * rho * rho_t - p_x = 2.0 * rho * rho_x - p_y = 2.0 * rho * rho_y - p_z = 2.0 * rho * rho_z - - # Total energy and its derivatives; simiplifies from ansatz that v2 = v1 and v3 = v1 - E = p * inv_gamma_minus_one + 1.5 * rho * v1^2 - E_t = p_t * inv_gamma_minus_one + 1.5 * rho_t * v1^2 + 3.0 * rho * v1 * v1_t - E_x = p_x * inv_gamma_minus_one + 1.5 * rho_x * v1^2 + 3.0 * rho * v1 * v1_x - E_y = p_y * inv_gamma_minus_one + 1.5 * rho_y * v1^2 + 3.0 * rho * v1 * v1_y - E_z = p_z * inv_gamma_minus_one + 1.5 * rho_z * v1^2 + 3.0 * rho * v1 * v1_z - - # Divergence of Fick's law ∇⋅∇q = kappa ∇⋅∇T; simplifies because p = rho², so T = p/rho = rho - kappa = equations.gamma * inv_gamma_minus_one / Pr - q_xx = kappa * rho_xx # kappa T_xx - q_yy = kappa * rho_yy # kappa T_yy - q_zz = kappa * rho_zz # kappa T_zz - - # Stress tensor and its derivatives (exploit symmetry) - tau11 = 4.0 / 3.0 * v1_x - 2.0 / 3.0 * (v2_y + v3_z) - tau12 = v1_y + v2_x - tau13 = v1_z + v3_x - tau22 = 4.0 / 3.0 * v2_y - 2.0 / 3.0 * (v1_x + v3_z) - tau23 = v2_z + v3_y - tau33 = 4.0 / 3.0 * v3_z - 2.0 / 3.0 * (v1_x + v2_y) - - tau11_x = 4.0 / 3.0 * v1_xx - 2.0 / 3.0 * (v2_xy + v3_xz) - tau12_x = v1_xy + v2_xx - tau13_x = v1_xz + v3_xx - - tau12_y = v1_yy + v2_xy - tau22_y = 4.0 / 3.0 * v2_yy - 2.0 / 3.0 * (v1_xy + v3_yz) - tau23_y = v2_yz + v3_yy - - tau13_z = v1_zz + v3_xz - tau23_z = v2_zz + v3_yz - tau33_z = 4.0 / 3.0 * v3_zz - 2.0 / 3.0 * (v1_xz + v2_yz) - - # Compute the source terms - # Density equation - du1 = ( rho_t + rho_x * v1 + rho * v1_x - + rho_y * v2 + rho * v2_y - + rho_z * v3 + rho * v3_z ) - # x-momentum equation - du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 - + 2.0 * rho * v1 * v1_x - + rho_y * v1 * v2 - + rho * v1_y * v2 - + rho * v1 * v2_y - + rho_z * v1 * v3 - + rho * v1_z * v3 - + rho * v1 * v3_z - - mu_ * (tau11_x + tau12_y + tau13_z) ) - # y-momentum equation - du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 - + rho * v1_x * v2 - + rho * v1 * v2_x - + rho_y * v2^2 - + 2.0 * rho * v2 * v2_y - + rho_z * v2 * v3 - + rho * v2_z * v3 - + rho * v2 * v3_z - - mu_ * (tau12_x + tau22_y + tau23_z) ) - # z-momentum equation - du4 = ( rho_t * v3 + rho * v3_t + p_z + rho_x * v1 * v3 - + rho * v1_x * v3 - + rho * v1 * v3_x - + rho_y * v2 * v3 - + rho * v2_y * v3 - + rho * v2 * v3_y - + rho_z * v3^2 - + 2.0 * rho * v3 * v3_z - - mu_ * (tau13_x + tau23_y + tau33_z) ) - # Total energy equation - du5 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) - + v2_y * (E + p) + v2 * (E_y + p_y) - + v3_z * (E + p) + v3 * (E_z + p_z) - # stress tensor and temperature gradient from x-direction - - mu_ * ( q_xx + v1_x * tau11 + v2_x * tau12 + v3_x * tau13 - + v1 * tau11_x + v2 * tau12_x + v3 * tau13_x) - # stress tensor and temperature gradient terms from y-direction - - mu_ * ( q_yy + v1_y * tau12 + v2_y * tau22 + v3_y * tau23 - + v1 * tau12_y + v2 * tau22_y + v3 * tau23_y) - # stress tensor and temperature gradient terms from z-direction - - mu_ * ( q_zz + v1_z * tau13 + v2_z * tau23 + v3_z * tau33 - + v1 * tau13_z + v2 * tau23_z + v3 * tau33_z) ) - - return SVector(du1, du2, du3, du4, du5) + # TODO: parabolic + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + mu_ = mu() + + # Constants. OBS! Must match those in `initial_condition_navier_stokes_convergence_test` + c = 2.0 + A1 = 0.5 + A2 = 1.0 + A3 = 0.5 + + # Convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_z = pi * x[3] + pi_t = pi * t + + # Define auxiliary functions for the strange function of the y variable + # to make expressions easier to read + g = log(x[2] + 2.0) * (1.0 - exp(-A3 * (x[2] - 1.0))) + g_y = (A3 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0)) + + (1.0 - exp(-A3 * (x[2] - 1.0))) / (x[2] + 2.0)) + g_yy = (2.0 * A3 * exp(-A3 * (x[2] - 1.0)) / (x[2] + 2.0) - + (1.0 - exp(-A3 * (x[2] - 1.0))) / ((x[2] + 2.0)^2) - + A3^2 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0))) + + # Density and its derivatives + rho = c + A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t) + rho_t = -pi * A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * sin(pi_t) + rho_x = pi * A1 * cos(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t) + rho_y = -pi * A1 * sin(pi_x) * sin(pi_y) * sin(pi_z) * cos(pi_t) + rho_z = pi * A1 * sin(pi_x) * cos(pi_y) * cos(pi_z) * cos(pi_t) + rho_xx = -pi^2 * (rho - c) + rho_yy = -pi^2 * (rho - c) + rho_zz = -pi^2 * (rho - c) + + # Velocities and their derivatives + # v1 terms + v1 = A2 * sin(pi_x) * g * sin(pi_z) * cos(pi_t) + v1_t = -pi * A2 * sin(pi_x) * g * sin(pi_z) * sin(pi_t) + v1_x = pi * A2 * cos(pi_x) * g * sin(pi_z) * cos(pi_t) + v1_y = A2 * sin(pi_x) * g_y * sin(pi_z) * cos(pi_t) + v1_z = pi * A2 * sin(pi_x) * g * cos(pi_z) * cos(pi_t) + v1_xx = -pi^2 * v1 + v1_yy = A2 * sin(pi_x) * g_yy * sin(pi_z) * cos(pi_t) + v1_zz = -pi^2 * v1 + v1_xy = pi * A2 * cos(pi_x) * g_y * sin(pi_z) * cos(pi_t) + v1_xz = pi^2 * A2 * cos(pi_x) * g * cos(pi_z) * cos(pi_t) + v1_yz = pi * A2 * sin(pi_x) * g_y * cos(pi_z) * cos(pi_t) + # v2 terms (simplifies from ansatz) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_z = v1_z + v2_xx = v1_xx + v2_yy = v1_yy + v2_zz = v1_zz + v2_xy = v1_xy + v2_yz = v1_yz + # v3 terms (simplifies from ansatz) + v3 = v1 + v3_t = v1_t + v3_x = v1_x + v3_y = v1_y + v3_z = v1_z + v3_xx = v1_xx + v3_yy = v1_yy + v3_zz = v1_zz + v3_xz = v1_xz + v3_yz = v1_yz + + # Pressure and its derivatives + p = rho^2 + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_z = 2.0 * rho * rho_z + + # Total energy and its derivatives; simiplifies from ansatz that v2 = v1 and v3 = v1 + E = p * inv_gamma_minus_one + 1.5 * rho * v1^2 + E_t = p_t * inv_gamma_minus_one + 1.5 * rho_t * v1^2 + 3.0 * rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + 1.5 * rho_x * v1^2 + 3.0 * rho * v1 * v1_x + E_y = p_y * inv_gamma_minus_one + 1.5 * rho_y * v1^2 + 3.0 * rho * v1 * v1_y + E_z = p_z * inv_gamma_minus_one + 1.5 * rho_z * v1^2 + 3.0 * rho * v1 * v1_z + + # Divergence of Fick's law ∇⋅∇q = kappa ∇⋅∇T; simplifies because p = rho², so T = p/rho = rho + kappa = equations.gamma * inv_gamma_minus_one / Pr + q_xx = kappa * rho_xx # kappa T_xx + q_yy = kappa * rho_yy # kappa T_yy + q_zz = kappa * rho_zz # kappa T_zz + + # Stress tensor and its derivatives (exploit symmetry) + tau11 = 4.0 / 3.0 * v1_x - 2.0 / 3.0 * (v2_y + v3_z) + tau12 = v1_y + v2_x + tau13 = v1_z + v3_x + tau22 = 4.0 / 3.0 * v2_y - 2.0 / 3.0 * (v1_x + v3_z) + tau23 = v2_z + v3_y + tau33 = 4.0 / 3.0 * v3_z - 2.0 / 3.0 * (v1_x + v2_y) + + tau11_x = 4.0 / 3.0 * v1_xx - 2.0 / 3.0 * (v2_xy + v3_xz) + tau12_x = v1_xy + v2_xx + tau13_x = v1_xz + v3_xx + + tau12_y = v1_yy + v2_xy + tau22_y = 4.0 / 3.0 * v2_yy - 2.0 / 3.0 * (v1_xy + v3_yz) + tau23_y = v2_yz + v3_yy + + tau13_z = v1_zz + v3_xz + tau23_z = v2_zz + v3_yz + tau33_z = 4.0 / 3.0 * v3_zz - 2.0 / 3.0 * (v1_xz + v2_yz) + + # Compute the source terms + # Density equation + du1 = (rho_t + rho_x * v1 + rho * v1_x + + rho_y * v2 + rho * v2_y + + rho_z * v3 + rho * v3_z) + # x-momentum equation + du2 = (rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y + + rho_z * v1 * v3 + + rho * v1_z * v3 + + rho * v1 * v3_z - + mu_ * (tau11_x + tau12_y + tau13_z)) + # y-momentum equation + du3 = (rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y + + rho_z * v2 * v3 + + rho * v2_z * v3 + + rho * v2 * v3_z - + mu_ * (tau12_x + tau22_y + tau23_z)) + # z-momentum equation + du4 = (rho_t * v3 + rho * v3_t + p_z + rho_x * v1 * v3 + + rho * v1_x * v3 + + rho * v1 * v3_x + + rho_y * v2 * v3 + + rho * v2_y * v3 + + rho * v2 * v3_y + + rho_z * v3^2 + + 2.0 * rho * v3 * v3_z - + mu_ * (tau13_x + tau23_y + tau33_z)) + # Total energy equation + du5 = (E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) + + v3_z * (E + p) + v3 * (E_z + p_z) - + # stress tensor and temperature gradient from x-direction + mu_ * (q_xx + v1_x * tau11 + v2_x * tau12 + v3_x * tau13 + + v1 * tau11_x + v2 * tau12_x + v3 * tau13_x) - + # stress tensor and temperature gradient terms from y-direction + mu_ * (q_yy + v1_y * tau12 + v2_y * tau22 + v3_y * tau23 + + v1 * tau12_y + v2 * tau22_y + v3 * tau23_y) - + # stress tensor and temperature gradient terms from z-direction + mu_ * (q_zz + v1_z * tau13 + v2_z * tau23 + v3_z * tau33 + + v1 * tau13_z + v2 * tau23_z + v3 * tau33_z)) + + return SVector(du1, du2, du3, du4, du5) end initial_condition = initial_condition_navier_stokes_convergence_test # BC types velocity_bc_top_bottom = NoSlip() do x, t, equations - u = initial_condition_navier_stokes_convergence_test(x, t, equations) - return SVector(u[2], u[3], u[4]) + u = initial_condition_navier_stokes_convergence_test(x, t, equations) + return SVector(u[2], u[3], u[4]) end heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) -boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, heat_bc_top_bottom) +boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, + heat_bc_top_bottom) # define inviscid boundary conditions -boundary_conditions = Dict( - :y_neg => boundary_condition_slip_wall, - :y_pos => boundary_condition_slip_wall - ) +boundary_conditions = Dict(:y_neg => boundary_condition_slip_wall, + :y_pos => boundary_condition_slip_wall) # define viscous boundary conditions -boundary_conditions_parabolic = Dict( - :y_neg => boundary_condition_top_bottom, - :y_pos => boundary_condition_top_bottom - ) +boundary_conditions_parabolic = Dict(:y_neg => boundary_condition_top_bottom, + :y_pos => boundary_condition_top_bottom) -semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; - boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), - source_terms=source_terms_navier_stokes_convergence_test) +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic), + source_terms = source_terms_navier_stokes_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -251,16 +252,15 @@ tspan = (0.0, 0.2) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, dt = 1e-5, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary - diff --git a/examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex.jl b/examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex.jl index c5b9ccf2e38..d785013f5a9 100644 --- a/examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex.jl +++ b/examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex.jl @@ -10,42 +10,45 @@ prandtl_number() = 0.72 mu() = 6.25e-4 # equivalent to Re = 1600 equations = CompressibleEulerEquations3D(1.4) -equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu=mu(), - Prandtl=prandtl_number()) +equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu = mu(), + Prandtl = prandtl_number()) """ initial_condition_taylor_green_vortex(x, t, equations::CompressibleEulerEquations3D) The classical inviscid Taylor-Green vortex. """ -function initial_condition_taylor_green_vortex(x, t, equations::CompressibleEulerEquations3D) - A = 1.0 # magnitude of speed - Ms = 0.1 # maximum Mach number - - rho = 1.0 - v1 = A * sin(x[1]) * cos(x[2]) * cos(x[3]) - v2 = -A * cos(x[1]) * sin(x[2]) * cos(x[3]) - v3 = 0.0 - p = (A / Ms)^2 * rho / equations.gamma # scaling to get Ms - p = p + 1.0/16.0 * A^2 * rho * (cos(2*x[1])*cos(2*x[3]) + 2*cos(2*x[2]) + 2*cos(2*x[1]) + cos(2*x[2])*cos(2*x[3])) - - return prim2cons(SVector(rho, v1, v2, v3, p), equations) +function initial_condition_taylor_green_vortex(x, t, + equations::CompressibleEulerEquations3D) + A = 1.0 # magnitude of speed + Ms = 0.1 # maximum Mach number + + rho = 1.0 + v1 = A * sin(x[1]) * cos(x[2]) * cos(x[3]) + v2 = -A * cos(x[1]) * sin(x[2]) * cos(x[3]) + v3 = 0.0 + p = (A / Ms)^2 * rho / equations.gamma # scaling to get Ms + p = p + + 1.0 / 16.0 * A^2 * rho * + (cos(2 * x[1]) * cos(2 * x[3]) + 2 * cos(2 * x[2]) + 2 * cos(2 * x[1]) + + cos(2 * x[2]) * cos(2 * x[3])) + + return prim2cons(SVector(rho, v1, v2, v3, p), equations) end initial_condition = initial_condition_taylor_green_vortex volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_hll, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_hll, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-1.0, -1.0, -1.0) .* pi -coordinates_max = ( 1.0, 1.0, 1.0) .* pi +coordinates_max = (1.0, 1.0, 1.0) .* pi trees_per_dimension = (2, 2, 2) -mesh = P4estMesh(trees_per_dimension, polydeg=3, - coordinates_min=coordinates_min, coordinates_max=coordinates_max, - periodicity=(true, true, true), initial_refinement_level=2) - +mesh = P4estMesh(trees_per_dimension, polydeg = 3, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + periodicity = (true, true, true), initial_refinement_level = 2) semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver) @@ -59,24 +62,25 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 50 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=true, - extra_analysis_integrals=(energy_kinetic, - energy_internal, - enstrophy)) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) -alive_callback = AliveCallback(analysis_interval=analysis_interval,) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_integrals = (energy_kinetic, + energy_internal, + enstrophy)) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) +alive_callback = AliveCallback(analysis_interval = analysis_interval) callbacks = CallbackSet(summary_callback, analysis_callback, - alive_callback,save_solution) + alive_callback, save_solution) ############################################################################### # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary diff --git a/examples/paper_self_gravitating_gas_dynamics/elixir_euler_convergence.jl b/examples/paper_self_gravitating_gas_dynamics/elixir_euler_convergence.jl index 316f36adc9b..aabfce0f66b 100644 --- a/examples/paper_self_gravitating_gas_dynamics/elixir_euler_convergence.jl +++ b/examples/paper_self_gravitating_gas_dynamics/elixir_euler_convergence.jl @@ -8,18 +8,16 @@ equations = CompressibleEulerEquations2D(2.0) initial_condition = initial_condition_eoc_test_coupled_euler_gravity -solver = DGSEM(polydeg=3, surface_flux=flux_hll) +solver = DGSEM(polydeg = 3, surface_flux = flux_hll) coordinates_min = (0.0, 0.0) coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=10_000) - + initial_refinement_level = 2, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_eoc_test_euler) - + source_terms = source_terms_eoc_test_euler) ############################################################################### # ODE solvers, callbacks etc. @@ -29,26 +27,25 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) analysis_interval = 100 -alive_callback = AliveCallback(analysis_interval=analysis_interval) -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) callbacks = CallbackSet(summary_callback, stepsize_callback, save_solution, analysis_callback, alive_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); +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/paper_self_gravitating_gas_dynamics/elixir_eulergravity_convergence.jl b/examples/paper_self_gravitating_gas_dynamics/elixir_eulergravity_convergence.jl index f2693c89583..ce1d2cd05bd 100644 --- a/examples/paper_self_gravitating_gas_dynamics/elixir_eulergravity_convergence.jl +++ b/examples/paper_self_gravitating_gas_dynamics/elixir_eulergravity_convergence.jl @@ -2,10 +2,8 @@ using OrdinaryDiffEq using Trixi - initial_condition = initial_condition_eoc_test_coupled_euler_gravity - ############################################################################### # semidiscretization of the compressible Euler equations gamma = 2.0 @@ -17,12 +15,12 @@ solver_euler = DGSEM(polydeg, flux_hll) coordinates_min = (0.0, 0.0) coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=10_000) - -semi_euler = SemidiscretizationHyperbolic(mesh, equations_euler, initial_condition, solver_euler, - source_terms=source_terms_eoc_test_coupled_euler_gravity) + initial_refinement_level = 2, + n_cells_max = 10_000) +semi_euler = SemidiscretizationHyperbolic(mesh, equations_euler, initial_condition, + solver_euler, + source_terms = source_terms_eoc_test_coupled_euler_gravity) ############################################################################### # semidiscretization of the hyperbolic diffusion equations @@ -30,24 +28,23 @@ equations_gravity = HyperbolicDiffusionEquations2D() solver_gravity = DGSEM(polydeg, flux_lax_friedrichs) -semi_gravity = SemidiscretizationHyperbolic(mesh, equations_gravity, initial_condition, solver_gravity, - source_terms=source_terms_harmonic) - +semi_gravity = SemidiscretizationHyperbolic(mesh, equations_gravity, initial_condition, + solver_gravity, + source_terms = source_terms_harmonic) ############################################################################### # combining both semidiscretizations for Euler + self-gravity -parameters = ParametersEulerGravity(background_density=2.0, # aka rho0 +parameters = ParametersEulerGravity(background_density = 2.0, # aka rho0 # rho0 is (ab)used to add a "+8π" term to the source terms # for the manufactured solution - gravitational_constant=1.0, # aka G - cfl=1.1, - resid_tol=1.0e-10, - n_iterations_max=1000, - timestep_gravity=timestep_gravity_erk52_3Sstar!) + gravitational_constant = 1.0, # aka G + cfl = 1.1, + resid_tol = 1.0e-10, + n_iterations_max = 1000, + timestep_gravity = timestep_gravity_erk52_3Sstar!) semi = SemidiscretizationEulerGravity(semi_euler, semi_gravity, parameters) - ############################################################################### # ODE solvers, callbacks etc. tspan = (0.0, 0.5) @@ -55,28 +52,27 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) -save_solution = SaveSolutionCallback(interval=10, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 10, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) analysis_interval = 100 -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -analysis_callback = AnalysisCallback(semi_euler, interval=analysis_interval, - save_analysis=true) +analysis_callback = AnalysisCallback(semi_euler, interval = analysis_interval, + save_analysis = true) callbacks = CallbackSet(summary_callback, stepsize_callback, save_solution, analysis_callback, alive_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); +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 println("Number of gravity subcycles: ", semi.gravity_counter.ncalls_since_readout) diff --git a/examples/paper_self_gravitating_gas_dynamics/elixir_eulergravity_jeans_instability.jl b/examples/paper_self_gravitating_gas_dynamics/elixir_eulergravity_jeans_instability.jl index fb445616cd4..f081f6bb91a 100644 --- a/examples/paper_self_gravitating_gas_dynamics/elixir_eulergravity_jeans_instability.jl +++ b/examples/paper_self_gravitating_gas_dynamics/elixir_eulergravity_jeans_instability.jl @@ -2,7 +2,6 @@ using OrdinaryDiffEq using Trixi - """ initial_condition_jeans_instability(x, t, equations::Union{CompressibleEulerEquations2D, @@ -19,52 +18,51 @@ The classical Jeans instability taken from in CGS (centimeter, gram, second) units. """ function initial_condition_jeans_instability(x, t, - equations::CompressibleEulerEquations2D) - # Jeans gravitational instability test case - # see Derigs et al. https://arxiv.org/abs/1605.03572; Sec. 4.6 - # OBS! this uses cgs (centimeter, gram, second) units - # periodic boundaries - # domain size [0,L]^2 depends on the wave number chosen for the perturbation - # OBS! Be very careful here L must be chosen such that problem is periodic - # typical final time is T = 5 - # gamma = 5/3 - dens0 = 1.5e7 # g/cm^3 - pres0 = 1.5e7 # dyn/cm^2 - delta0 = 1e-3 - # set wave vector values for perturbation (units 1/cm) - # see FLASH manual: https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node189.html#SECTION010131000000000000000 - kx = 2.0*pi/0.5 # 2π/λ_x, λ_x = 0.5 - ky = 0.0 # 2π/λ_y, λ_y = 1e10 - k_dot_x = kx*x[1] + ky*x[2] - # perturb density and pressure away from reference states ρ_0 and p_0 - dens = dens0*(1.0 + delta0*cos(k_dot_x)) # g/cm^3 - pres = pres0*(1.0 + equations.gamma*delta0*cos(k_dot_x)) # dyn/cm^2 - # flow starts as stationary - velx = 0.0 # cm/s - vely = 0.0 # cm/s - return prim2cons((dens, velx, vely, pres), equations) + equations::CompressibleEulerEquations2D) + # Jeans gravitational instability test case + # see Derigs et al. https://arxiv.org/abs/1605.03572; Sec. 4.6 + # OBS! this uses cgs (centimeter, gram, second) units + # periodic boundaries + # domain size [0,L]^2 depends on the wave number chosen for the perturbation + # OBS! Be very careful here L must be chosen such that problem is periodic + # typical final time is T = 5 + # gamma = 5/3 + dens0 = 1.5e7 # g/cm^3 + pres0 = 1.5e7 # dyn/cm^2 + delta0 = 1e-3 + # set wave vector values for perturbation (units 1/cm) + # see FLASH manual: https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node189.html#SECTION010131000000000000000 + kx = 2.0 * pi / 0.5 # 2π/λ_x, λ_x = 0.5 + ky = 0.0 # 2π/λ_y, λ_y = 1e10 + k_dot_x = kx * x[1] + ky * x[2] + # perturb density and pressure away from reference states ρ_0 and p_0 + dens = dens0 * (1.0 + delta0 * cos(k_dot_x)) # g/cm^3 + pres = pres0 * (1.0 + equations.gamma * delta0 * cos(k_dot_x)) # dyn/cm^2 + # flow starts as stationary + velx = 0.0 # cm/s + vely = 0.0 # cm/s + return prim2cons((dens, velx, vely, pres), equations) end function initial_condition_jeans_instability(x, t, equations::HyperbolicDiffusionEquations2D) - # gravity equation: -Δϕ = -4πGρ - # Constants taken from the FLASH manual - # https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node189.html#SECTION010131000000000000000 - rho0 = 1.5e7 - delta0 = 1e-3 - - phi = rho0*delta0 # constant background perturbation magnitude - q1 = 0.0 - q2 = 0.0 - return (phi, q1, q2) + # gravity equation: -Δϕ = -4πGρ + # Constants taken from the FLASH manual + # https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node189.html#SECTION010131000000000000000 + rho0 = 1.5e7 + delta0 = 1e-3 + + phi = rho0 * delta0 # constant background perturbation magnitude + q1 = 0.0 + q2 = 0.0 + return (phi, q1, q2) end initial_condition = initial_condition_jeans_instability - ############################################################################### # semidiscretization of the compressible Euler equations -gamma = 5/3 +gamma = 5 / 3 equations_euler = CompressibleEulerEquations2D(gamma) polydeg = 3 @@ -73,11 +71,11 @@ solver_euler = DGSEM(polydeg, flux_hll) coordinates_min = (0.0, 0.0) coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - -semi_euler = SemidiscretizationHyperbolic(mesh, equations_euler, initial_condition, solver_euler) + initial_refinement_level = 4, + n_cells_max = 10_000) +semi_euler = SemidiscretizationHyperbolic(mesh, equations_euler, initial_condition, + solver_euler) ############################################################################### # semidiscretization of the hyperbolic diffusion equations @@ -85,22 +83,21 @@ equations_gravity = HyperbolicDiffusionEquations2D() solver_gravity = DGSEM(polydeg, flux_lax_friedrichs) -semi_gravity = SemidiscretizationHyperbolic(mesh, equations_gravity, initial_condition, solver_gravity, - source_terms=source_terms_harmonic) - +semi_gravity = SemidiscretizationHyperbolic(mesh, equations_gravity, initial_condition, + solver_gravity, + source_terms = source_terms_harmonic) ############################################################################### # combining both semidiscretizations for Euler + self-gravity -parameters = ParametersEulerGravity(background_density=1.5e7, # aka rho0 - gravitational_constant=6.674e-8, # aka G - cfl=1.6, - resid_tol=1.0e-4, - n_iterations_max=1000, - timestep_gravity=timestep_gravity_carpenter_kennedy_erk54_2N!) +parameters = ParametersEulerGravity(background_density = 1.5e7, # aka rho0 + gravitational_constant = 6.674e-8, # aka G + cfl = 1.6, + resid_tol = 1.0e-4, + n_iterations_max = 1000, + timestep_gravity = timestep_gravity_carpenter_kennedy_erk54_2N!) semi = SemidiscretizationEulerGravity(semi_euler, semi_gravity, parameters) - ############################################################################### # ODE solvers, callbacks etc. tspan = (0.0, 5.0) @@ -108,51 +105,58 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) -save_solution = SaveSolutionCallback(interval=10, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 10, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) analysis_interval = 100 -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) Trixi.pretty_form_utf(::Val{:energy_potential}) = "∑e_potential" Trixi.pretty_form_ascii(::Val{:energy_potential}) = "e_potential" -function Trixi.analyze(::Val{:energy_potential}, du, u_euler, t, semi::SemidiscretizationEulerGravity) - - u_gravity = Trixi.wrap_array(semi.cache.u_ode, semi.semi_gravity) - - mesh, equations_euler, dg, cache = Trixi.mesh_equations_solver_cache(semi.semi_euler) - _, equations_gravity, _, _ = Trixi.mesh_equations_solver_cache(semi.semi_gravity) - - e_potential = Trixi.integrate_via_indices(u_euler, mesh, equations_euler, dg, cache, equations_gravity, u_gravity) do u, i, j, element, equations_euler, dg, equations_gravity, u_gravity - u_euler_local = Trixi.get_node_vars(u_euler, equations_euler, dg, i, j, element) - u_gravity_local = Trixi.get_node_vars(u_gravity, equations_gravity, dg, i, j, element) - # OBS! subtraction is specific to Jeans instability test where rho0 = 1.5e7 - return (u_euler_local[1] - 1.5e7) * u_gravity_local[1] - end - return e_potential +function Trixi.analyze(::Val{:energy_potential}, du, u_euler, t, + semi::SemidiscretizationEulerGravity) + u_gravity = Trixi.wrap_array(semi.cache.u_ode, semi.semi_gravity) + + mesh, equations_euler, dg, cache = Trixi.mesh_equations_solver_cache(semi.semi_euler) + _, equations_gravity, _, _ = Trixi.mesh_equations_solver_cache(semi.semi_gravity) + + e_potential = Trixi.integrate_via_indices(u_euler, mesh, equations_euler, dg, cache, + equations_gravity, + u_gravity) do u, i, j, element, + equations_euler, dg, + equations_gravity, u_gravity + u_euler_local = Trixi.get_node_vars(u_euler, equations_euler, dg, i, j, element) + u_gravity_local = Trixi.get_node_vars(u_gravity, equations_gravity, dg, i, j, + element) + # OBS! subtraction is specific to Jeans instability test where rho0 = 1.5e7 + return (u_euler_local[1] - 1.5e7) * u_gravity_local[1] + end + return e_potential end -analysis_callback = AnalysisCallback(semi_euler, interval=analysis_interval, - save_analysis=true, - extra_analysis_integrals=(energy_total, energy_kinetic, energy_internal, Val(:energy_potential))) +analysis_callback = AnalysisCallback(semi_euler, interval = analysis_interval, + save_analysis = true, + extra_analysis_integrals = (energy_total, + energy_kinetic, + energy_internal, + Val(:energy_potential))) callbacks = CallbackSet(summary_callback, stepsize_callback, save_restart, save_solution, analysis_callback, alive_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); +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 println("Number of gravity subcycles: ", semi.gravity_counter.ncalls_since_readout) diff --git a/examples/paper_self_gravitating_gas_dynamics/elixir_eulergravity_sedov_blast_wave.jl b/examples/paper_self_gravitating_gas_dynamics/elixir_eulergravity_sedov_blast_wave.jl index 8933224a2c7..b7be2320228 100644 --- a/examples/paper_self_gravitating_gas_dynamics/elixir_eulergravity_sedov_blast_wave.jl +++ b/examples/paper_self_gravitating_gas_dynamics/elixir_eulergravity_sedov_blast_wave.jl @@ -19,33 +19,33 @@ based on Should be used together with [`boundary_condition_sedov_self_gravity`](@ref). """ function initial_condition_sedov_self_gravity(x, t, equations::CompressibleEulerEquations2D) - # Set up polar coordinates - r = sqrt(x[1]^2 + x[2]^2) - - # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114100000000000000 - r0 = 0.125 # = 4.0 * smallest dx (for domain length=8 and max-ref=8) - E = 1.0 - p_inner = (equations.gamma - 1) * E / (pi * r0^2) - p_ambient = 1e-5 # = true Sedov setup - - # Calculate primitive variables - # use a logistic function to transfer density value smoothly - L = 1.0 # maximum of function - x0 = 1.0 # center point of function - k = -150.0 # sharpness of transfer - logistic_function_rho = L/(1.0 + exp(-k*(r - x0))) - rho_ambient = 1e-5 - rho = max(logistic_function_rho, rho_ambient) # clip background density to not be so tiny - - # velocities are zero - v1 = 0.0 - v2 = 0.0 - - # use a logistic function to transfer pressure value smoothly - logistic_function_p = p_inner/(1.0 + exp(-k*(r - r0))) - p = max(logistic_function_p, p_ambient) - - return prim2cons(SVector(rho, v1, v2, p), equations) + # Set up polar coordinates + r = sqrt(x[1]^2 + x[2]^2) + + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114100000000000000 + r0 = 0.125 # = 4.0 * smallest dx (for domain length=8 and max-ref=8) + E = 1.0 + p_inner = (equations.gamma - 1) * E / (pi * r0^2) + p_ambient = 1e-5 # = true Sedov setup + + # Calculate primitive variables + # use a logistic function to transfer density value smoothly + L = 1.0 # maximum of function + x0 = 1.0 # center point of function + k = -150.0 # sharpness of transfer + logistic_function_rho = L / (1.0 + exp(-k * (r - x0))) + rho_ambient = 1e-5 + rho = max(logistic_function_rho, rho_ambient) # clip background density to not be so tiny + + # velocities are zero + v1 = 0.0 + v2 = 0.0 + + # use a logistic function to transfer pressure value smoothly + logistic_function_p = p_inner / (1.0 + exp(-k * (r - r0))) + p = max(logistic_function_p, p_ambient) + + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_sedov_self_gravity @@ -65,50 +65,50 @@ Should be used together with [`initial_condition_sedov_self_gravity`](@ref). function boundary_condition_sedov_self_gravity(u_inner, orientation, direction, x, t, surface_flux_function, equations::CompressibleEulerEquations2D) - # velocities are zero, density/pressure are ambient values according to - # initial_condition_sedov_self_gravity - rho = 1e-5 - v1 = 0.0 - v2 = 0.0 - p = 1e-5 - - u_boundary = prim2cons(SVector(rho, v1, v2, p), equations) - - # Calculate boundary flux - if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary - flux = surface_flux_function(u_inner, u_boundary, orientation, equations) - else # u_boundary is "left" of boundary, u_inner is "right" of boundary - flux = surface_flux_function(u_boundary, u_inner, orientation, equations) - end - - return flux + # velocities are zero, density/pressure are ambient values according to + # initial_condition_sedov_self_gravity + rho = 1e-5 + v1 = 0.0 + v2 = 0.0 + p = 1e-5 + + u_boundary = prim2cons(SVector(rho, v1, v2, p), equations) + + # Calculate boundary flux + if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary + flux = surface_flux_function(u_inner, u_boundary, orientation, equations) + else # u_boundary is "left" of boundary, u_inner is "right" of boundary + flux = surface_flux_function(u_boundary, u_inner, orientation, equations) + end + + return flux end boundary_conditions = boundary_condition_sedov_self_gravity surface_flux = flux_hll -volume_flux = flux_chandrashekar +volume_flux = flux_chandrashekar polydeg = 3 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations_euler, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver_euler = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-4, -4) -coordinates_max = ( 4, 4) +coordinates_max = (4, 4) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=100_000, - periodicity=false) - -semi_euler = SemidiscretizationHyperbolic(mesh, equations_euler, initial_condition, solver_euler, - boundary_conditions=boundary_conditions) + initial_refinement_level = 2, + n_cells_max = 100_000, + periodicity = false) +semi_euler = SemidiscretizationHyperbolic(mesh, equations_euler, initial_condition, + solver_euler, + boundary_conditions = boundary_conditions) ############################################################################### # semidiscretization of the hyperbolic diffusion equations @@ -125,12 +125,13 @@ based on - https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114100000000000000 Should be used together with [`boundary_condition_sedov_self_gravity`](@ref). """ -function initial_condition_sedov_self_gravity(x, t, equations::HyperbolicDiffusionEquations2D) - # for now just use constant initial condition for sedov blast wave (can likely be improved) - phi = 0.0 - q1 = 0.0 - q2 = 0.0 - return SVector(phi, q1, q2) +function initial_condition_sedov_self_gravity(x, t, + equations::HyperbolicDiffusionEquations2D) + # for now just use constant initial condition for sedov blast wave (can likely be improved) + phi = 0.0 + q1 = 0.0 + q2 = 0.0 + return SVector(phi, q1, q2) end """ @@ -147,39 +148,38 @@ based on Should be used together with [`initial_condition_sedov_self_gravity`](@ref). """ function boundary_condition_sedov_self_gravity(u_inner, orientation, direction, x, t, - surface_flux_function, - equations::HyperbolicDiffusionEquations2D) - u_boundary = initial_condition_sedov_self_gravity(x, t, equations) - - # Calculate boundary flux - if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary - flux = surface_flux_function(u_inner, u_boundary, orientation, equations) - else # u_boundary is "left" of boundary, u_inner is "right" of boundary - flux = surface_flux_function(u_boundary, u_inner, orientation, equations) - end - - return flux + surface_flux_function, + equations::HyperbolicDiffusionEquations2D) + u_boundary = initial_condition_sedov_self_gravity(x, t, equations) + + # Calculate boundary flux + if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary + flux = surface_flux_function(u_inner, u_boundary, orientation, equations) + else # u_boundary is "left" of boundary, u_inner is "right" of boundary + flux = surface_flux_function(u_boundary, u_inner, orientation, equations) + end + + return flux end solver_gravity = DGSEM(polydeg, flux_lax_friedrichs) -semi_gravity = SemidiscretizationHyperbolic(mesh, equations_gravity, initial_condition, solver_gravity, - boundary_conditions=boundary_conditions, - source_terms=source_terms_harmonic) - +semi_gravity = SemidiscretizationHyperbolic(mesh, equations_gravity, initial_condition, + solver_gravity, + boundary_conditions = boundary_conditions, + source_terms = source_terms_harmonic) ############################################################################### # combining both semidiscretizations for Euler + self-gravity -parameters = ParametersEulerGravity(background_density=0.0, # aka rho0 - gravitational_constant=6.674e-8, # aka G - cfl=2.4, - resid_tol=1.0e-4, - n_iterations_max=100, - timestep_gravity=timestep_gravity_erk52_3Sstar!) +parameters = ParametersEulerGravity(background_density = 0.0, # aka rho0 + gravitational_constant = 6.674e-8, # aka G + cfl = 2.4, + resid_tol = 1.0e-4, + n_iterations_max = 100, + timestep_gravity = timestep_gravity_erk52_3Sstar!) semi = SemidiscretizationEulerGravity(semi_euler, semi_gravity, parameters) - ############################################################################### # ODE solvers, callbacks etc. tspan = (0.0, 1.0) @@ -188,41 +188,42 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=1.0, - alpha_min=0.0, - alpha_smooth=false, - variable=density_pressure) + alpha_max = 1.0, + alpha_min = 0.0, + alpha_smooth = false, + variable = density_pressure) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=2, - max_level =8, max_threshold=0.0003) + base_level = 2, + max_level = 8, max_threshold = 0.0003) amr_callback = AMRCallback(semi, amr_controller, - interval=1, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 1, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) analysis_interval = 100 -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -analysis_callback = AnalysisCallback(semi_euler, interval=analysis_interval, - save_analysis=true, - extra_analysis_integrals=(energy_total, energy_kinetic, energy_internal)) +analysis_callback = AnalysisCallback(semi_euler, interval = analysis_interval, + save_analysis = true, + extra_analysis_integrals = (energy_total, + energy_kinetic, + energy_internal)) callbacks = CallbackSet(summary_callback, amr_callback, stepsize_callback, save_solution, analysis_callback, alive_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); +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 println("Number of gravity subcycles: ", semi.gravity_counter.ncalls_since_readout) diff --git a/examples/paper_self_gravitating_gas_dynamics/elixir_hypdiff_convergence.jl b/examples/paper_self_gravitating_gas_dynamics/elixir_hypdiff_convergence.jl index 029c19380cf..df6e4e6349f 100644 --- a/examples/paper_self_gravitating_gas_dynamics/elixir_hypdiff_convergence.jl +++ b/examples/paper_self_gravitating_gas_dynamics/elixir_hypdiff_convergence.jl @@ -9,10 +9,10 @@ equations = HyperbolicDiffusionEquations2D() initial_condition = initial_condition_poisson_nonperiodic # 1 => -x, 2 => +x, 3 => -y, 4 => +y as usual for orientations -boundary_conditions = (x_neg=boundary_condition_poisson_nonperiodic, - x_pos=boundary_condition_poisson_nonperiodic, - y_neg=boundary_condition_periodic, - y_pos=boundary_condition_periodic) +boundary_conditions = (x_neg = boundary_condition_poisson_nonperiodic, + x_pos = boundary_condition_poisson_nonperiodic, + y_neg = boundary_condition_periodic, + y_pos = boundary_condition_periodic) polydeg = 3 surface_flux = flux_lax_friedrichs @@ -21,15 +21,13 @@ solver = DGSEM(polydeg, surface_flux) coordinates_min = (0.0, 0.0) coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=30_000, - periodicity=(false, true)) - + initial_refinement_level = 2, + n_cells_max = 30_000, + periodicity = (false, true)) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_poisson_nonperiodic, - boundary_conditions=boundary_conditions) - + source_terms = source_terms_poisson_nonperiodic, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -40,29 +38,28 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() resid_tol = 1.0e-10 -steady_state_callback = SteadyStateCallback(abstol=resid_tol, reltol=0.0) +steady_state_callback = SteadyStateCallback(abstol = resid_tol, reltol = 0.0) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) analysis_interval = 500 -alive_callback = AliveCallback(analysis_interval=analysis_interval) -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy, energy_total)) +alive_callback = AliveCallback(analysis_interval = analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy, energy_total)) callbacks = CallbackSet(summary_callback, steady_state_callback, stepsize_callback, save_solution, analysis_callback, alive_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); +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/special_elixirs/elixir_euler_ad.jl b/examples/special_elixirs/elixir_euler_ad.jl index 48fd37cc9d4..3aa44f9a773 100644 --- a/examples/special_elixirs/elixir_euler_ad.jl +++ b/examples/special_elixirs/elixir_euler_ad.jl @@ -6,10 +6,10 @@ using Trixi, LinearAlgebra, ForwardDiff equations = CompressibleEulerEquations2D(1.4) mesh = TreeMesh((-1.0, -1.0), (1.0, 1.0), - initial_refinement_level=2, n_cells_max=10^5) + initial_refinement_level = 2, n_cells_max = 10^5) -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs, - volume_integral=VolumeIntegralFluxDifferencing(flux_ranocha)) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralFluxDifferencing(flux_ranocha)) """ initial_condition_isentropic_vortex(x, t, equations::CompressibleEulerEquations2D) @@ -21,43 +21,45 @@ The classical isentropic vortex test case of [NASA/CR-97-206253](https://ntrs.nasa.gov/citations/19980007543) """ function initial_condition_isentropic_vortex(x, t, equations::CompressibleEulerEquations2D) - # needs appropriate mesh size, e.g. [-10,-10]x[10,10] - # for error convergence: make sure that the end time is such that the vortex is back at the initial state!! - # for the current velocity and domain size: t_end should be a multiple of 20s - # initial center of the vortex - inicenter = SVector(0.0, 0.0) - # size and strength of the vortex - iniamplitude = 5.0 - # base flow - rho = 1.0 - v1 = 1.0 - v2 = 1.0 - vel = SVector(v1, v2) - p = 25.0 - rt = p / rho # ideal gas equation - t_loc = 0.0 - cent = inicenter + vel*t_loc # advection of center - # ATTENTION: handle periodic BC, but only for v1 = v2 = 1.0 (!!!!) - cent = x - cent # distance to center point - # cent = cross(iniaxis, cent) # distance to axis, tangent vector, length r - # cross product with iniaxis = [0, 0, 1] - cent = SVector(-cent[2], cent[1]) - r2 = cent[1]^2 + cent[2]^2 - du = iniamplitude / (2*π) * exp(0.5 * (1 - r2)) # vel. perturbation - dtemp = -(equations.gamma - 1) / (2 * equations.gamma * rt) * du^2 # isentropic - rho = rho * (1 + dtemp)^(1 / (equations.gamma - 1)) - vel = vel + du * cent - v1, v2 = vel - p = p * (1 + dtemp)^(equations.gamma / (equations.gamma - 1)) - prim = SVector(rho, v1, v2, p) - return prim2cons(prim, equations) + # needs appropriate mesh size, e.g. [-10,-10]x[10,10] + # for error convergence: make sure that the end time is such that the vortex is back at the initial state!! + # for the current velocity and domain size: t_end should be a multiple of 20s + # initial center of the vortex + inicenter = SVector(0.0, 0.0) + # size and strength of the vortex + iniamplitude = 5.0 + # base flow + rho = 1.0 + v1 = 1.0 + v2 = 1.0 + vel = SVector(v1, v2) + p = 25.0 + rt = p / rho # ideal gas equation + t_loc = 0.0 + cent = inicenter + vel * t_loc # advection of center + # ATTENTION: handle periodic BC, but only for v1 = v2 = 1.0 (!!!!) + cent = x - cent # distance to center point + # cent = cross(iniaxis, cent) # distance to axis, tangent vector, length r + # cross product with iniaxis = [0, 0, 1] + cent = SVector(-cent[2], cent[1]) + r2 = cent[1]^2 + cent[2]^2 + du = iniamplitude / (2 * π) * exp(0.5 * (1 - r2)) # vel. perturbation + dtemp = -(equations.gamma - 1) / (2 * equations.gamma * rt) * du^2 # isentropic + rho = rho * (1 + dtemp)^(1 / (equations.gamma - 1)) + vel = vel + du * cent + v1, v2 = vel + p = p * (1 + dtemp)^(equations.gamma / (equations.gamma - 1)) + prim = SVector(rho, v1, v2, p) + return prim2cons(prim, equations) end -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_isentropic_vortex, solver) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_isentropic_vortex, + solver) u0_ode = compute_coefficients(0.0, semi) J = ForwardDiff.jacobian((du_ode, γ) -> begin - equations_inner = CompressibleEulerEquations2D(first(γ)) - semi_inner = Trixi.remake(semi, equations=equations_inner, uEltype=eltype(γ)) - Trixi.rhs!(du_ode, u0_ode, semi_inner, 0.0) - end, similar(u0_ode), [1.4]); # γ needs to be an `AbstractArray` + equations_inner = CompressibleEulerEquations2D(first(γ)) + semi_inner = Trixi.remake(semi, equations = equations_inner, + uEltype = eltype(γ)) + Trixi.rhs!(du_ode, u0_ode, semi_inner, 0.0) + end, similar(u0_ode), [1.4]); # γ needs to be an `AbstractArray` diff --git a/examples/structured_1d_dgsem/elixir_advection_basic.jl b/examples/structured_1d_dgsem/elixir_advection_basic.jl index 82464f23964..cdabeb4c61a 100644 --- a/examples/structured_1d_dgsem/elixir_advection_basic.jl +++ b/examples/structured_1d_dgsem/elixir_advection_basic.jl @@ -11,7 +11,7 @@ advection_velocity = 1.0 equations = LinearScalarAdvectionEquation1D(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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0,) # minimum coordinate coordinates_max = (1.0,) # maximum coordinate @@ -21,8 +21,8 @@ cells_per_dimension = (16,) 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) - +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, + solver) ############################################################################### # ODE solvers, callbacks etc. @@ -35,26 +35,26 @@ ode = semidiscretize(semi, (0.0, 1.0)); summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +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.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) # 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) - +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/structured_1d_dgsem/elixir_advection_nonperiodic.jl b/examples/structured_1d_dgsem/elixir_advection_nonperiodic.jl index e87e0b36b0a..1e0c579ffcf 100644 --- a/examples/structured_1d_dgsem/elixir_advection_nonperiodic.jl +++ b/examples/structured_1d_dgsem/elixir_advection_nonperiodic.jl @@ -11,18 +11,16 @@ equations = LinearScalarAdvectionEquation1D(advection_velocity) initial_condition = initial_condition_gauss boundary_conditions = BoundaryConditionDirichlet(initial_condition) -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0,) coordinates_max = (5.0,) -mesh = StructuredMesh((16,), coordinates_min, coordinates_max, periodicity=false) - +mesh = StructuredMesh((16,), coordinates_min, coordinates_max, periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -33,31 +31,30 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_restart, save_solution, stepsize_callback); - ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=stepsize_callback(ode), # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = stepsize_callback(ode), # 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_1d_dgsem/elixir_advection_shockcapturing.jl b/examples/structured_1d_dgsem/elixir_advection_shockcapturing.jl index 313812fe08d..96566bc2373 100644 --- a/examples/structured_1d_dgsem/elixir_advection_shockcapturing.jl +++ b/examples/structured_1d_dgsem/elixir_advection_shockcapturing.jl @@ -17,30 +17,30 @@ Slight simplification from [DOI: 10.1006/jcph.1996.0130](https://doi.org/10.1006/jcph.1996.0130) """ function initial_condition_composite(x, t, equations::LinearScalarAdvectionEquation1D) - xmin, xmax = -1.0, 1.0 # Only works if the domain is [-1.0,1.0] - x_trans = x[1] - t - L = xmax - xmin - if x_trans > xmax - x_ = x_trans - L * floor((x_trans + xmin) / L) - elseif x_trans < xmin - x_ = x_trans + L * floor((xmax - x_trans) / L) - else - x_ = x_trans - end - - if x_ > -0.8 && x_ < -0.6 - value = exp(-log(2.0) * (x_ + 0.7)^2 / 0.0009) - elseif x_ > -0.4 && x_ < -0.2 - value = 1.0 - elseif x_ > 0.0 && x_ < 0.2 - value = 1.0 - abs(10.0 * (x_ - 0.1)) - elseif x_ > 0.4 && x_ < 0.6 - value = sqrt(1.0 - 100.0 * (x_ - 0.5)^2) - else - value = 0.0 - end - - return SVector(value) + xmin, xmax = -1.0, 1.0 # Only works if the domain is [-1.0,1.0] + x_trans = x[1] - t + L = xmax - xmin + if x_trans > xmax + x_ = x_trans - L * floor((x_trans + xmin) / L) + elseif x_trans < xmin + x_ = x_trans + L * floor((xmax - x_trans) / L) + else + x_ = x_trans + end + + if x_ > -0.8 && x_ < -0.6 + value = exp(-log(2.0) * (x_ + 0.7)^2 / 0.0009) + elseif x_ > -0.4 && x_ < -0.2 + value = 1.0 + elseif x_ > 0.0 && x_ < 0.2 + value = 1.0 - abs(10.0 * (x_ - 0.1)) + elseif x_ > 0.4 && x_ < 0.6 + value = sqrt(1.0 - 100.0 * (x_ - 0.5)^2) + else + value = 0.0 + end + + return SVector(value) end initial_condition = initial_condition_composite @@ -52,13 +52,13 @@ volume_flux = flux_central polydeg = 3 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=Trixi.first) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = Trixi.first) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) # Create curved mesh @@ -66,12 +66,11 @@ cells_per_dimension = (120,) coordinates_min = (-1.0,) # minimum coordinate coordinates_max = (1.0,) # maximum coordinate mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, - periodicity=true) + periodicity = true) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -84,23 +83,23 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +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=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) # 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) - +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.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 \ No newline at end of file +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/structured_1d_dgsem/elixir_euler_sedov.jl b/examples/structured_1d_dgsem/elixir_euler_sedov.jl index 9d7be21a5c1..4ffa100cc71 100644 --- a/examples/structured_1d_dgsem/elixir_euler_sedov.jl +++ b/examples/structured_1d_dgsem/elixir_euler_sedov.jl @@ -14,50 +14,50 @@ The Sedov blast wave setup based on Flash - https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations1D) - # Set up polar coordinates - inicenter = SVector(0.0) - x_norm = x[1] - inicenter[1] - r = abs(x_norm) - - # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 - r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) - # r0 = 0.5 # = more reasonable setup - E = 1.0 - p0_inner = 6 * (equations.gamma - 1) * E / (3 * pi * r0) - p0_outer = 1.0e-5 # = true Sedov setup - - # Calculate primitive variables - rho = 1.0 - v1 = 0.0 - p = r > r0 ? p0_outer : p0_inner - - return prim2cons(SVector(rho, v1, p), equations) + # Set up polar coordinates + inicenter = SVector(0.0) + x_norm = x[1] - inicenter[1] + r = abs(x_norm) + + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 + r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) + # r0 = 0.5 # = more reasonable setup + E = 1.0 + p0_inner = 6 * (equations.gamma - 1) * E / (3 * pi * r0) + p0_outer = 1.0e-5 # = true Sedov setup + + # Calculate primitive variables + rho = 1.0 + v1 = 0.0 + p = r > r0 ? p0_outer : p0_inner + + return prim2cons(SVector(rho, v1, p), equations) end initial_condition = initial_condition_sedov_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_ranocha +volume_flux = flux_ranocha basis = LobattoLegendreBasis(3) shock_indicator_variable = density_pressure indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=1.0, - alpha_min=0.001, - alpha_smooth=true, - variable=shock_indicator_variable) + alpha_max = 1.0, + alpha_min = 0.001, + alpha_smooth = true, + variable = shock_indicator_variable) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) cells_per_dimension = (64,) coordinates_min = (-2.0,) -coordinates_max = ( 2.0,) -mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity=true) +coordinates_max = (2.0,) +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, + periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -67,16 +67,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -84,11 +84,10 @@ callbacks = CallbackSet(summary_callback, save_solution, stepsize_callback) - ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=stepsize_callback(ode), # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = stepsize_callback(ode), # 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_1d_dgsem/elixir_euler_source_terms.jl b/examples/structured_1d_dgsem/elixir_euler_source_terms.jl index cbda7087052..97767f3e127 100644 --- a/examples/structured_1d_dgsem/elixir_euler_source_terms.jl +++ b/examples/structured_1d_dgsem/elixir_euler_source_terms.jl @@ -13,7 +13,7 @@ initial_condition = initial_condition_convergence_test # Note that the expected EOC of 5 is not reached with this flux. # Using flux_hll instead yields the expected EOC. -solver = DGSEM(polydeg=4, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 4, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0,) coordinates_max = (2.0,) @@ -21,10 +21,8 @@ cells_per_dimension = (16,) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) - semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -35,29 +33,28 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_errors=(:l2_error_primitive, - :linf_error_primitive)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:l2_error_primitive, + :linf_error_primitive)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/structured_1d_dgsem/elixir_euler_source_terms_nonperiodic.jl b/examples/structured_1d_dgsem/elixir_euler_source_terms_nonperiodic.jl index 9aa5b7f4979..d5063838136 100644 --- a/examples/structured_1d_dgsem/elixir_euler_source_terms_nonperiodic.jl +++ b/examples/structured_1d_dgsem/elixir_euler_source_terms_nonperiodic.jl @@ -15,20 +15,18 @@ source_terms = source_terms_convergence_test # 1*ndims == 2 directions or you can pass a tuple containing BCs for # each direction boundary_condition = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = (x_neg=boundary_condition, - x_pos=boundary_condition) +boundary_conditions = (x_neg = boundary_condition, + x_pos = boundary_condition) -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) f1() = SVector(0.0) f2() = SVector(2.0) -mesh = StructuredMesh((16,), (f1, f2), periodicity=false) - +mesh = StructuredMesh((16,), (f1, f2), periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms, - boundary_conditions=boundary_conditions) - + source_terms = source_terms, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -39,30 +37,29 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_restart, save_solution, 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); +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/structured_2d_dgsem/elixir_advection_basic.jl b/examples/structured_2d_dgsem/elixir_advection_basic.jl index 7d2e1f49276..1d7235fc214 100644 --- a/examples/structured_2d_dgsem/elixir_advection_basic.jl +++ b/examples/structured_2d_dgsem/elixir_advection_basic.jl @@ -11,10 +11,10 @@ advection_velocity = (0.2, -0.7) 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) -coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) +coordinates_max = (1.0, 1.0) # maximum coordinates (max(x), max(y)) cells_per_dimension = (16, 16) @@ -22,8 +22,8 @@ cells_per_dimension = (16, 16) 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) - +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, + solver) ############################################################################### # ODE solvers, callbacks etc. @@ -36,26 +36,26 @@ ode = semidiscretize(semi, (0.0, 1.0)); summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +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.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) # 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) - +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/structured_2d_dgsem/elixir_advection_coupled.jl b/examples/structured_2d_dgsem/elixir_advection_coupled.jl index 1e54e411db6..2a56d23f4c0 100644 --- a/examples/structured_2d_dgsem/elixir_advection_coupled.jl +++ b/examples/structured_2d_dgsem/elixir_advection_coupled.jl @@ -1,7 +1,6 @@ using OrdinaryDiffEq using Trixi - ############################################################################### # Coupled semidiscretization of two linear advection systems, which are connected periodically # @@ -35,11 +34,11 @@ advection_velocity = (0.2, -0.7) 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) # First mesh is the left half of a [-1,1]^2 square coordinates_min1 = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) -coordinates_max1 = ( 0.0, 1.0) # maximum coordinates (max(x), max(y)) +coordinates_max1 = (0.0, 1.0) # maximum coordinates (max(x), max(y)) # Define identical resolution as a variable such that it is easier to change from `trixi_include` cells_per_dimension = (8, 16) @@ -49,32 +48,45 @@ cells_per_dimension1 = cells_per_dimension mesh1 = StructuredMesh(cells_per_dimension1, coordinates_min1, coordinates_max1) # A semidiscretization collects data structures and functions for the spatial discretization -semi1 = SemidiscretizationHyperbolic(mesh1, equations, initial_condition_convergence_test, solver, - boundary_conditions=( - # Connect left boundary with right boundary of right mesh - x_neg=BoundaryConditionCoupled(2, (:end, :i_forward), Float64), - # Connect right boundary with left boundary of right mesh - x_pos=BoundaryConditionCoupled(2, (:begin, :i_forward), Float64), - y_neg=boundary_condition_periodic, - y_pos=boundary_condition_periodic)) - +semi1 = SemidiscretizationHyperbolic(mesh1, equations, initial_condition_convergence_test, + solver, + boundary_conditions = ( + # Connect left boundary with right boundary of right mesh + x_neg = BoundaryConditionCoupled(2, + (:end, + :i_forward), + Float64), + # Connect right boundary with left boundary of right mesh + x_pos = BoundaryConditionCoupled(2, + (:begin, + :i_forward), + Float64), + y_neg = boundary_condition_periodic, + y_pos = boundary_condition_periodic)) # Second mesh is the right half of a [-1,1]^2 square coordinates_min2 = (0.0, -1.0) # minimum coordinates (min(x), min(y)) -coordinates_max2 = (1.0, 1.0) # maximum coordinates (max(x), max(y)) +coordinates_max2 = (1.0, 1.0) # maximum coordinates (max(x), max(y)) cells_per_dimension2 = cells_per_dimension mesh2 = StructuredMesh(cells_per_dimension2, coordinates_min2, coordinates_max2) -semi2 = SemidiscretizationHyperbolic(mesh2, equations, initial_condition_convergence_test, solver, - boundary_conditions=( - # Connect left boundary with right boundary of left mesh - x_neg=BoundaryConditionCoupled(1, (:end, :i_forward), Float64), - # Connect right boundary with left boundary of left mesh - x_pos=BoundaryConditionCoupled(1, (:begin, :i_forward), Float64), - y_neg=boundary_condition_periodic, - y_pos=boundary_condition_periodic)) +semi2 = SemidiscretizationHyperbolic(mesh2, equations, initial_condition_convergence_test, + solver, + boundary_conditions = ( + # Connect left boundary with right boundary of left mesh + x_neg = BoundaryConditionCoupled(1, + (:end, + :i_forward), + Float64), + # Connect right boundary with left boundary of left mesh + x_pos = BoundaryConditionCoupled(1, + (:begin, + :i_forward), + Float64), + y_neg = boundary_condition_periodic, + y_pos = boundary_condition_periodic)) # Create a semidiscretization that bundles semi1 and semi2 semi = SemidiscretizationCoupled(semi1, semi2) @@ -90,28 +102,28 @@ ode = semidiscretize(semi, (0.0, 2.0)); summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback1 = AnalysisCallback(semi1, interval=100) -analysis_callback2 = AnalysisCallback(semi2, interval=100) +analysis_callback1 = AnalysisCallback(semi1, interval = 100) +analysis_callback2 = AnalysisCallback(semi2, interval = 100) analysis_callback = AnalysisCallbackCoupled(semi, analysis_callback1, analysis_callback2) # The SaveSolutionCallback allows to save the solution to a file in regular intervals -save_solution = SaveSolutionCallback(interval=100, - solution_variables=cons2prim) +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.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) # 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) - +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/structured_2d_dgsem/elixir_advection_extended.jl b/examples/structured_2d_dgsem/elixir_advection_extended.jl index fbaa7783d99..df7e1f375a9 100644 --- a/examples/structured_2d_dgsem/elixir_advection_extended.jl +++ b/examples/structured_2d_dgsem/elixir_advection_extended.jl @@ -18,11 +18,11 @@ initial_condition = initial_condition_convergence_test boundary_conditions = boundary_condition_periodic # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) # The initial condition is 2-periodic coordinates_min = (-1.5, 1.3) # minimum coordinates (min(x), min(y)) -coordinates_max = ( 0.5, 5.3) # maximum coordinates (max(x), max(y)) +coordinates_max = (0.5, 5.3) # maximum coordinates (max(x), max(y)) cells_per_dimension = (19, 37) @@ -31,8 +31,7 @@ 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, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -47,24 +46,24 @@ summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy, energy_total)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy, energy_total)) # The AliveCallback prints short status information in regular intervals -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) # The SaveRestartCallback allows to save a file from which a Trixi.jl simulation can be restarted -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) # The SaveSolutionCallback allows to save the solution to a file in regular intervals -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) # The StepsizeCallback handles the re-calculation of the maximum Δt after each time step -stepsize_callback = StepsizeCallback(cfl=1.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver callbacks = CallbackSet(summary_callback, @@ -72,14 +71,13 @@ callbacks = CallbackSet(summary_callback, save_restart, 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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/structured_2d_dgsem/elixir_advection_free_stream.jl b/examples/structured_2d_dgsem/elixir_advection_free_stream.jl index 155a2d19fc9..7785b4f9e18 100644 --- a/examples/structured_2d_dgsem/elixir_advection_free_stream.jl +++ b/examples/structured_2d_dgsem/elixir_advection_free_stream.jl @@ -11,21 +11,21 @@ equations = LinearScalarAdvectionEquation2D(advection_velocity) initial_condition = initial_condition_constant # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) # Mapping as described in https://arxiv.org/abs/2012.12040, but reduced to 2D function mapping(xi_, eta_) - # Transform input variables between -1 and 1 onto [0,3] - xi = 1.5 * xi_ + 1.5 - eta = 1.5 * eta_ + 1.5 + # Transform input variables between -1 and 1 onto [0,3] + xi = 1.5 * xi_ + 1.5 + eta = 1.5 * eta_ + 1.5 - y = eta + 3/8 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3)) + y = eta + 3 / 8 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3)) - x = xi + 3/8 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3)) + x = xi + 3 / 8 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3)) - return SVector(x, y) + return SVector(x, y) end cells_per_dimension = (16, 16) @@ -36,7 +36,6 @@ mesh = StructuredMesh(cells_per_dimension, mapping) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -48,30 +47,30 @@ ode = semidiscretize(semi, (0.0, 1.0)); summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +save_solution = SaveSolutionCallback(interval = 100, + solution_variables = cons2prim) # The SaveRestartCallback allows to save a file from which a Trixi.jl simulation can be restarted -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) # The StepsizeCallback handles the re-calculation of the maximum Δt after each time step -stepsize_callback = StepsizeCallback(cfl=2.0) +stepsize_callback = StepsizeCallback(cfl = 2.0) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver -callbacks = CallbackSet(summary_callback, analysis_callback, save_restart, save_solution, stepsize_callback) - +callbacks = CallbackSet(summary_callback, analysis_callback, save_restart, 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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/structured_2d_dgsem/elixir_advection_nonperiodic.jl b/examples/structured_2d_dgsem/elixir_advection_nonperiodic.jl index 2aad3a01566..e2e113b168d 100644 --- a/examples/structured_2d_dgsem/elixir_advection_nonperiodic.jl +++ b/examples/structured_2d_dgsem/elixir_advection_nonperiodic.jl @@ -13,16 +13,14 @@ initial_condition = initial_condition_gauss # you can either use a single function to impose the BCs weakly in all # 2*ndims == 4 directions or you can pass a tuple containing BCs for each direction boundary_conditions = BoundaryConditionDirichlet(initial_condition) -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-5.0, -5.0) -coordinates_max = ( 5.0, 5.0) -mesh = StructuredMesh((16, 16), coordinates_min, coordinates_max, periodicity=false) - +coordinates_max = (5.0, 5.0) +mesh = StructuredMesh((16, 16), coordinates_min, coordinates_max, periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -33,17 +31,17 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -52,7 +50,7 @@ callbacks = CallbackSet(summary_callback, ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=stepsize_callback(ode), # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = stepsize_callback(ode), # 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_parallelogram.jl b/examples/structured_2d_dgsem/elixir_advection_parallelogram.jl index b9a6d3f91ae..b70deb12318 100644 --- a/examples/structured_2d_dgsem/elixir_advection_parallelogram.jl +++ b/examples/structured_2d_dgsem/elixir_advection_parallelogram.jl @@ -7,24 +7,23 @@ using OrdinaryDiffEq using Trixi - # initial_condition_convergence_test transformed to the parallelogram function initial_condition_parallelogram(x, t, equation::LinearScalarAdvectionEquation2D) - # Transform back to unit square - x_transformed = SVector(x[1] - x[2], x[2]) - a = equation.advection_velocity - a_transformed = SVector(a[1] - a[2], a[2]) - - # Store translated coordinate for easy use of exact solution - x_translated = x_transformed - a_transformed * t - - c = 1.0 - A = 0.5 - L = 2 - f = 1/L - omega = 2 * pi * f - scalar = c + A * sin(omega * sum(x_translated)) - return SVector(scalar) + # Transform back to unit square + x_transformed = SVector(x[1] - x[2], x[2]) + a = equation.advection_velocity + a_transformed = SVector(a[1] - a[2], a[2]) + + # Store translated coordinate for easy use of exact solution + x_translated = x_transformed - a_transformed * t + + c = 1.0 + A = 0.5 + L = 2 + f = 1 / L + omega = 2 * pi * f + scalar = c + A * sin(omega * sum(x_translated)) + return SVector(scalar) end ############################################################################### @@ -35,7 +34,7 @@ advection_velocity = (-0.5, -0.7) 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) # Define faces for a parallelogram that looks like this # @@ -49,11 +48,11 @@ mapping(xi, eta) = SVector(xi + eta, eta) cells_per_dimension = (16, 16) # Create curved mesh with 16 x 16 elements, periodic in both dimensions -mesh = StructuredMesh(cells_per_dimension, mapping; periodicity=(true, true)) +mesh = StructuredMesh(cells_per_dimension, mapping; periodicity = (true, true)) # A semidiscretization collects data structures and functions for the spatial discretization -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_parallelogram, solver) - +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_parallelogram, + solver) ############################################################################### # ODE solvers, callbacks etc. @@ -66,26 +65,26 @@ ode = semidiscretize(semi, (0.0, 1.0)); summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +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.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) # 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) - +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/structured_2d_dgsem/elixir_advection_restart.jl b/examples/structured_2d_dgsem/elixir_advection_restart.jl index 82eaa21333a..19863faae8d 100644 --- a/examples/structured_2d_dgsem/elixir_advection_restart.jl +++ b/examples/structured_2d_dgsem/elixir_advection_restart.jl @@ -10,7 +10,6 @@ restart_file = "restart_000021.h5" trixi_include(@__MODULE__, joinpath(@__DIR__, elixir_file)) - ############################################################################### # adapt the parameters that have changed compared to "elixir_advection_extended.jl" @@ -29,9 +28,9 @@ ode = semidiscretize(semi, tspan, restart_filename); # Do not overwrite the initial snapshot written by elixir_advection_extended.jl. save_solution.condition.save_initial_solution = false -integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=dt, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +integrator = init(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); # Get the last time index and work with that. load_timestep!(integrator, restart_filename) diff --git a/examples/structured_2d_dgsem/elixir_advection_rotated.jl b/examples/structured_2d_dgsem/elixir_advection_rotated.jl index 7dfee23a067..826c7ebaacb 100644 --- a/examples/structured_2d_dgsem/elixir_advection_rotated.jl +++ b/examples/structured_2d_dgsem/elixir_advection_rotated.jl @@ -7,7 +7,6 @@ using OrdinaryDiffEq using Trixi - # Define new structs inside a module to allow re-evaluating the file. # This module name needs to be unique among all examples, otherwise Julia will throw warnings # if multiple test cases using the same module name are run in the same session. @@ -17,40 +16,41 @@ using Trixi # initial_condition_convergence_test transformed to the rotated rectangle struct InitialConditionConvergenceTestRotated - sin_alpha::Float64 - cos_alpha::Float64 + sin_alpha::Float64 + cos_alpha::Float64 end function InitialConditionConvergenceTestRotated(alpha) - sin_alpha, cos_alpha = sincos(alpha) + sin_alpha, cos_alpha = sincos(alpha) - InitialConditionConvergenceTestRotated(sin_alpha, cos_alpha) + InitialConditionConvergenceTestRotated(sin_alpha, cos_alpha) end -function (initial_condition::InitialConditionConvergenceTestRotated)(x, t, equation::LinearScalarAdvectionEquation2D) - sin_ = initial_condition.sin_alpha - cos_ = initial_condition.cos_alpha +function (initial_condition::InitialConditionConvergenceTestRotated)(x, t, + equation::LinearScalarAdvectionEquation2D) + sin_ = initial_condition.sin_alpha + cos_ = initial_condition.cos_alpha - # Rotate back to unit square + # Rotate back to unit square - # Clockwise rotation by α and translation by 1 - # Multiply with [ cos(α) sin(α); - # -sin(α) cos(α)] - x_rot = SVector(cos_ * x[1] + sin_ * x[2], -sin_ * x[1] + cos_ * x[2]) - a = equation.advection_velocity - a_rot = SVector(cos_ * a[1] + sin_ * a[2], -sin_ * a[1] + cos_ * a[2]) + # Clockwise rotation by α and translation by 1 + # Multiply with [ cos(α) sin(α); + # -sin(α) cos(α)] + x_rot = SVector(cos_ * x[1] + sin_ * x[2], -sin_ * x[1] + cos_ * x[2]) + a = equation.advection_velocity + a_rot = SVector(cos_ * a[1] + sin_ * a[2], -sin_ * a[1] + cos_ * a[2]) - # Store translated coordinate for easy use of exact solution - x_trans = x_rot - a_rot * t + # Store translated coordinate for easy use of exact solution + x_trans = x_rot - a_rot * t - c = 1.0 - A = 0.5 - L = 2 - f = 1/L - omega = 2 * pi * f - scalar = c + A * sin(omega * sum(x_trans)) + c = 1.0 + A = 0.5 + L = 2 + f = 1 / L + omega = 2 * pi * f + scalar = c + A * sin(omega * sum(x_trans)) - return SVector(scalar) + return SVector(scalar) end end # module TrixiExtensionAdvectionRotated @@ -70,7 +70,7 @@ advection_velocity = Tuple(T * [0.2, -0.7]) 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) mapping(xi, eta) = T * SVector(xi, eta) @@ -82,7 +82,6 @@ mesh = StructuredMesh(cells_per_dimension, mapping) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -94,26 +93,26 @@ ode = semidiscretize(semi, (0.0, 1.0)); summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +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.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) # 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) - +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/structured_2d_dgsem/elixir_advection_waving_flag.jl b/examples/structured_2d_dgsem/elixir_advection_waving_flag.jl index d0db19ea635..50393d50a19 100644 --- a/examples/structured_2d_dgsem/elixir_advection_waving_flag.jl +++ b/examples/structured_2d_dgsem/elixir_advection_waving_flag.jl @@ -11,14 +11,14 @@ equations = LinearScalarAdvectionEquation2D(advection_velocity) initial_condition = initial_condition_convergence_test # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) # Deformed rectangle that looks like a waving flag, # lower and upper faces are sinus curves, left and right are vertical lines. f1(s) = SVector(-1.0, s - 1.0) -f2(s) = SVector( 1.0, s + 1.0) +f2(s) = SVector(1.0, s + 1.0) f3(s) = SVector(s, -1.0 + sin(0.5 * pi * s)) -f4(s) = SVector(s, 1.0 + sin(0.5 * pi * s)) +f4(s) = SVector(s, 1.0 + sin(0.5 * pi * s)) cells_per_dimension = (16, 16) @@ -28,7 +28,6 @@ mesh = StructuredMesh(cells_per_dimension, (f1, f2, f3, f4)) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -40,30 +39,30 @@ ode = semidiscretize(semi, (0.0, 1.0)); summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +analysis_callback = AnalysisCallback(semi, interval = 100) # The SaveRestartCallback allows to save a file from which a Trixi.jl simulation can be restarted -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) # The SaveSolutionCallback allows to save the solution to a file in regular intervals -save_solution = SaveSolutionCallback(interval=100, - solution_variables=cons2prim) +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.4) +stepsize_callback = StepsizeCallback(cfl = 1.4) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver -callbacks = CallbackSet(summary_callback, analysis_callback, save_restart, save_solution, stepsize_callback) - +callbacks = CallbackSet(summary_callback, analysis_callback, save_restart, 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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/structured_2d_dgsem/elixir_euler_ec.jl b/examples/structured_2d_dgsem/elixir_euler_ec.jl index 2c91349ff98..29686bd3cb7 100644 --- a/examples/structured_2d_dgsem/elixir_euler_ec.jl +++ b/examples/structured_2d_dgsem/elixir_euler_ec.jl @@ -13,25 +13,25 @@ initial_condition = initial_condition_weak_blast_wave # Get the DG approximation space volume_flux = flux_ranocha -solver = DGSEM(polydeg=4, surface_flux=flux_ranocha, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 4, surface_flux = flux_ranocha, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the curved quad mesh from a mapping function # Mapping as described in https://arxiv.org/abs/2012.12040, but reduced to 2D function mapping(xi_, eta_) - # Transform input variables between -1 and 1 onto [0,3] - xi = 1.5 * xi_ + 1.5 - eta = 1.5 * eta_ + 1.5 + # Transform input variables between -1 and 1 onto [0,3] + xi = 1.5 * xi_ + 1.5 + eta = 1.5 * eta_ + 1.5 - y = eta + 3/8 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3)) + y = eta + 3 / 8 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3)) - x = xi + 3/8 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3)) + x = xi + 3 / 8 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3)) - return SVector(x, y) + return SVector(x, y) end cells_per_dimension = (16, 16) @@ -53,15 +53,15 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -72,7 +72,7 @@ callbacks = CallbackSet(summary_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); +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/structured_2d_dgsem/elixir_euler_free_stream.jl b/examples/structured_2d_dgsem/elixir_euler_free_stream.jl index c4ddb887e5f..3aab4be979e 100644 --- a/examples/structured_2d_dgsem/elixir_euler_free_stream.jl +++ b/examples/structured_2d_dgsem/elixir_euler_free_stream.jl @@ -9,21 +9,21 @@ equations = CompressibleEulerEquations2D(1.4) initial_condition = initial_condition_constant -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) # Mapping as described in https://arxiv.org/abs/2012.12040, but reduced to 2D function mapping(xi_, eta_) - # Transform input variables between -1 and 1 onto [0,3] - xi = 1.5 * xi_ + 1.5 - eta = 1.5 * eta_ + 1.5 + # Transform input variables between -1 and 1 onto [0,3] + xi = 1.5 * xi_ + 1.5 + eta = 1.5 * eta_ + 1.5 - y = eta + 3/8 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3)) + y = eta + 3 / 8 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3)) - x = xi + 3/8 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3)) + x = xi + 3 / 8 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3)) - return SVector(x, y) + return SVector(x, y) end cells_per_dimension = (16, 16) @@ -32,7 +32,6 @@ mesh = StructuredMesh(cells_per_dimension, mapping) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -42,16 +41,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=2.0) +stepsize_callback = StepsizeCallback(cfl = 2.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -61,7 +60,7 @@ callbacks = CallbackSet(summary_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); +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/structured_2d_dgsem/elixir_euler_rayleigh_taylor_instability.jl b/examples/structured_2d_dgsem/elixir_euler_rayleigh_taylor_instability.jl index bb5870ab9d5..6c254e8bd8b 100644 --- a/examples/structured_2d_dgsem/elixir_euler_rayleigh_taylor_instability.jl +++ b/examples/structured_2d_dgsem/elixir_euler_rayleigh_taylor_instability.jl @@ -29,40 +29,40 @@ defined below. """ @inline function initial_condition_rayleigh_taylor_instability(x, t, equations::CompressibleEulerEquations2D, - slope=1000) - tol = 1e2*eps() - - if x[2] < 0.5 - p = 2*x[2] + 1 - else - p = x[2] + 3/2 - end - - # smooth the discontinuity to avoid ambiguity at element interfaces - smoothed_heaviside(x, left, right) = left + 0.5*(1 + tanh(slope * x)) * (right-left) - rho = smoothed_heaviside(x[2] - 0.5, 2.0, 1.0) - - c = sqrt(equations.gamma * p / rho) - # the velocity is multiplied by sin(pi*y)^6 as in Remacle et al. 2003 to ensure that the - # initial condition satisfies reflective boundary conditions at the top/bottom boundaries. - v = -0.025 * c * cos(8*pi*x[1]) * sin(pi*x[2])^6 - u = 0.0 - - return prim2cons(SVector(rho, u, v, p), equations) + slope = 1000) + tol = 1e2 * eps() + + if x[2] < 0.5 + p = 2 * x[2] + 1 + else + p = x[2] + 3 / 2 + end + + # smooth the discontinuity to avoid ambiguity at element interfaces + smoothed_heaviside(x, left, right) = left + 0.5 * (1 + tanh(slope * x)) * (right - left) + rho = smoothed_heaviside(x[2] - 0.5, 2.0, 1.0) + + c = sqrt(equations.gamma * p / rho) + # the velocity is multiplied by sin(pi*y)^6 as in Remacle et al. 2003 to ensure that the + # initial condition satisfies reflective boundary conditions at the top/bottom boundaries. + v = -0.025 * c * cos(8 * pi * x[1]) * sin(pi * x[2])^6 + u = 0.0 + + return prim2cons(SVector(rho, u, v, p), equations) end @inline function source_terms_rayleigh_taylor_instability(u, x, t, equations::CompressibleEulerEquations2D) - g = 1.0 - rho, rho_v1, rho_v2, rho_e = u + g = 1.0 + rho, rho_v1, rho_v2, rho_e = u - return SVector(0.0, 0.0, g*rho, g*rho_v2) + return SVector(0.0, 0.0, g * rho, g * rho_v2) end # numerical parameters volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_hll, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_hll, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) # The domain is [0, 0.25] x [0, 1] mapping(xi, eta) = SVector(0.25 * 0.5 * (1.0 + xi), 0.5 * (1.0 + eta)) @@ -72,12 +72,10 @@ cells_per_dimension = (num_elements_per_dimension, num_elements_per_dimension * mesh = StructuredMesh(cells_per_dimension, mapping) initial_condition = initial_condition_rayleigh_taylor_instability -boundary_conditions = ( - x_neg=boundary_condition_slip_wall, - x_pos=boundary_condition_slip_wall, - y_neg=boundary_condition_slip_wall, - y_pos=boundary_condition_slip_wall, - ) +boundary_conditions = (x_neg = boundary_condition_slip_wall, + x_pos = boundary_condition_slip_wall, + y_neg = boundary_condition_slip_wall, + y_pos = boundary_condition_slip_wall) # # Alternative setup: left/right periodic BCs and Dirichlet BCs on the top/bottom. # boundary_conditions = ( @@ -88,8 +86,8 @@ boundary_conditions = ( # ) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver; - source_terms=source_terms_rayleigh_taylor_instability, - boundary_conditions=boundary_conditions) + source_terms = source_terms_rayleigh_taylor_instability, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -100,9 +98,9 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -111,7 +109,7 @@ callbacks = CallbackSet(summary_callback, ############################################################################### # run the simulation -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-6, reltol=1.0e-6, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-6, reltol = 1.0e-6, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/structured_2d_dgsem/elixir_euler_sedov.jl b/examples/structured_2d_dgsem/elixir_euler_sedov.jl index efc3b6627c0..42094d7191c 100644 --- a/examples/structured_2d_dgsem/elixir_euler_sedov.jl +++ b/examples/structured_2d_dgsem/elixir_euler_sedov.jl @@ -14,25 +14,25 @@ The Sedov blast wave setup based on Flash - https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_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) - - # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 - r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) - E = 1.0 - p0_inner = 3 * (equations.gamma - 1) * E / (3 * pi * r0^2) - p0_outer = 1.0e-5 # = true Sedov setup - - # Calculate primitive variables - rho = 1.0 - v1 = 0.0 - v2 = 0.0 - p = r > r0 ? p0_outer : p0_inner - - return prim2cons(SVector(rho, v1, v2, p), equations) + # 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) + + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 + r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) + E = 1.0 + p0_inner = 3 * (equations.gamma - 1) * E / (3 * pi * r0^2) + p0_outer = 1.0e-5 # = true Sedov setup + + # Calculate primitive variables + rho = 1.0 + 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_sedov_blast_wave @@ -43,29 +43,30 @@ 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) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) -solver = DGSEM(polydeg=polydeg, surface_flux=surface_flux, volume_integral=volume_integral) +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral) # Get the curved quad mesh from a mapping function # Mapping as described in https://arxiv.org/abs/2012.12040 function mapping(xi, eta) - y = eta + 0.125 * (cos(1.5 * pi * xi) * cos(0.5 * pi * 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 * pi * y)) + x = xi + 0.125 * (cos(0.5 * pi * xi) * cos(2 * pi * y)) - return SVector(x, y) + return SVector(x, y) end cells_per_dimension = (16, 16) -mesh = StructuredMesh(cells_per_dimension, mapping, periodicity=true) +mesh = StructuredMesh(cells_per_dimension, mapping, periodicity = true) # create the semidiscretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -79,15 +80,15 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 300 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=300, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 300, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -98,7 +99,7 @@ callbacks = CallbackSet(summary_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); +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/structured_2d_dgsem/elixir_euler_source_terms.jl b/examples/structured_2d_dgsem/elixir_euler_source_terms.jl index 70d3e060dd0..6827848e185 100644 --- a/examples/structured_2d_dgsem/elixir_euler_source_terms.jl +++ b/examples/structured_2d_dgsem/elixir_euler_source_terms.jl @@ -11,7 +11,7 @@ equations = CompressibleEulerEquations2D(1.4) initial_condition = initial_condition_convergence_test -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0, 0.0) coordinates_max = (2.0, 2.0) @@ -20,10 +20,8 @@ cells_per_dimension = (16, 16) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) - semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -34,16 +32,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -53,7 +51,7 @@ callbacks = CallbackSet(summary_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); +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/structured_2d_dgsem/elixir_euler_source_terms_nonperiodic.jl b/examples/structured_2d_dgsem/elixir_euler_source_terms_nonperiodic.jl index 94537ecef0d..f42d223611a 100644 --- a/examples/structured_2d_dgsem/elixir_euler_source_terms_nonperiodic.jl +++ b/examples/structured_2d_dgsem/elixir_euler_source_terms_nonperiodic.jl @@ -12,21 +12,20 @@ initial_condition = initial_condition_convergence_test # you can either use a single function to impose the BCs weakly in all # 2*ndims == 4 directions or you can pass a tuple containing BCs for each direction boundary_condition = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = (x_neg=boundary_condition, - x_pos=boundary_condition, - y_neg=boundary_condition, - y_pos=boundary_condition,) +boundary_conditions = (x_neg = boundary_condition, + x_pos = boundary_condition, + y_neg = boundary_condition, + y_pos = boundary_condition) -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0, 0.0) coordinates_max = (2.0, 2.0) -mesh = StructuredMesh((16, 16), coordinates_min, coordinates_max, periodicity=false) +mesh = StructuredMesh((16, 16), coordinates_min, coordinates_max, periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test, - boundary_conditions=boundary_conditions) - + source_terms = source_terms_convergence_test, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -37,19 +36,19 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -58,7 +57,7 @@ callbacks = CallbackSet(summary_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); +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/structured_2d_dgsem/elixir_euler_source_terms_parallelogram.jl b/examples/structured_2d_dgsem/elixir_euler_source_terms_parallelogram.jl index a9c08049f41..5d6b0908389 100644 --- a/examples/structured_2d_dgsem/elixir_euler_source_terms_parallelogram.jl +++ b/examples/structured_2d_dgsem/elixir_euler_source_terms_parallelogram.jl @@ -9,7 +9,7 @@ equations = CompressibleEulerEquations2D(1.4) initial_condition = initial_condition_convergence_test -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) # Define faces for a parallelogram that looks like this # @@ -24,10 +24,8 @@ cells_per_dimension = (16, 16) mesh = StructuredMesh(cells_per_dimension, mapping) - semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -38,16 +36,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -57,7 +55,7 @@ callbacks = CallbackSet(summary_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); +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/structured_2d_dgsem/elixir_euler_source_terms_rotated.jl b/examples/structured_2d_dgsem/elixir_euler_source_terms_rotated.jl index fdd189ffb55..f2e3c448893 100644 --- a/examples/structured_2d_dgsem/elixir_euler_source_terms_rotated.jl +++ b/examples/structured_2d_dgsem/elixir_euler_source_terms_rotated.jl @@ -2,7 +2,6 @@ using OrdinaryDiffEq using Trixi - # Define new structs inside a module to allow re-evaluating the file. # This module name needs to be unique among all examples, otherwise Julia will throw warnings # if multiple test cases using the same module name are run in the same session. @@ -12,68 +11,69 @@ using Trixi # initial_condition_convergence_test transformed to the rotated rectangle struct InitialConditionSourceTermsRotated - sin_alpha::Float64 - cos_alpha::Float64 + sin_alpha::Float64 + cos_alpha::Float64 end function InitialConditionSourceTermsRotated(alpha) - sin_alpha, cos_alpha = sincos(alpha) + sin_alpha, cos_alpha = sincos(alpha) - InitialConditionSourceTermsRotated(sin_alpha, cos_alpha) + InitialConditionSourceTermsRotated(sin_alpha, cos_alpha) end -function (initial_condition::InitialConditionSourceTermsRotated)(x, t, equations::CompressibleEulerEquations2D) - sin_ = initial_condition.sin_alpha - cos_ = initial_condition.cos_alpha +function (initial_condition::InitialConditionSourceTermsRotated)(x, t, + equations::CompressibleEulerEquations2D) + sin_ = initial_condition.sin_alpha + cos_ = initial_condition.cos_alpha - # Rotate back to unit square and translate from [-1, 1]^2 to [0, 2]^2 + # Rotate back to unit square and translate from [-1, 1]^2 to [0, 2]^2 - # Clockwise rotation by α and translation by 1 - # Multiply with [ cos(α) sin(α); - # -sin(α) cos(α)] - x1 = cos_ * x[1] + sin_ * x[2] + 1 - x2 = -sin_ * x[1] + cos_ * x[2] + 1 + # Clockwise rotation by α and translation by 1 + # Multiply with [ cos(α) sin(α); + # -sin(α) cos(α)] + x1 = cos_ * x[1] + sin_ * x[2] + 1 + x2 = -sin_ * x[1] + cos_ * x[2] + 1 - rho, rho_v1, rho_v2, rho_e = initial_condition_convergence_test(SVector(x1, x2), t, equations) + rho, rho_v1, rho_v2, rho_e = initial_condition_convergence_test(SVector(x1, x2), t, + equations) - # Rotate velocity vector counterclockwise - # Multiply with [ cos(α) -sin(α); - # sin(α) cos(α)] - rho_v1_rot = cos_ * rho_v1 - sin_ * rho_v2 - rho_v2_rot = sin_ * rho_v1 + cos_ * rho_v2 + # Rotate velocity vector counterclockwise + # Multiply with [ cos(α) -sin(α); + # sin(α) cos(α)] + rho_v1_rot = cos_ * rho_v1 - sin_ * rho_v2 + rho_v2_rot = sin_ * rho_v1 + cos_ * rho_v2 - return SVector(rho, rho_v1_rot, rho_v2_rot, rho_e) + return SVector(rho, rho_v1_rot, rho_v2_rot, rho_e) end +@inline function (source_terms::InitialConditionSourceTermsRotated)(u, x, t, + equations::CompressibleEulerEquations2D) + sin_ = source_terms.sin_alpha + cos_ = source_terms.cos_alpha -@inline function (source_terms::InitialConditionSourceTermsRotated)(u, x, t, equations::CompressibleEulerEquations2D) - sin_ = source_terms.sin_alpha - cos_ = source_terms.cos_alpha - - # Rotate back to unit square and translate from [-1, 1]^2 to [0, 2]^2 + # Rotate back to unit square and translate from [-1, 1]^2 to [0, 2]^2 - # Clockwise rotation by α and translation by 1 - # Multiply with [ cos(α) sin(α); - # -sin(α) cos(α)] - x1 = cos_ * x[1] + sin_ * x[2] + 1 - x2 = -sin_ * x[1] + cos_ * x[2] + 1 + # Clockwise rotation by α and translation by 1 + # Multiply with [ cos(α) sin(α); + # -sin(α) cos(α)] + x1 = cos_ * x[1] + sin_ * x[2] + 1 + x2 = -sin_ * x[1] + cos_ * x[2] + 1 - du1, du2, du3, du4 = source_terms_convergence_test(u, SVector(x1, x2), t, equations) + du1, du2, du3, du4 = source_terms_convergence_test(u, SVector(x1, x2), t, equations) - # Rotate velocity vector counterclockwise - # Multiply with [ cos(α) -sin(α); - # sin(α) cos(α)] - du2_rotated = cos_ * du2 - sin_ * du3 - du3_rotated = sin_ * du2 + cos_ * du3 + # Rotate velocity vector counterclockwise + # Multiply with [ cos(α) -sin(α); + # sin(α) cos(α)] + du2_rotated = cos_ * du2 - sin_ * du3 + du3_rotated = sin_ * du2 + cos_ * du3 - return SVector(du1, du2_rotated, du3_rotated, du4) + return SVector(du1, du2_rotated, du3_rotated, du4) end end # module TrixiExtensionEulerRotated import .TrixiExtensionEulerRotated - ############################################################################### # semidiscretization of the compressible Euler equations @@ -85,8 +85,7 @@ sin_ = initial_condition_source_terms.sin_alpha cos_ = initial_condition_source_terms.cos_alpha T = [cos_ -sin_; sin_ cos_] - -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) mapping(xi, eta) = T * SVector(xi, eta) @@ -94,10 +93,8 @@ cells_per_dimension = (16, 16) mesh = StructuredMesh(cells_per_dimension, mapping) - semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_source_terms, solver, - source_terms=initial_condition_source_terms) - + source_terms = initial_condition_source_terms) ############################################################################### # ODE solvers, callbacks etc. @@ -108,16 +105,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -127,7 +124,7 @@ callbacks = CallbackSet(summary_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); +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/structured_2d_dgsem/elixir_euler_source_terms_waving_flag.jl b/examples/structured_2d_dgsem/elixir_euler_source_terms_waving_flag.jl index 505e28ecd8d..4a78b65ae0b 100644 --- a/examples/structured_2d_dgsem/elixir_euler_source_terms_waving_flag.jl +++ b/examples/structured_2d_dgsem/elixir_euler_source_terms_waving_flag.jl @@ -9,23 +9,21 @@ equations = CompressibleEulerEquations2D(1.4) initial_condition = initial_condition_convergence_test -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) # Deformed rectangle that looks like a waving flag, # lower and upper faces are sinus curves, left and right are vertical lines. f1(s) = SVector(-1.0, s - 1.0) -f2(s) = SVector( 1.0, s + 1.0) +f2(s) = SVector(1.0, s + 1.0) f3(s) = SVector(s, -1.0 + sin(0.5 * pi * s)) -f4(s) = SVector(s, 1.0 + sin(0.5 * pi * s)) +f4(s) = SVector(s, 1.0 + sin(0.5 * pi * s)) cells_per_dimension = (16, 16) mesh = StructuredMesh(cells_per_dimension, (f1, f2, f3, f4)) - semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -36,16 +34,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -55,7 +53,7 @@ callbacks = CallbackSet(summary_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); +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/structured_2d_dgsem/elixir_eulerpolytropic_ec.jl b/examples/structured_2d_dgsem/elixir_eulerpolytropic_ec.jl index de15f6b2bc3..b96f1d3cd68 100644 --- a/examples/structured_2d_dgsem/elixir_eulerpolytropic_ec.jl +++ b/examples/structured_2d_dgsem/elixir_eulerpolytropic_ec.jl @@ -15,25 +15,25 @@ initial_condition = initial_condition_weak_blast_wave # Get the DG approximation space volume_flux = flux_winters_etal -solver = DGSEM(polydeg=4, surface_flux=flux_winters_etal, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 4, surface_flux = flux_winters_etal, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the curved quad mesh from a mapping function # Mapping as described in https://arxiv.org/abs/2012.12040, but reduced to 2D function mapping(xi_, eta_) - # Transform input variables between -1 and 1 onto [0,3] - xi = 1.5 * xi_ + 1.5 - eta = 1.5 * eta_ + 1.5 + # Transform input variables between -1 and 1 onto [0,3] + xi = 1.5 * xi_ + 1.5 + eta = 1.5 * eta_ + 1.5 - y = eta + 3/8 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3)) + y = eta + 3 / 8 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3)) - x = xi + 3/8 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3)) + x = xi + 3 / 8 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3)) - return SVector(x, y) + return SVector(x, y) end cells_per_dimension = (16, 16) @@ -55,15 +55,15 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -74,7 +74,7 @@ callbacks = CallbackSet(summary_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); +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/structured_2d_dgsem/elixir_hypdiff_harmonic_nonperiodic.jl b/examples/structured_2d_dgsem/elixir_hypdiff_harmonic_nonperiodic.jl index 6730b1c4beb..ccb74fa4b68 100644 --- a/examples/structured_2d_dgsem/elixir_hypdiff_harmonic_nonperiodic.jl +++ b/examples/structured_2d_dgsem/elixir_hypdiff_harmonic_nonperiodic.jl @@ -7,43 +7,42 @@ using Trixi equations = HyperbolicDiffusionEquations2D() -@inline function initial_condition_harmonic_nonperiodic(x, t, equations::HyperbolicDiffusionEquations2D) - # elliptic equation: -ν Δϕ = 0 in Ω, u = g on ∂Ω - if t == 0.0 - phi = 1.0 - q1 = 1.0 - q2 = 1.0 - else - C = inv(sinh(pi)) - sinpi_x1, cospi_x1 = sincos(pi*x[1]) - sinpi_x2, cospi_x2 = sincos(pi*x[2]) - sinh_pix1 = sinh(pi*x[1]) - cosh_pix1 = cosh(pi*x[1]) - sinh_pix2 = sinh(pi*x[2]) - cosh_pix2 = cosh(pi*x[2]) - phi = C * (sinh_pix1 * sinpi_x2 + sinh_pix2 * sinpi_x1) - q1 = C * pi * (cosh_pix1 * sinpi_x2 + sinh_pix2 * cospi_x1) - q2 = C * pi * (sinh_pix1 * cospi_x2 + cosh_pix2 * sinpi_x1) - end - return SVector(phi, q1, q2) +@inline function initial_condition_harmonic_nonperiodic(x, t, + equations::HyperbolicDiffusionEquations2D) + # elliptic equation: -ν Δϕ = 0 in Ω, u = g on ∂Ω + if t == 0.0 + phi = 1.0 + q1 = 1.0 + q2 = 1.0 + else + C = inv(sinh(pi)) + sinpi_x1, cospi_x1 = sincos(pi * x[1]) + sinpi_x2, cospi_x2 = sincos(pi * x[2]) + sinh_pix1 = sinh(pi * x[1]) + cosh_pix1 = cosh(pi * x[1]) + sinh_pix2 = sinh(pi * x[2]) + cosh_pix2 = cosh(pi * x[2]) + phi = C * (sinh_pix1 * sinpi_x2 + sinh_pix2 * sinpi_x1) + q1 = C * pi * (cosh_pix1 * sinpi_x2 + sinh_pix2 * cospi_x1) + q2 = C * pi * (sinh_pix1 * cospi_x2 + cosh_pix2 * sinpi_x1) + end + return SVector(phi, q1, q2) end initial_condition = initial_condition_harmonic_nonperiodic boundary_conditions = BoundaryConditionDirichlet(initial_condition) -solver = DGSEM(polydeg=4, surface_flux=flux_godunov) +solver = DGSEM(polydeg = 4, surface_flux = flux_godunov) coordinates_min = (0.0, 0.0) coordinates_max = (1.0, 1.0) cells_per_dimension = (8, 8) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, - periodicity=false) - + periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions, - source_terms=source_terms_harmonic) - + boundary_conditions = boundary_conditions, + source_terms = source_terms_harmonic) ############################################################################### # ODE solvers, callbacks etc. @@ -54,30 +53,29 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() resid_tol = 5.0e-12 -steady_state_callback = SteadyStateCallback(abstol=resid_tol, reltol=0.0) +steady_state_callback = SteadyStateCallback(abstol = resid_tol, reltol = 0.0) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, steady_state_callback, analysis_callback, alive_callback, save_solution, 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); +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/structured_2d_dgsem/elixir_hypdiff_nonperiodic.jl b/examples/structured_2d_dgsem/elixir_hypdiff_nonperiodic.jl index ba77dca9a99..681b3bd781b 100644 --- a/examples/structured_2d_dgsem/elixir_hypdiff_nonperiodic.jl +++ b/examples/structured_2d_dgsem/elixir_hypdiff_nonperiodic.jl @@ -9,40 +9,38 @@ equations = HyperbolicDiffusionEquations2D() initial_condition = initial_condition_poisson_nonperiodic -solver = DGSEM(polydeg=6, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 6, surface_flux = flux_lax_friedrichs) -boundary_conditions = (x_neg=boundary_condition_poisson_nonperiodic, - x_pos=boundary_condition_poisson_nonperiodic, - y_neg=boundary_condition_periodic, - y_pos=boundary_condition_periodic) +boundary_conditions = (x_neg = boundary_condition_poisson_nonperiodic, + x_pos = boundary_condition_poisson_nonperiodic, + y_neg = boundary_condition_periodic, + y_pos = boundary_condition_periodic) ############################################################################### # Get the curved quad mesh from a mapping function # # Mapping as described in https://arxiv.org/abs/2012.12040, but reduced to 2D function mapping(xi_, eta_) - # Transform input variables between -1 and 1 onto [0,3] - xi = 1.5 * xi_ + 1.5 - eta = 1.5 * eta_ + 1.5 + # Transform input variables between -1 and 1 onto [0,3] + xi = 1.5 * xi_ + 1.5 + eta = 1.5 * eta_ + 1.5 - y = eta + 3/8 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3)) + y = eta + 3 / 8 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3)) - x = xi + 3/8 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3)) + x = xi + 3 / 8 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3)) - return SVector(x, y) + return SVector(x, y) end # Create curved mesh with 8 x 8 elements cells_per_dimension = (8, 8) -mesh = StructuredMesh(cells_per_dimension, mapping, periodicity=(false, true)) - +mesh = StructuredMesh(cells_per_dimension, mapping, periodicity = (false, true)) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_poisson_nonperiodic, - boundary_conditions=boundary_conditions) - + source_terms = source_terms_poisson_nonperiodic, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -53,31 +51,30 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() resid_tol = 5.0e-12 -steady_state_callback = SteadyStateCallback(abstol=resid_tol, reltol=0.0) +steady_state_callback = SteadyStateCallback(abstol = resid_tol, reltol = 0.0) analysis_interval = 4000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy, energy_total)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy, energy_total)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=4000, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 4000, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.9) +stepsize_callback = StepsizeCallback(cfl = 1.9) callbacks = CallbackSet(summary_callback, steady_state_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) - ############################################################################### # run the simulation sol = Trixi.solve(ode, Trixi.HypDiffN3Erk3Sstar52(), - dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); + 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/structured_2d_dgsem/elixir_mhd_alfven_wave.jl b/examples/structured_2d_dgsem/elixir_mhd_alfven_wave.jl index 259875050c6..e8f2b2ecc3a 100644 --- a/examples/structured_2d_dgsem/elixir_mhd_alfven_wave.jl +++ b/examples/structured_2d_dgsem/elixir_mhd_alfven_wave.jl @@ -5,31 +5,34 @@ using Trixi ############################################################################### # semidiscretization of the compressible ideal GLM-MHD equations -gamma = 5/3 +gamma = 5 / 3 equations = IdealGlmMhdEquations2D(gamma) initial_condition = initial_condition_convergence_test # Get the DG approximation space volume_flux = (flux_central, flux_nonconservative_powell) -solver = DGSEM(polydeg=3, surface_flux=(flux_lax_friedrichs, flux_nonconservative_powell), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, + surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) # Get the curved quad mesh from a mapping function # Mapping as described in https://arxiv.org/abs/1809.01178 function mapping(xi_, eta_) - # Transform input variables between -1 and 1 onto [0, sqrt(2)] - # Note, we use the domain [0, sqrt(2)]^2 for the Alfvén wave convergence test case - xi = 0.5 * sqrt(2) * xi_ + 0.5 * sqrt(2) - eta = 0.5 * sqrt(2) * eta_ + 0.5 * sqrt(2) + # Transform input variables between -1 and 1 onto [0, sqrt(2)] + # Note, we use the domain [0, sqrt(2)]^2 for the Alfvén wave convergence test case + xi = 0.5 * sqrt(2) * xi_ + 0.5 * sqrt(2) + eta = 0.5 * sqrt(2) * eta_ + 0.5 * sqrt(2) - y = eta + sqrt(2)/12 * (cos(1.5 * pi * (2 * xi - sqrt(2))/sqrt(2)) * - cos(0.5 * pi * (2 * eta - sqrt(2))/sqrt(2))) + y = eta + + sqrt(2) / 12 * (cos(1.5 * pi * (2 * xi - sqrt(2)) / sqrt(2)) * + cos(0.5 * pi * (2 * eta - sqrt(2)) / sqrt(2))) - x = xi + sqrt(2)/12 * (cos(0.5 * pi * (2 * xi - sqrt(2))/sqrt(2)) * - cos(2 * pi * (2 * y - sqrt(2))/sqrt(2))) + x = xi + + sqrt(2) / 12 * (cos(0.5 * pi * (2 * xi - sqrt(2)) / sqrt(2)) * + cos(2 * pi * (2 * y - sqrt(2)) / sqrt(2))) - return SVector(x, y) + return SVector(x, y) end cells_per_dimension = (4, 4) @@ -47,21 +50,24 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false, - extra_analysis_integrals=(entropy, energy_total, - energy_kinetic, energy_internal, - energy_magnetic, cross_helicity)) - -alive_callback = AliveCallback(analysis_interval=analysis_interval) - -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = false, + extra_analysis_integrals = (entropy, energy_total, + energy_kinetic, + energy_internal, + energy_magnetic, + cross_helicity)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) cfl = 2.0 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -73,7 +79,7 @@ callbacks = CallbackSet(summary_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); +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/structured_2d_dgsem/elixir_mhd_ec.jl b/examples/structured_2d_dgsem/elixir_mhd_ec.jl index 634738e5c8b..a6c31744ca5 100644 --- a/examples/structured_2d_dgsem/elixir_mhd_ec.jl +++ b/examples/structured_2d_dgsem/elixir_mhd_ec.jl @@ -8,45 +8,46 @@ using Trixi equations = IdealGlmMhdEquations2D(1.4) function initial_condition_shifted_weak_blast_wave(x, t, equations::IdealGlmMhdEquations2D) - # Adapted MHD version of the weak blast wave from Hennemann & Gassner JCP paper 2020 (Sec. 6.3) - # Same discontinuity in the velocities but with magnetic fields - # Set up polar coordinates - inicenter = (1.5, 1.5) - 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) - - # 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) - p = r > 0.5 ? 1.0 : 1.245 - - return prim2cons(SVector(rho, v1, v2, 0.0, p, 1.0, 1.0, 1.0, 0.0), equations) + # Adapted MHD version of the weak blast wave from Hennemann & Gassner JCP paper 2020 (Sec. 6.3) + # Same discontinuity in the velocities but with magnetic fields + # Set up polar coordinates + inicenter = (1.5, 1.5) + 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) + + # 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) + p = r > 0.5 ? 1.0 : 1.245 + + return prim2cons(SVector(rho, v1, v2, 0.0, p, 1.0, 1.0, 1.0, 0.0), equations) end initial_condition = initial_condition_shifted_weak_blast_wave # Get the DG approximation space volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -solver = DGSEM(polydeg=5, surface_flux=(flux_hindenlang_gassner, flux_nonconservative_powell), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 5, + surface_flux = (flux_hindenlang_gassner, flux_nonconservative_powell), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) # Get the curved quad mesh from a mapping function # Mapping as described in https://arxiv.org/abs/2012.12040, but reduced to 2D function mapping(xi_, eta_) - # Transform input variables between -1 and 1 onto [0,3] - xi = 1.5 * xi_ + 1.5 - eta = 1.5 * eta_ + 1.5 + # Transform input variables between -1 and 1 onto [0,3] + xi = 1.5 * xi_ + 1.5 + eta = 1.5 * eta_ + 1.5 - y = eta + 3/8 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3)) + y = eta + 3 / 8 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3)) - x = xi + 3/8 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3)) + x = xi + 3 / 8 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3)) - return SVector(x, y) + return SVector(x, y) end # Create curved mesh with 8 x 8 elements @@ -65,21 +66,24 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false, - extra_analysis_integrals=(entropy, energy_total, - energy_kinetic, energy_internal, - energy_magnetic, cross_helicity)) - -alive_callback = AliveCallback(analysis_interval=analysis_interval) - -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = false, + extra_analysis_integrals = (entropy, energy_total, + energy_kinetic, + energy_internal, + energy_magnetic, + cross_helicity)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) cfl = 1.0 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -91,7 +95,7 @@ callbacks = CallbackSet(summary_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); +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/structured_2d_dgsem/elixir_mhd_ec_shockcapturing.jl b/examples/structured_2d_dgsem/elixir_mhd_ec_shockcapturing.jl index 084aeca90b9..6668014a0b6 100644 --- a/examples/structured_2d_dgsem/elixir_mhd_ec_shockcapturing.jl +++ b/examples/structured_2d_dgsem/elixir_mhd_ec_shockcapturing.jl @@ -2,7 +2,6 @@ using OrdinaryDiffEq using Trixi - ############################################################################### # semidiscretization of the compressible ideal GLM-MHD equations equations = IdealGlmMhdEquations2D(1.4) @@ -10,17 +9,17 @@ equations = IdealGlmMhdEquations2D(1.4) initial_condition = initial_condition_weak_blast_wave surface_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) +volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) polydeg = 4 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) # Get the curved quad mesh from a mapping function @@ -31,16 +30,14 @@ function mapping(xi, eta) x = 2.0 * xi + 1.0 / 6.0 * (cos(0.5 * pi * xi) * cos(2 * pi * y)) return SVector(x, y) - end +end cells_per_dimension = (16, 16) -mesh = StructuredMesh(cells_per_dimension, mapping, periodicity=true) - +mesh = StructuredMesh(cells_per_dimension, mapping, periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -50,14 +47,14 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) cfl = 1.0 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -68,7 +65,7 @@ callbacks = CallbackSet(summary_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); +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/structured_2d_dgsem/elixir_shallowwater_conical_island.jl b/examples/structured_2d_dgsem/elixir_shallowwater_conical_island.jl index 44bc7a12b35..e65ed19221e 100644 --- a/examples/structured_2d_dgsem/elixir_shallowwater_conical_island.jl +++ b/examples/structured_2d_dgsem/elixir_shallowwater_conical_island.jl @@ -2,12 +2,12 @@ using OrdinaryDiffEq using Trixi - ############################################################################### - # Semidiscretization of the shallow water equations +############################################################################### +# Semidiscretization of the shallow water equations # # TODO: TrixiShallowWater: wet/dry example elixir -equations = ShallowWaterEquations2D(gravity_constant=9.81, H0=1.4) +equations = ShallowWaterEquations2D(gravity_constant = 9.81, H0 = 1.4) """ initial_condition_conical_island(x, t, equations::ShallowWaterEquations2D) @@ -20,29 +20,29 @@ discontinuous water height is smoothed by a logistic function. This simulation u boundary conditions. """ function initial_condition_conical_island(x, t, equations::ShallowWaterEquations2D) - # Set the background values + # Set the background values - v1 = 0.0 - v2 = 0.0 + v1 = 0.0 + v2 = 0.0 - x1, x2 = x - b = max(0.1, 1.0 - 4.0 * sqrt(x1^2 + x2^2)) + x1, x2 = x + b = max(0.1, 1.0 - 4.0 * sqrt(x1^2 + x2^2)) - # use a logistic function to transfer water height value smoothly - L = equations.H0 # maximum of function - x0 = 0.3 # center point of function - k = -25.0 # sharpness of transfer + # use a logistic function to transfer water height value smoothly + L = equations.H0 # maximum of function + x0 = 0.3 # center point of function + k = -25.0 # sharpness of transfer - H = max(b, L/(1.0 + exp(-k*(sqrt(x1^2+x2^2) - x0)))) + H = max(b, L / (1.0 + exp(-k * (sqrt(x1^2 + x2^2) - x0)))) - # It is mandatory to shift the water level at dry areas to make sure the water height h - # stays positive. The system would not be stable for h set to a hard 0 due to division by h in - # the computation of velocity, e.g., (h v1) / h. Therefore, a small dry state threshold - # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above - # for the ShallowWaterEquations and added to the initial condition if h = 0. - # This default value can be changed within the constructor call depending on the simulation setup. - H = max(H, b + equations.threshold_limiter) - return prim2cons(SVector(H, v1, v2, b), equations) + # It is mandatory to shift the water level at dry areas to make sure the water height h + # stays positive. The system would not be stable for h set to a hard 0 due to division by h in + # the computation of velocity, e.g., (h v1) / h. Therefore, a small dry state threshold + # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above + # for the ShallowWaterEquations and added to the initial condition if h = 0. + # This default value can be changed within the constructor call depending on the simulation setup. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v1, v2, b), equations) end initial_condition = initial_condition_conical_island @@ -51,19 +51,20 @@ initial_condition = initial_condition_conical_island # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, + hydrostatic_reconstruction_chen_noelle), flux_nonconservative_chen_noelle) basis = LobattoLegendreBasis(4) indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=waterheight_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = waterheight_pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) @@ -71,7 +72,7 @@ solver = DGSEM(basis, surface_flux, volume_integral) # Get the StructuredMesh and setup a periodic mesh coordinates_min = (-1.0, -1.0) -coordinates_max = (1.0, 1.0) +coordinates_max = (1.0, 1.0) cells_per_dimension = (16, 16) @@ -92,22 +93,22 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) ############################################################################### # run the simulation -stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) +stage_limiter! = PositivityPreservingLimiterShallowWater(variables = (Trixi.waterheight,)) sol = solve(ode, SSPRK43(stage_limiter!); - ode_default_options()..., callback=callbacks); + ode_default_options()..., callback = callbacks); -summary_callback() # print the timer summary \ No newline at end of file +summary_callback() # print the timer summary diff --git a/examples/structured_2d_dgsem/elixir_shallowwater_parabolic_bowl.jl b/examples/structured_2d_dgsem/elixir_shallowwater_parabolic_bowl.jl index 15cfe6698fc..bc198f18835 100644 --- a/examples/structured_2d_dgsem/elixir_shallowwater_parabolic_bowl.jl +++ b/examples/structured_2d_dgsem/elixir_shallowwater_parabolic_bowl.jl @@ -7,7 +7,7 @@ using Trixi # # TODO: TrixiShallowWater: wet/dry example elixir -equations = ShallowWaterEquations2D(gravity_constant=9.81) +equations = ShallowWaterEquations2D(gravity_constant = 9.81) """ initial_condition_parabolic_bowl(x, t, equations:: ShallowWaterEquations2D) @@ -28,53 +28,52 @@ The particular setup below is taken from Section 6.2 of curvilinear meshes with wet/dry fronts accelerated by GPUs [DOI: 10.1016/j.jcp.2018.08.038](https://doi.org/10.1016/j.jcp.2018.08.038). """ -function initial_condition_parabolic_bowl(x, t, equations:: ShallowWaterEquations2D) - a = 1.0 - h_0 = 0.1 - sigma = 0.5 - ω = sqrt(2 * equations.gravity * h_0) / a - - v1 = -sigma * ω * sin(ω * t) - v2 = sigma * ω * cos(ω * t) - - b = h_0 * ((x[1])^2 + (x[2])^2) / a^2 - - H = sigma * h_0 / a^2 * (2 * x[1] * cos(ω * t) + 2 * x[2] * sin(ω * t) - sigma) + h_0 - - # It is mandatory to shift the water level at dry areas to make sure the water height h - # stays positive. The system would not be stable for h set to a hard 0 due to division by h in - # the computation of velocity, e.g., (h v1) / h. Therefore, a small dry state threshold - # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above - # for the ShallowWaterEquations and added to the initial condition if h = 0. - # This default value can be changed within the constructor call depending on the simulation setup. - H = max(H, b + equations.threshold_limiter) - return prim2cons(SVector(H, v1, v2, b), equations) +function initial_condition_parabolic_bowl(x, t, equations::ShallowWaterEquations2D) + a = 1.0 + h_0 = 0.1 + sigma = 0.5 + ω = sqrt(2 * equations.gravity * h_0) / a + + v1 = -sigma * ω * sin(ω * t) + v2 = sigma * ω * cos(ω * t) + + b = h_0 * ((x[1])^2 + (x[2])^2) / a^2 + + H = sigma * h_0 / a^2 * (2 * x[1] * cos(ω * t) + 2 * x[2] * sin(ω * t) - sigma) + h_0 + + # It is mandatory to shift the water level at dry areas to make sure the water height h + # stays positive. The system would not be stable for h set to a hard 0 due to division by h in + # the computation of velocity, e.g., (h v1) / h. Therefore, a small dry state threshold + # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above + # for the ShallowWaterEquations and added to the initial condition if h = 0. + # This default value can be changed within the constructor call depending on the simulation setup. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v1, v2, b), equations) end initial_condition = initial_condition_parabolic_bowl - ############################################################################### # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, + hydrostatic_reconstruction_chen_noelle), flux_nonconservative_chen_noelle) basis = LobattoLegendreBasis(4) indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, - alpha_max=0.6, - alpha_min=0.001, - alpha_smooth=true, - variable=waterheight_pressure) + alpha_max = 0.6, + alpha_min = 0.001, + alpha_smooth = true, + variable = waterheight_pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) - ############################################################################### coordinates_min = (-2.0, -2.0) @@ -96,24 +95,25 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false, - extra_analysis_integrals=(energy_kinetic, - energy_internal)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = false, + extra_analysis_integrals = (energy_kinetic, + energy_internal)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) -stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) +stage_limiter! = PositivityPreservingLimiterShallowWater(variables = (Trixi.waterheight,)) ############################################################################### # run the simulation sol = solve(ode, SSPRK43(stage_limiter!); - ode_default_options()..., callback=callbacks); + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/structured_2d_dgsem/elixir_shallowwater_source_terms.jl b/examples/structured_2d_dgsem/elixir_shallowwater_source_terms.jl index 18f48080850..48fe37b9996 100644 --- a/examples/structured_2d_dgsem/elixir_shallowwater_source_terms.jl +++ b/examples/structured_2d_dgsem/elixir_shallowwater_source_terms.jl @@ -5,13 +5,14 @@ using Trixi ############################################################################### # semidiscretization of the shallow water equations -equations = ShallowWaterEquations2D(gravity_constant=9.81) +equations = ShallowWaterEquations2D(gravity_constant = 9.81) initial_condition = initial_condition_convergence_test volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -solver = DGSEM(polydeg=3, surface_flux=(flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, + surface_flux = (flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (0.0, 0.0) coordinates_max = (sqrt(2.0), sqrt(2.0)) @@ -20,10 +21,8 @@ cells_per_dimension = (8, 8) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) - semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -34,16 +33,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=2.0) +stepsize_callback = StepsizeCallback(cfl = 2.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -53,7 +52,7 @@ callbacks = CallbackSet(summary_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); +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/structured_2d_dgsem/elixir_shallowwater_well_balanced.jl b/examples/structured_2d_dgsem/elixir_shallowwater_well_balanced.jl index 17836fa6b8f..61dd252fd83 100644 --- a/examples/structured_2d_dgsem/elixir_shallowwater_well_balanced.jl +++ b/examples/structured_2d_dgsem/elixir_shallowwater_well_balanced.jl @@ -7,21 +7,21 @@ using Trixi # semidiscretization of the shallow water equations with a discontinuous # bottom topography function (set in the initial conditions) -equations = ShallowWaterEquations2D(gravity_constant=9.81, H0=3.0) +equations = ShallowWaterEquations2D(gravity_constant = 9.81, H0 = 3.0) # An initial condition with constant total water height and zero velocities to test well-balancedness. # Note, this routine is used to compute errors in the analysis callback but the initialization is # overwritten by `initial_condition_discontinuous_well_balancedness` below. function initial_condition_well_balancedness(x, t, equations::ShallowWaterEquations2D) - # Set the background values - H = equations.H0 - v1 = 0.0 - v2 = 0.0 - # bottom topography taken from Pond.control in [HOHQMesh](https://github.com/trixi-framework/HOHQMesh) - x1, x2 = x - b = ( 1.5 / exp( 0.5 * ((x1 - 1.0)^2 + (x2 - 1.0)^2) ) - + 0.75 / exp( 0.5 * ((x1 + 1.0)^2 + (x2 + 1.0)^2) ) ) - return prim2cons(SVector(H, v1, v2, b), equations) + # Set the background values + H = equations.H0 + v1 = 0.0 + v2 = 0.0 + # bottom topography taken from Pond.control in [HOHQMesh](https://github.com/trixi-framework/HOHQMesh) + x1, x2 = x + b = (1.5 / exp(0.5 * ((x1 - 1.0)^2 + (x2 - 1.0)^2)) + + 0.75 / exp(0.5 * ((x1 + 1.0)^2 + (x2 + 1.0)^2))) + return prim2cons(SVector(H, v1, v2, b), equations) end initial_condition = initial_condition_well_balancedness @@ -30,16 +30,17 @@ initial_condition = initial_condition_well_balancedness # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -surface_flux = (FluxHydrostaticReconstruction(flux_lax_friedrichs, hydrostatic_reconstruction_audusse_etal), +surface_flux = (FluxHydrostaticReconstruction(flux_lax_friedrichs, + hydrostatic_reconstruction_audusse_etal), flux_nonconservative_audusse_etal) -solver = DGSEM(polydeg=4, surface_flux=surface_flux, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 4, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # This setup a structured periodic mesh coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) cells_per_dimension = (4, 4) @@ -64,30 +65,33 @@ ode = semidiscretize(semi, tspan) # 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_discontinuous_well_balancedness(x, t, element_id, equations::ShallowWaterEquations2D) - # Set the background values - H = equations.H0 - v1 = 0.0 - v2 = 0.0 - b = 0.0 - - # Setup a discontinuous bottom topography using the element id number - if element_id == 7 - b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) + 0.5 * cos(2.0 * pi * x[2]) - end - - return prim2cons(SVector(H, v1, v2, b), equations) +function initial_condition_discontinuous_well_balancedness(x, t, element_id, + equations::ShallowWaterEquations2D) + # Set the background values + H = equations.H0 + v1 = 0.0 + v2 = 0.0 + b = 0.0 + + # Setup a discontinuous bottom topography using the element id number + if element_id == 7 + b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) + 0.5 * cos(2.0 * pi * 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_discontinuous_well_balancedness(x_node, first(tspan), element, equations) - Trixi.set_node_vars!(u, u_node, equations, semi.solver, i, j, element) - end + 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_discontinuous_well_balancedness(x_node, first(tspan), + element, equations) + Trixi.set_node_vars!(u, u_node, equations, semi.solver, i, j, element) + end end ############################################################################### @@ -96,16 +100,16 @@ end summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(lake_at_rest_error,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (lake_at_rest_error,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=3.0) +stepsize_callback = StepsizeCallback(cfl = 3.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) @@ -113,7 +117,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav ############################################################################### # 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); +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/structured_2d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl b/examples/structured_2d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl index b18b02e0b4c..8e492b1ba05 100644 --- a/examples/structured_2d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl +++ b/examples/structured_2d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl @@ -8,8 +8,7 @@ using Printf: @printf, @sprintf # # TODO: TrixiShallowWater: wet/dry example elixir - -equations = ShallowWaterEquations2D(gravity_constant=9.812) +equations = ShallowWaterEquations2D(gravity_constant = 9.812) """ initial_condition_well_balanced_chen_noelle(x, t, equations:: ShallowWaterEquations2D) @@ -24,29 +23,30 @@ The initial condition is taken from Section 5.2 of the paper: A new hydrostatic reconstruction scheme based on subcell reconstructions [DOI:10.1137/15M1053074](https://dx.doi.org/10.1137/15M1053074) """ -function initial_condition_complex_bottom_well_balanced(x, t, equations:: ShallowWaterEquations2D) - v1 = 0 - v2 = 0 - b = sin(4 * pi * x[1]) + 3 - - if x[1] >= 0.5 - b = sin(4 * pi * x[1]) + 1 - end - - H = max(b, 2.5) - - if x[1] >= 0.5 - H = max(b, 1.5) - end - - # It is mandatory to shift the water level at dry areas to make sure the water height h - # stays positive. The system would not be stable for h set to a hard 0 due to division by h in - # the computation of velocity, e.g., (h v1) / h. Therefore, a small dry state threshold - # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above - # for the ShallowWaterEquations and added to the initial condition if h = 0. - # This default value can be changed within the constructor call depending on the simulation setup. - H = max(H, b + equations.threshold_limiter) - return prim2cons(SVector(H, v1, v2, b), equations) +function initial_condition_complex_bottom_well_balanced(x, t, + equations::ShallowWaterEquations2D) + v1 = 0 + v2 = 0 + b = sin(4 * pi * x[1]) + 3 + + if x[1] >= 0.5 + b = sin(4 * pi * x[1]) + 1 + end + + H = max(b, 2.5) + + if x[1] >= 0.5 + H = max(b, 1.5) + end + + # It is mandatory to shift the water level at dry areas to make sure the water height h + # stays positive. The system would not be stable for h set to a hard 0 due to division by h in + # the computation of velocity, e.g., (h v1) / h. Therefore, a small dry state threshold + # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above + # for the ShallowWaterEquations and added to the initial condition if h = 0. + # This default value can be changed within the constructor call depending on the simulation setup. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v1, v2, b), equations) end initial_condition = initial_condition_complex_bottom_well_balanced @@ -56,23 +56,23 @@ initial_condition = initial_condition_complex_bottom_well_balanced volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, + hydrostatic_reconstruction_chen_noelle), flux_nonconservative_chen_noelle) basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=waterheight_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = waterheight_pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) - ############################################################################### # Create the StructuredMesh for the domain [0, 1]^2 @@ -83,7 +83,6 @@ cells_per_dimension = (16, 16) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) - # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -107,18 +106,20 @@ ode = semidiscretize(semi, tspan) 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) - # We know that the discontinuity is a vertical line. Slightly augment the x value by a factor - # of unit roundoff to avoid the repeted value from the LGL nodes at at interface. - if i == 1 - x_node = SVector(nextfloat(x_node[1]) , x_node[2]) - elseif i == nnodes(semi.solver) - x_node = SVector(prevfloat(x_node[1]) , x_node[2]) + 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) + # We know that the discontinuity is a vertical line. Slightly augment the x value by a factor + # of unit roundoff to avoid the repeted value from the LGL nodes at at interface. + if i == 1 + x_node = SVector(nextfloat(x_node[1]), x_node[2]) + elseif i == nnodes(semi.solver) + x_node = SVector(prevfloat(x_node[1]), x_node[2]) + end + u_node = initial_condition_complex_bottom_well_balanced(x_node, first(tspan), + equations) + Trixi.set_node_vars!(u, u_node, equations, semi.solver, i, j, element) end - u_node = initial_condition_complex_bottom_well_balanced(x_node, first(tspan), equations) - Trixi.set_node_vars!(u, u_node, equations, semi.solver, i, j, element) - end end ############################################################################### @@ -127,25 +128,27 @@ end summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = false) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) -callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, + stepsize_callback) -stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) +stage_limiter! = PositivityPreservingLimiterShallowWater(variables = (Trixi.waterheight,)) ############################################################################### # run the simulation -sol = solve(ode, SSPRK43(stage_limiter!); dt=1.0, - ode_default_options()..., callback=callbacks, adaptive=false); +sol = solve(ode, SSPRK43(stage_limiter!); dt = 1.0, + ode_default_options()..., callback = callbacks, adaptive = false); summary_callback() # print the timer summary @@ -160,39 +163,43 @@ summary_callback() # print the timer summary function lake_at_rest_error_two_level(u, x, equations::ShallowWaterEquations2D) h, _, _, b = u - # For well-balancedness testing with possible wet/dry regions the reference - # water height `H0` accounts for the possibility that the bottom topography - # can emerge out of the water as well as for the threshold offset to avoid - # division by a "hard" zero water heights as well. - if x[1] < 0.5 - H0_wet_dry = max( 2.5 , b + equations.threshold_limiter ) - else - H0_wet_dry = max( 1.5 , b + equations.threshold_limiter ) - end - - return abs(H0_wet_dry - (h + b)) + # For well-balancedness testing with possible wet/dry regions the reference + # water height `H0` accounts for the possibility that the bottom topography + # can emerge out of the water as well as for the threshold offset to avoid + # division by a "hard" zero water heights as well. + if x[1] < 0.5 + H0_wet_dry = max(2.5, b + equations.threshold_limiter) + else + H0_wet_dry = max(1.5, b + equations.threshold_limiter) + end + + return abs(H0_wet_dry - (h + b)) end # point to the data we want to analyze u = Trixi.wrap_array(sol[end], semi) # Perform the actual integration of the well-balancedness error over the domain -l1_well_balance_error = Trixi.integrate_via_indices(u, mesh, equations, semi.solver, semi.cache; normalize=true) do u, i, j, element, equations, solver - x_node = Trixi.get_node_coords(semi.cache.elements.node_coordinates, equations, solver, i, j, element) - # We know that the discontinuity is a vertical line. Slightly augment the x value by a factor - # of unit roundoff to avoid the repeted value from the LGL nodes at at interface. - if i == 1 - x_node = SVector(nextfloat(x_node[1]) , x_node[2]) - elseif i == nnodes(semi.solver) - x_node = SVector(prevfloat(x_node[1]) , x_node[2]) - end - u_local = Trixi.get_node_vars(u, equations, solver, i, j, element) - return lake_at_rest_error_two_level(u_local, x_node, equations) +l1_well_balance_error = Trixi.integrate_via_indices(u, mesh, equations, semi.solver, + semi.cache; + normalize = true) do u, i, j, element, + equations, solver + x_node = Trixi.get_node_coords(semi.cache.elements.node_coordinates, equations, solver, + i, j, element) + # We know that the discontinuity is a vertical line. Slightly augment the x value by a factor + # of unit roundoff to avoid the repeted value from the LGL nodes at at interface. + if i == 1 + x_node = SVector(nextfloat(x_node[1]), x_node[2]) + elseif i == nnodes(semi.solver) + x_node = SVector(prevfloat(x_node[1]), x_node[2]) + end + u_local = Trixi.get_node_vars(u, equations, solver, i, j, element) + return lake_at_rest_error_two_level(u_local, x_node, equations) end # report the well-balancedness lake-at-rest error to the screen println("─"^100) println(" Lake-at-rest error for '", Trixi.get_name(equations), "' with ", summary(solver), - " at final time " * @sprintf("%10.8e", tspan[end])) + " at final time " * @sprintf("%10.8e", tspan[end])) @printf(" %-12s:", Trixi.pretty_form_utf(lake_at_rest_error)) @printf(" % 10.8e", l1_well_balance_error) diff --git a/examples/structured_3d_dgsem/elixir_advection_basic.jl b/examples/structured_3d_dgsem/elixir_advection_basic.jl index 47ae6352485..5b0bb371fe8 100644 --- a/examples/structured_3d_dgsem/elixir_advection_basic.jl +++ b/examples/structured_3d_dgsem/elixir_advection_basic.jl @@ -11,18 +11,18 @@ advection_velocity = (0.2, -0.7, 0.5) equations = LinearScalarAdvectionEquation3D(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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -1.0, -1.0) # minimum coordinates (min(x), min(y), min(z)) -coordinates_max = ( 1.0, 1.0, 1.0) # maximum coordinates (max(x), max(y), max(z)) +coordinates_max = (1.0, 1.0, 1.0) # maximum coordinates (max(x), max(y), max(z)) cells_per_dimension = (8, 8, 8) # Create curved mesh with 8 x 8 x 8 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) - +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, + solver) ############################################################################### # ODE solvers, callbacks etc. @@ -35,30 +35,30 @@ ode = semidiscretize(semi, (0.0, 1.0)); summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +save_solution = SaveSolutionCallback(interval = 100, + solution_variables = cons2prim) # The SaveRestartCallback allows to save a file from which a Trixi.jl simulation can be restarted -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) # The StepsizeCallback handles the re-calculation of the maximum Δt after each time step -stepsize_callback = StepsizeCallback(cfl=1.2) +stepsize_callback = StepsizeCallback(cfl = 1.2) # 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, save_restart, stepsize_callback) - +callbacks = CallbackSet(summary_callback, analysis_callback, save_solution, save_restart, + 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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/structured_3d_dgsem/elixir_advection_free_stream.jl b/examples/structured_3d_dgsem/elixir_advection_free_stream.jl index 749233b8c68..12d52f15160 100644 --- a/examples/structured_3d_dgsem/elixir_advection_free_stream.jl +++ b/examples/structured_3d_dgsem/elixir_advection_free_stream.jl @@ -13,24 +13,27 @@ solver = DGSEM(3, flux_lax_friedrichs) # Mapping as described in https://arxiv.org/abs/2012.12040 function mapping(xi_, eta_, zeta_) - # Transform input variables between -1 and 1 onto [0,3] - xi = 1.5 * xi_ + 1.5 - eta = 1.5 * eta_ + 1.5 - zeta = 1.5 * zeta_ + 1.5 - - y = eta + 3/8 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - x = xi + 3/8 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - z = zeta + 3/8 * (cos(0.5 * pi * (2 * x - 3)/3) * - cos(pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - return SVector(x, y, z) + # Transform input variables between -1 and 1 onto [0,3] + xi = 1.5 * xi_ + 1.5 + eta = 1.5 * eta_ + 1.5 + zeta = 1.5 * zeta_ + 1.5 + + y = eta + + 3 / 8 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + x = xi + + 3 / 8 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + z = zeta + + 3 / 8 * (cos(0.5 * pi * (2 * x - 3) / 3) * + cos(pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + return SVector(x, y, z) end cells_per_dimension = (8, 8, 8) @@ -41,7 +44,6 @@ mesh = StructuredMesh(cells_per_dimension, mapping) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_constant, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -53,26 +55,26 @@ ode = semidiscretize(semi, (0.0, 1.0)); summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +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=2.0) +stepsize_callback = StepsizeCallback(cfl = 2.0) # 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) - +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/structured_3d_dgsem/elixir_advection_nonperiodic_curved.jl b/examples/structured_3d_dgsem/elixir_advection_nonperiodic_curved.jl index fa8ae756566..1a20a9c8533 100644 --- a/examples/structured_3d_dgsem/elixir_advection_nonperiodic_curved.jl +++ b/examples/structured_3d_dgsem/elixir_advection_nonperiodic_curved.jl @@ -11,36 +11,38 @@ equations = LinearScalarAdvectionEquation3D(advection_velocity) initial_condition = initial_condition_convergence_test boundary_conditions = BoundaryConditionDirichlet(initial_condition) -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) # Mapping as described in https://arxiv.org/abs/2012.12040 but with less warping. function mapping(xi, eta, zeta) - # Don't transform input variables between -1 and 1 onto [0,3] to obtain curved boundaries - # xi = 1.5 * xi_ + 1.5 - # eta = 1.5 * eta_ + 1.5 - # zeta = 1.5 * zeta_ + 1.5 - - y = eta + 1/6 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - x = xi + 1/6 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - z = zeta + 1/6 * (cos(0.5 * pi * (2 * x - 3)/3) * - cos(pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - return SVector(x, y, z) + # Don't transform input variables between -1 and 1 onto [0,3] to obtain curved boundaries + # xi = 1.5 * xi_ + 1.5 + # eta = 1.5 * eta_ + 1.5 + # zeta = 1.5 * zeta_ + 1.5 + + y = eta + + 1 / 6 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + x = xi + + 1 / 6 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + z = zeta + + 1 / 6 * (cos(0.5 * pi * (2 * x - 3) / 3) * + cos(pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + return SVector(x, y, z) end cells_per_dimension = (8, 8, 8) -mesh = StructuredMesh(cells_per_dimension, mapping, periodicity=false) +mesh = StructuredMesh(cells_per_dimension, mapping, periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -51,20 +53,20 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.2) +stepsize_callback = StepsizeCallback(cfl = 1.2) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -76,7 +78,7 @@ callbacks = CallbackSet(summary_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); +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/structured_3d_dgsem/elixir_advection_restart.jl b/examples/structured_3d_dgsem/elixir_advection_restart.jl index 921c5310340..e81ad5d6430 100644 --- a/examples/structured_3d_dgsem/elixir_advection_restart.jl +++ b/examples/structured_3d_dgsem/elixir_advection_restart.jl @@ -6,8 +6,7 @@ using Trixi # create a restart file trixi_include(@__MODULE__, joinpath(@__DIR__, "elixir_advection_basic.jl"), - cells_per_dimension=(4, 4, 4)) - + cells_per_dimension = (4, 4, 4)) ############################################################################### # adapt the parameters that have changed compared to "elixir_advection_extended.jl" @@ -18,7 +17,8 @@ trixi_include(@__MODULE__, joinpath(@__DIR__, "elixir_advection_basic.jl"), restart_filename = joinpath("out", "restart_000010.h5") mesh = load_mesh(restart_filename) -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, solver) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, + solver) tspan = (load_time(restart_filename), 2.0) dt = load_dt(restart_filename) @@ -27,14 +27,13 @@ ode = semidiscretize(semi, tspan, restart_filename); # Do not overwrite the initial snapshot written by elixir_advection_extended.jl. save_solution.condition.save_initial_solution = false -integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=dt, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +integrator = init(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); # Get the last time index and work with that. load_timestep!(integrator, restart_filename) - ############################################################################### # run the simulation diff --git a/examples/structured_3d_dgsem/elixir_euler_ec.jl b/examples/structured_3d_dgsem/elixir_euler_ec.jl index 0009eb31180..1330006760e 100644 --- a/examples/structured_3d_dgsem/elixir_euler_ec.jl +++ b/examples/structured_3d_dgsem/elixir_euler_ec.jl @@ -5,7 +5,7 @@ using Trixi ############################################################################### # semidiscretization of the compressible Euler equations -equations = CompressibleEulerEquations3D(5/3) +equations = CompressibleEulerEquations3D(5 / 3) initial_condition = initial_condition_weak_blast_wave @@ -13,32 +13,35 @@ initial_condition = initial_condition_weak_blast_wave # Get the DG approximation space volume_flux = flux_ranocha -solver = DGSEM(polydeg=5, surface_flux=flux_ranocha, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 5, surface_flux = flux_ranocha, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the curved quad mesh from a file # Mapping as described in https://arxiv.org/abs/2012.12040 function mapping(xi_, eta_, zeta_) - # Transform input variables between -1 and 1 onto [0,3] - xi = 1.5 * xi_ + 1.5 - eta = 1.5 * eta_ + 1.5 - zeta = 1.5 * zeta_ + 1.5 - - y = eta + 3/8 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - x = xi + 3/8 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - z = zeta + 3/8 * (cos(0.5 * pi * (2 * x - 3)/3) * - cos(pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - return SVector(x, y, z) + # Transform input variables between -1 and 1 onto [0,3] + xi = 1.5 * xi_ + 1.5 + eta = 1.5 * eta_ + 1.5 + zeta = 1.5 * zeta_ + 1.5 + + y = eta + + 3 / 8 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + x = xi + + 3 / 8 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + z = zeta + + 3 / 8 * (cos(0.5 * pi * (2 * x - 3) / 3) * + cos(pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + return SVector(x, y, z) end cells_per_dimension = (4, 4, 4) @@ -59,15 +62,15 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -78,7 +81,7 @@ callbacks = CallbackSet(summary_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); +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/structured_3d_dgsem/elixir_euler_free_stream.jl b/examples/structured_3d_dgsem/elixir_euler_free_stream.jl index b0e71435767..1b01287100e 100644 --- a/examples/structured_3d_dgsem/elixir_euler_free_stream.jl +++ b/examples/structured_3d_dgsem/elixir_euler_free_stream.jl @@ -9,29 +9,32 @@ equations = CompressibleEulerEquations3D(1.4) initial_condition = initial_condition_constant -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs, - volume_integral=VolumeIntegralWeakForm()) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralWeakForm()) # Mapping as described in https://arxiv.org/abs/2012.12040 function mapping(xi_, eta_, zeta_) - # Transform input variables between -1 and 1 onto [0,3] - xi = 1.5 * xi_ + 1.5 - eta = 1.5 * eta_ + 1.5 - zeta = 1.5 * zeta_ + 1.5 - - y = eta + 3/8 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - x = xi + 3/8 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - z = zeta + 3/8 * (cos(0.5 * pi * (2 * x - 3)/3) * - cos(pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - return SVector(x, y, z) + # Transform input variables between -1 and 1 onto [0,3] + xi = 1.5 * xi_ + 1.5 + eta = 1.5 * eta_ + 1.5 + zeta = 1.5 * zeta_ + 1.5 + + y = eta + + 3 / 8 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + x = xi + + 3 / 8 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + z = zeta + + 3 / 8 * (cos(0.5 * pi * (2 * x - 3) / 3) * + cos(pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + return SVector(x, y, z) end cells_per_dimension = (4, 4, 4) @@ -40,7 +43,6 @@ mesh = StructuredMesh(cells_per_dimension, mapping) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -50,30 +52,29 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.3) +stepsize_callback = StepsizeCallback(cfl = 1.3) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_restart, save_solution, 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); +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/structured_3d_dgsem/elixir_euler_sedov.jl b/examples/structured_3d_dgsem/elixir_euler_sedov.jl index e0595437c99..1f2d9d2eeb6 100644 --- a/examples/structured_3d_dgsem/elixir_euler_sedov.jl +++ b/examples/structured_3d_dgsem/elixir_euler_sedov.jl @@ -14,28 +14,29 @@ The Sedov blast wave setup based on Flash - https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 with smaller strength of the initial discontinuity. """ -function initial_condition_medium_sedov_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) - - # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 - r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) - E = 1.0 - p0_inner = 3 * (equations.gamma - 1) * E / (4 * pi * r0^2) - p0_outer = 1.0e-3 - - # Calculate primitive variables - rho = 1.0 - 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) +function initial_condition_medium_sedov_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) + + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 + r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) + E = 1.0 + p0_inner = 3 * (equations.gamma - 1) * E / (4 * pi * r0^2) + p0_outer = 1.0e-3 + + # Calculate primitive variables + rho = 1.0 + 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_medium_sedov_blast_wave @@ -45,30 +46,31 @@ volume_flux = flux_ranocha polydeg = 3 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=1.0, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) -solver = DGSEM(polydeg=polydeg, surface_flux=surface_flux, volume_integral=volume_integral) +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral) # Mapping as described in https://arxiv.org/abs/2012.12040 function mapping(xi, eta, zeta) - y = eta + 0.125 * (cos(1.5 * pi * xi) * cos(0.5 * pi * eta) * cos(0.5 * pi * zeta)) + y = eta + 0.125 * (cos(1.5 * pi * xi) * cos(0.5 * pi * eta) * cos(0.5 * pi * zeta)) - x = xi + 0.125 * (cos(0.5 * pi * xi) * cos(2 * pi * y) * cos(0.5 * pi * zeta)) + x = xi + 0.125 * (cos(0.5 * pi * xi) * cos(2 * pi * y) * cos(0.5 * pi * zeta)) - z = zeta + 0.125 * (cos(0.5 * pi * x) * cos(pi * y) * cos(0.5 * pi * zeta)) + z = zeta + 0.125 * (cos(0.5 * pi * x) * cos(pi * y) * cos(0.5 * pi * zeta)) - return SVector(x, y, z) + return SVector(x, y, z) end cells_per_dimension = (4, 4, 4) -mesh = StructuredMesh(cells_per_dimension, mapping, periodicity=true) +mesh = StructuredMesh(cells_per_dimension, mapping, periodicity = true) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -82,15 +84,15 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -101,7 +103,7 @@ callbacks = CallbackSet(summary_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); +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/structured_3d_dgsem/elixir_euler_source_terms.jl b/examples/structured_3d_dgsem/elixir_euler_source_terms.jl index d8c6ea4bb83..ebf1336c12c 100644 --- a/examples/structured_3d_dgsem/elixir_euler_source_terms.jl +++ b/examples/structured_3d_dgsem/elixir_euler_source_terms.jl @@ -11,8 +11,8 @@ equations = CompressibleEulerEquations3D(1.4) initial_condition = initial_condition_convergence_test -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs, - volume_integral=VolumeIntegralWeakForm()) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralWeakForm()) # coordinates_min = (0.0, 0.0, 0.0) # coordinates_max = (2.0, 2.0, 2.0) @@ -28,8 +28,7 @@ cells_per_dimension = (4, 4, 4) mesh = StructuredMesh(cells_per_dimension, (f1, f2, f3, f4, f5, f6)) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -40,27 +39,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.6) +stepsize_callback = StepsizeCallback(cfl = 0.6) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/structured_3d_dgsem/elixir_euler_source_terms_nonperiodic_curved.jl b/examples/structured_3d_dgsem/elixir_euler_source_terms_nonperiodic_curved.jl index 8ddfd426553..eb358fa5da1 100644 --- a/examples/structured_3d_dgsem/elixir_euler_source_terms_nonperiodic_curved.jl +++ b/examples/structured_3d_dgsem/elixir_euler_source_terms_nonperiodic_curved.jl @@ -12,46 +12,48 @@ initial_condition = initial_condition_convergence_test # you can either use a single function to impose the BCs weakly in all # 2*ndims == 4 directions or you can pass a tuple containing BCs for each direction boundary_condition = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = (x_neg=boundary_condition, - x_pos=boundary_condition, - y_neg=boundary_condition, - y_pos=boundary_condition, - z_neg=boundary_condition, - z_pos=boundary_condition,) +boundary_conditions = (x_neg = boundary_condition, + x_pos = boundary_condition, + y_neg = boundary_condition, + y_pos = boundary_condition, + z_neg = boundary_condition, + z_pos = boundary_condition) -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs, - volume_integral=VolumeIntegralWeakForm()) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralWeakForm()) # Mapping as described in https://arxiv.org/abs/2012.12040 but with less warping. function mapping(xi, eta, zeta) - # Don't transform input variables between -1 and 1 onto [0,3] to obtain curved boundaries - # xi = 1.5 * xi_ + 1.5 - # eta = 1.5 * eta_ + 1.5 - # zeta = 1.5 * zeta_ + 1.5 - - y = eta + 1/6 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - x = xi + 1/6 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - z = zeta + 1/6 * (cos(0.5 * pi * (2 * x - 3)/3) * - cos(pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - # Transform the weird deformed cube to be approximately the cube [0,2]^3 - return SVector(x + 1, y + 1, z + 1) + # Don't transform input variables between -1 and 1 onto [0,3] to obtain curved boundaries + # xi = 1.5 * xi_ + 1.5 + # eta = 1.5 * eta_ + 1.5 + # zeta = 1.5 * zeta_ + 1.5 + + y = eta + + 1 / 6 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + x = xi + + 1 / 6 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + z = zeta + + 1 / 6 * (cos(0.5 * pi * (2 * x - 3) / 3) * + cos(pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + # Transform the weird deformed cube to be approximately the cube [0,2]^3 + return SVector(x + 1, y + 1, z + 1) end cells_per_dimension = (4, 4, 4) -mesh = StructuredMesh(cells_per_dimension, mapping, periodicity=false) +mesh = StructuredMesh(cells_per_dimension, mapping, periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test, - boundary_conditions=boundary_conditions) - + source_terms = source_terms_convergence_test, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -62,27 +64,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.6) +stepsize_callback = StepsizeCallback(cfl = 0.6) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/structured_3d_dgsem/elixir_mhd_alfven_wave.jl b/examples/structured_3d_dgsem/elixir_mhd_alfven_wave.jl index f4da8ee9470..6eb35078ef4 100644 --- a/examples/structured_3d_dgsem/elixir_mhd_alfven_wave.jl +++ b/examples/structured_3d_dgsem/elixir_mhd_alfven_wave.jl @@ -5,13 +5,13 @@ using Trixi ############################################################################### # semidiscretization of the compressible ideal GLM-MHD equations -equations = IdealGlmMhdEquations3D(5/3) +equations = IdealGlmMhdEquations3D(5 / 3) initial_condition = initial_condition_convergence_test volume_flux = (flux_central, flux_nonconservative_powell) -solver = DGSEM(polydeg=5, surface_flux=(flux_hll, flux_nonconservative_powell), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 5, surface_flux = (flux_hll, flux_nonconservative_powell), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) # Create the mesh # Note, we use the domain [-1, 1]^3 for the Alfvén wave convergence test case so the @@ -19,13 +19,13 @@ solver = DGSEM(polydeg=5, surface_flux=(flux_hll, flux_nonconservative_powell), # Mapping as described in https://arxiv.org/abs/2012.12040 function mapping(xi, eta, zeta) - y = eta + 0.125 * (cos(1.5 * pi * xi) * cos(0.5 * pi * eta) * cos(0.5 * pi * zeta)) + y = eta + 0.125 * (cos(1.5 * pi * xi) * cos(0.5 * pi * eta) * cos(0.5 * pi * zeta)) - x = xi + 0.125 * (cos(0.5 * pi * xi) * cos(2 * pi * y) * cos(0.5 * pi * zeta)) + x = xi + 0.125 * (cos(0.5 * pi * xi) * cos(2 * pi * y) * cos(0.5 * pi * zeta)) - z = zeta + 0.125 * (cos(0.5 * pi * x) * cos(pi * y) * cos(0.5 * pi * zeta)) + z = zeta + 0.125 * (cos(0.5 * pi * x) * cos(pi * y) * cos(0.5 * pi * zeta)) - return SVector(x, y, z) + return SVector(x, y, z) end cells_per_dimension = (4, 4, 4) @@ -43,18 +43,18 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) cfl = 1.2 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -62,11 +62,10 @@ callbacks = CallbackSet(summary_callback, stepsize_callback, glm_speed_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); +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/structured_3d_dgsem/elixir_mhd_ec.jl b/examples/structured_3d_dgsem/elixir_mhd_ec.jl index a8c2288e811..5b3cd6f3718 100644 --- a/examples/structured_3d_dgsem/elixir_mhd_ec.jl +++ b/examples/structured_3d_dgsem/elixir_mhd_ec.jl @@ -10,31 +10,35 @@ equations = IdealGlmMhdEquations3D(1.4) initial_condition = initial_condition_weak_blast_wave volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -solver = DGSEM(polydeg=3, surface_flux=(flux_hindenlang_gassner, flux_nonconservative_powell), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, + surface_flux = (flux_hindenlang_gassner, flux_nonconservative_powell), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) # Create a heavily warped curved mesh # Mapping as described in https://arxiv.org/abs/2012.12040 function mapping(xi_, eta_, zeta_) - # Transform input variables between -1 and 1 onto [0,3] - xi = 1.5 * xi_ + 1.5 - eta = 1.5 * eta_ + 1.5 - zeta = 1.5 * zeta_ + 1.5 - - y = eta + 3/8 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - x = xi + 3/8 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - z = zeta + 3/8 * (cos(0.5 * pi * (2 * x - 3)/3) * - cos(pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - return SVector(x, y, z) + # Transform input variables between -1 and 1 onto [0,3] + xi = 1.5 * xi_ + 1.5 + eta = 1.5 * eta_ + 1.5 + zeta = 1.5 * zeta_ + 1.5 + + y = eta + + 3 / 8 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + x = xi + + 3 / 8 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + z = zeta + + 3 / 8 * (cos(0.5 * pi * (2 * x - 3) / 3) * + cos(pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + return SVector(x, y, z) end cells_per_dimension = (4, 4, 4) @@ -52,19 +56,19 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) cfl = 1.4 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -72,11 +76,10 @@ callbacks = CallbackSet(summary_callback, stepsize_callback, glm_speed_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); +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/structured_3d_dgsem/elixir_mhd_ec_shockcapturing.jl b/examples/structured_3d_dgsem/elixir_mhd_ec_shockcapturing.jl index d669c2350a5..084e2ee962a 100644 --- a/examples/structured_3d_dgsem/elixir_mhd_ec_shockcapturing.jl +++ b/examples/structured_3d_dgsem/elixir_mhd_ec_shockcapturing.jl @@ -10,42 +10,46 @@ equations = IdealGlmMhdEquations3D(1.4) initial_condition = initial_condition_weak_blast_wave surface_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) +volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) polydeg = 4 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) -solver = DGSEM(polydeg=polydeg, surface_flux=surface_flux, volume_integral=volume_integral) +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral) # Create a heavily warped curved mesh # Mapping as described in https://arxiv.org/abs/2012.12040 function mapping(xi_, eta_, zeta_) - # Transform input variables between -1 and 1 onto [0,3] - xi = 1.5 * xi_ + 1.5 - eta = 1.5 * eta_ + 1.5 - zeta = 1.5 * zeta_ + 1.5 - - y = eta + 3/8 * (cos(1.5 * pi * (2 * xi - 3)/3) * - cos(0.5 * pi * (2 * eta - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - x = xi + 3/8 * (cos(0.5 * pi * (2 * xi - 3)/3) * - cos(2 * pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - z = zeta + 3/8 * (cos(0.5 * pi * (2 * x - 3)/3) * - cos(pi * (2 * y - 3)/3) * - cos(0.5 * pi * (2 * zeta - 3)/3)) - - return SVector(x, y, z) + # Transform input variables between -1 and 1 onto [0,3] + xi = 1.5 * xi_ + 1.5 + eta = 1.5 * eta_ + 1.5 + zeta = 1.5 * zeta_ + 1.5 + + y = eta + + 3 / 8 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + x = xi + + 3 / 8 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + z = zeta + + 3 / 8 * (cos(0.5 * pi * (2 * x - 3) / 3) * + cos(pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + return SVector(x, y, z) end cells_per_dimension = (8, 8, 8) @@ -63,25 +67,24 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) cfl = 1.4 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, stepsize_callback, glm_speed_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); +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_eulergravity_convergence.jl b/examples/t8code_2d_dgsem/elixir_eulergravity_convergence.jl index 32649eacff4..6d6bb27e0c3 100644 --- a/examples/t8code_2d_dgsem/elixir_eulergravity_convergence.jl +++ b/examples/t8code_2d_dgsem/elixir_eulergravity_convergence.jl @@ -22,9 +22,9 @@ mesh = T8codeMesh(trees_per_dimension, polydeg = 1, mapping = mapping, initial_refinement_level = 2) -semi_euler = SemidiscretizationHyperbolic(mesh, equations_euler, initial_condition, solver_euler, - source_terms=source_terms_eoc_test_coupled_euler_gravity) - +semi_euler = SemidiscretizationHyperbolic(mesh, equations_euler, initial_condition, + solver_euler, + source_terms = source_terms_eoc_test_coupled_euler_gravity) ############################################################################### # semidiscretization of the hyperbolic diffusion equations @@ -32,24 +32,23 @@ equations_gravity = HyperbolicDiffusionEquations2D() solver_gravity = DGSEM(polydeg, flux_lax_friedrichs) -semi_gravity = SemidiscretizationHyperbolic(mesh, equations_gravity, initial_condition, solver_gravity, - source_terms=source_terms_harmonic) - +semi_gravity = SemidiscretizationHyperbolic(mesh, equations_gravity, initial_condition, + solver_gravity, + source_terms = source_terms_harmonic) ############################################################################### # combining both semidiscretizations for Euler + self-gravity -parameters = ParametersEulerGravity(background_density=2.0, # aka rho0 +parameters = ParametersEulerGravity(background_density = 2.0, # aka rho0 # rho0 is (ab)used to add a "+8π" term to the source terms # for the manufactured solution - gravitational_constant=1.0, # aka G - cfl=1.1, - resid_tol=1.0e-10, - n_iterations_max=1000, - timestep_gravity=timestep_gravity_erk52_3Sstar!) + gravitational_constant = 1.0, # aka G + cfl = 1.1, + resid_tol = 1.0e-10, + n_iterations_max = 1000, + timestep_gravity = timestep_gravity_erk52_3Sstar!) semi = SemidiscretizationEulerGravity(semi_euler, semi_gravity, parameters) - ############################################################################### # ODE solvers, callbacks etc. tspan = (0.0, 0.5) @@ -57,21 +56,21 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) analysis_interval = 100 -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -analysis_callback = AnalysisCallback(semi_euler, interval=analysis_interval, - save_analysis=true) +analysis_callback = AnalysisCallback(semi_euler, interval = analysis_interval, + save_analysis = true) callbacks = CallbackSet(summary_callback, stepsize_callback, analysis_callback, alive_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); +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 println("Number of gravity subcycles: ", semi.gravity_counter.ncalls_since_readout) diff --git a/examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl b/examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl index 463f916fa2e..8040f79cafd 100644 --- a/examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl +++ b/examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl @@ -4,26 +4,26 @@ using Trixi ############################################################################### # Semidiscretization of the compressible ideal GLM-MHD equations. -gamma = 5/3 +gamma = 5 / 3 equations = IdealGlmMhdEquations2D(gamma) initial_condition = initial_condition_convergence_test # Get the DG approximation space volume_flux = (flux_central, flux_nonconservative_powell) -solver = DGSEM(polydeg=4, surface_flux=(flux_hll, flux_nonconservative_powell), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 4, surface_flux = (flux_hll, flux_nonconservative_powell), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) -coordinates_min = (0.0 , 0.0 ) +coordinates_min = (0.0, 0.0) coordinates_max = (sqrt(2.0), sqrt(2.0)) mapping = Trixi.coordinates2mapping(coordinates_min, coordinates_max) trees_per_dimension = (8, 8) -mesh = T8codeMesh(trees_per_dimension, polydeg=3, - mapping=mapping, - initial_refinement_level=0, periodicity=true) +mesh = T8codeMesh(trees_per_dimension, polydeg = 3, + mapping = mapping, + initial_refinement_level = 0, periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -36,14 +36,14 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) cfl = 0.9 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -54,7 +54,7 @@ callbacks = CallbackSet(summary_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); +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_shallowwater_source_terms.jl b/examples/t8code_2d_dgsem/elixir_shallowwater_source_terms.jl index c19f440ebc7..b2d5097036f 100644 --- a/examples/t8code_2d_dgsem/elixir_shallowwater_source_terms.jl +++ b/examples/t8code_2d_dgsem/elixir_shallowwater_source_terms.jl @@ -4,17 +4,17 @@ using Trixi ############################################################################### # Semidiscretization of the shallow water equations. -equations = ShallowWaterEquations2D(gravity_constant=9.81) +equations = ShallowWaterEquations2D(gravity_constant = 9.81) initial_condition = initial_condition_convergence_test # MMS EOC test - ############################################################################### # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -solver = DGSEM(polydeg=3, surface_flux=(flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, + surface_flux = (flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the P4estMesh and setup a periodic mesh @@ -26,14 +26,13 @@ mapping = Trixi.coordinates2mapping(coordinates_min, coordinates_max) trees_per_dimension = (8, 8) -mesh = T8codeMesh(trees_per_dimension, polydeg=3, - mapping=mapping, - initial_refinement_level=1) +mesh = T8codeMesh(trees_per_dimension, polydeg = 3, + mapping = mapping, + initial_refinement_level = 1) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -45,9 +44,9 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 500 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) @@ -55,6 +54,6 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) # run the simulation # use a Runge-Kutta method with automatic (error based) time step size control -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-8, reltol=1.0e-8, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-8, reltol = 1.0e-8, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_1d_dgsem/elixir_advection_amr.jl b/examples/tree_1d_dgsem/elixir_advection_amr.jl index dc371233bc8..1071c98ab7e 100644 --- a/examples/tree_1d_dgsem/elixir_advection_amr.jl +++ b/examples/tree_1d_dgsem/elixir_advection_amr.jl @@ -10,18 +10,16 @@ equations = LinearScalarAdvectionEquation1D(advection_velocity) initial_condition = initial_condition_gauss -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-5.0,) -coordinates_max = ( 5.0,) +coordinates_max = (5.0,) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=30_000) - + initial_refinement_level = 4, + n_cells_max = 30_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -31,37 +29,36 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable=first), - base_level=4, - med_level=5, med_threshold=0.1, - max_level=6, max_threshold=0.6) +amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first), + base_level = 4, + med_level = 5, med_threshold = 0.1, + max_level = 6, max_threshold = 0.6) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) 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); +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/tree_1d_dgsem/elixir_advection_amr_nonperiodic.jl b/examples/tree_1d_dgsem/elixir_advection_amr_nonperiodic.jl index 098deedb9d6..ff62e905429 100644 --- a/examples/tree_1d_dgsem/elixir_advection_amr_nonperiodic.jl +++ b/examples/tree_1d_dgsem/elixir_advection_amr_nonperiodic.jl @@ -11,21 +11,19 @@ equations = LinearScalarAdvectionEquation1D(advection_velocity) initial_condition = initial_condition_gauss boundary_conditions = BoundaryConditionDirichlet(initial_condition) -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0,) coordinates_max = (5.0,) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000, - periodicity=false) - + initial_refinement_level = 4, + n_cells_max = 10_000, + periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -36,40 +34,39 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable=first), - base_level=4, - med_level=5, med_threshold=0.1, - max_level=6, max_threshold=0.6) +amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first), + base_level = 4, + med_level = 5, med_threshold = 0.1, + max_level = 6, max_threshold = 0.6) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_restart, save_solution, amr_callback, stepsize_callback); - ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=stepsize_callback(ode), # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = stepsize_callback(ode), # 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/tree_1d_dgsem/elixir_advection_basic.jl b/examples/tree_1d_dgsem/elixir_advection_basic.jl index d61062c772e..cba522f6366 100644 --- a/examples/tree_1d_dgsem/elixir_advection_basic.jl +++ b/examples/tree_1d_dgsem/elixir_advection_basic.jl @@ -9,19 +9,19 @@ advection_velocity = 1.0 equations = LinearScalarAdvectionEquation1D(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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = -1.0 # minimum coordinate -coordinates_max = 1.0 # maximum coordinate +coordinates_max = 1.0 # maximum coordinate # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=30_000) # set maximum capacity of tree data structure + initial_refinement_level = 4, + n_cells_max = 30_000) # set maximum capacity of tree data structure # A semidiscretization collects data structures and functions for the spatial discretization -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, solver) - +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, + solver) ############################################################################### # ODE solvers, callbacks etc. @@ -34,26 +34,26 @@ ode = semidiscretize(semi, (0.0, 1.0)); summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +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.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) # 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) - +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/tree_1d_dgsem/elixir_advection_diffusion.jl b/examples/tree_1d_dgsem/elixir_advection_diffusion.jl index 0472bd25a71..72b8b3f1933 100644 --- a/examples/tree_1d_dgsem/elixir_advection_diffusion.jl +++ b/examples/tree_1d_dgsem/elixir_advection_diffusion.jl @@ -11,49 +11,52 @@ diffusivity() = 0.1 equations_parabolic = LaplaceDiffusion1D(diffusivity(), equations) # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = -pi # minimum coordinate -coordinates_max = pi # maximum coordinate +coordinates_max = pi # maximum coordinate # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=30_000, # set maximum capacity of tree data structure - periodicity=true) - -function x_trans_periodic(x, domain_length = SVector(2*pi), center = SVector(0.0)) - x_normalized = x .- center - x_shifted = x_normalized .% domain_length - x_offset = ((x_shifted .< -0.5*domain_length) - (x_shifted .> 0.5*domain_length)) .* domain_length - return center + x_shifted + x_offset + initial_refinement_level = 4, + n_cells_max = 30_000, # set maximum capacity of tree data structure + periodicity = true) + +function x_trans_periodic(x, domain_length = SVector(2 * pi), center = SVector(0.0)) + x_normalized = x .- center + x_shifted = x_normalized .% domain_length + x_offset = ((x_shifted .< -0.5 * domain_length) - (x_shifted .> 0.5 * domain_length)) .* + domain_length + return center + x_shifted + x_offset end # Define initial condition -function initial_condition_diffusive_convergence_test(x, t, equation::LinearScalarAdvectionEquation1D) - # Store translated coordinate for easy use of exact solution - x_trans = x_trans_periodic(x - equation.advection_velocity * t) - - nu = diffusivity() - c = 0.0 - A = 1.0 - L = 2 - f = 1/L - omega = 1.0 - scalar = c + A * sin(omega * sum(x_trans)) * exp(-nu * omega^2 * t) - return SVector(scalar) +function initial_condition_diffusive_convergence_test(x, t, + equation::LinearScalarAdvectionEquation1D) + # Store translated coordinate for easy use of exact solution + x_trans = x_trans_periodic(x - equation.advection_velocity * t) + + nu = diffusivity() + c = 0.0 + A = 1.0 + L = 2 + f = 1 / L + omega = 1.0 + scalar = c + A * sin(omega * sum(x_trans)) * exp(-nu * omega^2 * t) + return SVector(scalar) end initial_condition = initial_condition_diffusive_convergence_test - + # define periodic boundary conditions everywhere boundary_conditions = boundary_condition_periodic boundary_conditions_parabolic = boundary_condition_periodic # A semidiscretization collects data structures and functions for the spatial discretization -semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), - initial_condition_diffusive_convergence_test, solver; - boundary_conditions=(boundary_conditions, boundary_conditions_parabolic)) - +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition_diffusive_convergence_test, + solver; + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic)) ############################################################################### # ODE solvers, callbacks etc. @@ -67,23 +70,22 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +analysis_callback = AnalysisCallback(semi, interval = 100) # The AliveCallback prints short status information in regular intervals -alive_callback = AliveCallback(analysis_interval=100) +alive_callback = AliveCallback(analysis_interval = 100) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) - ############################################################################### # run the simulation # OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks time_int_tol = 1.0e-10 time_abs_tol = 1.0e-10 -sol = solve(ode, KenCarp4(autodiff=false), abstol=time_abs_tol, reltol=time_int_tol, - save_everystep=false, callback=callbacks) +sol = solve(ode, KenCarp4(autodiff = false), abstol = time_abs_tol, reltol = time_int_tol, + save_everystep = false, callback = callbacks) # Print the timer summary summary_callback() diff --git a/examples/tree_1d_dgsem/elixir_advection_extended.jl b/examples/tree_1d_dgsem/elixir_advection_extended.jl index 5c87ac7ef5c..df185834701 100644 --- a/examples/tree_1d_dgsem/elixir_advection_extended.jl +++ b/examples/tree_1d_dgsem/elixir_advection_extended.jl @@ -18,21 +18,20 @@ initial_condition = initial_condition_convergence_test boundary_conditions = boundary_condition_periodic # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = -1.0 # minimum coordinate -coordinates_max = 1.0 # maximum coordinate +coordinates_max = 1.0 # maximum coordinate # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=30_000, # set maximum capacity of tree data structure - periodicity=true) + initial_refinement_level = 4, + n_cells_max = 30_000, # set maximum capacity of tree data structure + periodicity = true) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -47,24 +46,24 @@ summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy, energy_total)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy, energy_total)) # The AliveCallback prints short status information in regular intervals -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) # The SaveRestartCallback allows to save a file from which a Trixi.jl simulation can be restarted -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) # The SaveSolutionCallback allows to save the solution to a file in regular intervals -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) # The StepsizeCallback handles the re-calculation of the maximum Δt after each time step -stepsize_callback = StepsizeCallback(cfl=1.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver callbacks = CallbackSet(summary_callback, @@ -72,14 +71,13 @@ callbacks = CallbackSet(summary_callback, save_restart, 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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/tree_1d_dgsem/elixir_advection_finite_volume.jl b/examples/tree_1d_dgsem/elixir_advection_finite_volume.jl index 28518e7276a..62701f3ecf5 100644 --- a/examples/tree_1d_dgsem/elixir_advection_finite_volume.jl +++ b/examples/tree_1d_dgsem/elixir_advection_finite_volume.jl @@ -10,19 +10,19 @@ equations = LinearScalarAdvectionEquation1D(advection_velocity) # Create DG solver with polynomial degree = 0, i.e., a first order finite volume solver, # with (local) Lax-Friedrichs/Rusanov flux as surface flux -solver = DGSEM(polydeg=0, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 0, surface_flux = flux_lax_friedrichs) coordinates_min = -1.0 # minimum coordinate -coordinates_max = 1.0 # maximum coordinate +coordinates_max = 1.0 # maximum coordinate # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=5, - n_cells_max=30_000) # set maximum capacity of tree data structure + initial_refinement_level = 5, + n_cells_max = 30_000) # set maximum capacity of tree data structure # A semidiscretization collects data structures and functions for the spatial discretization -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, solver) - +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, + solver) ############################################################################### # ODE solvers, callbacks etc. @@ -35,22 +35,21 @@ ode = semidiscretize(semi, (0.0, 1.0)); summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +analysis_callback = AnalysisCallback(semi, interval = 100) # The StepsizeCallback handles the re-calculation of the maximum Δt after each time step -stepsize_callback = StepsizeCallback(cfl=0.9) +stepsize_callback = StepsizeCallback(cfl = 0.9) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver callbacks = CallbackSet(summary_callback, analysis_callback, stepsize_callback) - ############################################################################### # run the simulation # OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks sol = solve(ode, Euler(), - dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); + dt = 1.0, # 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/tree_1d_dgsem/elixir_burgers_basic.jl b/examples/tree_1d_dgsem/elixir_burgers_basic.jl index cebd9b11201..f57b8e730fe 100644 --- a/examples/tree_1d_dgsem/elixir_burgers_basic.jl +++ b/examples/tree_1d_dgsem/elixir_burgers_basic.jl @@ -9,18 +9,16 @@ equations = InviscidBurgersEquation1D() initial_condition = initial_condition_convergence_test -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = 0.0 coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -31,29 +29,28 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_errors=(:l2_error_primitive, - :linf_error_primitive)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:l2_error_primitive, + :linf_error_primitive)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_burgers_linear_stability.jl b/examples/tree_1d_dgsem/elixir_burgers_linear_stability.jl index 6a25f94ca05..ae2039edde6 100644 --- a/examples/tree_1d_dgsem/elixir_burgers_linear_stability.jl +++ b/examples/tree_1d_dgsem/elixir_burgers_linear_stability.jl @@ -8,23 +8,22 @@ using Trixi equations = InviscidBurgersEquation1D() function initial_condition_linear_stability(x, t, equation::InviscidBurgersEquation1D) - k = 1 - 2 + sinpi(k * (x[1] - 0.7)) |> SVector + k = 1 + 2 + sinpi(k * (x[1] - 0.7)) |> SVector end volume_flux = flux_ec -solver = DGSEM(polydeg=3, surface_flux=flux_ec, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_ec, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = -1.0 -coordinates_max = 1.0 +coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_linear_stability, solver) + initial_refinement_level = 4, + n_cells_max = 10_000) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_linear_stability, + solver) ############################################################################### # ODE solvers, callbacks etc. @@ -35,23 +34,22 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_errors=(:l2_error_primitive, - :linf_error_primitive)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:l2_error_primitive, + :linf_error_primitive)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) callbacks = CallbackSet(summary_callback, analysis_callback, alive_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); +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/tree_1d_dgsem/elixir_burgers_rarefaction.jl b/examples/tree_1d_dgsem/elixir_burgers_rarefaction.jl index 28ab7b7c768..d32b9d6f1f4 100644 --- a/examples/tree_1d_dgsem/elixir_burgers_rarefaction.jl +++ b/examples/tree_1d_dgsem/elixir_burgers_rarefaction.jl @@ -10,18 +10,18 @@ equations = InviscidBurgersEquation1D() basis = LobattoLegendreBasis(3) # Use shock capturing techniques to suppress oscillations at discontinuities indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=1.0, - alpha_min=0.001, - alpha_smooth=true, - variable=first) + alpha_max = 1.0, + alpha_min = 0.001, + alpha_smooth = true, + variable = first) -volume_flux = flux_ec +volume_flux = flux_ec surface_flux = flux_lax_friedrichs volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) - + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) + solver = DGSEM(basis, surface_flux, volume_integral) coordinate_min = 0.0 @@ -29,42 +29,41 @@ coordinate_max = 1.0 # Make sure to turn periodicity explicitly off as special boundary conditions are specified mesh = TreeMesh(coordinate_min, coordinate_max, - initial_refinement_level=6, - n_cells_max=10_000, - periodicity=false) + initial_refinement_level = 6, + n_cells_max = 10_000, + periodicity = false) # Discontinuous initial condition (Riemann Problem) leading to a rarefaction fan. function initial_condition_rarefaction(x, t, equation::InviscidBurgersEquation1D) - scalar = x[1] < 0.5 ? 0.5 : 1.5 + scalar = x[1] < 0.5 ? 0.5 : 1.5 - return SVector(scalar) -end + return SVector(scalar) +end ############################################################################### # Specify non-periodic boundary conditions function inflow(x, t, equations::InviscidBurgersEquation1D) - return initial_condition_rarefaction(coordinate_min, t, equations) + return initial_condition_rarefaction(coordinate_min, t, equations) end boundary_condition_inflow = BoundaryConditionDirichlet(inflow) function boundary_condition_outflow(u_inner, orientation, normal_direction, x, t, - surface_flux_function, equations::InviscidBurgersEquation1D) - # Calculate the boundary flux entirely from the internal solution state - flux = Trixi.flux(u_inner, normal_direction, equations) + surface_flux_function, + equations::InviscidBurgersEquation1D) + # Calculate the boundary flux entirely from the internal solution state + flux = Trixi.flux(u_inner, normal_direction, equations) - return flux + return flux end +boundary_conditions = (x_neg = boundary_condition_inflow, + x_pos = boundary_condition_outflow) -boundary_conditions = (x_neg=boundary_condition_inflow, - x_pos=boundary_condition_outflow) - initial_condition = initial_condition_rarefaction semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -75,12 +74,11 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) - -stepsize_callback = StepsizeCallback(cfl=0.9) +alive_callback = AliveCallback(analysis_interval = analysis_interval) +stepsize_callback = StepsizeCallback(cfl = 0.9) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -89,9 +87,8 @@ callbacks = CallbackSet(summary_callback, ############################################################################### # run the simulation - -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=42, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 42, # 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/tree_1d_dgsem/elixir_burgers_shock.jl b/examples/tree_1d_dgsem/elixir_burgers_shock.jl index 00b5314e19f..1f0b0e7e042 100644 --- a/examples/tree_1d_dgsem/elixir_burgers_shock.jl +++ b/examples/tree_1d_dgsem/elixir_burgers_shock.jl @@ -10,17 +10,17 @@ equations = InviscidBurgersEquation1D() basis = LobattoLegendreBasis(3) # Use shock capturing techniques to suppress oscillations at discontinuities indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=1.0, - alpha_min=0.001, - alpha_smooth=true, - variable=first) + alpha_max = 1.0, + alpha_min = 0.001, + alpha_smooth = true, + variable = first) -volume_flux = flux_ec +volume_flux = flux_ec surface_flux = flux_lax_friedrichs volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=surface_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = surface_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) @@ -29,42 +29,41 @@ coordinate_max = 1.0 # Make sure to turn periodicity explicitly off as special boundary conditions are specified mesh = TreeMesh(coordinate_min, coordinate_max, - initial_refinement_level=6, - n_cells_max=10_000, - periodicity=false) + initial_refinement_level = 6, + n_cells_max = 10_000, + periodicity = false) # Discontinuous initial condition (Riemann Problem) leading to a shock to test e.g. correct shock speed. function initial_condition_shock(x, t, equation::InviscidBurgersEquation1D) - scalar = x[1] < 0.5 ? 1.5 : 0.5 + scalar = x[1] < 0.5 ? 1.5 : 0.5 - return SVector(scalar) + return SVector(scalar) end ############################################################################### # Specify non-periodic boundary conditions function inflow(x, t, equations::InviscidBurgersEquation1D) - return initial_condition_shock(coordinate_min, t, equations) + return initial_condition_shock(coordinate_min, t, equations) end boundary_condition_inflow = BoundaryConditionDirichlet(inflow) function boundary_condition_outflow(u_inner, orientation, normal_direction, x, t, - surface_flux_function, equations::InviscidBurgersEquation1D) - # Calculate the boundary flux entirely from the internal solution state - flux = Trixi.flux(u_inner, normal_direction, equations) + surface_flux_function, + equations::InviscidBurgersEquation1D) + # Calculate the boundary flux entirely from the internal solution state + flux = Trixi.flux(u_inner, normal_direction, equations) - return flux + return flux end - -boundary_conditions = (x_neg=boundary_condition_inflow, - x_pos=boundary_condition_outflow) +boundary_conditions = (x_neg = boundary_condition_inflow, + x_pos = boundary_condition_outflow) initial_condition = initial_condition_shock semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -75,12 +74,11 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) - -stepsize_callback = StepsizeCallback(cfl=0.85) +alive_callback = AliveCallback(analysis_interval = analysis_interval) +stepsize_callback = StepsizeCallback(cfl = 0.85) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -89,9 +87,8 @@ callbacks = CallbackSet(summary_callback, ############################################################################### # run the simulation - -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=42, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 42, # 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/tree_1d_dgsem/elixir_euler_blast_wave.jl b/examples/tree_1d_dgsem/elixir_euler_blast_wave.jl index 2318063c2be..9cba4936d22 100644 --- a/examples/tree_1d_dgsem/elixir_euler_blast_wave.jl +++ b/examples/tree_1d_dgsem/elixir_euler_blast_wave.jl @@ -16,49 +16,47 @@ A medium blast wave taken from [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) """ function initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations1D) - # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" - # Set up polar coordinates - inicenter = SVector(0.0) - x_norm = x[1] - inicenter[1] - r = abs(x_norm) - # The following code is equivalent to - # phi = atan(0.0, x_norm) - # cos_phi = cos(phi) - # in 1D but faster - cos_phi = x_norm > 0 ? one(x_norm) : -one(x_norm) - - # Calculate primitive variables - rho = r > 0.5 ? 1.0 : 1.1691 - v1 = r > 0.5 ? 0.0 : 0.1882 * cos_phi - p = r > 0.5 ? 1.0E-3 : 1.245 - - return prim2cons(SVector(rho, v1, p), equations) + # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" + # Set up polar coordinates + inicenter = SVector(0.0) + x_norm = x[1] - inicenter[1] + r = abs(x_norm) + # The following code is equivalent to + # phi = atan(0.0, x_norm) + # cos_phi = cos(phi) + # in 1D but faster + cos_phi = x_norm > 0 ? one(x_norm) : -one(x_norm) + + # Calculate primitive variables + rho = r > 0.5 ? 1.0 : 1.1691 + v1 = r > 0.5 ? 0.0 : 0.1882 * cos_phi + p = r > 0.5 ? 1.0E-3 : 1.245 + + return prim2cons(SVector(rho, v1, p), equations) end initial_condition = initial_condition_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_ranocha +volume_flux = flux_ranocha basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-2.0,) -coordinates_max = ( 2.0,) +coordinates_max = (2.0,) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - n_cells_max=10_000) - + initial_refinement_level = 6, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -69,27 +67,26 @@ summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl b/examples/tree_1d_dgsem/elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl index d35dec6bc73..05f392624fd 100644 --- a/examples/tree_1d_dgsem/elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl +++ b/examples/tree_1d_dgsem/elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl @@ -2,7 +2,8 @@ using Downloads: download using Flux using BSON: load network = joinpath(@__DIR__, "modelnnpp-0.97-0.0001.bson") -download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelnnpp-0.97-0.0001.bson", network) +download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelnnpp-0.97-0.0001.bson", + network) model1d = load(network, @__MODULE__)[:model1d] using OrdinaryDiffEq @@ -14,7 +15,6 @@ using Trixi # University of Cologne, advisors: Gregor Gassner, Michael Schlottke-Lakemper # This motivates the particular choice of fluxes, mesh resolution etc. - ############################################################################### # semidiscretization of the compressible Euler equations @@ -29,53 +29,51 @@ A medium blast wave taken from [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) """ function initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations1D) - # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" - # Set up polar coordinates - inicenter = SVector(0.0) - x_norm = x[1] - inicenter[1] - r = abs(x_norm) - # The following code is equivalent to - # phi = atan(0.0, x_norm) - # cos_phi = cos(phi) - # in 1D but faster - cos_phi = x_norm > 0 ? one(x_norm) : -one(x_norm) - - # Calculate primitive variables - rho = r > 0.5 ? 1.0 : 1.1691 - v1 = r > 0.5 ? 0.0 : 0.1882 * cos_phi - p = r > 0.5 ? 1.0E-3 : 1.245 - - return prim2cons(SVector(rho, v1, p), equations) + # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" + # Set up polar coordinates + inicenter = SVector(0.0) + x_norm = x[1] - inicenter[1] + r = abs(x_norm) + # The following code is equivalent to + # phi = atan(0.0, x_norm) + # cos_phi = cos(phi) + # in 1D but faster + cos_phi = x_norm > 0 ? one(x_norm) : -one(x_norm) + + # Calculate primitive variables + rho = r > 0.5 ? 1.0 : 1.1691 + v1 = r > 0.5 ? 0.0 : 0.1882 * cos_phi + p = r > 0.5 ? 1.0E-3 : 1.245 + + return prim2cons(SVector(rho, v1, p), equations) end initial_condition = initial_condition_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_chandrashekar +volume_flux = flux_chandrashekar basis = LobattoLegendreBasis(3) indicator_sc = IndicatorNeuralNetwork(equations, basis, - indicator_type=NeuralNetworkPerssonPeraire(), - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - alpha_continuous=false, - alpha_amr=false, - variable=density_pressure, - network=model1d) + indicator_type = NeuralNetworkPerssonPeraire(), + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + alpha_continuous = false, + alpha_amr = false, + variable = density_pressure, + network = model1d) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-2.0,) -coordinates_max = ( 2.0,) +coordinates_max = (2.0,) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - n_cells_max=10_000) - + initial_refinement_level = 6, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -86,27 +84,26 @@ summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl b/examples/tree_1d_dgsem/elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl index fb36f8540f8..de2f5134a49 100644 --- a/examples/tree_1d_dgsem/elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl +++ b/examples/tree_1d_dgsem/elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl @@ -2,7 +2,8 @@ using Downloads: download using Flux using BSON: load network = joinpath(@__DIR__, "modelnnrh-0.95-0.009.bson") -download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelnnrh-0.95-0.009.bson", network) +download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelnnrh-0.95-0.009.bson", + network) model1d = load(network, @__MODULE__)[:model1d] using OrdinaryDiffEq @@ -14,7 +15,6 @@ using Trixi # University of Cologne, advisors: Gregor Gassner, Michael Schlottke-Lakemper # This motivates the particular choice of fluxes, mesh resolution etc. - ############################################################################### # semidiscretization of the compressible Euler equations @@ -29,53 +29,51 @@ A medium blast wave taken from [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) """ function initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations1D) - # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" - # Set up polar coordinates - inicenter = SVector(0.0) - x_norm = x[1] - inicenter[1] - r = abs(x_norm) - # The following code is equivalent to - # phi = atan(0.0, x_norm) - # cos_phi = cos(phi) - # in 1D but faster - cos_phi = x_norm > 0 ? one(x_norm) : -one(x_norm) - - # Calculate primitive variables - rho = r > 0.5 ? 1.0 : 1.1691 - v1 = r > 0.5 ? 0.0 : 0.1882 * cos_phi - p = r > 0.5 ? 1.0E-3 : 1.245 - - return prim2cons(SVector(rho, v1, p), equations) + # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" + # Set up polar coordinates + inicenter = SVector(0.0) + x_norm = x[1] - inicenter[1] + r = abs(x_norm) + # The following code is equivalent to + # phi = atan(0.0, x_norm) + # cos_phi = cos(phi) + # in 1D but faster + cos_phi = x_norm > 0 ? one(x_norm) : -one(x_norm) + + # Calculate primitive variables + rho = r > 0.5 ? 1.0 : 1.1691 + v1 = r > 0.5 ? 0.0 : 0.1882 * cos_phi + p = r > 0.5 ? 1.0E-3 : 1.245 + + return prim2cons(SVector(rho, v1, p), equations) end initial_condition = initial_condition_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_chandrashekar +volume_flux = flux_chandrashekar basis = LobattoLegendreBasis(3) indicator_sc = IndicatorNeuralNetwork(equations, basis, - indicator_type=NeuralNetworkRayHesthaven(), - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - alpha_continuous=false, - alpha_amr=false, - variable=density_pressure, - network=model1d) + indicator_type = NeuralNetworkRayHesthaven(), + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + alpha_continuous = false, + alpha_amr = false, + variable = density_pressure, + network = model1d) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-2.0,) -coordinates_max = ( 2.0,) +coordinates_max = (2.0,) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - n_cells_max=10_000) - + initial_refinement_level = 6, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -86,27 +84,26 @@ summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_euler_convergence_pure_fv.jl b/examples/tree_1d_dgsem/elixir_euler_convergence_pure_fv.jl index fe221ea5bd7..1fa07d4edda 100644 --- a/examples/tree_1d_dgsem/elixir_euler_convergence_pure_fv.jl +++ b/examples/tree_1d_dgsem/elixir_euler_convergence_pure_fv.jl @@ -9,19 +9,17 @@ equations = CompressibleEulerEquations1D(1.4) initial_condition = initial_condition_convergence_test -solver = DGSEM(polydeg=3, surface_flux=flux_hllc, - volume_integral=VolumeIntegralPureLGLFiniteVolume(flux_hllc)) +solver = DGSEM(polydeg = 3, surface_flux = flux_hllc, + volume_integral = VolumeIntegralPureLGLFiniteVolume(flux_hllc)) coordinates_min = 0.0 coordinates_max = 2.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -32,29 +30,28 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_errors=(:l2_error_primitive, - :linf_error_primitive)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:l2_error_primitive, + :linf_error_primitive)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_euler_density_wave.jl b/examples/tree_1d_dgsem/elixir_euler_density_wave.jl index 746989dfe56..01ccbb2b517 100644 --- a/examples/tree_1d_dgsem/elixir_euler_density_wave.jl +++ b/examples/tree_1d_dgsem/elixir_euler_density_wave.jl @@ -8,18 +8,16 @@ equations = CompressibleEulerEquations1D(1.4) initial_condition = initial_condition_density_wave -solver = DGSEM(polydeg=5, surface_flux=flux_central) +solver = DGSEM(polydeg = 5, surface_flux = flux_central) coordinates_min = -1.0 -coordinates_max = 1.0 +coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=30_000) - + initial_refinement_level = 2, + n_cells_max = 30_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -29,16 +27,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 2000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -48,7 +46,7 @@ callbacks = CallbackSet(summary_callback, ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=stepsize_callback(ode), # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = stepsize_callback(ode), # 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/tree_1d_dgsem/elixir_euler_ec.jl b/examples/tree_1d_dgsem/elixir_euler_ec.jl index f20bd4fd69e..0be9c8fbf4c 100644 --- a/examples/tree_1d_dgsem/elixir_euler_ec.jl +++ b/examples/tree_1d_dgsem/elixir_euler_ec.jl @@ -9,19 +9,17 @@ equations = CompressibleEulerEquations1D(1.4) initial_condition = initial_condition_weak_blast_wave volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_ranocha, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_ranocha, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-2.0,) -coordinates_max = ( 2.0,) +coordinates_max = (2.0,) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=5, - n_cells_max=10_000) - + initial_refinement_level = 5, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -31,27 +29,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_euler_positivity.jl b/examples/tree_1d_dgsem/elixir_euler_positivity.jl index 966661e8894..3fb96fb807b 100644 --- a/examples/tree_1d_dgsem/elixir_euler_positivity.jl +++ b/examples/tree_1d_dgsem/elixir_euler_positivity.jl @@ -14,97 +14,92 @@ The Sedov blast wave setup based on Flash - https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations1D) - # Set up polar coordinates - inicenter = SVector(0.0) - x_norm = x[1] - inicenter[1] - r = abs(x_norm) - - # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 - r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) - # r0 = 0.5 # = more reasonable setup - E = 1.0 - p0_inner = 6 * (equations.gamma - 1) * E / (3 * pi * r0) - p0_outer = 1.0e-5 # = true Sedov setup - # p0_outer = 1.0e-3 # = more reasonable setup - - # Calculate primitive variables - rho = 1.0 - v1 = 0.0 - p = r > r0 ? p0_outer : p0_inner - - return prim2cons(SVector(rho, v1, p), equations) + # Set up polar coordinates + inicenter = SVector(0.0) + x_norm = x[1] - inicenter[1] + r = abs(x_norm) + + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 + r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) + # r0 = 0.5 # = more reasonable setup + E = 1.0 + p0_inner = 6 * (equations.gamma - 1) * E / (3 * pi * r0) + p0_outer = 1.0e-5 # = true Sedov setup + # p0_outer = 1.0e-3 # = more reasonable setup + + # Calculate primitive variables + rho = 1.0 + v1 = 0.0 + p = r > r0 ? p0_outer : p0_inner + + return prim2cons(SVector(rho, v1, p), equations) end initial_condition = initial_condition_sedov_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_ranocha +volume_flux = flux_ranocha basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-2.0,) -coordinates_max = ( 2.0,) +coordinates_max = (2.0,) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - n_cells_max=10_000) - + initial_refinement_level = 6, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. tspan = (0.0, 4.0) ode = semidiscretize(semi, tspan) - summary_callback = SummaryCallback() analysis_interval = 500 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorLöhner(semi, - variable=density_pressure) + variable = density_pressure) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=4, - med_level =0, med_threshold=0.1, # med_level = current level - max_level =6, max_threshold=0.3) + base_level = 4, + med_level = 0, med_threshold = 0.1, # med_level = current level + max_level = 6, max_threshold = 0.3) amr_callback = AMRCallback(semi, amr_controller, - interval=2, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 2, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, amr_callback, stepsize_callback) - -stage_limiter! = PositivityPreservingLimiterZhangShu(thresholds=(5.0e-6, 5.0e-6), - variables=(Trixi.density, pressure)) - +stage_limiter! = PositivityPreservingLimiterZhangShu(thresholds = (5.0e-6, 5.0e-6), + variables = (Trixi.density, pressure)) ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(stage_limiter!, 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); +sol = solve(ode, CarpenterKennedy2N54(stage_limiter!, 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/tree_1d_dgsem/elixir_euler_sedov_blast_wave.jl b/examples/tree_1d_dgsem/elixir_euler_sedov_blast_wave.jl index 106ccacf4f5..b67b2bc602e 100644 --- a/examples/tree_1d_dgsem/elixir_euler_sedov_blast_wave.jl +++ b/examples/tree_1d_dgsem/elixir_euler_sedov_blast_wave.jl @@ -14,96 +14,92 @@ The Sedov blast wave setup based on Flash - https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations1D) - # Set up polar coordinates - inicenter = SVector(0.0) - x_norm = x[1] - inicenter[1] - r = abs(x_norm) - - # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 - r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) - # r0 = 0.5 # = more reasonable setup - E = 1.0 - p0_inner = 6 * (equations.gamma - 1) * E / (3 * pi * r0) - p0_outer = 1.0e-5 # = true Sedov setup - # p0_outer = 1.0e-3 # = more reasonable setup - - # Calculate primitive variables - rho = 1.0 - v1 = 0.0 - p = r > r0 ? p0_outer : p0_inner - - return prim2cons(SVector(rho, v1, p), equations) + # Set up polar coordinates + inicenter = SVector(0.0) + x_norm = x[1] - inicenter[1] + r = abs(x_norm) + + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 + r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) + # r0 = 0.5 # = more reasonable setup + E = 1.0 + p0_inner = 6 * (equations.gamma - 1) * E / (3 * pi * r0) + p0_outer = 1.0e-5 # = true Sedov setup + # p0_outer = 1.0e-3 # = more reasonable setup + + # Calculate primitive variables + rho = 1.0 + v1 = 0.0 + p = r > r0 ? p0_outer : p0_inner + + return prim2cons(SVector(rho, v1, p), equations) end initial_condition = initial_condition_sedov_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_chandrashekar +volume_flux = flux_chandrashekar basis = LobattoLegendreBasis(3) shock_indicator_variable = density_pressure indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=shock_indicator_variable) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = shock_indicator_variable) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-2.0,) -coordinates_max = ( 2.0,) +coordinates_max = (2.0,) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - n_cells_max=10_000) - + initial_refinement_level = 6, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. tspan = (0.0, 12.5) ode = semidiscretize(semi, tspan) - summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = density_pressure) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=4, - max_level=6, max_threshold=0.01) + base_level = 4, + max_level = 6, max_threshold = 0.01) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=0.5) +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=stepsize_callback(ode), # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = stepsize_callback(ode), # 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/tree_1d_dgsem/elixir_euler_sedov_blast_wave_pure_fv.jl b/examples/tree_1d_dgsem/elixir_euler_sedov_blast_wave_pure_fv.jl index ebe8fa7cebf..8a0241680b9 100644 --- a/examples/tree_1d_dgsem/elixir_euler_sedov_blast_wave_pure_fv.jl +++ b/examples/tree_1d_dgsem/elixir_euler_sedov_blast_wave_pure_fv.jl @@ -14,25 +14,25 @@ The Sedov blast wave setup based on Flash - https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations1D) - # Set up polar coordinates - inicenter = SVector(0.0) - x_norm = x[1] - inicenter[1] - r = abs(x_norm) - - # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 - r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) - # r0 = 0.5 # = more reasonable setup - E = 1.0 - p0_inner = 6 * (equations.gamma - 1) * E / (3 * pi * r0) - p0_outer = 1.0e-5 # = true Sedov setup - # p0_outer = 1.0e-3 # = more reasonable setup - - # Calculate primitive variables - rho = 1.0 - v1 = 0.0 - p = r > r0 ? p0_outer : p0_inner - - return prim2cons(SVector(rho, v1, p), equations) + # Set up polar coordinates + inicenter = SVector(0.0) + x_norm = x[1] - inicenter[1] + r = abs(x_norm) + + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 + r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) + # r0 = 0.5 # = more reasonable setup + E = 1.0 + p0_inner = 6 * (equations.gamma - 1) * E / (3 * pi * r0) + p0_outer = 1.0e-5 # = true Sedov setup + # p0_outer = 1.0e-3 # = more reasonable setup + + # Calculate primitive variables + rho = 1.0 + v1 = 0.0 + p = r > r0 ? p0_outer : p0_inner + + return prim2cons(SVector(rho, v1, p), equations) end initial_condition = initial_condition_sedov_blast_wave @@ -42,59 +42,55 @@ volume_integral = VolumeIntegralPureLGLFiniteVolume(flux_hllc) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-2.0,) -coordinates_max = ( 2.0,) +coordinates_max = (2.0,) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=7, - n_cells_max=10_000) - + initial_refinement_level = 7, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. tspan = (0.0, 12.5) ode = semidiscretize(semi, tspan) - summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = density_pressure) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=4, - max_level=7, max_threshold=0.01) + base_level = 4, + max_level = 7, max_threshold = 0.01) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=0.25) +stepsize_callback = StepsizeCallback(cfl = 0.25) 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=stepsize_callback(ode), # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = stepsize_callback(ode), # 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/tree_1d_dgsem/elixir_euler_shockcapturing.jl b/examples/tree_1d_dgsem/elixir_euler_shockcapturing.jl index 90547f8ddc1..08367505377 100644 --- a/examples/tree_1d_dgsem/elixir_euler_shockcapturing.jl +++ b/examples/tree_1d_dgsem/elixir_euler_shockcapturing.jl @@ -10,28 +10,26 @@ equations = CompressibleEulerEquations1D(1.4) initial_condition = initial_condition_weak_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_shima_etal +volume_flux = flux_shima_etal basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = -2.0 -coordinates_max = 2.0 +coordinates_max = 2.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=5, - n_cells_max=10_000) - + initial_refinement_level = 5, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -41,27 +39,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_euler_source_terms.jl b/examples/tree_1d_dgsem/elixir_euler_source_terms.jl index 213206eb9e0..555910f69f0 100644 --- a/examples/tree_1d_dgsem/elixir_euler_source_terms.jl +++ b/examples/tree_1d_dgsem/elixir_euler_source_terms.jl @@ -11,18 +11,16 @@ initial_condition = initial_condition_convergence_test # Note that the expected EOC of 5 is not reached with this flux. # Using flux_hll instead yields the expected EOC. -solver = DGSEM(polydeg=4, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 4, surface_flux = flux_lax_friedrichs) coordinates_min = 0.0 coordinates_max = 2.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -33,29 +31,28 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_errors=(:l2_error_primitive, - :linf_error_primitive)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:l2_error_primitive, + :linf_error_primitive)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_euler_source_terms_nonperiodic.jl b/examples/tree_1d_dgsem/elixir_euler_source_terms_nonperiodic.jl index 3794e0c8d54..922ac3dd97d 100644 --- a/examples/tree_1d_dgsem/elixir_euler_source_terms_nonperiodic.jl +++ b/examples/tree_1d_dgsem/elixir_euler_source_terms_nonperiodic.jl @@ -13,23 +13,21 @@ initial_condition = initial_condition_convergence_test # 1*ndims == 2 directions or you can pass a tuple containing BCs for # each direction boundary_condition = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = (x_neg=boundary_condition, - x_pos=boundary_condition) +boundary_conditions = (x_neg = boundary_condition, + x_pos = boundary_condition) -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0,) coordinates_max = (2.0,) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000, - periodicity=false) - + initial_refinement_level = 4, + n_cells_max = 10_000, + periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test, - boundary_conditions=boundary_conditions) - + source_terms = source_terms_convergence_test, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -40,30 +38,29 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_restart, save_solution, 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); +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/tree_1d_dgsem/elixir_eulergravity_convergence.jl b/examples/tree_1d_dgsem/elixir_eulergravity_convergence.jl index 42de0e18e51..acde04780ee 100644 --- a/examples/tree_1d_dgsem/elixir_eulergravity_convergence.jl +++ b/examples/tree_1d_dgsem/elixir_eulergravity_convergence.jl @@ -15,11 +15,11 @@ solver_euler = DGSEM(polydeg, flux_hll) coordinates_min = 0.0 coordinates_max = 2.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=10_000) - -semi_euler = SemidiscretizationHyperbolic(mesh, equations_euler, initial_condition, solver_euler) + initial_refinement_level = 2, + n_cells_max = 10_000) +semi_euler = SemidiscretizationHyperbolic(mesh, equations_euler, initial_condition, + solver_euler) ############################################################################### # semidiscretization of the hyperbolic diffusion equations @@ -27,22 +27,21 @@ equations_gravity = HyperbolicDiffusionEquations1D() solver_gravity = DGSEM(polydeg, flux_lax_friedrichs) -semi_gravity = SemidiscretizationHyperbolic(mesh, equations_gravity, initial_condition, solver_gravity, - source_terms=source_terms_harmonic) - +semi_gravity = SemidiscretizationHyperbolic(mesh, equations_gravity, initial_condition, + solver_gravity, + source_terms = source_terms_harmonic) ############################################################################### # combining both semidiscretizations for Euler + self-gravity -parameters = ParametersEulerGravity(background_density=2.0, # aka rho0 - gravitational_constant=1.0, # aka G - cfl=1.5, - resid_tol=1.0e-10, - n_iterations_max=1000, - timestep_gravity=timestep_gravity_erk52_3Sstar!) +parameters = ParametersEulerGravity(background_density = 2.0, # aka rho0 + gravitational_constant = 1.0, # aka G + cfl = 1.5, + resid_tol = 1.0e-10, + n_iterations_max = 1000, + timestep_gravity = timestep_gravity_erk52_3Sstar!) semi = SemidiscretizationEulerGravity(semi_euler, semi_gravity, parameters) - ############################################################################### # ODE solvers, callbacks etc. tspan = (0.0, 0.5) @@ -51,20 +50,20 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi_euler, interval=analysis_interval, - save_analysis=true) +analysis_callback = AnalysisCallback(semi_euler, interval = analysis_interval, + save_analysis = true) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=10, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 10, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.1) +stepsize_callback = StepsizeCallback(cfl = 1.1) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -73,11 +72,10 @@ callbacks = CallbackSet(summary_callback, save_solution, 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); +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 println("Number of gravity subcycles: ", semi.gravity_counter.ncalls_since_readout) diff --git a/examples/tree_1d_dgsem/elixir_eulermulti_convergence_ec.jl b/examples/tree_1d_dgsem/elixir_eulermulti_convergence_ec.jl index 2444fe8611d..6d6316898b7 100644 --- a/examples/tree_1d_dgsem/elixir_eulermulti_convergence_ec.jl +++ b/examples/tree_1d_dgsem/elixir_eulermulti_convergence_ec.jl @@ -4,25 +4,23 @@ using Trixi ############################################################################### # semidiscretization of the compressible Euler multicomponent equations -equations = CompressibleEulerMulticomponentEquations1D(gammas = (1.4, 1.4), +equations = CompressibleEulerMulticomponentEquations1D(gammas = (1.4, 1.4), gas_constants = (0.4, 0.4)) initial_condition = initial_condition_convergence_test volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_ranocha, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_ranocha, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-1.0,) -coordinates_max = ( 1.0,) +coordinates_max = (1.0,) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=30_000) - + initial_refinement_level = 3, + n_cells_max = 30_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -33,27 +31,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_eulermulti_convergence_es.jl b/examples/tree_1d_dgsem/elixir_eulermulti_convergence_es.jl index 86f4a4bad04..1b37a8a2279 100644 --- a/examples/tree_1d_dgsem/elixir_eulermulti_convergence_es.jl +++ b/examples/tree_1d_dgsem/elixir_eulermulti_convergence_es.jl @@ -4,25 +4,23 @@ using Trixi ############################################################################### # semidiscretization of the compressible Euler multicomponent equations -equations = CompressibleEulerMulticomponentEquations1D(gammas = (1.4, 1.4, 1.4, 1.4), +equations = CompressibleEulerMulticomponentEquations1D(gammas = (1.4, 1.4, 1.4, 1.4), gas_constants = (0.4, 0.4, 0.4, 0.4)) initial_condition = initial_condition_convergence_test volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-1.0,) -coordinates_max = ( 1.0,) +coordinates_max = (1.0,) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=30_000) - + initial_refinement_level = 3, + n_cells_max = 30_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -33,27 +31,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_eulermulti_ec.jl b/examples/tree_1d_dgsem/elixir_eulermulti_ec.jl index 04d937a9a8f..73f8de15d82 100644 --- a/examples/tree_1d_dgsem/elixir_eulermulti_ec.jl +++ b/examples/tree_1d_dgsem/elixir_eulermulti_ec.jl @@ -4,26 +4,23 @@ using Trixi ############################################################################### # semidiscretization of the compressible Euler multicomponent equations -equations = CompressibleEulerMulticomponentEquations1D(gammas = (1.4, 1.4, 1.4), +equations = CompressibleEulerMulticomponentEquations1D(gammas = (1.4, 1.4, 1.4), gas_constants = (0.4, 0.4, 0.4)) - initial_condition = initial_condition_weak_blast_wave volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_ranocha, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_ranocha, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-2.0,) -coordinates_max = ( 2.0,) +coordinates_max = (2.0,) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=5, - n_cells_max=10_000) - + initial_refinement_level = 5, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -34,28 +31,27 @@ summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(Trixi.density,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (Trixi.density,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_eulermulti_es.jl b/examples/tree_1d_dgsem/elixir_eulermulti_es.jl index 7abb3b0d021..7fbec0c0055 100644 --- a/examples/tree_1d_dgsem/elixir_eulermulti_es.jl +++ b/examples/tree_1d_dgsem/elixir_eulermulti_es.jl @@ -4,26 +4,23 @@ using Trixi ############################################################################### # semidiscretization of the compressible Euler multicomponent equations -equations = CompressibleEulerMulticomponentEquations1D(gammas = (1.4, 1.4), +equations = CompressibleEulerMulticomponentEquations1D(gammas = (1.4, 1.4), gas_constants = (0.4, 0.4)) - initial_condition = initial_condition_weak_blast_wave volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-2.0,) -coordinates_max = ( 2.0,) +coordinates_max = (2.0,) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=5, - n_cells_max=10_000) - + initial_refinement_level = 5, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -34,31 +31,30 @@ summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(Trixi.density,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (Trixi.density,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_restart, save_solution, 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); +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/tree_1d_dgsem/elixir_eulermulti_two_interacting_blast_waves.jl b/examples/tree_1d_dgsem/elixir_eulermulti_two_interacting_blast_waves.jl index 81966194180..c093420cc7c 100644 --- a/examples/tree_1d_dgsem/elixir_eulermulti_two_interacting_blast_waves.jl +++ b/examples/tree_1d_dgsem/elixir_eulermulti_two_interacting_blast_waves.jl @@ -5,8 +5,8 @@ using Trixi ############################################################################### # semidiscretization of the compressible Euler equations -equations = CompressibleEulerMulticomponentEquations1D(gammas = (1.4, 1.4, 1.4), - gas_constants = (0.4, 0.4, 0.4)) +equations = CompressibleEulerMulticomponentEquations1D(gammas = (1.4, 1.4, 1.4), + gas_constants = (0.4, 0.4, 0.4)) """ initial_condition_two_interacting_blast_waves(x, t, equations::CompressibleEulerMulticomponentEquations1D) @@ -16,69 +16,67 @@ A multicomponent two interacting blast wave test taken from The consistent multi-fluid advection method [arXiv: 9807241](https://arxiv.org/pdf/astro-ph/9807241.pdf) """ -function initial_condition_two_interacting_blast_waves(x, t, equations::CompressibleEulerMulticomponentEquations1D) +function initial_condition_two_interacting_blast_waves(x, t, + equations::CompressibleEulerMulticomponentEquations1D) + rho1 = 0.5 * x[1]^2 + rho2 = 0.5 * (sin(20 * x[1]))^2 + rho3 = 1 - rho1 - rho2 - rho1 = 0.5 * x[1]^2 - rho2 = 0.5 * (sin(20 * x[1]))^2 - rho3 = 1 - rho1 - rho2 + prim_rho = SVector{3, real(equations)}(rho1, rho2, rho3) - prim_rho = SVector{3, real(equations)}(rho1, rho2, rho3) + v1 = 0.0 - v1 = 0.0 + if x[1] <= 0.1 + p = 1000 + elseif x[1] < 0.9 + p = 0.01 + else + p = 100 + end - if x[1] <= 0.1 - p = 1000 - elseif x[1] < 0.9 - p = 0.01 - else - p = 100 - end + prim_other = SVector{2, real(equations)}(v1, p) - prim_other = SVector{2, real(equations)}(v1, p) - - return prim2cons(vcat(prim_other, prim_rho), equations) + return prim2cons(vcat(prim_other, prim_rho), equations) end initial_condition = initial_condition_two_interacting_blast_waves -function boundary_condition_two_interacting_blast_waves(u_inner, orientation, direction, x, t, - surface_flux_function, +function boundary_condition_two_interacting_blast_waves(u_inner, orientation, direction, + x, t, surface_flux_function, equations::CompressibleEulerMulticomponentEquations1D) - - u_inner_reflect = SVector(-u_inner[1], u_inner[2], u_inner[3], u_inner[4], u_inner[5]) - # Calculate boundary flux - if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary - flux = surface_flux_function(u_inner, u_inner_reflect, orientation, equations) - else # u_boundary is "left" of boundary, u_inner is "right" of boundary - flux = surface_flux_function(u_inner_reflect, u_inner, orientation, equations) - end - - return flux + u_inner_reflect = SVector(-u_inner[1], u_inner[2], u_inner[3], u_inner[4], u_inner[5]) + # Calculate boundary flux + if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary + flux = surface_flux_function(u_inner, u_inner_reflect, orientation, equations) + else # u_boundary is "left" of boundary, u_inner is "right" of boundary + flux = surface_flux_function(u_inner_reflect, u_inner, orientation, equations) + end + + return flux end boundary_conditions = boundary_condition_two_interacting_blast_waves surface_flux = flux_lax_friedrichs -volume_flux = flux_ranocha +volume_flux = flux_ranocha basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassner(equations, basis, alpha_max = 0.8, alpha_min = 0.0, alpha_smooth = true, - variable=pressure) + variable = pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (0.0,) coordinates_max = (1.0,) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=9, - n_cells_max=10_000, - periodicity=false) - - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions=boundary_conditions) + initial_refinement_level = 9, + n_cells_max = 10_000, + periodicity = false) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -90,16 +88,16 @@ summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.1) +stepsize_callback = StepsizeCallback(cfl = 0.1) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -109,7 +107,7 @@ callbacks = CallbackSet(summary_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); +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/tree_1d_dgsem/elixir_hypdiff_harmonic_nonperiodic.jl b/examples/tree_1d_dgsem/elixir_hypdiff_harmonic_nonperiodic.jl index 9a19807ae29..b9173ec9f49 100644 --- a/examples/tree_1d_dgsem/elixir_hypdiff_harmonic_nonperiodic.jl +++ b/examples/tree_1d_dgsem/elixir_hypdiff_harmonic_nonperiodic.jl @@ -5,7 +5,7 @@ using Trixi ############################################################################### # semidiscretization of the hyperbolic diffusion equations -equations = HyperbolicDiffusionEquations1D(nu=1.25) +equations = HyperbolicDiffusionEquations1D(nu = 1.25) """ initial_condition_poisson_nonperiodic(x, t, equations::HyperbolicDiffusionEquations1D) @@ -16,36 +16,36 @@ A non-priodic harmonic function used in combination with !!! note The only harmonic functions in 1D have the form phi(x) = A + Bx """ -function initial_condition_harmonic_nonperiodic(x, t, equations::HyperbolicDiffusionEquations1D) - # elliptic equation: -νΔϕ = f - if t == 0.0 - phi = 5.0 - q1 = 0.0 - else - A = 3 - B = exp(1) - phi = A + B * x[1] - q1 = B - end - return SVector(phi, q1) +function initial_condition_harmonic_nonperiodic(x, t, + equations::HyperbolicDiffusionEquations1D) + # elliptic equation: -νΔϕ = f + if t == 0.0 + phi = 5.0 + q1 = 0.0 + else + A = 3 + B = exp(1) + phi = A + B * x[1] + q1 = B + end + return SVector(phi, q1) end initial_condition = initial_condition_harmonic_nonperiodic boundary_conditions = BoundaryConditionDirichlet(initial_condition) -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = -1.0 -coordinates_max = 2.0 +coordinates_max = 2.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=30_000, - periodicity=false) + initial_refinement_level = 2, + n_cells_max = 30_000, + periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions, - source_terms=source_terms_harmonic) - + boundary_conditions = boundary_conditions, + source_terms = source_terms_harmonic) ############################################################################### # ODE solvers, callbacks etc. @@ -56,30 +56,29 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() resid_tol = 5.0e-12 -steady_state_callback = SteadyStateCallback(abstol=resid_tol, reltol=0.0) +steady_state_callback = SteadyStateCallback(abstol = resid_tol, reltol = 0.0) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.75) +stepsize_callback = StepsizeCallback(cfl = 1.75) callbacks = CallbackSet(summary_callback, steady_state_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) - ############################################################################### # run the simulation sol = Trixi.solve(ode, Trixi.HypDiffN3Erk3Sstar52(), - dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); + 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/tree_1d_dgsem/elixir_hypdiff_nonperiodic.jl b/examples/tree_1d_dgsem/elixir_hypdiff_nonperiodic.jl index 827d8d25ce7..4da3b33a466 100644 --- a/examples/tree_1d_dgsem/elixir_hypdiff_nonperiodic.jl +++ b/examples/tree_1d_dgsem/elixir_hypdiff_nonperiodic.jl @@ -11,19 +11,18 @@ initial_condition = initial_condition_poisson_nonperiodic boundary_conditions = boundary_condition_poisson_nonperiodic -solver = DGSEM(polydeg=4, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 4, surface_flux = flux_lax_friedrichs) coordinates_min = 0.0 coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=30_000, - periodicity=false) + initial_refinement_level = 3, + n_cells_max = 30_000, + periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions, - source_terms=source_terms_poisson_nonperiodic) - + boundary_conditions = boundary_conditions, + source_terms = source_terms_poisson_nonperiodic) ############################################################################### # ODE solvers, callbacks etc. @@ -34,31 +33,30 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() resid_tol = 5.0e-12 -steady_state_callback = SteadyStateCallback(abstol=resid_tol, reltol=0.0) +steady_state_callback = SteadyStateCallback(abstol = resid_tol, reltol = 0.0) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy, energy_total)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy, energy_total)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, steady_state_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_mhd_alfven_wave.jl b/examples/tree_1d_dgsem/elixir_mhd_alfven_wave.jl index 82bca93c707..1a66ac60b9b 100644 --- a/examples/tree_1d_dgsem/elixir_mhd_alfven_wave.jl +++ b/examples/tree_1d_dgsem/elixir_mhd_alfven_wave.jl @@ -4,25 +4,23 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -gamma = 5/3 +gamma = 5 / 3 equations = IdealGlmMhdEquations1D(gamma) initial_condition = initial_condition_convergence_test volume_flux = flux_hindenlang_gassner -solver = DGSEM(polydeg=4, surface_flux=flux_lax_friedrichs, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 4, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = 0.0 coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=10_000) - + initial_refinement_level = 2, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -32,32 +30,33 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_errors=(:l2_error_primitive, - :linf_error_primitive), - extra_analysis_integrals=(entropy, energy_total, - energy_kinetic, energy_internal, - energy_magnetic, cross_helicity)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:l2_error_primitive, + :linf_error_primitive), + extra_analysis_integrals = (entropy, energy_total, + energy_kinetic, + energy_internal, + energy_magnetic, + cross_helicity)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_mhd_briowu_shock_tube.jl b/examples/tree_1d_dgsem/elixir_mhd_briowu_shock_tube.jl index c5727109d92..bb294af68cb 100644 --- a/examples/tree_1d_dgsem/elixir_mhd_briowu_shock_tube.jl +++ b/examples/tree_1d_dgsem/elixir_mhd_briowu_shock_tube.jl @@ -17,46 +17,44 @@ MHD extension of the Sod shock tube. Taken from Section V of the article [DOI: 10.1016/0021-9991(88)90120-9](https://doi.org/10.1016/0021-9991(88)90120-9) """ function initial_condition_briowu_shock_tube(x, t, equations::IdealGlmMhdEquations1D) - # domain must be set to [0, 1], γ = 2, final time = 0.12 - rho = x[1] < 0.5 ? 1.0 : 0.125 - v1 = 0.0 - v2 = 0.0 - v3 = 0.0 - p = x[1] < 0.5 ? 1.0 : 0.1 - B1 = 0.75 - B2 = x[1] < 0.5 ? 1.0 : -1.0 - B3 = 0.0 - return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3), equations) + # domain must be set to [0, 1], γ = 2, final time = 0.12 + rho = x[1] < 0.5 ? 1.0 : 0.125 + v1 = 0.0 + v2 = 0.0 + v3 = 0.0 + p = x[1] < 0.5 ? 1.0 : 0.1 + B1 = 0.75 + B2 = x[1] < 0.5 ? 1.0 : -1.0 + B3 = 0.0 + return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3), equations) end initial_condition = initial_condition_briowu_shock_tube boundary_conditions = BoundaryConditionDirichlet(initial_condition) surface_flux = flux_hll -volume_flux = flux_derigs_etal +volume_flux = flux_derigs_etal basis = LobattoLegendreBasis(4) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = 0.0 coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000, - periodicity=false) - + initial_refinement_level = 4, + n_cells_max = 10_000, + periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -67,45 +65,44 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_errors=(:l2_error_primitive, - :linf_error_primitive)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:l2_error_primitive, + :linf_error_primitive)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = density_pressure) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=4, - max_level=6, max_threshold=0.01) + base_level = 4, + max_level = 6, max_threshold = 0.01) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=0.65) +stepsize_callback = StepsizeCallback(cfl = 0.65) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_restart, 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); +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/tree_1d_dgsem/elixir_mhd_ec.jl b/examples/tree_1d_dgsem/elixir_mhd_ec.jl index 1f2e77006b1..e5da808f696 100644 --- a/examples/tree_1d_dgsem/elixir_mhd_ec.jl +++ b/examples/tree_1d_dgsem/elixir_mhd_ec.jl @@ -10,19 +10,17 @@ equations = IdealGlmMhdEquations1D(gamma) initial_condition = initial_condition_weak_blast_wave volume_flux = flux_hindenlang_gassner -solver = DGSEM(polydeg=3, surface_flux=flux_hindenlang_gassner, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_hindenlang_gassner, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = 0.0 coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -32,29 +30,28 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_errors=(:l2_error_primitive, - :linf_error_primitive)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:l2_error_primitive, + :linf_error_primitive)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_mhd_ryujones_shock_tube.jl b/examples/tree_1d_dgsem/elixir_mhd_ryujones_shock_tube.jl index 010788d48f5..b6f856fbc64 100644 --- a/examples/tree_1d_dgsem/elixir_mhd_ryujones_shock_tube.jl +++ b/examples/tree_1d_dgsem/elixir_mhd_ryujones_shock_tube.jl @@ -4,7 +4,7 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -gamma = 5/3 +gamma = 5 / 3 equations = IdealGlmMhdEquations1D(gamma) """ @@ -22,48 +22,46 @@ present in the one dimensional MHD equations. It is the second test from Section This paper has a typo in the initial conditions. Their variable `E` should be `p`. """ function initial_condition_ryujones_shock_tube(x, t, equations::IdealGlmMhdEquations1D) - # domain must be set to [0, 1], γ = 5/3, final time = 0.2 - rho = x[1] <= 0.5 ? 1.08 : 1.0 - v1 = x[1] <= 0.5 ? 1.2 : 0.0 - v2 = x[1] <= 0.5 ? 0.01 : 0.0 - v3 = x[1] <= 0.5 ? 0.5 : 0.0 - p = x[1] <= 0.5 ? 0.95 : 1.0 - inv_sqrt4pi = 1.0 / sqrt(4 * pi) - B1 = 2 * inv_sqrt4pi - B2 = x[1] <= 0.5 ? 3.6 * inv_sqrt4pi : 4.0 * inv_sqrt4pi - B3 = B1 - - return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3), equations) + # domain must be set to [0, 1], γ = 5/3, final time = 0.2 + rho = x[1] <= 0.5 ? 1.08 : 1.0 + v1 = x[1] <= 0.5 ? 1.2 : 0.0 + v2 = x[1] <= 0.5 ? 0.01 : 0.0 + v3 = x[1] <= 0.5 ? 0.5 : 0.0 + p = x[1] <= 0.5 ? 0.95 : 1.0 + inv_sqrt4pi = 1.0 / sqrt(4 * pi) + B1 = 2 * inv_sqrt4pi + B2 = x[1] <= 0.5 ? 3.6 * inv_sqrt4pi : 4.0 * inv_sqrt4pi + B3 = B1 + + return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3), equations) end initial_condition = initial_condition_ryujones_shock_tube boundary_conditions = BoundaryConditionDirichlet(initial_condition) surface_flux = flux_hll -volume_flux = flux_hindenlang_gassner +volume_flux = flux_hindenlang_gassner basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=Trixi.density) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = Trixi.density) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = 0.0 coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=7, - n_cells_max=10_000, - periodicity=false) - + initial_refinement_level = 7, + n_cells_max = 10_000, + periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -74,27 +72,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_mhd_shu_osher_shock_tube.jl b/examples/tree_1d_dgsem/elixir_mhd_shu_osher_shock_tube.jl index 8c60b449e90..8c0317277b0 100644 --- a/examples/tree_1d_dgsem/elixir_mhd_shu_osher_shock_tube.jl +++ b/examples/tree_1d_dgsem/elixir_mhd_shu_osher_shock_tube.jl @@ -4,7 +4,7 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -gamma = 5/3 +gamma = 5 / 3 equations = IdealGlmMhdEquations1D(gamma) """ @@ -17,19 +17,19 @@ Taken from Section 4.1 of [DOI: 10.1016/j.jcp.2016.04.048](https://doi.org/10.1016/j.jcp.2016.04.048) """ function initial_condition_shu_osher_shock_tube(x, t, equations::IdealGlmMhdEquations1D) - # domain must be set to [-5, 5], γ = 5/3, final time = 0.7 - # initial shock location is taken to be at x = -4 - x_0 = -4.0 - rho = x[1] <= x_0 ? 3.5 : 1.0 + 0.2 * sin(5.0 * x[1]) - v1 = x[1] <= x_0 ? 5.8846 : 0.0 - v2 = x[1] <= x_0 ? 1.1198 : 0.0 - v3 = 0.0 - p = x[1] <= x_0 ? 42.0267 : 1.0 - B1 = 1.0 - B2 = x[1] <= x_0 ? 3.6359 : 1.0 - B3 = 0.0 - - return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3), equations) + # domain must be set to [-5, 5], γ = 5/3, final time = 0.7 + # initial shock location is taken to be at x = -4 + x_0 = -4.0 + rho = x[1] <= x_0 ? 3.5 : 1.0 + 0.2 * sin(5.0 * x[1]) + v1 = x[1] <= x_0 ? 5.8846 : 0.0 + v2 = x[1] <= x_0 ? 1.1198 : 0.0 + v3 = 0.0 + p = x[1] <= x_0 ? 42.0267 : 1.0 + B1 = 1.0 + B2 = x[1] <= x_0 ? 3.6359 : 1.0 + B3 = 0.0 + + return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3), equations) end """ @@ -41,50 +41,49 @@ but shock propagates from right to left. !!! note This is useful to exercise some of the components of the HLL flux. """ -function initial_condition_shu_osher_shock_tube_flipped(x, t, equations::IdealGlmMhdEquations1D) - # domain must be set to [-5, 5], γ = 5/3, final time = 0.7 - # initial shock location is taken to be at x = 4 - x_0 = 4.0 - rho = x[1] <= x_0 ? 1.0 + 0.2 * sin(5.0 * x[1]) : 3.5 - v1 = x[1] <= x_0 ? 0.0 : -5.8846 - v2 = x[1] <= x_0 ? 0.0 : -1.1198 - v3 = 0.0 - p = x[1] <= x_0 ? 1.0 : 42.0267 - B1 = 1.0 - B2 = x[1] <= x_0 ? 1.0 : 3.6359 - B3 = 0.0 - - return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3), equations) +function initial_condition_shu_osher_shock_tube_flipped(x, t, + equations::IdealGlmMhdEquations1D) + # domain must be set to [-5, 5], γ = 5/3, final time = 0.7 + # initial shock location is taken to be at x = 4 + x_0 = 4.0 + rho = x[1] <= x_0 ? 1.0 + 0.2 * sin(5.0 * x[1]) : 3.5 + v1 = x[1] <= x_0 ? 0.0 : -5.8846 + v2 = x[1] <= x_0 ? 0.0 : -1.1198 + v3 = 0.0 + p = x[1] <= x_0 ? 1.0 : 42.0267 + B1 = 1.0 + B2 = x[1] <= x_0 ? 1.0 : 3.6359 + B3 = 0.0 + + return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3), equations) end initial_condition = initial_condition_shu_osher_shock_tube boundary_conditions = BoundaryConditionDirichlet(initial_condition) surface_flux = flux_hll -volume_flux = flux_hindenlang_gassner +volume_flux = flux_hindenlang_gassner basis = LobattoLegendreBasis(4) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = -5.0 -coordinates_max = 5.0 +coordinates_max = 5.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000, - periodicity=false) - + initial_refinement_level = 4, + n_cells_max = 10_000, + periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -95,42 +94,43 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(energy_kinetic, energy_internal, - energy_magnetic, cross_helicity)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (energy_kinetic, + energy_internal, + energy_magnetic, + cross_helicity)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = density_pressure) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=4, - max_level=7, max_threshold=0.01) + base_level = 4, + max_level = 7, max_threshold = 0.01) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) 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); +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/tree_1d_dgsem/elixir_mhd_torrilhon_shock_tube.jl b/examples/tree_1d_dgsem/elixir_mhd_torrilhon_shock_tube.jl index 68556764293..3b366c35e0f 100644 --- a/examples/tree_1d_dgsem/elixir_mhd_torrilhon_shock_tube.jl +++ b/examples/tree_1d_dgsem/elixir_mhd_torrilhon_shock_tube.jl @@ -4,7 +4,7 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -gamma = 5/3 +gamma = 5 / 3 equations = IdealGlmMhdEquations1D(gamma) """ @@ -16,46 +16,44 @@ Torrilhon's shock tube test case for one dimensional ideal MHD equations. [DOI: 10.1017/S0022377803002186](https://doi.org/10.1017/S0022377803002186) """ function initial_condition_torrilhon_shock_tube(x, t, equations::IdealGlmMhdEquations1D) - # domain must be set to [-1, 1.5], γ = 5/3, final time = 0.4 - rho = x[1] <= 0 ? 3.0 : 1.0 - v1 = 0.0 - v2 = 0.0 - v3 = 0.0 - p = x[1] <= 0 ? 3.0 : 1.0 - B1 = 1.5 - B2 = x[1] <= 0 ? 1.0 : cos(1.5) - B3 = x[1] <= 0 ? 0.0 : sin(1.5) - return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3), equations) + # domain must be set to [-1, 1.5], γ = 5/3, final time = 0.4 + rho = x[1] <= 0 ? 3.0 : 1.0 + v1 = 0.0 + v2 = 0.0 + v3 = 0.0 + p = x[1] <= 0 ? 3.0 : 1.0 + B1 = 1.5 + B2 = x[1] <= 0 ? 1.0 : cos(1.5) + B3 = x[1] <= 0 ? 0.0 : sin(1.5) + return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3), equations) end initial_condition = initial_condition_torrilhon_shock_tube boundary_conditions = BoundaryConditionDirichlet(initial_condition) surface_flux = flux_lax_friedrichs -volume_flux = flux_central +volume_flux = flux_central basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = -1.0 -coordinates_max = 1.5 +coordinates_max = 1.5 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=7, - n_cells_max=10_000, - periodicity=false) - + initial_refinement_level = 7, + n_cells_max = 10_000, + periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -66,29 +64,28 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_errors=(:l2_error_primitive, - :linf_error_primitive)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:l2_error_primitive, + :linf_error_primitive)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_mhdmulti_briowu_shock_tube.jl b/examples/tree_1d_dgsem/elixir_mhdmulti_briowu_shock_tube.jl index 376f11d52a2..831fa7afedb 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmulti_briowu_shock_tube.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmulti_briowu_shock_tube.jl @@ -4,8 +4,8 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealGlmMhdMulticomponentEquations1D(gammas = (2.0, 2.0), - gas_constants = (2.0, 2.0)) +equations = IdealGlmMhdMulticomponentEquations1D(gammas = (2.0, 2.0), + gas_constants = (2.0, 2.0)) """ initial_condition_briowu_shock_tube(x, t, equations::IdealGlmMhdMulticomponentEquations1D) @@ -16,55 +16,62 @@ MHD extension of the Sod shock tube. Taken from Section V of the article An Upwind Differencing Scheme for the Equations of Ideal Magnetohydrodynamics [DOI: 10.1016/0021-9991(88)90120-9](https://doi.org/10.1016/0021-9991(88)90120-9) """ -function initial_condition_briowu_shock_tube(x, t, equations::IdealGlmMhdMulticomponentEquations1D) - # domain must be set to [0, 1], γ = 2, final time = 0.12 - if x[1] < 0.5 - rho = 1.0 - prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) - else - rho = 0.125 - prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) - end - v1 = 0.0 - v2 = 0.0 - v3 = 0.0 - p = x[1] < 0.5 ? 1.0 : 0.1 - B1 = 0.75 - B2 = x[1] < 0.5 ? 1.0 : -1.0 - B3 = 0.0 - - prim_other = SVector(v1, v2, v3, p, B1, B2, B3) - return prim2cons(vcat(prim_other, prim_rho), equations) +function initial_condition_briowu_shock_tube(x, t, + equations::IdealGlmMhdMulticomponentEquations1D) + # domain must be set to [0, 1], γ = 2, final time = 0.12 + if x[1] < 0.5 + rho = 1.0 + prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i - 1) * (1 - 2) / + (1 - + 2^ncomponents(equations)) * + rho + for i in eachcomponent(equations)) + else + rho = 0.125 + prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i - 1) * (1 - 2) / + (1 - + 2^ncomponents(equations)) * + rho + for i in eachcomponent(equations)) + end + v1 = 0.0 + v2 = 0.0 + v3 = 0.0 + p = x[1] < 0.5 ? 1.0 : 0.1 + B1 = 0.75 + B2 = x[1] < 0.5 ? 1.0 : -1.0 + B3 = 0.0 + + prim_other = SVector(v1, v2, v3, p, B1, B2, B3) + return prim2cons(vcat(prim_other, prim_rho), equations) end initial_condition = initial_condition_briowu_shock_tube boundary_conditions = BoundaryConditionDirichlet(initial_condition) surface_flux = flux_lax_friedrichs -volume_flux = flux_hindenlang_gassner +volume_flux = flux_hindenlang_gassner basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.8, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.8, + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = 0.0 coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000, - periodicity=false) - + initial_refinement_level = 4, + n_cells_max = 10_000, + periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -75,45 +82,44 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_errors=(:l2_error_primitive, - :linf_error_primitive)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:l2_error_primitive, + :linf_error_primitive)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = density_pressure) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=4, - max_level=6, max_threshold=0.01) + base_level = 4, + max_level = 6, max_threshold = 0.01) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_restart, 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); +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/tree_1d_dgsem/elixir_mhdmulti_convergence.jl b/examples/tree_1d_dgsem/elixir_mhdmulti_convergence.jl index 573bf6bc3e9..a1636c08478 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmulti_convergence.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmulti_convergence.jl @@ -5,25 +5,23 @@ using Trixi ############################################################################### # semidiscretization of the compressible ideal GLM-MHD equations -equations = IdealGlmMhdMulticomponentEquations1D(gammas = (5/3, 5/3, 5/3), - gas_constants = (2.08, 2.08, 2.08)) +equations = IdealGlmMhdMulticomponentEquations1D(gammas = (5 / 3, 5 / 3, 5 / 3), + gas_constants = (2.08, 2.08, 2.08)) initial_condition = initial_condition_convergence_test volume_flux = flux_hindenlang_gassner -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = 0.0 coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=10_000) - + initial_refinement_level = 2, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -33,17 +31,18 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=true) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=10, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 10, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) cfl = 0.5 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -51,11 +50,10 @@ callbacks = CallbackSet(summary_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_mhdmulti_ec.jl b/examples/tree_1d_dgsem/elixir_mhdmulti_ec.jl index 69ea0551bed..71466f3138a 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmulti_ec.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmulti_ec.jl @@ -4,25 +4,23 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealGlmMhdMulticomponentEquations1D(gammas = (2.0, 2.0, 2.0), +equations = IdealGlmMhdMulticomponentEquations1D(gammas = (2.0, 2.0, 2.0), gas_constants = (2.0, 2.0, 2.0)) initial_condition = initial_condition_weak_blast_wave volume_flux = flux_hindenlang_gassner -solver = DGSEM(polydeg=3, surface_flux=flux_hindenlang_gassner, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_hindenlang_gassner, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = 0.0 coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -32,26 +30,25 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_mhdmulti_es.jl b/examples/tree_1d_dgsem/elixir_mhdmulti_es.jl index 93cf3e0fdb2..37623e048ed 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmulti_es.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmulti_es.jl @@ -4,25 +4,23 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealGlmMhdMulticomponentEquations1D(gammas = (2.0, 2.0, 2.0), +equations = IdealGlmMhdMulticomponentEquations1D(gammas = (2.0, 2.0, 2.0), gas_constants = (2.0, 2.0, 2.0)) initial_condition = initial_condition_weak_blast_wave volume_flux = flux_hindenlang_gassner -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = 0.0 coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -32,29 +30,28 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_errors=(:l2_error_primitive, - :linf_error_primitive)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:l2_error_primitive, + :linf_error_primitive)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_navierstokes_convergence_periodic.jl b/examples/tree_1d_dgsem/elixir_navierstokes_convergence_periodic.jl index 3f72d319b0b..33ad0d5271c 100644 --- a/examples/tree_1d_dgsem/elixir_navierstokes_convergence_periodic.jl +++ b/examples/tree_1d_dgsem/elixir_navierstokes_convergence_periodic.jl @@ -10,101 +10,101 @@ prandtl_number() = 0.72 mu() = 6.25e-4 # equivalent to Re = 1600 equations = CompressibleEulerEquations1D(1.4) -equations_parabolic = CompressibleNavierStokesDiffusion1D(equations, mu=mu(), - Prandtl=prandtl_number()) +equations_parabolic = CompressibleNavierStokesDiffusion1D(equations, mu = mu(), + Prandtl = prandtl_number()) # This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) # (Simplified version of the 2D) function initial_condition_navier_stokes_convergence_test(x, t, equations) - # Amplitude and shift - A = 0.5 - c = 2.0 + # Amplitude and shift + A = 0.5 + c = 2.0 - # convenience values for trig. functions - pi_x = pi * x[1] - pi_t = pi * t + # convenience values for trig. functions + pi_x = pi * x[1] + pi_t = pi * t - rho = c + A * sin(pi_x) * cos(pi_t) - v1 = sin(pi_x) * cos(pi_t) - p = rho^2 + rho = c + A * sin(pi_x) * cos(pi_t) + v1 = sin(pi_x) * cos(pi_t) + p = rho^2 - return prim2cons(SVector(rho, v1, p), equations) + return prim2cons(SVector(rho, v1, p), equations) end initial_condition = initial_condition_navier_stokes_convergence_test @inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) - # we currently need to hardcode these parameters until we fix the "combined equation" issue - # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 - inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = prandtl_number() - mu_ = mu() - - # Same settings as in `initial_condition` - # Amplitude and shift - A = 0.5 - c = 2.0 - - # convenience values for trig. functions - pi_x = pi * x[1] - pi_t = pi * t - - # compute the manufactured solution and all necessary derivatives - rho = c + A * sin(pi_x) * cos(pi_t) - rho_t = -pi * A * sin(pi_x) * sin(pi_t) - rho_x = pi * A * cos(pi_x) * cos(pi_t) - rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_t) - - v1 = sin(pi_x) * cos(pi_t) - v1_t = -pi * sin(pi_x) * sin(pi_t) - v1_x = pi * cos(pi_x) * cos(pi_t) - v1_xx = -pi * pi * sin(pi_x) * cos(pi_t) - - p = rho * rho - p_t = 2.0 * rho * rho_t - p_x = 2.0 * rho * rho_x - p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x - - E = p * inv_gamma_minus_one + 0.5 * rho * v1^2 - E_t = p_t * inv_gamma_minus_one + 0.5 * rho_t * v1^2 + rho * v1 * v1_t - E_x = p_x * inv_gamma_minus_one + 0.5 * rho_x * v1^2 + rho * v1 * v1_x - - # Some convenience constants - T_const = equations.gamma * inv_gamma_minus_one / Pr - inv_rho_cubed = 1.0 / (rho^3) - - # compute the source terms - # density equation - du1 = rho_t + rho_x * v1 + rho * v1_x - - # x-momentum equation - du2 = ( rho_t * v1 + rho * v1_t - + p_x + rho_x * v1^2 + 2.0 * rho * v1 * v1_x - # stress tensor from x-direction - - v1_xx * mu_) - - # total energy equation - du3 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) - # stress tensor and temperature gradient terms from x-direction - - v1_xx * v1 * mu_ - - v1_x * v1_x * mu_ - - T_const * inv_rho_cubed * ( p_xx * rho * rho - - 2.0 * p_x * rho * rho_x - + 2.0 * p * rho_x * rho_x - - p * rho * rho_xx ) * mu_) - - return SVector(du1, du2, du3) + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + mu_ = mu() + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * sin(pi_x) * cos(pi_t) + rho_t = -pi * A * sin(pi_x) * sin(pi_t) + rho_x = pi * A * cos(pi_x) * cos(pi_t) + rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_t) + + v1 = sin(pi_x) * cos(pi_t) + v1_t = -pi * sin(pi_x) * sin(pi_t) + v1_x = pi * cos(pi_x) * cos(pi_t) + v1_xx = -pi * pi * sin(pi_x) * cos(pi_t) + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + + E = p * inv_gamma_minus_one + 0.5 * rho * v1^2 + E_t = p_t * inv_gamma_minus_one + 0.5 * rho_t * v1^2 + rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + 0.5 * rho_x * v1^2 + rho * v1 * v1_x + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one / Pr + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + + # x-momentum equation + du2 = (rho_t * v1 + rho * v1_t + + p_x + rho_x * v1^2 + 2.0 * rho * v1 * v1_x - + # stress tensor from x-direction + v1_xx * mu_) + + # total energy equation + du3 = (E_t + v1_x * (E + p) + v1 * (E_x + p_x) - + # stress tensor and temperature gradient terms from x-direction + v1_xx * v1 * mu_ - + v1_x * v1_x * mu_ - + T_const * inv_rho_cubed * + (p_xx * rho * rho - + 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x - + p * rho * rho_xx) * mu_) + + return SVector(du1, du2, du3) end volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_hllc, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_hllc, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = -1.0 -coordinates_max = 1.0 +coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=100_000) - + initial_refinement_level = 4, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver, @@ -119,9 +119,9 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval,) +alive_callback = AliveCallback(analysis_interval = analysis_interval) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -131,6 +131,6 @@ callbacks = CallbackSet(summary_callback, # run the simulation time_int_tol = 1e-9 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) -summary_callback() # print the timer summary \ No newline at end of file +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) +summary_callback() # print the timer summary diff --git a/examples/tree_1d_dgsem/elixir_navierstokes_convergence_walls.jl b/examples/tree_1d_dgsem/elixir_navierstokes_convergence_walls.jl index 181a2cb209f..40030d53345 100644 --- a/examples/tree_1d_dgsem/elixir_navierstokes_convergence_walls.jl +++ b/examples/tree_1d_dgsem/elixir_navierstokes_convergence_walls.jl @@ -8,135 +8,145 @@ prandtl_number() = 0.72 mu() = 0.01 equations = CompressibleEulerEquations1D(1.4) -equations_parabolic = CompressibleNavierStokesDiffusion1D(equations, mu=mu(), Prandtl=prandtl_number(), - gradient_variables=GradientVariablesPrimitive()) +equations_parabolic = CompressibleNavierStokesDiffusion1D(equations, mu = mu(), + Prandtl = prandtl_number(), + gradient_variables = GradientVariablesPrimitive()) # 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, - volume_integral=VolumeIntegralWeakForm()) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralWeakForm()) coordinates_min = -1.0 -coordinates_max = 1.0 +coordinates_max = 1.0 # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - periodicity=false, - n_cells_max=30_000) # set maximum capacity of tree data structure + initial_refinement_level = 3, + periodicity = false, + n_cells_max = 30_000) # set maximum capacity of tree data structure # Note: the initial condition cannot be specialized to `CompressibleNavierStokesDiffusion1D` # since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesDiffusion1D`) # and by the initial condition (which passes in `CompressibleEulerEquations1D`). # This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) function initial_condition_navier_stokes_convergence_test(x, t, equations) - # Amplitude and shift - A = 0.5 - c = 2.0 + # Amplitude and shift + A = 0.5 + c = 2.0 - # convenience values for trig. functions - pi_x = pi * x[1] - pi_t = pi * t + # convenience values for trig. functions + pi_x = pi * x[1] + pi_t = pi * t - rho = c + A * cos(pi_x) * cos(pi_t) - v1 = log(x[1] + 2.0) * (1.0 - exp(-A * (x[1] - 1.0)) ) * cos(pi_t) - p = rho^2 + rho = c + A * cos(pi_x) * cos(pi_t) + v1 = log(x[1] + 2.0) * (1.0 - exp(-A * (x[1] - 1.0))) * cos(pi_t) + p = rho^2 - return prim2cons(SVector(rho, v1, p), equations) + return prim2cons(SVector(rho, v1, p), equations) end @inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) - x = x[1] - - # TODO: parabolic - # we currently need to hardcode these parameters until we fix the "combined equation" issue - # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 - inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = prandtl_number() - mu_ = mu() - - # Same settings as in `initial_condition` - # Amplitude and shift - A = 0.5 - c = 2.0 - - # convenience values for trig. functions - pi_x = pi * x - pi_t = pi * t - - # compute the manufactured solution and all necessary derivatives - rho = c + A * cos(pi_x) * cos(pi_t) - rho_t = -pi * A * cos(pi_x) * sin(pi_t) - rho_x = -pi * A * sin(pi_x) * cos(pi_t) - rho_xx = -pi * pi * A * cos(pi_x) * cos(pi_t) - - v1 = log(x + 2.0) * (1.0 - exp(-A * (x - 1.0))) * cos(pi_t) - v1_t = -pi * log(x + 2.0) * (1.0 - exp(-A * (x - 1.0))) * sin(pi_t) - v1_x = (A * log(x + 2.0) * exp(-A * (x - 1.0)) + (1.0 - exp(-A * (x - 1.0))) / (x + 2.0)) * cos(pi_t) - v1_xx = (( 2.0 * A * exp(-A * (x - 1.0)) / (x + 2.0) - - A * A * log(x + 2.0) * exp(-A * (x - 1.0)) - - (1.0 - exp(-A * (x - 1.0))) / ((x + 2.0) * (x + 2.0))) * cos(pi_t)) - - p = rho * rho - p_t = 2.0 * rho * rho_t - p_x = 2.0 * rho * rho_x - p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x - - # Note this simplifies slightly because the ansatz assumes that v1 = v2 - E = p * inv_gamma_minus_one + 0.5 * rho * v1^2 - E_t = p_t * inv_gamma_minus_one + 0.5 * rho_t * v1^2 + rho * v1 * v1_t - E_x = p_x * inv_gamma_minus_one + 0.5 * rho_x * v1^2 + rho * v1 * v1_x - - # Some convenience constants - T_const = equations.gamma * inv_gamma_minus_one / Pr - inv_rho_cubed = 1.0 / (rho^3) - - # compute the source terms - # density equation - du1 = rho_t + rho_x * v1 + rho * v1_x - - # y-momentum equation - du2 = ( rho_t * v1 + rho * v1_t - + p_x + rho_x * v1^2 + 2.0 * rho * v1 * v1_x - # stress tensor from y-direction - - v1_xx * mu_) - - # total energy equation - du3 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) - # stress tensor and temperature gradient terms from x-direction - - v1_xx * v1 * mu_ - - v1_x * v1_x * mu_ - - T_const * inv_rho_cubed * ( p_xx * rho * rho - - 2.0 * p_x * rho * rho_x - + 2.0 * p * rho_x * rho_x - - p * rho * rho_xx ) * mu_ ) - - return SVector(du1, du2, du3) + x = x[1] + + # TODO: parabolic + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + mu_ = mu() + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * cos(pi_x) * cos(pi_t) + rho_t = -pi * A * cos(pi_x) * sin(pi_t) + rho_x = -pi * A * sin(pi_x) * cos(pi_t) + rho_xx = -pi * pi * A * cos(pi_x) * cos(pi_t) + + v1 = log(x + 2.0) * (1.0 - exp(-A * (x - 1.0))) * cos(pi_t) + v1_t = -pi * log(x + 2.0) * (1.0 - exp(-A * (x - 1.0))) * sin(pi_t) + v1_x = (A * log(x + 2.0) * exp(-A * (x - 1.0)) + + (1.0 - exp(-A * (x - 1.0))) / (x + 2.0)) * cos(pi_t) + v1_xx = ((2.0 * A * exp(-A * (x - 1.0)) / (x + 2.0) - + A * A * log(x + 2.0) * exp(-A * (x - 1.0)) - + (1.0 - exp(-A * (x - 1.0))) / ((x + 2.0) * (x + 2.0))) * cos(pi_t)) + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + + # Note this simplifies slightly because the ansatz assumes that v1 = v2 + E = p * inv_gamma_minus_one + 0.5 * rho * v1^2 + E_t = p_t * inv_gamma_minus_one + 0.5 * rho_t * v1^2 + rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + 0.5 * rho_x * v1^2 + rho * v1 * v1_x + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one / Pr + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + + # y-momentum equation + du2 = (rho_t * v1 + rho * v1_t + + p_x + rho_x * v1^2 + 2.0 * rho * v1 * v1_x - + # stress tensor from y-direction + v1_xx * mu_) + + # total energy equation + du3 = (E_t + v1_x * (E + p) + v1 * (E_x + p_x) - + # stress tensor and temperature gradient terms from x-direction + v1_xx * v1 * mu_ - + v1_x * v1_x * mu_ - + T_const * inv_rho_cubed * + (p_xx * rho * rho - + 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x - + p * rho * rho_xx) * mu_) + + return SVector(du1, du2, du3) end initial_condition = initial_condition_navier_stokes_convergence_test # BC types -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)) +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) -> 0.0) -boundary_condition_left = BoundaryConditionNavierStokesWall(velocity_bc_left_right, heat_bc_left) -boundary_condition_right = BoundaryConditionNavierStokesWall(velocity_bc_left_right, heat_bc_right) +boundary_condition_left = BoundaryConditionNavierStokesWall(velocity_bc_left_right, + heat_bc_left) +boundary_condition_right = BoundaryConditionNavierStokesWall(velocity_bc_left_right, + heat_bc_right) # define inviscid boundary conditions boundary_conditions = (; x_neg = boundary_condition_slip_wall, - x_pos = boundary_condition_slip_wall) + x_pos = boundary_condition_slip_wall) # define viscous boundary conditions boundary_conditions_parabolic = (; x_neg = boundary_condition_left, - x_pos = boundary_condition_right) + x_pos = boundary_condition_right) -semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; - boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), - source_terms=source_terms_navier_stokes_convergence_test) +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic), + source_terms = source_terms_navier_stokes_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -146,15 +156,15 @@ tspan = (0.0, 1.0) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, - ode_default_options()..., callback=callbacks) -summary_callback() # print the timer summary \ No newline at end of file +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, dt = 1e-5, + ode_default_options()..., callback = callbacks) +summary_callback() # print the timer summary diff --git a/examples/tree_1d_dgsem/elixir_navierstokes_convergence_walls_amr.jl b/examples/tree_1d_dgsem/elixir_navierstokes_convergence_walls_amr.jl index 1daeab04a71..e833155a68e 100644 --- a/examples/tree_1d_dgsem/elixir_navierstokes_convergence_walls_amr.jl +++ b/examples/tree_1d_dgsem/elixir_navierstokes_convergence_walls_amr.jl @@ -8,135 +8,145 @@ prandtl_number() = 0.72 mu() = 0.01 equations = CompressibleEulerEquations1D(1.4) -equations_parabolic = CompressibleNavierStokesDiffusion1D(equations, mu=mu(), Prandtl=prandtl_number(), - gradient_variables=GradientVariablesEntropy()) +equations_parabolic = CompressibleNavierStokesDiffusion1D(equations, mu = mu(), + Prandtl = prandtl_number(), + gradient_variables = GradientVariablesEntropy()) # 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, - volume_integral=VolumeIntegralWeakForm()) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralWeakForm()) coordinates_min = -1.0 -coordinates_max = 1.0 +coordinates_max = 1.0 # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - periodicity=false, - n_cells_max=30_000) # set maximum capacity of tree data structure + initial_refinement_level = 3, + periodicity = false, + n_cells_max = 30_000) # set maximum capacity of tree data structure # Note: the initial condition cannot be specialized to `CompressibleNavierStokesDiffusion1D` # since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesDiffusion1D`) # and by the initial condition (which passes in `CompressibleEulerEquations1D`). # This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) function initial_condition_navier_stokes_convergence_test(x, t, equations) - # Amplitude and shift - A = 0.5 - c = 2.0 + # Amplitude and shift + A = 0.5 + c = 2.0 - # convenience values for trig. functions - pi_x = pi * x[1] - pi_t = pi * t + # convenience values for trig. functions + pi_x = pi * x[1] + pi_t = pi * t - rho = c + A * cos(pi_x) * cos(pi_t) - v1 = log(x[1] + 2.0) * (1.0 - exp(-A * (x[1] - 1.0)) ) * cos(pi_t) - p = rho^2 + rho = c + A * cos(pi_x) * cos(pi_t) + v1 = log(x[1] + 2.0) * (1.0 - exp(-A * (x[1] - 1.0))) * cos(pi_t) + p = rho^2 - return prim2cons(SVector(rho, v1, p), equations) + return prim2cons(SVector(rho, v1, p), equations) end @inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) - x = x[1] - - # TODO: parabolic - # we currently need to hardcode these parameters until we fix the "combined equation" issue - # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 - inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = prandtl_number() - mu_ = mu() - - # Same settings as in `initial_condition` - # Amplitude and shift - A = 0.5 - c = 2.0 - - # convenience values for trig. functions - pi_x = pi * x - pi_t = pi * t - - # compute the manufactured solution and all necessary derivatives - rho = c + A * cos(pi_x) * cos(pi_t) - rho_t = -pi * A * cos(pi_x) * sin(pi_t) - rho_x = -pi * A * sin(pi_x) * cos(pi_t) - rho_xx = -pi * pi * A * cos(pi_x) * cos(pi_t) - - v1 = log(x + 2.0) * (1.0 - exp(-A * (x - 1.0))) * cos(pi_t) - v1_t = -pi * log(x + 2.0) * (1.0 - exp(-A * (x - 1.0))) * sin(pi_t) - v1_x = (A * log(x + 2.0) * exp(-A * (x - 1.0)) + (1.0 - exp(-A * (x - 1.0))) / (x + 2.0)) * cos(pi_t) - v1_xx = (( 2.0 * A * exp(-A * (x - 1.0)) / (x + 2.0) - - A * A * log(x + 2.0) * exp(-A * (x - 1.0)) - - (1.0 - exp(-A * (x - 1.0))) / ((x + 2.0) * (x + 2.0))) * cos(pi_t)) - - p = rho * rho - p_t = 2.0 * rho * rho_t - p_x = 2.0 * rho * rho_x - p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x - - # Note this simplifies slightly because the ansatz assumes that v1 = v2 - E = p * inv_gamma_minus_one + 0.5 * rho * v1^2 - E_t = p_t * inv_gamma_minus_one + 0.5 * rho_t * v1^2 + rho * v1 * v1_t - E_x = p_x * inv_gamma_minus_one + 0.5 * rho_x * v1^2 + rho * v1 * v1_x - - # Some convenience constants - T_const = equations.gamma * inv_gamma_minus_one / Pr - inv_rho_cubed = 1.0 / (rho^3) - - # compute the source terms - # density equation - du1 = rho_t + rho_x * v1 + rho * v1_x - - # y-momentum equation - du2 = ( rho_t * v1 + rho * v1_t - + p_x + rho_x * v1^2 + 2.0 * rho * v1 * v1_x - # stress tensor from y-direction - - v1_xx * mu_) - - # total energy equation - du3 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) - # stress tensor and temperature gradient terms from x-direction - - v1_xx * v1 * mu_ - - v1_x * v1_x * mu_ - - T_const * inv_rho_cubed * ( p_xx * rho * rho - - 2.0 * p_x * rho * rho_x - + 2.0 * p * rho_x * rho_x - - p * rho * rho_xx ) * mu_ ) - - return SVector(du1, du2, du3) + x = x[1] + + # TODO: parabolic + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + mu_ = mu() + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * cos(pi_x) * cos(pi_t) + rho_t = -pi * A * cos(pi_x) * sin(pi_t) + rho_x = -pi * A * sin(pi_x) * cos(pi_t) + rho_xx = -pi * pi * A * cos(pi_x) * cos(pi_t) + + v1 = log(x + 2.0) * (1.0 - exp(-A * (x - 1.0))) * cos(pi_t) + v1_t = -pi * log(x + 2.0) * (1.0 - exp(-A * (x - 1.0))) * sin(pi_t) + v1_x = (A * log(x + 2.0) * exp(-A * (x - 1.0)) + + (1.0 - exp(-A * (x - 1.0))) / (x + 2.0)) * cos(pi_t) + v1_xx = ((2.0 * A * exp(-A * (x - 1.0)) / (x + 2.0) - + A * A * log(x + 2.0) * exp(-A * (x - 1.0)) - + (1.0 - exp(-A * (x - 1.0))) / ((x + 2.0) * (x + 2.0))) * cos(pi_t)) + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + + # Note this simplifies slightly because the ansatz assumes that v1 = v2 + E = p * inv_gamma_minus_one + 0.5 * rho * v1^2 + E_t = p_t * inv_gamma_minus_one + 0.5 * rho_t * v1^2 + rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + 0.5 * rho_x * v1^2 + rho * v1 * v1_x + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one / Pr + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + + # y-momentum equation + du2 = (rho_t * v1 + rho * v1_t + + p_x + rho_x * v1^2 + 2.0 * rho * v1 * v1_x - + # stress tensor from y-direction + v1_xx * mu_) + + # total energy equation + du3 = (E_t + v1_x * (E + p) + v1 * (E_x + p_x) - + # stress tensor and temperature gradient terms from x-direction + v1_xx * v1 * mu_ - + v1_x * v1_x * mu_ - + T_const * inv_rho_cubed * + (p_xx * rho * rho - + 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x - + p * rho * rho_xx) * mu_) + + return SVector(du1, du2, du3) end initial_condition = initial_condition_navier_stokes_convergence_test # BC types -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)) +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) -> 0.0) -boundary_condition_left = BoundaryConditionNavierStokesWall(velocity_bc_left_right, heat_bc_left) -boundary_condition_right = BoundaryConditionNavierStokesWall(velocity_bc_left_right, heat_bc_right) +boundary_condition_left = BoundaryConditionNavierStokesWall(velocity_bc_left_right, + heat_bc_left) +boundary_condition_right = BoundaryConditionNavierStokesWall(velocity_bc_left_right, + heat_bc_right) # define inviscid boundary conditions boundary_conditions = (; x_neg = boundary_condition_slip_wall, - x_pos = boundary_condition_slip_wall) + x_pos = boundary_condition_slip_wall) # define viscous boundary conditions boundary_conditions_parabolic = (; x_neg = boundary_condition_left, - x_pos = boundary_condition_right) + x_pos = boundary_condition_right) -semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; - boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), - source_terms=source_terms_navier_stokes_convergence_test) +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic), + source_terms = source_terms_navier_stokes_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -146,19 +156,19 @@ tspan = (0.0, 1.0) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -amr_controller = ControllerThreeLevel(semi, - IndicatorLöhner(semi, variable=Trixi.density), - base_level=3, - med_level=4, med_threshold=0.005, - max_level=5, max_threshold=0.01) +amr_controller = ControllerThreeLevel(semi, + IndicatorLöhner(semi, variable = Trixi.density), + base_level = 3, + med_level = 4, med_threshold = 0.005, + max_level = 5, max_threshold = 0.01) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true) + interval = 5, + adapt_initial_condition = true) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, amr_callback) @@ -167,6 +177,6 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, amr # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, - ode_default_options()..., callback=callbacks) -summary_callback() # print the timer summary \ No newline at end of file +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, dt = 1e-5, + ode_default_options()..., callback = callbacks) +summary_callback() # print the timer summary diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_beach.jl b/examples/tree_1d_dgsem/elixir_shallowwater_beach.jl index 1288bc5e66a..378079ca334 100644 --- a/examples/tree_1d_dgsem/elixir_shallowwater_beach.jl +++ b/examples/tree_1d_dgsem/elixir_shallowwater_beach.jl @@ -7,7 +7,7 @@ using Trixi # # TODO: TrixiShallowWater: wet/dry example elixir -equations = ShallowWaterEquations1D(gravity_constant=9.812) +equations = ShallowWaterEquations1D(gravity_constant = 9.812) """ initial_condition_beach(x, t, equations:: ShallowWaterEquations1D) @@ -22,33 +22,33 @@ found in section 5.2 of the paper: Finite volume evolution Galerkin methods for the shallow water equations with dry beds\n [DOI: 10.4208/cicp.220210.020710a](https://dx.doi.org/10.4208/cicp.220210.020710a) """ -function initial_condition_beach(x, t, equations:: ShallowWaterEquations1D) - D = 1 - delta = 0.02 - gamma = sqrt((3 * delta) / (4 * D)) - x_a = sqrt((4 * D) / (3 * delta)) * acosh(sqrt(20)) - - f = D + 40 * delta * sech(gamma * (8 * x[1] - x_a))^2 - - # steep curved beach - b = 0.01 + 99 / 409600 * 4^x[1] - - if x[1] >= 6 - H = b - v = 0.0 - else - H = f - v = sqrt(equations.gravity / D) * H - end - - # It is mandatory to shift the water level at dry areas to make sure the water height h - # stays positive. The system would not be stable for h set to a hard 0 due to division by h in - # the computation of velocity, e.g., (h v) / h. Therefore, a small dry state threshold - # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above - # for the ShallowWaterEquations and added to the initial condition if h = 0. - # This default value can be changed within the constructor call depending on the simulation setup. - H = max(H, b + equations.threshold_limiter) - return prim2cons(SVector(H, v, b), equations) +function initial_condition_beach(x, t, equations::ShallowWaterEquations1D) + D = 1 + delta = 0.02 + gamma = sqrt((3 * delta) / (4 * D)) + x_a = sqrt((4 * D) / (3 * delta)) * acosh(sqrt(20)) + + f = D + 40 * delta * sech(gamma * (8 * x[1] - x_a))^2 + + # steep curved beach + b = 0.01 + 99 / 409600 * 4^x[1] + + if x[1] >= 6 + H = b + v = 0.0 + else + H = f + v = sqrt(equations.gravity / D) * H + end + + # It is mandatory to shift the water level at dry areas to make sure the water height h + # stays positive. The system would not be stable for h set to a hard 0 due to division by h in + # the computation of velocity, e.g., (h v) / h. Therefore, a small dry state threshold + # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above + # for the ShallowWaterEquations and added to the initial condition if h = 0. + # This default value can be changed within the constructor call depending on the simulation setup. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v, b), equations) end initial_condition = initial_condition_beach @@ -58,19 +58,20 @@ boundary_condition = boundary_condition_slip_wall # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, + hydrostatic_reconstruction_chen_noelle), flux_nonconservative_chen_noelle) basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=waterheight_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = waterheight_pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) @@ -81,13 +82,13 @@ coordinates_min = 0.0 coordinates_max = 8.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=7, - n_cells_max=10_000, - periodicity=false) + initial_refinement_level = 7, + n_cells_max = 10_000, + periodicity = false) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_condition) + boundary_conditions = boundary_condition) ############################################################################### # ODE solvers, callbacks etc. @@ -98,24 +99,25 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false, - extra_analysis_integrals=(energy_kinetic, - energy_internal)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = false, + extra_analysis_integrals = (energy_kinetic, + energy_internal)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(dt=0.5, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(dt = 0.5, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) -stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) +stage_limiter! = PositivityPreservingLimiterShallowWater(variables = (Trixi.waterheight,)) ############################################################################### # run the simulation sol = solve(ode, SSPRK43(stage_limiter!); - ode_default_options()..., callback=callbacks); + ode_default_options()..., callback = callbacks); -summary_callback() # print the timer summary \ No newline at end of file +summary_callback() # print the timer summary diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_ec.jl b/examples/tree_1d_dgsem/elixir_shallowwater_ec.jl index 1469afec1ca..a3df37fb966 100644 --- a/examples/tree_1d_dgsem/elixir_shallowwater_ec.jl +++ b/examples/tree_1d_dgsem/elixir_shallowwater_ec.jl @@ -6,7 +6,7 @@ using Trixi # Semidiscretization of the shallow water equations with a discontinuous # bottom topography function -equations = ShallowWaterEquations1D(gravity_constant=9.81) +equations = ShallowWaterEquations1D(gravity_constant = 9.81) # Initial condition with a truly discontinuous water height, velocity, and bottom # topography function as an academic testcase for entropy conservation. @@ -16,23 +16,23 @@ equations = ShallowWaterEquations1D(gravity_constant=9.81) # refinement level is changed the initial condition below may need changed as well to # ensure that the discontinuities lie on an element interface. function initial_condition_ec_discontinuous_bottom(x, t, equations::ShallowWaterEquations1D) - # Set the background values - H = 4.25 - v = 0.0 - b = sin(x[1]) # arbitrary continuous function - - # Setup the discontinuous water height and velocity - if x[1] >= 0.125 && x[1] <= 0.25 - H = 5.0 - v = 0.1882 - end - - # Setup a discontinuous bottom topography - if x[1] >= -0.25 && x[1] <= -0.125 - b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) - end - - return prim2cons(SVector(H, v, b), equations) + # Set the background values + H = 4.25 + v = 0.0 + b = sin(x[1]) # arbitrary continuous function + + # Setup the discontinuous water height and velocity + if x[1] >= 0.125 && x[1] <= 0.25 + H = 5.0 + v = 0.1882 + end + + # Setup a discontinuous bottom topography + if x[1] >= -0.25 && x[1] <= -0.125 + b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) + end + + return prim2cons(SVector(H, v, b), equations) end initial_condition = initial_condition_ec_discontinuous_bottom @@ -41,8 +41,9 @@ initial_condition = initial_condition_ec_discontinuous_bottom # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -solver = DGSEM(polydeg=4, surface_flux=(flux_fjordholm_etal, flux_nonconservative_fjordholm_etal), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 4, + surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the TreeMesh and setup a periodic mesh @@ -50,8 +51,8 @@ solver = DGSEM(polydeg=4, surface_flux=(flux_fjordholm_etal, flux_nonconservativ coordinates_min = -1.0 coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) + initial_refinement_level = 4, + n_cells_max = 10_000) # Create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -68,15 +69,15 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=3.0) +stepsize_callback = StepsizeCallback(cfl = 3.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) @@ -84,7 +85,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav ############################################################################### # 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); +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/tree_1d_dgsem/elixir_shallowwater_parabolic_bowl.jl b/examples/tree_1d_dgsem/elixir_shallowwater_parabolic_bowl.jl index 916bba76ece..a586562af7e 100644 --- a/examples/tree_1d_dgsem/elixir_shallowwater_parabolic_bowl.jl +++ b/examples/tree_1d_dgsem/elixir_shallowwater_parabolic_bowl.jl @@ -7,7 +7,7 @@ using Trixi # # TODO: TrixiShallowWater: wet/dry example elixir -equations = ShallowWaterEquations1D(gravity_constant=9.81) +equations = ShallowWaterEquations1D(gravity_constant = 9.81) """ initial_condition_parabolic_bowl(x, t, equations:: ShallowWaterEquations1D) @@ -28,26 +28,26 @@ The particular setup below is taken from Section 6.2 of curvilinear meshes with wet/dry fronts accelerated by GPUs [DOI: 10.1016/j.jcp.2018.08.038](https://doi.org/10.1016/j.jcp.2018.08.038). """ -function initial_condition_parabolic_bowl(x, t, equations:: ShallowWaterEquations1D) - a = 1 - h_0 = 0.1 - sigma = 0.5 - ω = sqrt(2 * equations.gravity * h_0) / a - - v = -sigma * ω * sin(ω * t) - - b = h_0 * x[1]^2 / a^2 - - H = sigma * h_0 / a^2 * (2 * x[1] * cos(ω * t) - sigma) + h_0 - - # It is mandatory to shift the water level at dry areas to make sure the water height h - # stays positive. The system would not be stable for h set to a hard 0 due to division by h in - # the computation of velocity, e.g., (h v) / h. Therefore, a small dry state threshold - # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above - # for the ShallowWaterEquations and added to the initial condition if h = 0. - # This default value can be changed within the constructor call depending on the simulation setup. - H = max(H, b + equations.threshold_limiter) - return prim2cons(SVector(H, v, b), equations) +function initial_condition_parabolic_bowl(x, t, equations::ShallowWaterEquations1D) + a = 1 + h_0 = 0.1 + sigma = 0.5 + ω = sqrt(2 * equations.gravity * h_0) / a + + v = -sigma * ω * sin(ω * t) + + b = h_0 * x[1]^2 / a^2 + + H = sigma * h_0 / a^2 * (2 * x[1] * cos(ω * t) - sigma) + h_0 + + # It is mandatory to shift the water level at dry areas to make sure the water height h + # stays positive. The system would not be stable for h set to a hard 0 due to division by h in + # the computation of velocity, e.g., (h v) / h. Therefore, a small dry state threshold + # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above + # for the ShallowWaterEquations and added to the initial condition if h = 0. + # This default value can be changed within the constructor call depending on the simulation setup. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v, b), equations) end initial_condition = initial_condition_parabolic_bowl @@ -56,19 +56,20 @@ initial_condition = initial_condition_parabolic_bowl # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, + hydrostatic_reconstruction_chen_noelle), flux_nonconservative_chen_noelle) basis = LobattoLegendreBasis(5) indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=waterheight_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = waterheight_pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) @@ -79,8 +80,8 @@ coordinates_min = -2.0 coordinates_max = 2.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - n_cells_max=10_000) + initial_refinement_level = 6, + n_cells_max = 10_000) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -94,24 +95,25 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false, - extra_analysis_integrals=(energy_kinetic, - energy_internal)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = false, + extra_analysis_integrals = (energy_kinetic, + energy_internal)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) -stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) +stage_limiter! = PositivityPreservingLimiterShallowWater(variables = (Trixi.waterheight,)) ############################################################################### # run the simulation sol = solve(ode, SSPRK43(stage_limiter!); - ode_default_options()..., callback=callbacks); + ode_default_options()..., callback = callbacks); -summary_callback() # print the timer summary \ No newline at end of file +summary_callback() # print the timer summary diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_shock_capturing.jl b/examples/tree_1d_dgsem/elixir_shallowwater_shock_capturing.jl index 62346d7b5ab..511f33d1101 100644 --- a/examples/tree_1d_dgsem/elixir_shallowwater_shock_capturing.jl +++ b/examples/tree_1d_dgsem/elixir_shallowwater_shock_capturing.jl @@ -5,36 +5,37 @@ using Trixi ############################################################################### # Semidiscretization of the shallow water equations -equations = ShallowWaterEquations1D(gravity_constant=9.812, H0=1.75) +equations = ShallowWaterEquations1D(gravity_constant = 9.812, H0 = 1.75) # Initial condition with a truly discontinuous velocity and bottom topography. # Works as intended for TreeMesh1D with `initial_refinement_level=3`. If the mesh # refinement level is changed the initial condition below may need changed as well to # ensure that the discontinuities lie on an element interface. -function initial_condition_stone_throw_discontinuous_bottom(x, t, equations::ShallowWaterEquations1D) +function initial_condition_stone_throw_discontinuous_bottom(x, t, + equations::ShallowWaterEquations1D) - # Calculate primitive variables + # Calculate primitive variables - # flat lake - H = equations.H0 + # flat lake + H = equations.H0 - # Discontinuous velocity - v = 0.0 - if x[1] >= -0.75 && x[1] <= 0.0 - v = -1.0 - elseif x[1] >= 0.0 && x[1] <= 0.75 - v = 1.0 - end + # Discontinuous velocity + v = 0.0 + if x[1] >= -0.75 && x[1] <= 0.0 + v = -1.0 + elseif x[1] >= 0.0 && x[1] <= 0.75 + v = 1.0 + end - b = ( 1.5 / exp( 0.5 * ((x[1] - 1.0)^2 ) ) - + 0.75 / exp( 0.5 * ((x[1] + 1.0)^2 ) ) ) + b = (1.5 / exp(0.5 * ((x[1] - 1.0)^2)) + + 0.75 / exp(0.5 * ((x[1] + 1.0)^2))) - # Force a discontinuous bottom topography - if x[1] >= -1.5 && x[1] <= 0.0 - b = 0.5 - end + # Force a discontinuous bottom topography + if x[1] >= -1.5 && x[1] <= 0.0 + b = 0.5 + end - return prim2cons(SVector(H, v, b), equations) + return prim2cons(SVector(H, v, b), equations) end initial_condition = initial_condition_stone_throw_discontinuous_bottom @@ -45,18 +46,19 @@ boundary_condition = boundary_condition_slip_wall # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -surface_flux = (FluxHydrostaticReconstruction(flux_lax_friedrichs, hydrostatic_reconstruction_audusse_etal), +surface_flux = (FluxHydrostaticReconstruction(flux_lax_friedrichs, + hydrostatic_reconstruction_audusse_etal), flux_nonconservative_audusse_etal) basis = LobattoLegendreBasis(4) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=waterheight_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = waterheight_pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) @@ -66,9 +68,9 @@ solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = -3.0 coordinates_max = 3.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=10_000, - periodicity=false) + initial_refinement_level = 3, + n_cells_max = 10_000, + periodicity = false) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, @@ -86,28 +88,29 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false, - extra_analysis_integrals=(energy_kinetic, - energy_internal, - lake_at_rest_error)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = false, + extra_analysis_integrals = (energy_kinetic, + energy_internal, + lake_at_rest_error)) # Enable in-situ visualization with a new plot generated every 50 time steps # and we explicitly pass that the plot data will be one-dimensional # visualization = VisualizationCallback(interval=50, plot_data_creator=PlotData1D) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution)#, - # visualization) +# visualization) ############################################################################### # run the simulation # use a Runge-Kutta method with automatic (error based) time step size control -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-7, reltol=1.0e-7, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-7, reltol = 1.0e-7, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_source_terms.jl b/examples/tree_1d_dgsem/elixir_shallowwater_source_terms.jl index 2f9f93f4335..af596a377f8 100644 --- a/examples/tree_1d_dgsem/elixir_shallowwater_source_terms.jl +++ b/examples/tree_1d_dgsem/elixir_shallowwater_source_terms.jl @@ -5,17 +5,17 @@ using Trixi ############################################################################### # Semidiscretization of the shallow water equations -equations = ShallowWaterEquations1D(gravity_constant=9.81) +equations = ShallowWaterEquations1D(gravity_constant = 9.81) initial_condition = initial_condition_convergence_test - ############################################################################### # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -solver = DGSEM(polydeg=3, surface_flux=(flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, + surface_flux = (flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the TreeMesh and setup a periodic mesh @@ -23,13 +23,13 @@ solver = DGSEM(polydeg=3, surface_flux=(flux_lax_friedrichs, flux_nonconservativ coordinates_min = 0.0 coordinates_max = sqrt(2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=10_000, - periodicity=true) + initial_refinement_level = 3, + n_cells_max = 10_000, + periodicity = true) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -40,13 +40,13 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 500 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=200, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 200, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) @@ -54,6 +54,6 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav # run the simulation # use a Runge-Kutta method with automatic (error based) time step size control -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-8, reltol=1.0e-8, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-8, reltol = 1.0e-8, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_source_terms_dirichlet.jl b/examples/tree_1d_dgsem/elixir_shallowwater_source_terms_dirichlet.jl index c8ef1c1b70b..cbc98a30f9f 100644 --- a/examples/tree_1d_dgsem/elixir_shallowwater_source_terms_dirichlet.jl +++ b/examples/tree_1d_dgsem/elixir_shallowwater_source_terms_dirichlet.jl @@ -5,7 +5,7 @@ using Trixi ############################################################################### # Semidiscretization of the shallow water equations -equations = ShallowWaterEquations1D(gravity_constant=9.81) +equations = ShallowWaterEquations1D(gravity_constant = 9.81) initial_condition = initial_condition_convergence_test @@ -16,8 +16,8 @@ boundary_condition = BoundaryConditionDirichlet(initial_condition) volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) surface_flux = (flux_lax_friedrichs, flux_nonconservative_fjordholm_etal) -solver = DGSEM(polydeg=3, surface_flux=surface_flux, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the TreeMesh and setup a periodic mesh @@ -25,14 +25,14 @@ solver = DGSEM(polydeg=3, surface_flux=surface_flux, coordinates_min = 0.0 coordinates_max = sqrt(2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=10_000, - periodicity=false) + initial_refinement_level = 3, + n_cells_max = 10_000, + periodicity = false) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions = boundary_condition, - source_terms=source_terms_convergence_test) + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -43,13 +43,13 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 500 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=200, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 200, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) @@ -57,6 +57,6 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav # run the simulation # use a Runge-Kutta method with automatic (error based) time step size control -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-8, reltol=1.0e-8, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-8, reltol = 1.0e-8, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_convergence.jl b/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_convergence.jl index e9f444aed27..fc76b4f034b 100644 --- a/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_convergence.jl +++ b/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_convergence.jl @@ -5,18 +5,18 @@ using Trixi ############################################################################### # Semidiscretization of the two-layer shallow water equations -equations = ShallowWaterTwoLayerEquations1D(gravity_constant=10.0, rho_upper=0.9, rho_lower=1.0) +equations = ShallowWaterTwoLayerEquations1D(gravity_constant = 10.0, rho_upper = 0.9, + rho_lower = 1.0) initial_condition = initial_condition_convergence_test - ############################################################################### # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -solver = DGSEM(polydeg=3, surface_flux=(flux_fjordholm_etal, flux_nonconservative_fjordholm_etal), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) - +solver = DGSEM(polydeg = 3, + surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the TreeMesh and setup a periodic mesh @@ -24,13 +24,13 @@ solver = DGSEM(polydeg=3, surface_flux=(flux_fjordholm_etal, flux_nonconservativ coordinates_min = 0.0 coordinates_max = sqrt(2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=10_000, - periodicity=true) + initial_refinement_level = 3, + n_cells_max = 10_000, + periodicity = true) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -41,13 +41,13 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 500 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=500, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 500, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) @@ -55,6 +55,6 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav # run the simulation # use a Runge-Kutta method with automatic (error based) time step size control - sol = solve(ode, RDPK3SpFSAL49(), abstol=1.0e-8, reltol=1.0e-8, - save_everystep=false, callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(), abstol = 1.0e-8, reltol = 1.0e-8, + save_everystep = false, callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_dam_break.jl b/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_dam_break.jl index 60770d158fa..b2e6a81401b 100644 --- a/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_dam_break.jl +++ b/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_dam_break.jl @@ -6,28 +6,29 @@ using Trixi # Semidiscretization of the two-layer shallow water equations for a dam break # test with a discontinuous bottom topography function to test entropy conservation -equations = ShallowWaterTwoLayerEquations1D(gravity_constant=9.81, H0=2.0, rho_upper=0.9, rho_lower=1.0) +equations = ShallowWaterTwoLayerEquations1D(gravity_constant = 9.81, H0 = 2.0, + rho_upper = 0.9, rho_lower = 1.0) # Initial condition of a dam break with a discontinuous water heights and bottom topography. # Works as intended for TreeMesh1D with `initial_refinement_level=5`. If the mesh # refinement level is changed the initial condition below may need changed as well to # ensure that the discontinuities lie on an element interface. function initial_condition_dam_break(x, t, equations::ShallowWaterTwoLayerEquations1D) - v1_upper = 0.0 - v1_lower = 0.0 - - # Set the discontinuity - if x[1] <= 10.0 - H_lower = 2.0 - H_upper = 4.0 - b = 0.0 - else - H_lower = 1.5 - H_upper = 3.0 - b = 0.5 - end - - return prim2cons(SVector(H_upper, v1_upper, H_lower, v1_lower, b), equations) + v1_upper = 0.0 + v1_lower = 0.0 + + # Set the discontinuity + if x[1] <= 10.0 + H_lower = 2.0 + H_upper = 4.0 + b = 0.0 + else + H_lower = 1.5 + H_upper = 3.0 + b = 0.5 + end + + return prim2cons(SVector(H_upper, v1_upper, H_lower, v1_lower, b), equations) end initial_condition = initial_condition_dam_break @@ -36,8 +37,9 @@ initial_condition = initial_condition_dam_break # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -solver = DGSEM(polydeg=3, surface_flux=(flux_fjordholm_etal, flux_nonconservative_fjordholm_etal), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, + surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the TreeMesh and setup a non-periodic mesh @@ -45,20 +47,20 @@ solver = DGSEM(polydeg=3, surface_flux=(flux_fjordholm_etal, flux_nonconservativ coordinates_min = 0.0 coordinates_max = 20.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=5, - n_cells_max=10000, - periodicity=false) + initial_refinement_level = 5, + n_cells_max = 10000, + periodicity = false) boundary_condition = boundary_condition_slip_wall # create the semidiscretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_condition) + boundary_conditions = boundary_condition) ############################################################################### # ODE solvers -tspan = (0.0,0.4) +tspan = (0.0, 0.4) ode = semidiscretize(semi, tspan) ############################################################################### @@ -67,16 +69,19 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 500 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false, - extra_analysis_integrals=(energy_total, energy_kinetic, energy_internal,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = false, + extra_analysis_integrals = (energy_total, + energy_kinetic, + energy_internal)) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=500, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 500, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) @@ -84,6 +89,6 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav # run the simulation # use a Runge-Kutta method with automatic (error based) time step size control -sol = solve(ode, RDPK3SpFSAL49(), abstol=1.0e-8, reltol=1.0e-8, - save_everystep=false, callback=callbacks); -summary_callback() # print the timer summary \ No newline at end of file +sol = solve(ode, RDPK3SpFSAL49(), abstol = 1.0e-8, reltol = 1.0e-8, + save_everystep = false, callback = callbacks); +summary_callback() # print the timer summary diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl b/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl index bec0b8ab69c..7236f1697d0 100644 --- a/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl +++ b/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl @@ -5,7 +5,8 @@ using Trixi ############################################################################### # Semidiscretization of the two-layer shallow water equations to test well-balancedness -equations = ShallowWaterTwoLayerEquations1D(gravity_constant=1.0, H0=0.6, rho_upper=0.9, rho_lower=1.0) +equations = ShallowWaterTwoLayerEquations1D(gravity_constant = 1.0, H0 = 0.6, + rho_upper = 0.9, rho_lower = 1.0) """ initial_condition_fjordholm_well_balanced(x, t, equations::ShallowWaterTwoLayerEquations1D) @@ -15,7 +16,8 @@ Initial condition to test well balanced with a bottom topography from Fjordholm Energy conservative and stable schemes for the two-layer shallow water equations. [DOI: 10.1142/9789814417099_0039](https://doi.org/10.1142/9789814417099_0039) """ -function initial_condition_fjordholm_well_balanced(x, t, equations::ShallowWaterTwoLayerEquations1D) +function initial_condition_fjordholm_well_balanced(x, t, + equations::ShallowWaterTwoLayerEquations1D) inicenter = 0.5 x_norm = x[1] - inicenter r = abs(x_norm) @@ -24,9 +26,9 @@ function initial_condition_fjordholm_well_balanced(x, t, equations::ShallowWater H_upper = 0.6 v1_upper = 0.0 v1_lower = 0.0 - b = r <= 0.1 ? 0.2 * (cos(10 * pi * (x[1] - 0.5)) + 1) : 0.0 + b = r <= 0.1 ? 0.2 * (cos(10 * pi * (x[1] - 0.5)) + 1) : 0.0 return prim2cons(SVector(H_upper, v1_upper, H_lower, v1_lower, b), equations) - end +end initial_condition = initial_condition_fjordholm_well_balanced @@ -34,8 +36,9 @@ initial_condition = initial_condition_fjordholm_well_balanced # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -solver = DGSEM(polydeg=3, surface_flux=(flux_es_fjordholm_etal, flux_nonconservative_fjordholm_etal), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, + surface_flux = (flux_es_fjordholm_etal, flux_nonconservative_fjordholm_etal), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the TreeMesh and setup a periodic mesh @@ -43,9 +46,9 @@ solver = DGSEM(polydeg=3, surface_flux=(flux_es_fjordholm_etal, flux_nonconserva coordinates_min = 0.0 coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000, - periodicity=true) + initial_refinement_level = 4, + n_cells_max = 10_000, + periodicity = true) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -59,16 +62,17 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false, - extra_analysis_integrals=(lake_at_rest_error,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = false, + extra_analysis_integrals = (lake_at_rest_error,)) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) @@ -76,7 +80,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav ############################################################################### # 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); +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/tree_1d_dgsem/elixir_shallowwater_well_balanced.jl b/examples/tree_1d_dgsem/elixir_shallowwater_well_balanced.jl index e07bc04d76a..649e5023f6d 100644 --- a/examples/tree_1d_dgsem/elixir_shallowwater_well_balanced.jl +++ b/examples/tree_1d_dgsem/elixir_shallowwater_well_balanced.jl @@ -6,7 +6,7 @@ using Trixi # semidiscretization of the shallow water equations with a discontinuous # bottom topography function -equations = ShallowWaterEquations1D(gravity_constant=9.81, H0=3.25) +equations = ShallowWaterEquations1D(gravity_constant = 9.81, H0 = 3.25) # Setup a truly discontinuous bottom topography function for this academic # testcase of well-balancedness. The errors from the analysis callback are @@ -15,18 +15,19 @@ equations = ShallowWaterEquations1D(gravity_constant=9.81, H0=3.25) # Works as intended for TreeMesh1D with `initial_refinement_level=3`. If the mesh # refinement level is changed the initial condition below may need changed as well to # ensure that the discontinuities lie on an element interface. -function initial_condition_discontinuous_well_balancedness(x, t, equations::ShallowWaterEquations1D) - # Set the background values - H = equations.H0 - v = 0.0 - b = 0.0 - - # Setup a discontinuous bottom topography - if x[1] >= 0.5 && x[1] <= 0.75 - b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) - end - - return prim2cons(SVector(H, v, b), equations) +function initial_condition_discontinuous_well_balancedness(x, t, + equations::ShallowWaterEquations1D) + # Set the background values + H = equations.H0 + v = 0.0 + b = 0.0 + + # Setup a discontinuous bottom topography + if x[1] >= 0.5 && x[1] <= 0.75 + b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) + end + + return prim2cons(SVector(H, v, b), equations) end initial_condition = initial_condition_discontinuous_well_balancedness @@ -36,17 +37,17 @@ initial_condition = initial_condition_discontinuous_well_balancedness volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal) -solver = DGSEM(polydeg=4, surface_flux=surface_flux, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 4, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the TreeMesh and setup a periodic mesh coordinates_min = -1.0 -coordinates_max = 1.0 +coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=10_000) + initial_refinement_level = 3, + n_cells_max = 10_000) # Create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -63,16 +64,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(lake_at_rest_error,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (lake_at_rest_error,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=3.0) +stepsize_callback = StepsizeCallback(cfl = 3.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) @@ -80,7 +81,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav ############################################################################### # 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); +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/tree_1d_dgsem/elixir_shallowwater_well_balanced_nonperiodic.jl b/examples/tree_1d_dgsem/elixir_shallowwater_well_balanced_nonperiodic.jl index ef707b803e9..e55fffc101e 100644 --- a/examples/tree_1d_dgsem/elixir_shallowwater_well_balanced_nonperiodic.jl +++ b/examples/tree_1d_dgsem/elixir_shallowwater_well_balanced_nonperiodic.jl @@ -5,19 +5,19 @@ using Trixi ############################################################################### # Semidiscretization of the shallow water equations -equations = ShallowWaterEquations1D(gravity_constant=1.0, H0=3.0) +equations = ShallowWaterEquations1D(gravity_constant = 1.0, H0 = 3.0) # An initial condition with constant total water height and zero velocities to test well-balancedness. function initial_condition_well_balancedness(x, t, equations::ShallowWaterEquations1D) - # Set the background values - H = equations.H0 - v = 0.0 + # Set the background values + H = equations.H0 + v = 0.0 - b = (1.5 / exp( 0.5 * ((x[1] - 1.0)^2))+ 0.75 / exp(0.5 * ((x[1] + 1.0)^2))) + b = (1.5 / exp(0.5 * ((x[1] - 1.0)^2)) + 0.75 / exp(0.5 * ((x[1] + 1.0)^2))) - return prim2cons(SVector(H, v, b), equations) + return prim2cons(SVector(H, v, b), equations) end - + initial_condition = initial_condition_well_balancedness boundary_condition = BoundaryConditionDirichlet(initial_condition) @@ -26,8 +26,8 @@ boundary_condition = BoundaryConditionDirichlet(initial_condition) # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -solver = DGSEM(polydeg=4, surface_flux=(flux_hll, flux_nonconservative_fjordholm_etal), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 4, surface_flux = (flux_hll, flux_nonconservative_fjordholm_etal), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the TreeMesh and setup a periodic mesh @@ -35,9 +35,9 @@ solver = DGSEM(polydeg=4, surface_flux=(flux_hll, flux_nonconservative_fjordholm coordinates_min = 0.0 coordinates_max = sqrt(2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=10_000, - periodicity=false) + initial_refinement_level = 3, + n_cells_max = 10_000, + periodicity = false) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, @@ -52,25 +52,25 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - save_analysis=true, - extra_analysis_integrals=(lake_at_rest_error,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_integrals = (lake_at_rest_error,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) -callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_1d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl b/examples/tree_1d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl index 8de46c61794..26a8960ab46 100644 --- a/examples/tree_1d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl +++ b/examples/tree_1d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl @@ -8,7 +8,7 @@ using Printf: @printf, @sprintf # # TODO: TrixiShallowWater: wet/dry example elixir -equations = ShallowWaterEquations1D(gravity_constant=9.812) +equations = ShallowWaterEquations1D(gravity_constant = 9.812) """ initial_condition_complex_bottom_well_balanced(x, t, equations:: ShallowWaterEquations1D) @@ -23,28 +23,29 @@ The initial condition is taken from Section 5.2 of the paper: A new hydrostatic reconstruction scheme based on subcell reconstructions [DOI:10.1137/15M1053074](https://dx.doi.org/10.1137/15M1053074) """ -function initial_condition_complex_bottom_well_balanced(x, t, equations:: ShallowWaterEquations1D) - v = 0.0 - b = sin(4 * pi * x[1]) + 3 - - if x[1] >= 0.5 - b = sin(4 * pi * x[1]) + 1 - end - - H = max(b, 2.5) - - if x[1] >= 0.5 - H = max(b, 1.5) - end - - # It is mandatory to shift the water level at dry areas to make sure the water height h - # stays positive. The system would not be stable for h set to a hard 0 due to division by h in - # the computation of velocity, e.g., (h v) / h. Therefore, a small dry state threshold - # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above - # for the ShallowWaterEquations and added to the initial condition if h = 0. - # This default value can be changed within the constructor call depending on the simulation setup. - H = max(H, b + equations.threshold_limiter) - return prim2cons(SVector(H, v, b), equations) +function initial_condition_complex_bottom_well_balanced(x, t, + equations::ShallowWaterEquations1D) + v = 0.0 + b = sin(4 * pi * x[1]) + 3 + + if x[1] >= 0.5 + b = sin(4 * pi * x[1]) + 1 + end + + H = max(b, 2.5) + + if x[1] >= 0.5 + H = max(b, 1.5) + end + + # It is mandatory to shift the water level at dry areas to make sure the water height h + # stays positive. The system would not be stable for h set to a hard 0 due to division by h in + # the computation of velocity, e.g., (h v) / h. Therefore, a small dry state threshold + # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above + # for the ShallowWaterEquations and added to the initial condition if h = 0. + # This default value can be changed within the constructor call depending on the simulation setup. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v, b), equations) end initial_condition = initial_condition_complex_bottom_well_balanced @@ -53,19 +54,20 @@ initial_condition = initial_condition_complex_bottom_well_balanced # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, + hydrostatic_reconstruction_chen_noelle), flux_nonconservative_chen_noelle) basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=waterheight_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = waterheight_pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) @@ -76,8 +78,8 @@ coordinates_min = 0.0 coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - n_cells_max=10_000) + initial_refinement_level = 6, + n_cells_max = 10_000) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -91,26 +93,27 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 5000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = false) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=5000, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 5000, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=1.5) +stepsize_callback = StepsizeCallback(cfl = 1.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) -stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) +stage_limiter! = PositivityPreservingLimiterShallowWater(variables = (Trixi.waterheight,)) ############################################################################### # run the simulation -sol = solve(ode, SSPRK43(stage_limiter!); dt=1.0, - ode_default_options()..., callback=callbacks, adaptive=false); +sol = solve(ode, SSPRK43(stage_limiter!); dt = 1.0, + ode_default_options()..., callback = callbacks, adaptive = false); summary_callback() # print the timer summary @@ -123,35 +126,39 @@ summary_callback() # print the timer summary # Declare a special version of the function to compute the lake-at-rest error # OBS! The reference water height values are hardcoded for convenience. function lake_at_rest_error_two_level(u, x, equations::ShallowWaterEquations1D) - h, _, b = u - - # For well-balancedness testing with possible wet/dry regions the reference - # water height `H0` accounts for the possibility that the bottom topography - # can emerge out of the water as well as for the threshold offset to avoid - # division by a "hard" zero water heights as well. - if x[1] < 0.5 - H0_wet_dry = max( 2.5 , b + equations.threshold_limiter ) - else - H0_wet_dry = max( 1.5 , b + equations.threshold_limiter ) - end - - return abs(H0_wet_dry - (h + b)) - end + h, _, b = u + + # For well-balancedness testing with possible wet/dry regions the reference + # water height `H0` accounts for the possibility that the bottom topography + # can emerge out of the water as well as for the threshold offset to avoid + # division by a "hard" zero water heights as well. + if x[1] < 0.5 + H0_wet_dry = max(2.5, b + equations.threshold_limiter) + else + H0_wet_dry = max(1.5, b + equations.threshold_limiter) + end + + return abs(H0_wet_dry - (h + b)) +end # point to the data we want to analyze u = Trixi.wrap_array(sol[end], semi) # Perform the actual integration of the well-balancedness error over the domain -l1_well_balance_error = Trixi.integrate_via_indices(u, mesh, equations, semi.solver, semi.cache; normalize=true) do u, i, element, equations, solver - x_node = Trixi.get_node_coords(semi.cache.elements.node_coordinates, equations, solver, i, element) - # We know that the discontinuity is a vertical line. Slightly augment the x value by a factor - # of unit roundoff to avoid the repeted value from the LGL nodes at at interface. - if i == 1 - x_node = SVector(nextfloat(x_node[1])) - elseif i == nnodes(semi.solver) - x_node = SVector(prevfloat(x_node[1])) - end - u_local = Trixi.get_node_vars(u, equations, solver, i, element) - return lake_at_rest_error_two_level(u_local, x_node, equations) +l1_well_balance_error = Trixi.integrate_via_indices(u, mesh, equations, semi.solver, + semi.cache; + normalize = true) do u, i, element, + equations, solver + x_node = Trixi.get_node_coords(semi.cache.elements.node_coordinates, equations, solver, + i, element) + # We know that the discontinuity is a vertical line. Slightly augment the x value by a factor + # of unit roundoff to avoid the repeted value from the LGL nodes at at interface. + if i == 1 + x_node = SVector(nextfloat(x_node[1])) + elseif i == nnodes(semi.solver) + x_node = SVector(prevfloat(x_node[1])) + end + u_local = Trixi.get_node_vars(u, equations, solver, i, element) + return lake_at_rest_error_two_level(u_local, x_node, equations) end # report the well-balancedness lake-at-rest error to the screen @@ -162,4 +169,4 @@ println(" Lake-at-rest error for '", Trixi.get_name(equations), "' with ", summa @printf(" %-12s:", Trixi.pretty_form_utf(lake_at_rest_error)) @printf(" % 10.8e", l1_well_balance_error) println() -println("─"^100) \ No newline at end of file +println("─"^100) diff --git a/examples/tree_1d_fdsbp/elixir_advection_upwind.jl b/examples/tree_1d_fdsbp/elixir_advection_upwind.jl index 1f2498e0866..389a8566c97 100644 --- a/examples/tree_1d_fdsbp/elixir_advection_upwind.jl +++ b/examples/tree_1d_fdsbp/elixir_advection_upwind.jl @@ -24,7 +24,7 @@ solver = FDSBP(D_upw, volume_integral = VolumeIntegralUpwind(flux_splitting)) coordinates_min = -1.0 -coordinates_max = 1.0 +coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, initial_refinement_level = 4, n_cells_max = 10_000, @@ -32,7 +32,6 @@ mesh = TreeMesh(coordinates_min, coordinates_max, semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_sin, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -42,17 +41,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) - ############################################################################### # run the simulation -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-6, reltol=1.0e-6, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-6, reltol = 1.0e-6, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_1d_fdsbp/elixir_advection_upwind_periodic.jl b/examples/tree_1d_fdsbp/elixir_advection_upwind_periodic.jl index 035d3568a80..2d7c13d7e57 100644 --- a/examples/tree_1d_fdsbp/elixir_advection_upwind_periodic.jl +++ b/examples/tree_1d_fdsbp/elixir_advection_upwind_periodic.jl @@ -23,7 +23,7 @@ solver = FDSBP(D_upw, volume_integral = VolumeIntegralUpwind(flux_splitting)) coordinates_min = -1.0 -coordinates_max = 1.0 +coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, initial_refinement_level = 0, n_cells_max = 10_000, @@ -31,7 +31,6 @@ mesh = TreeMesh(coordinates_min, coordinates_max, semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_sin, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -41,17 +40,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) - ############################################################################### # run the simulation -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-6, reltol=1.0e-6, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-6, reltol = 1.0e-6, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_1d_fdsbp/elixir_burgers_basic.jl b/examples/tree_1d_fdsbp/elixir_burgers_basic.jl index c7b0176dfdc..c58fc497e14 100644 --- a/examples/tree_1d_fdsbp/elixir_burgers_basic.jl +++ b/examples/tree_1d_fdsbp/elixir_burgers_basic.jl @@ -12,24 +12,23 @@ equations = InviscidBurgersEquation1D() initial_condition = initial_condition_convergence_test D_upw = upwind_operators(SummationByPartsOperators.Mattsson2017, - derivative_order=1, - accuracy_order=4, - xmin=-1.0, xmax=1.0, - N=32) + derivative_order = 1, + accuracy_order = 4, + xmin = -1.0, xmax = 1.0, + N = 32) flux_splitting = splitting_lax_friedrichs solver = FDSBP(D_upw, - surface_integral=SurfaceIntegralUpwind(flux_splitting), - volume_integral=VolumeIntegralUpwind(flux_splitting)) + surface_integral = SurfaceIntegralUpwind(flux_splitting), + volume_integral = VolumeIntegralUpwind(flux_splitting)) coordinates_min = 0.0 coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=10_000) + initial_refinement_level = 3, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -40,25 +39,24 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 200 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_errors=(:l2_error_primitive, - :linf_error_primitive)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:l2_error_primitive, + :linf_error_primitive)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) - ############################################################################### # run the simulation -sol = solve(ode, SSPRK43(); abstol=1.0e-9, reltol=1.0e-9, - ode_default_options()..., callback=callbacks); +sol = solve(ode, SSPRK43(); abstol = 1.0e-9, reltol = 1.0e-9, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_1d_fdsbp/elixir_burgers_linear_stability.jl b/examples/tree_1d_fdsbp/elixir_burgers_linear_stability.jl index 20508feba22..eeaae7a7843 100644 --- a/examples/tree_1d_fdsbp/elixir_burgers_linear_stability.jl +++ b/examples/tree_1d_fdsbp/elixir_burgers_linear_stability.jl @@ -10,28 +10,28 @@ using Trixi equations = InviscidBurgersEquation1D() function initial_condition_linear_stability(x, t, equation::InviscidBurgersEquation1D) - k = 1 - 2 + sinpi(k * (x[1] - 0.7)) |> SVector + k = 1 + 2 + sinpi(k * (x[1] - 0.7)) |> SVector end D_upw = upwind_operators(SummationByPartsOperators.Mattsson2017, - derivative_order=1, - accuracy_order=4, - xmin=-1.0, xmax=1.0, - N=16) + derivative_order = 1, + accuracy_order = 4, + xmin = -1.0, xmax = 1.0, + N = 16) flux_splitting = splitting_lax_friedrichs solver = FDSBP(D_upw, - surface_integral=SurfaceIntegralUpwind(flux_splitting), - volume_integral=VolumeIntegralUpwind(flux_splitting)) + surface_integral = SurfaceIntegralUpwind(flux_splitting), + volume_integral = VolumeIntegralUpwind(flux_splitting)) coordinates_min = -1.0 -coordinates_max = 1.0 +coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_linear_stability, solver) + initial_refinement_level = 4, + n_cells_max = 10_000) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_linear_stability, + solver) ############################################################################### # ODE solvers, callbacks etc. @@ -42,19 +42,18 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_errors=(:l2_error_primitive, - :linf_error_primitive)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:l2_error_primitive, + :linf_error_primitive)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) - ############################################################################### # run the simulation -sol = solve(ode, SSPRK43(); abstol=1.0e-6, reltol=1.0e-6, - ode_default_options()..., callback=callbacks); +sol = solve(ode, SSPRK43(); abstol = 1.0e-6, reltol = 1.0e-6, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_1d_fdsbp/elixir_euler_convergence.jl b/examples/tree_1d_fdsbp/elixir_euler_convergence.jl index f9f9297f7c8..7b6bfee946e 100644 --- a/examples/tree_1d_fdsbp/elixir_euler_convergence.jl +++ b/examples/tree_1d_fdsbp/elixir_euler_convergence.jl @@ -12,24 +12,23 @@ equations = CompressibleEulerEquations1D(1.4) initial_condition = initial_condition_convergence_test D_upw = upwind_operators(SummationByPartsOperators.Mattsson2017, - derivative_order=1, - accuracy_order=4, - xmin=-1.0, xmax=1.0, - N=32) + derivative_order = 1, + accuracy_order = 4, + xmin = -1.0, xmax = 1.0, + N = 32) flux_splitting = splitting_steger_warming solver = FDSBP(D_upw, - surface_integral=SurfaceIntegralUpwind(flux_splitting), - volume_integral=VolumeIntegralUpwind(flux_splitting)) + surface_integral = SurfaceIntegralUpwind(flux_splitting), + volume_integral = VolumeIntegralUpwind(flux_splitting)) coordinates_min = 0.0 coordinates_max = 2.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=1, - n_cells_max=10_000) + initial_refinement_level = 1, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -40,25 +39,24 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_errors=(:l2_error_primitive, - :linf_error_primitive)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:l2_error_primitive, + :linf_error_primitive)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) - ############################################################################### # run the simulation -sol = solve(ode, SSPRK43(); abstol=1.0e-6, reltol=1.0e-6, - ode_default_options()..., callback=callbacks) +sol = solve(ode, SSPRK43(); abstol = 1.0e-6, reltol = 1.0e-6, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary diff --git a/examples/tree_1d_fdsbp/elixir_euler_density_wave.jl b/examples/tree_1d_fdsbp/elixir_euler_density_wave.jl index 5c5192a3fbe..a28cd01120b 100644 --- a/examples/tree_1d_fdsbp/elixir_euler_density_wave.jl +++ b/examples/tree_1d_fdsbp/elixir_euler_density_wave.jl @@ -11,24 +11,23 @@ equations = CompressibleEulerEquations1D(1.4) initial_condition = initial_condition_density_wave D_upw = upwind_operators(SummationByPartsOperators.Mattsson2017, - derivative_order=1, - accuracy_order=4, - xmin=-1.0, xmax=1.0, - N=16) + derivative_order = 1, + accuracy_order = 4, + xmin = -1.0, xmax = 1.0, + N = 16) flux_splitting = splitting_coirier_vanleer solver = FDSBP(D_upw, - surface_integral=SurfaceIntegralUpwind(flux_splitting), - volume_integral=VolumeIntegralUpwind(flux_splitting)) + surface_integral = SurfaceIntegralUpwind(flux_splitting), + volume_integral = VolumeIntegralUpwind(flux_splitting)) coordinates_min = -1.0 -coordinates_max = 1.0 +coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=30_000) + initial_refinement_level = 2, + n_cells_max = 30_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -38,23 +37,22 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 10000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) - ############################################################################### # run the simulation -sol = solve(ode, SSPRK43(); abstol=1.0e-6, reltol=1.0e-6, - ode_default_options()..., callback=callbacks) +sol = solve(ode, SSPRK43(); abstol = 1.0e-6, reltol = 1.0e-6, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_acoustics_convergence.jl b/examples/tree_2d_dgsem/elixir_acoustics_convergence.jl index d34399a5576..615da951871 100644 --- a/examples/tree_2d_dgsem/elixir_acoustics_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_acoustics_convergence.jl @@ -4,26 +4,25 @@ using Trixi ############################################################################### # semidiscretization of the acoustic perturbation equations -equations = AcousticPerturbationEquations2D(v_mean_global=(0.5, 0.3), c_mean_global=2.0, - rho_mean_global=0.9) +equations = AcousticPerturbationEquations2D(v_mean_global = (0.5, 0.3), c_mean_global = 2.0, + rho_mean_global = 0.9) initial_condition = initial_condition_convergence_test # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0, 0.0) # minimum coordinates (min(x), min(y)) coordinates_max = (2.0, 2.0) # maximum coordinates (max(x), max(y)) # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=30_000) # set maximum capacity of tree data structure + initial_refinement_level = 3, + n_cells_max = 30_000) # set maximum capacity of tree data structure # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -37,26 +36,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +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=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) # 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) - +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/tree_2d_dgsem/elixir_acoustics_gauss.jl b/examples/tree_2d_dgsem/elixir_acoustics_gauss.jl index fa608e78693..b3fe55dccea 100644 --- a/examples/tree_2d_dgsem/elixir_acoustics_gauss.jl +++ b/examples/tree_2d_dgsem/elixir_acoustics_gauss.jl @@ -10,20 +10,19 @@ rho_mean_global = 1.0 equations = AcousticPerturbationEquations2D(v_mean_global, c_mean_global, rho_mean_global) # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) -coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) +coordinates_max = (1.0, 1.0) # maximum coordinates (max(x), max(y)) # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=30_000) # set maximum capacity of tree data structure + initial_refinement_level = 4, + n_cells_max = 30_000) # set maximum capacity of tree data structure # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_gauss, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -36,26 +35,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +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=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) # 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) - +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/tree_2d_dgsem/elixir_acoustics_gauss_wall.jl b/examples/tree_2d_dgsem/elixir_acoustics_gauss_wall.jl index 78102eaf874..918c0831fcd 100644 --- a/examples/tree_2d_dgsem/elixir_acoustics_gauss_wall.jl +++ b/examples/tree_2d_dgsem/elixir_acoustics_gauss_wall.jl @@ -4,20 +4,20 @@ using Trixi ############################################################################### # semidiscretization of the acoustic perturbation equations -equations = AcousticPerturbationEquations2D(v_mean_global=(0.5, 0.0), c_mean_global=1.0, - rho_mean_global=1.0) +equations = AcousticPerturbationEquations2D(v_mean_global = (0.5, 0.0), c_mean_global = 1.0, + rho_mean_global = 1.0) # Create DG solver with polynomial degree = 5 and (local) Lax-Friedrichs/Rusanov flux as surface flux -solver = DGSEM(polydeg=5, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 5, surface_flux = flux_lax_friedrichs) coordinates_min = (-100.0, 0.0) # minimum coordinates (min(x), min(y)) coordinates_max = (100.0, 200.0) # maximum coordinates (max(x), max(y)) # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=100_000, - periodicity=false) + initial_refinement_level = 4, + n_cells_max = 100_000, + periodicity = false) """ initial_condition_gauss_wall(x, t, equations::AcousticPerturbationEquations2D) @@ -26,20 +26,19 @@ A Gaussian pulse, used in the `gauss_wall` example elixir in combination with [`boundary_condition_wall`](@ref). Uses the global mean values from `equations`. """ function initial_condition_gauss_wall(x, t, equations::AcousticPerturbationEquations2D) - v1_prime = 0.0 - v2_prime = 0.0 - p_prime = exp(-log(2) * (x[1]^2 + (x[2] - 25)^2) / 25) + v1_prime = 0.0 + v2_prime = 0.0 + p_prime = exp(-log(2) * (x[1]^2 + (x[2] - 25)^2) / 25) - prim = SVector(v1_prime, v2_prime, p_prime, global_mean_vars(equations)...) + prim = SVector(v1_prime, v2_prime, p_prime, global_mean_vars(equations)...) - return prim2cons(prim, equations) + return prim2cons(prim, equations) end initial_condition = initial_condition_gauss_wall # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_condition_wall) - + boundary_conditions = boundary_condition_wall) ############################################################################### # ODE solvers, callbacks etc. @@ -53,24 +52,25 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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=cons2state) +save_solution = SaveSolutionCallback(interval = 100, solution_variables = cons2state) # The StepsizeCallback handles the re-calculation of the maximum Δt after each time step -stepsize_callback = StepsizeCallback(cfl=0.7) +stepsize_callback = StepsizeCallback(cfl = 0.7) # 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) +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks) +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) # Print the timer summary summary_callback() diff --git a/examples/tree_2d_dgsem/elixir_acoustics_gaussian_source.jl b/examples/tree_2d_dgsem/elixir_acoustics_gaussian_source.jl index 0a0e2520581..71d4f1a9f68 100644 --- a/examples/tree_2d_dgsem/elixir_acoustics_gaussian_source.jl +++ b/examples/tree_2d_dgsem/elixir_acoustics_gaussian_source.jl @@ -3,45 +3,45 @@ using Trixi # Oscillating Gaussian-shaped source terms function source_terms_gauss(u, x, t, equations::AcousticPerturbationEquations2D) - r = 0.1 - A = 1.0 - f = 2.0 + r = 0.1 + A = 1.0 + f = 2.0 - # Velocity sources - s1 = 0.0 - s2 = 0.0 - # Pressure source - s3 = exp(-(x[1]^2 + x[2]^2) / (2 * r^2)) * A * sin(2 * pi * f * t) + # Velocity sources + s1 = 0.0 + s2 = 0.0 + # Pressure source + s3 = exp(-(x[1]^2 + x[2]^2) / (2 * r^2)) * A * sin(2 * pi * f * t) - # Mean sources - s4 = s5 = s6 = s7 = 0.0 + # Mean sources + s4 = s5 = s6 = s7 = 0.0 - return SVector(s1, s2, s3, s4, s5, s6, s7) + return SVector(s1, s2, s3, s4, s5, s6, s7) end ############################################################################### # semidiscretization of the acoustic perturbation equations -equations = AcousticPerturbationEquations2D(v_mean_global=(-0.5, 0.25), c_mean_global=1.0, - rho_mean_global=1.0) +equations = AcousticPerturbationEquations2D(v_mean_global = (-0.5, 0.25), + c_mean_global = 1.0, + rho_mean_global = 1.0) initial_condition = initial_condition_constant # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-3.0, -3.0) # minimum coordinates (min(x), min(y)) -coordinates_max = ( 3.0, 3.0) # maximum coordinates (max(x), max(y)) +coordinates_max = (3.0, 3.0) # maximum coordinates (max(x), max(y)) # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=30_000) # set maximum capacity of tree data structure + initial_refinement_level = 4, + n_cells_max = 30_000) # set maximum capacity of tree data structure # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_gauss) - + source_terms = source_terms_gauss) ############################################################################### # ODE solvers, callbacks etc. @@ -55,30 +55,29 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +save_solution = SaveSolutionCallback(interval = 100, + solution_variables = cons2prim) # The TimeSeriesCallback records the solution at the given points over time time_series = TimeSeriesCallback(semi, [(0.0, 0.0), (-1.0, 0.5)]) # The StepsizeCallback handles the re-calculation of the maximum Δt after each time step -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) # 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, time_series, 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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/tree_2d_dgsem/elixir_acoustics_monopole.jl b/examples/tree_2d_dgsem/elixir_acoustics_monopole.jl index 0fdcbd22c44..d7265775114 100644 --- a/examples/tree_2d_dgsem/elixir_acoustics_monopole.jl +++ b/examples/tree_2d_dgsem/elixir_acoustics_monopole.jl @@ -4,11 +4,11 @@ using Trixi ############################################################################### # semidiscretization of the acoustic perturbation equations -equations = AcousticPerturbationEquations2D(v_mean_global=(0.0, 0.0), c_mean_global=0.0, - rho_mean_global=0.0) +equations = AcousticPerturbationEquations2D(v_mean_global = (0.0, 0.0), c_mean_global = 0.0, + rho_mean_global = 0.0) # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-20.6, 0.0) # minimum coordinates (min(x), min(y)) coordinates_max = (30.6, 51.2) # maximum coordinates (max(x), max(y)) @@ -20,20 +20,20 @@ Initial condition for the monopole in a boundary layer setup, used in combinatio [`boundary_condition_monopole`](@ref). """ function initial_condition_monopole(x, t, equations::AcousticPerturbationEquations2D) - m = 0.3 # Mach number + m = 0.3 # Mach number - v1_prime = 0.0 - v2_prime = 0.0 - p_prime = 0.0 + v1_prime = 0.0 + v2_prime = 0.0 + p_prime = 0.0 - v1_mean = x[2] > 1 ? m : m * (2*x[2] - 2*x[2]^2 + x[2]^4) - v2_mean = 0.0 - c_mean = 1.0 - rho_mean = 1.0 + v1_mean = x[2] > 1 ? m : m * (2 * x[2] - 2 * x[2]^2 + x[2]^4) + v2_mean = 0.0 + c_mean = 1.0 + rho_mean = 1.0 - prim = SVector(v1_prime, v2_prime, p_prime, v1_mean, v2_mean, c_mean, rho_mean) + prim = SVector(v1_prime, v2_prime, p_prime, v1_mean, v2_mean, c_mean, rho_mean) - return prim2cons(prim, equations) + return prim2cons(prim, equations) end initial_condition = initial_condition_monopole # does not use the global mean values given above @@ -45,32 +45,35 @@ Boundary condition for a monopole in a boundary layer at the -y boundary, i.e. ` This will return an error for any other direction. This boundary condition is used in combination with [`initial_condition_monopole`](@ref). """ -function boundary_condition_monopole(u_inner, orientation, direction, x, t, surface_flux_function, +function boundary_condition_monopole(u_inner, orientation, direction, x, t, + surface_flux_function, equations::AcousticPerturbationEquations2D) - if direction != 3 - error("expected direction = 3, got $direction instead") - end - - # Wall at the boundary in -y direction with a monopole at -0.05 <= x <= 0.05. In the monopole area - # we use a sinusoidal boundary state for the perturbed variables. For the rest of the -y boundary - # we set the boundary state to the inner state and multiply the perturbed velocity in the - # y-direction by -1. - if -0.05 <= x[1] <= 0.05 # Monopole - v1_prime = 0.0 - v2_prime = p_prime = sin(2 * pi * t) - - prim_boundary = SVector(v1_prime, v2_prime, p_prime, u_inner[4], u_inner[5], u_inner[6], u_inner[7]) - - u_boundary = prim2cons(prim_boundary, equations) - else # Wall - u_boundary = SVector(u_inner[1], -u_inner[2], u_inner[3], u_inner[4], u_inner[5], u_inner[6], - u_inner[7]) - end - - # Calculate boundary flux - flux = surface_flux_function(u_boundary, u_inner, orientation, equations) + if direction != 3 + error("expected direction = 3, got $direction instead") + end + + # Wall at the boundary in -y direction with a monopole at -0.05 <= x <= 0.05. In the monopole area + # we use a sinusoidal boundary state for the perturbed variables. For the rest of the -y boundary + # we set the boundary state to the inner state and multiply the perturbed velocity in the + # y-direction by -1. + if -0.05 <= x[1] <= 0.05 # Monopole + v1_prime = 0.0 + v2_prime = p_prime = sin(2 * pi * t) + + prim_boundary = SVector(v1_prime, v2_prime, p_prime, u_inner[4], u_inner[5], + u_inner[6], u_inner[7]) + + u_boundary = prim2cons(prim_boundary, equations) + else # Wall + u_boundary = SVector(u_inner[1], -u_inner[2], u_inner[3], u_inner[4], u_inner[5], + u_inner[6], + u_inner[7]) + end + + # Calculate boundary flux + flux = surface_flux_function(u_boundary, u_inner, orientation, equations) - return flux + return flux end """ @@ -80,42 +83,42 @@ end Boundary condition that uses a boundary state where the state variables are zero and the mean variables are the same as in `u_inner`. """ -function boundary_condition_zero(u_inner, orientation, direction, x, t, surface_flux_function, +function boundary_condition_zero(u_inner, orientation, direction, x, t, + surface_flux_function, equations::AcousticPerturbationEquations2D) - value = zero(eltype(u_inner)) - u_boundary = SVector(value, value, value, cons2mean(u_inner, equations)...) + value = zero(eltype(u_inner)) + u_boundary = SVector(value, value, value, cons2mean(u_inner, equations)...) - # Calculate boundary flux - if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary - flux = surface_flux_function(u_inner, u_boundary, orientation, equations) - else # u_boundary is "left" of boundary, u_inner is "right" of boundary - flux = surface_flux_function(u_boundary, u_inner, orientation, equations) - end + # Calculate boundary flux + if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary + flux = surface_flux_function(u_inner, u_boundary, orientation, equations) + else # u_boundary is "left" of boundary, u_inner is "right" of boundary + flux = surface_flux_function(u_boundary, u_inner, orientation, equations) + end - return flux + return flux end -boundary_conditions = (x_neg=boundary_condition_zero, - x_pos=boundary_condition_zero, - y_neg=boundary_condition_monopole, - y_pos=boundary_condition_zero) +boundary_conditions = (x_neg = boundary_condition_zero, + x_pos = boundary_condition_zero, + y_neg = boundary_condition_monopole, + y_pos = boundary_condition_zero) # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - n_cells_max=100_000, - periodicity=false) + initial_refinement_level = 6, + n_cells_max = 100_000, + periodicity = false) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. # Create ODE problem with time span from 0.0 to 24.0 -tspan = (0.0, 24.0) +tspan = (0.0, 24.0) ode = semidiscretize(semi, tspan) # At the beginning of the main loop, the SummaryCallback prints a summary of the simulation setup @@ -123,24 +126,25 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +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=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) # 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) +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks) +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) # Print the timer summary -summary_callback() \ No newline at end of file +summary_callback() diff --git a/examples/tree_2d_dgsem/elixir_advection_amr.jl b/examples/tree_2d_dgsem/elixir_advection_amr.jl index 84841877448..c3f971d2ffc 100644 --- a/examples/tree_2d_dgsem/elixir_advection_amr.jl +++ b/examples/tree_2d_dgsem/elixir_advection_amr.jl @@ -9,18 +9,16 @@ advection_velocity = (0.2, -0.7) equations = LinearScalarAdvectionEquation2D(advection_velocity) initial_condition = initial_condition_gauss -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-5.0, -5.0) -coordinates_max = ( 5.0, 5.0) +coordinates_max = (5.0, 5.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=30_000) - + initial_refinement_level = 4, + n_cells_max = 30_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -30,37 +28,36 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable=first), - base_level=4, - med_level=5, med_threshold=0.1, - max_level=6, max_threshold=0.6) +amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first), + base_level = 4, + med_level = 5, med_threshold = 0.1, + max_level = 6, max_threshold = 0.6) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) 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); +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/tree_2d_dgsem/elixir_advection_amr_coarsen_twice.jl b/examples/tree_2d_dgsem/elixir_advection_amr_coarsen_twice.jl index 897d3569e10..aa042e7500e 100644 --- a/examples/tree_2d_dgsem/elixir_advection_amr_coarsen_twice.jl +++ b/examples/tree_2d_dgsem/elixir_advection_amr_coarsen_twice.jl @@ -3,7 +3,6 @@ using OrdinaryDiffEq using Trixi - # Define new structs inside a module to allow re-evaluating the file. # This module name needs to be unique among all examples, otherwise Julia will throw warnings # if multiple test cases using the same module name are run in the same session. @@ -11,27 +10,27 @@ module TrixiExtensionCoarsen using Trixi -struct IndicatorAlwaysCoarsen{Cache<:NamedTuple} <: Trixi.AbstractIndicator - cache::Cache +struct IndicatorAlwaysCoarsen{Cache <: NamedTuple} <: Trixi.AbstractIndicator + cache::Cache end function IndicatorAlwaysCoarsen(semi) - basis = semi.solver.basis - alpha = Vector{real(basis)}() - cache = (; semi.mesh, alpha) + basis = semi.solver.basis + alpha = Vector{real(basis)}() + cache = (; semi.mesh, alpha) - return IndicatorAlwaysCoarsen{typeof(cache)}(cache) + return IndicatorAlwaysCoarsen{typeof(cache)}(cache) end -function (indicator::IndicatorAlwaysCoarsen)(u::AbstractArray{<:Any,4}, +function (indicator::IndicatorAlwaysCoarsen)(u::AbstractArray{<:Any, 4}, mesh, equations, dg, cache; t, kwargs...) - alpha = indicator.cache.alpha - resize!(alpha, nelements(dg, cache)) + alpha = indicator.cache.alpha + resize!(alpha, nelements(dg, cache)) - alpha .= -1.0 + alpha .= -1.0 - return alpha + return alpha end end # module TrixiExtensionCoarsen @@ -46,18 +45,16 @@ equations = LinearScalarAdvectionEquation2D(advection_velocity) initial_condition = initial_condition_gauss -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-5.0, -5.0) -coordinates_max = ( 5.0, 5.0) +coordinates_max = (5.0, 5.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=30_000) - + initial_refinement_level = 4, + n_cells_max = 30_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -67,37 +64,37 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -amr_controller = ControllerThreeLevel(semi, TrixiExtensionCoarsen.IndicatorAlwaysCoarsen(semi), - base_level=2, max_level=2, - med_threshold=0.1, max_threshold=0.6) +amr_controller = ControllerThreeLevel(semi, + TrixiExtensionCoarsen.IndicatorAlwaysCoarsen(semi), + base_level = 2, max_level = 2, + med_threshold = 0.1, max_threshold = 0.6) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) 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); +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/tree_2d_dgsem/elixir_advection_amr_nonperiodic.jl b/examples/tree_2d_dgsem/elixir_advection_amr_nonperiodic.jl index 42aee985889..abb8a5035be 100644 --- a/examples/tree_2d_dgsem/elixir_advection_amr_nonperiodic.jl +++ b/examples/tree_2d_dgsem/elixir_advection_amr_nonperiodic.jl @@ -14,19 +14,17 @@ initial_condition = initial_condition_gauss # 2*ndims == 4 directions or you can pass a tuple containing BCs for each direction boundary_conditions = BoundaryConditionDirichlet(initial_condition) -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-5.0, -5.0) -coordinates_max = ( 5.0, 5.0) +coordinates_max = (5.0, 5.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=30_000, - periodicity=false) - + initial_refinement_level = 4, + n_cells_max = 30_000, + periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -37,26 +35,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable=first), - base_level=4, - med_level=5, med_threshold=0.1, - max_level=6, max_threshold=0.6) +amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first), + base_level = 4, + med_level = 5, med_threshold = 0.1, + max_level = 6, max_threshold = 0.6) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -65,7 +63,7 @@ callbacks = CallbackSet(summary_callback, ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=stepsize_callback(ode), # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = stepsize_callback(ode), # 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/tree_2d_dgsem/elixir_advection_amr_refine_twice.jl b/examples/tree_2d_dgsem/elixir_advection_amr_refine_twice.jl index e69cab29bb6..7b441775204 100644 --- a/examples/tree_2d_dgsem/elixir_advection_amr_refine_twice.jl +++ b/examples/tree_2d_dgsem/elixir_advection_amr_refine_twice.jl @@ -3,7 +3,6 @@ using OrdinaryDiffEq using Trixi - # Define new structs inside a module to allow re-evaluating the file. # This module name needs to be unique among all examples, otherwise Julia will throw warnings # if multiple test cases using the same module name are run in the same session. @@ -11,27 +10,27 @@ module TrixiExtensionRefine using Trixi -struct IndicatorAlwaysRefine{Cache<:NamedTuple} <: Trixi.AbstractIndicator - cache::Cache +struct IndicatorAlwaysRefine{Cache <: NamedTuple} <: Trixi.AbstractIndicator + cache::Cache end function IndicatorAlwaysRefine(semi) - basis = semi.solver.basis - alpha = Vector{real(basis)}() - cache = (; semi.mesh, alpha) + basis = semi.solver.basis + alpha = Vector{real(basis)}() + cache = (; semi.mesh, alpha) - return IndicatorAlwaysRefine{typeof(cache)}(cache) + return IndicatorAlwaysRefine{typeof(cache)}(cache) end -function (indicator::IndicatorAlwaysRefine)(u::AbstractArray{<:Any,4}, +function (indicator::IndicatorAlwaysRefine)(u::AbstractArray{<:Any, 4}, mesh, equations, dg, cache; t, kwargs...) - alpha = indicator.cache.alpha - resize!(alpha, nelements(dg, cache)) + alpha = indicator.cache.alpha + resize!(alpha, nelements(dg, cache)) - alpha .= 1.0 + alpha .= 1.0 - return alpha + return alpha end end # module TrixiExtensionRefine @@ -46,18 +45,16 @@ equations = LinearScalarAdvectionEquation2D(advection_velocity) initial_condition = initial_condition_gauss -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-5.0, -5.0) -coordinates_max = ( 5.0, 5.0) +coordinates_max = (5.0, 5.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=30_000) - + initial_refinement_level = 2, + n_cells_max = 30_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -67,37 +64,37 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -amr_controller = ControllerThreeLevel(semi, TrixiExtensionRefine.IndicatorAlwaysRefine(semi), - base_level=4, max_level=4, - med_threshold=0.1, max_threshold=0.6) +amr_controller = ControllerThreeLevel(semi, + TrixiExtensionRefine.IndicatorAlwaysRefine(semi), + base_level = 4, max_level = 4, + med_threshold = 0.1, max_threshold = 0.6) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) 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); +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/tree_2d_dgsem/elixir_advection_amr_solution_independent.jl b/examples/tree_2d_dgsem/elixir_advection_amr_solution_independent.jl index efd282dab1f..03a213689ec 100644 --- a/examples/tree_2d_dgsem/elixir_advection_amr_solution_independent.jl +++ b/examples/tree_2d_dgsem/elixir_advection_amr_solution_independent.jl @@ -7,69 +7,68 @@ module TrixiExtension using Trixi -struct IndicatorSolutionIndependent{Cache<:NamedTuple} <: Trixi.AbstractIndicator - cache::Cache +struct IndicatorSolutionIndependent{Cache <: NamedTuple} <: Trixi.AbstractIndicator + cache::Cache end function IndicatorSolutionIndependent(semi) - basis = semi.solver.basis - alpha = Vector{real(basis)}() - cache = (; semi.mesh, alpha) - return IndicatorSolutionIndependent{typeof(cache)}(cache) + basis = semi.solver.basis + alpha = Vector{real(basis)}() + cache = (; semi.mesh, alpha) + return IndicatorSolutionIndependent{typeof(cache)}(cache) end -function (indicator::IndicatorSolutionIndependent)(u::AbstractArray{<:Any,4}, +function (indicator::IndicatorSolutionIndependent)(u::AbstractArray{<:Any, 4}, mesh, equations, dg, cache; t, kwargs...) - - mesh = indicator.cache.mesh - alpha = indicator.cache.alpha - resize!(alpha, nelements(dg, cache)) - - #Predict the theoretical center. - advection_velocity = (0.2, -0.7) - center = t.*advection_velocity - - inner_distance = 1 - outer_distance = 1.85 - - #Iterate over all elements - for element in 1:length(alpha) - #Calculate periodic distance between cell and center. - cell_id = cache.elements.cell_ids[element] - coordinates = mesh.tree.coordinates[1:2, cell_id] - - #The geometric shape of the amr should be preserved when the base_level is increased. - #This is done by looking at the original coordinates of each cell. - cell_coordinates = original_coordinates(coordinates, 5/8) - cell_distance = periodic_distance_2d(cell_coordinates, center, 10) - if cell_distance < (inner_distance+outer_distance)/2 - cell_coordinates = original_coordinates(coordinates, 5/16) - cell_distance = periodic_distance_2d(cell_coordinates, center, 10) + mesh = indicator.cache.mesh + alpha = indicator.cache.alpha + resize!(alpha, nelements(dg, cache)) + + #Predict the theoretical center. + advection_velocity = (0.2, -0.7) + center = t .* advection_velocity + + inner_distance = 1 + outer_distance = 1.85 + + #Iterate over all elements + for element in 1:length(alpha) + #Calculate periodic distance between cell and center. + cell_id = cache.elements.cell_ids[element] + coordinates = mesh.tree.coordinates[1:2, cell_id] + + #The geometric shape of the amr should be preserved when the base_level is increased. + #This is done by looking at the original coordinates of each cell. + cell_coordinates = original_coordinates(coordinates, 5 / 8) + cell_distance = periodic_distance_2d(cell_coordinates, center, 10) + if cell_distance < (inner_distance + outer_distance) / 2 + cell_coordinates = original_coordinates(coordinates, 5 / 16) + cell_distance = periodic_distance_2d(cell_coordinates, center, 10) + end + + #Set alpha according to cells position inside the circles. + target_level = (cell_distance < inner_distance) + (cell_distance < outer_distance) + alpha[element] = target_level / 2 end - - #Set alpha according to cells position inside the circles. - target_level = (cell_distance < inner_distance) + (cell_distance < outer_distance) - alpha[element] = target_level/2 - end - return alpha + return alpha end # For periodic domains, distance between two points must take into account # periodic extensions of the domain function periodic_distance_2d(coordinates, center, domain_length) - dx = coordinates .- center - dx_shifted = abs.(dx .% domain_length) - dx_periodic = min.(dx_shifted, domain_length .- dx_shifted) - return sqrt(sum(dx_periodic.^2)) + dx = coordinates .- center + dx_shifted = abs.(dx .% domain_length) + dx_periodic = min.(dx_shifted, domain_length .- dx_shifted) + return sqrt(sum(dx_periodic .^ 2)) end #This takes a cells coordinates and transforms them into the coordinates of a parent-cell it originally refined from. #It does it so that the parent-cell has given cell_length. function original_coordinates(coordinates, cell_length) - offset = coordinates .% cell_length - offset_sign = sign.(offset) - border = coordinates - offset - center = border + (offset_sign .* cell_length/2) - return center + offset = coordinates .% cell_length + offset_sign = sign.(offset) + border = coordinates - offset + center = border + (offset_sign .* cell_length / 2) + return center end end # module TrixiExtension @@ -83,18 +82,16 @@ equations = LinearScalarAdvectionEquation2D(advection_velocity) initial_condition = initial_condition_gauss -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-5.0, -5.0) -coordinates_max = ( 5.0, 5.0) +coordinates_max = (5.0, 5.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=30_000) - + initial_refinement_level = 4, + n_cells_max = 30_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -104,38 +101,38 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -amr_controller = ControllerThreeLevel(semi, TrixiExtension.IndicatorSolutionIndependent(semi), - base_level=4, - med_level=5, med_threshold=0.1, - max_level=6, max_threshold=0.6) +amr_controller = ControllerThreeLevel(semi, + TrixiExtension.IndicatorSolutionIndependent(semi), + base_level = 4, + med_level = 5, med_threshold = 0.1, + max_level = 6, max_threshold = 0.6) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) 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); +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/tree_2d_dgsem/elixir_advection_amr_visualization.jl b/examples/tree_2d_dgsem/elixir_advection_amr_visualization.jl index f517b4eb1cf..7b67b811177 100644 --- a/examples/tree_2d_dgsem/elixir_advection_amr_visualization.jl +++ b/examples/tree_2d_dgsem/elixir_advection_amr_visualization.jl @@ -9,27 +9,26 @@ using Plots advection_velocity = (0.2, -0.7) equations = LinearScalarAdvectionEquation2D(advection_velocity) -function initial_condition_gauss_largedomain(x, t, equation::LinearScalarAdvectionEquation2D) - # Store translated coordinate for easy use of exact solution - domain_length = SVector(10, 10) - x_trans = Trixi.x_trans_periodic_2d(x - equation.advection_velocity * t, domain_length) +function initial_condition_gauss_largedomain(x, t, + equation::LinearScalarAdvectionEquation2D) + # Store translated coordinate for easy use of exact solution + domain_length = SVector(10, 10) + x_trans = Trixi.x_trans_periodic_2d(x - equation.advection_velocity * t, domain_length) - return SVector(exp(-(x_trans[1]^2 + x_trans[2]^2))) + return SVector(exp(-(x_trans[1]^2 + x_trans[2]^2))) end initial_condition = initial_condition_gauss_largedomain -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-5.0, -5.0) -coordinates_max = ( 5.0, 5.0) +coordinates_max = (5.0, 5.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=30_000) - + initial_refinement_level = 3, + n_cells_max = 30_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -39,41 +38,40 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) # Enable in-situ visualization with a new plot generated every 20 time steps # and additional plotting options passed as keyword arguments -visualization = VisualizationCallback(interval=20, clims=(0,1)) +visualization = VisualizationCallback(interval = 20, clims = (0, 1)) -amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable=first), - base_level=3, - med_level=4, med_threshold=0.1, - max_level=5, max_threshold=0.6) +amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first), + base_level = 3, + med_level = 4, med_threshold = 0.1, + max_level = 5, max_threshold = 0.6) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, visualization, 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); +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/tree_2d_dgsem/elixir_advection_basic.jl b/examples/tree_2d_dgsem/elixir_advection_basic.jl index 269ab8cdd04..0ec0bc3629a 100644 --- a/examples/tree_2d_dgsem/elixir_advection_basic.jl +++ b/examples/tree_2d_dgsem/elixir_advection_basic.jl @@ -9,19 +9,19 @@ advection_velocity = (0.2, -0.7) 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) -coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) +coordinates_max = (1.0, 1.0) # maximum coordinates (max(x), max(y)) # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=30_000) # set maximum capacity of tree data structure + initial_refinement_level = 4, + n_cells_max = 30_000) # set maximum capacity of tree data structure # A semidiscretization collects data structures and functions for the spatial discretization -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, solver) - +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, + solver) ############################################################################### # ODE solvers, callbacks etc. @@ -34,26 +34,26 @@ ode = semidiscretize(semi, (0.0, 1.0)); summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +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.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) # 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) - +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/tree_2d_dgsem/elixir_advection_callbacks.jl b/examples/tree_2d_dgsem/elixir_advection_callbacks.jl index 2ddd3e92ed2..708cd0aa3a3 100644 --- a/examples/tree_2d_dgsem/elixir_advection_callbacks.jl +++ b/examples/tree_2d_dgsem/elixir_advection_callbacks.jl @@ -2,7 +2,6 @@ using OrdinaryDiffEq using Trixi - # define new structs inside a module to allow re-evaluating the file module TrixiExtensionExample @@ -14,83 +13,81 @@ using OrdinaryDiffEq: DiscreteCallback, u_modified! # each time it is called. Its sole purpose here is to showcase how to implement # a stage callback for Trixi.jl. struct ExampleStageCallback - times::Vector{Float64} - min_values::Vector{Float64} - max_values::Vector{Float64} - - # You can optionally define an inner constructor like the one below to set up - # some required stuff. You can also create outer constructors (not demonstrated - # here) for further customization options. - function ExampleStageCallback() - new(Float64[], Float64[], Float64[]) - end + times::Vector{Float64} + min_values::Vector{Float64} + max_values::Vector{Float64} + + # You can optionally define an inner constructor like the one below to set up + # some required stuff. You can also create outer constructors (not demonstrated + # here) for further customization options. + function ExampleStageCallback() + new(Float64[], Float64[], Float64[]) + end end # This method is called when the `ExampleStageCallback` is used as `stage_limiter!` # which gets called after every RK stage. There is no specific initialization # method for such `stage_limiter!`s in OrdinaryDiffEq.jl. function (example_stage_callback::ExampleStageCallback)(u_ode, _, semi, t) + min_val, max_val = extrema(u_ode) + push!(example_stage_callback.times, t) + push!(example_stage_callback.min_values, min_val) + push!(example_stage_callback.max_values, max_val) - min_val, max_val = extrema(u_ode) - push!(example_stage_callback.times, t) - push!(example_stage_callback.min_values, min_val) - push!(example_stage_callback.max_values, max_val) - - return nothing + return nothing end - # This is an example implementation for a simple step callback (i.e., a callable # that is potentially executed after each Runge-Kutta *step*), which records # some values each time it is called. Its sole purpose here is to showcase # how to implement a step callback for Trixi.jl. struct ExampleStepCallback - message::String - times::Vector{Float64} - min_values::Vector{Float64} - max_values::Vector{Float64} - - # You can optionally define an inner constructor like the one below to set up - # some required stuff. You can also create outer constructors (not demonstrated - # here) for further customization options. - function ExampleStepCallback(message::String) - new(message, Float64[], Float64[], Float64[]) - end + message::String + times::Vector{Float64} + min_values::Vector{Float64} + max_values::Vector{Float64} + + # You can optionally define an inner constructor like the one below to set up + # some required stuff. You can also create outer constructors (not demonstrated + # here) for further customization options. + function ExampleStepCallback(message::String) + new(message, Float64[], Float64[], Float64[]) + end end # This method is called when the `ExampleStepCallback` is used as callback # which gets called after RK steps. function (example_callback::ExampleStepCallback)(integrator) - u_ode = integrator.u - t = integrator.t - # You can also access semi = integrator.p - - min_val, max_val = extrema(u_ode) - push!(example_callback.times, t) - push!(example_callback.min_values, min_val) - push!(example_callback.max_values, max_val) - - # avoid re-evaluating possible FSAL stages - u_modified!(integrator, false) - return nothing + u_ode = integrator.u + t = integrator.t + # You can also access semi = integrator.p + + min_val, max_val = extrema(u_ode) + push!(example_callback.times, t) + push!(example_callback.min_values, min_val) + push!(example_callback.max_values, max_val) + + # avoid re-evaluating possible FSAL stages + u_modified!(integrator, false) + return nothing end # This method is used to wrap an `ExampleStepCallback` inside a `DiscreteCallback` # which gets called after every RK step. You can pass an additional initialization # method and a separate condition specifying whether the callback shall be called. function ExampleStepCallback(; message::String) - # Call the `ExampleStepCallback` after every RK step. - condition = (u_ode, t, integrator) -> true + # Call the `ExampleStepCallback` after every RK step. + condition = (u_ode, t, integrator) -> true - # You can optionally pass an initialization method. There, you can access the - # `ExampleStepCallback` as `cb.affect!`. - initialize = (cb, u_ode, t, integrator) -> println(cb.affect!.message) + # You can optionally pass an initialization method. There, you can access the + # `ExampleStepCallback` as `cb.affect!`. + initialize = (cb, u_ode, t, integrator) -> println(cb.affect!.message) - example_callback = ExampleStepCallback(message) + example_callback = ExampleStepCallback(message) - DiscreteCallback(condition, example_callback, - save_positions=(false,false), - initialize=initialize) + DiscreteCallback(condition, example_callback, + save_positions = (false, false), + initialize = initialize) end end # module TrixiExtensionExample @@ -104,18 +101,16 @@ advection_velocity = (0.2, -0.7) equations = LinearScalarAdvectionEquation2D(advection_velocity) initial_condition = initial_condition_convergence_test -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -1.0) -coordinates_max = ( 1.0, 1.0) +coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=30_000) - + initial_refinement_level = 4, + n_cells_max = 30_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -125,19 +120,19 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy, energy_total)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy, energy_total)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2cons) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2cons) -example_callback = TrixiExtensionExample.ExampleStepCallback(message="안녕하세요?") +example_callback = TrixiExtensionExample.ExampleStepCallback(message = "안녕하세요?") -stepsize_callback = StepsizeCallback(cfl=1.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -158,9 +153,10 @@ example_stage_callback! = TrixiExtensionExample.ExampleStageCallback() ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(example_stage_callback!, 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); +sol = solve(ode, + CarpenterKennedy2N54(example_stage_callback!, 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 # Check whether we recorded the same values. diff --git a/examples/tree_2d_dgsem/elixir_advection_diffusion.jl b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl index a716bd278b8..1f765ff3564 100644 --- a/examples/tree_2d_dgsem/elixir_advection_diffusion.jl +++ b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl @@ -10,30 +10,31 @@ diffusivity() = 5.0e-2 equations_parabolic = LaplaceDiffusion2D(diffusivity(), equations) # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) -coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) +coordinates_max = (1.0, 1.0) # maximum coordinates (max(x), max(y)) # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - periodicity=true, - n_cells_max=30_000) # set maximum capacity of tree data structure + initial_refinement_level = 4, + periodicity = true, + n_cells_max = 30_000) # set maximum capacity of tree data structure # Define initial condition -function initial_condition_diffusive_convergence_test(x, t, equation::LinearScalarAdvectionEquation2D) - # Store translated coordinate for easy use of exact solution - x_trans = x - equation.advection_velocity * t - - nu = diffusivity() - c = 1.0 - A = 0.5 - L = 2 - f = 1/L - omega = 2 * pi * f - scalar = c + A * sin(omega * sum(x_trans)) * exp(-2 * nu * omega^2 * t) - return SVector(scalar) +function initial_condition_diffusive_convergence_test(x, t, + equation::LinearScalarAdvectionEquation2D) + # Store translated coordinate for easy use of exact solution + x_trans = x - equation.advection_velocity * t + + nu = diffusivity() + c = 1.0 + A = 0.5 + L = 2 + f = 1 / L + omega = 2 * pi * f + scalar = c + A * sin(omega * sum(x_trans)) * exp(-2 * nu * omega^2 * t) + return SVector(scalar) end initial_condition = initial_condition_diffusive_convergence_test @@ -45,9 +46,8 @@ boundary_conditions_parabolic = boundary_condition_periodic semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; - boundary_conditions=(boundary_conditions, - boundary_conditions_parabolic)) - + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic)) ############################################################################### # ODE solvers, callbacks etc. @@ -62,23 +62,22 @@ summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) # The AliveCallback prints short status information in regular intervals -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) - ############################################################################### # run the simulation # OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks alg = RDPK3SpFSAL49() time_int_tol = 1.0e-11 -sol = solve(ode, alg; abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) +sol = solve(ode, alg; abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) # Print the timer summary summary_callback() diff --git a/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl b/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl index c3cd2ebeb20..8da542b0b5d 100644 --- a/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl +++ b/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl @@ -10,16 +10,16 @@ equations = LinearScalarAdvectionEquation2D(advection_velocity) equations_parabolic = LaplaceDiffusion2D(diffusivity(), equations) # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -0.5) # minimum coordinates (min(x), min(y)) -coordinates_max = ( 0.0, 0.5) # maximum coordinates (max(x), max(y)) +coordinates_max = (0.0, 0.5) # maximum coordinates (max(x), max(y)) # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - periodicity=false, - n_cells_max=30_000) # set maximum capacity of tree data structure + initial_refinement_level = 4, + periodicity = false, + n_cells_max = 30_000) # set maximum capacity of tree data structure # Example setup taken from # - Truman Ellis, Jesse Chan, and Leszek Demkowicz (2016). @@ -28,22 +28,22 @@ mesh = TreeMesh(coordinates_min, coordinates_max, # to numerical partial differential equations. # [DOI](https://doi.org/10.1007/978-3-319-41640-3_6). function initial_condition_eriksson_johnson(x, t, equations) - l = 4 - epsilon = diffusivity() # TODO: this requires epsilon < .6 due to sqrt - lambda_1 = (-1 + sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) - lambda_2 = (-1 - sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) - r1 = (1 + sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) - s1 = (1 - sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) - u = exp(-l * t) * (exp(lambda_1 * x[1]) - exp(lambda_2 * x[1])) + - cos(pi * x[2]) * (exp(s1 * x[1]) - exp(r1 * x[1])) / (exp(-s1) - exp(-r1)) - return SVector{1}(u) + l = 4 + epsilon = diffusivity() # TODO: this requires epsilon < .6 due to sqrt + lambda_1 = (-1 + sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + lambda_2 = (-1 - sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + r1 = (1 + sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + s1 = (1 - sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + u = exp(-l * t) * (exp(lambda_1 * x[1]) - exp(lambda_2 * x[1])) + + cos(pi * x[2]) * (exp(s1 * x[1]) - exp(r1 * x[1])) / (exp(-s1) - exp(-r1)) + return SVector{1}(u) end initial_condition = initial_condition_eriksson_johnson boundary_conditions = (; x_neg = BoundaryConditionDirichlet(initial_condition), - y_neg = BoundaryConditionDirichlet(initial_condition), - y_pos = BoundaryConditionDirichlet(initial_condition), - x_pos = boundary_condition_do_nothing) + y_neg = BoundaryConditionDirichlet(initial_condition), + y_pos = BoundaryConditionDirichlet(initial_condition), + x_pos = boundary_condition_do_nothing) boundary_conditions_parabolic = BoundaryConditionDirichlet(initial_condition) @@ -51,9 +51,8 @@ boundary_conditions_parabolic = BoundaryConditionDirichlet(initial_condition) semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; - boundary_conditions=(boundary_conditions, - boundary_conditions_parabolic)) - + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic)) ############################################################################### # ODE solvers, callbacks etc. @@ -68,22 +67,21 @@ summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) # The AliveCallback prints short status information in regular intervals -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) - ############################################################################### # run the simulation # OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks time_int_tol = 1.0e-11 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) # Print the timer summary summary_callback() diff --git a/examples/tree_2d_dgsem/elixir_advection_extended.jl b/examples/tree_2d_dgsem/elixir_advection_extended.jl index 278dc85386d..4d3da47b04a 100644 --- a/examples/tree_2d_dgsem/elixir_advection_extended.jl +++ b/examples/tree_2d_dgsem/elixir_advection_extended.jl @@ -18,21 +18,20 @@ initial_condition = initial_condition_convergence_test boundary_conditions = boundary_condition_periodic # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) -coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) +coordinates_max = (1.0, 1.0) # maximum coordinates (max(x), max(y)) # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=30_000, # set maximum capacity of tree data structure - periodicity=true) + initial_refinement_level = 4, + n_cells_max = 30_000, # set maximum capacity of tree data structure + periodicity = true) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -47,24 +46,24 @@ summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy, energy_total)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy, energy_total)) # The AliveCallback prints short status information in regular intervals -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) # The SaveRestartCallback allows to save a file from which a Trixi.jl simulation can be restarted -save_restart = SaveRestartCallback(interval=40, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 40, + save_final_restart = true) # The SaveSolutionCallback allows to save the solution to a file in regular intervals -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) # The StepsizeCallback handles the re-calculation of the maximum Δt after each time step -stepsize_callback = StepsizeCallback(cfl=1.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver callbacks = CallbackSet(summary_callback, @@ -72,15 +71,14 @@ callbacks = CallbackSet(summary_callback, save_restart, save_solution, stepsize_callback) - ############################################################################### # run the simulation # OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks -alg = CarpenterKennedy2N54(williamson_condition=false) +alg = CarpenterKennedy2N54(williamson_condition = false) sol = solve(ode, alg, - dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks; ode_default_options()...); + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks; ode_default_options()...); # Print the timer summary summary_callback() diff --git a/examples/tree_2d_dgsem/elixir_advection_mortar.jl b/examples/tree_2d_dgsem/elixir_advection_mortar.jl index 2a283fb9008..645c55ba438 100644 --- a/examples/tree_2d_dgsem/elixir_advection_mortar.jl +++ b/examples/tree_2d_dgsem/elixir_advection_mortar.jl @@ -9,22 +9,19 @@ advection_velocity = (0.2, -0.7) equations = LinearScalarAdvectionEquation2D(advection_velocity) initial_condition = initial_condition_convergence_test -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -1.0) -coordinates_max = ( 1.0, 1.0) -refinement_patches = ( - (type="box", coordinates_min=(0.0, -1.0), coordinates_max=(1.0, 1.0)), -) +coordinates_max = (1.0, 1.0) +refinement_patches = ((type = "box", coordinates_min = (0.0, -1.0), + coordinates_max = (1.0, 1.0)),) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - refinement_patches=refinement_patches, - n_cells_max=10_000,) - + initial_refinement_level = 2, + refinement_patches = refinement_patches, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -34,28 +31,27 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_advection_restart.jl b/examples/tree_2d_dgsem/elixir_advection_restart.jl index b63a8d1f7bc..770629bb15e 100644 --- a/examples/tree_2d_dgsem/elixir_advection_restart.jl +++ b/examples/tree_2d_dgsem/elixir_advection_restart.jl @@ -4,10 +4,10 @@ using Trixi ############################################################################### # Define time integration algorithm -alg = CarpenterKennedy2N54(williamson_condition=false) +alg = CarpenterKennedy2N54(williamson_condition = false) # Create a restart file -trixi_include(@__MODULE__, joinpath(@__DIR__, "elixir_advection_extended.jl"), alg = alg, tspan = (0.0, 10.0)) - +trixi_include(@__MODULE__, joinpath(@__DIR__, "elixir_advection_extended.jl"), alg = alg, + tspan = (0.0, 10.0)) ############################################################################### # adapt the parameters that have changed compared to "elixir_advection_extended.jl" @@ -28,8 +28,8 @@ ode = semidiscretize(semi, tspan, restart_filename); save_solution.condition.save_initial_solution = false integrator = init(ode, alg, - dt=dt, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks; ode_default_options()...) + dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks; ode_default_options()...) # Load saved context for adaptive time integrator if integrator.opts.adaptive diff --git a/examples/tree_2d_dgsem/elixir_advection_timeintegration.jl b/examples/tree_2d_dgsem/elixir_advection_timeintegration.jl index be87f24f817..06982bb9a27 100644 --- a/examples/tree_2d_dgsem/elixir_advection_timeintegration.jl +++ b/examples/tree_2d_dgsem/elixir_advection_timeintegration.jl @@ -9,18 +9,16 @@ advection_velocity = (0.2, -0.7) equations = LinearScalarAdvectionEquation2D(advection_velocity) initial_condition = initial_condition_gauss -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-5.0, -5.0) -coordinates_max = ( 5.0, 5.0) +coordinates_max = (5.0, 5.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=30_000) - + initial_refinement_level = 4, + n_cells_max = 30_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -30,39 +28,38 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2cons) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2cons) -amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable=first), - base_level=4, - med_level=5, med_threshold=0.1, - max_level=6, max_threshold=0.6) +amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first), + base_level = 4, + med_level = 5, med_threshold = 0.1, + max_level = 6, max_threshold = 0.6) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, amr_callback, stepsize_callback) - ############################################################################### # run the simulation # sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), ode_algorithm = Trixi.CarpenterKennedy2N54() sol = Trixi.solve(ode, ode_algorithm, - dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); + 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/tree_2d_dgsem/elixir_euler_astro_jet_amr.jl b/examples/tree_2d_dgsem/elixir_euler_astro_jet_amr.jl index c5790e455bc..1393f4a6cc8 100644 --- a/examples/tree_2d_dgsem/elixir_euler_astro_jet_amr.jl +++ b/examples/tree_2d_dgsem/elixir_euler_astro_jet_amr.jl @@ -4,7 +4,7 @@ using Trixi ############################################################################### # semidiscretization of the compressible Euler equations -gamma = 5/3 +gamma = 5 / 3 equations = CompressibleEulerEquations2D(gamma) # Initial condition adopted from @@ -13,55 +13,54 @@ equations = CompressibleEulerEquations2D(gamma) # https://tinyurl.com/c76fjtx4 # Mach = 2000 jet function initial_condition_astro_jet(x, t, equations::CompressibleEulerEquations2D) - @unpack gamma = equations - rho = 0.5 - v1 = 0 - v2 = 0 - p = 0.4127 - # add inflow for t>0 at x=-0.5 - # domain size is [-0.5,+0.5]^2 - if (t > 0) && (x[1] ≈ -0.5) && (abs(x[2]) < 0.05) - rho = 5 - v1 = 800 # about Mach number Ma = 2000 + @unpack gamma = equations + rho = 0.5 + v1 = 0 v2 = 0 p = 0.4127 - end - return prim2cons(SVector(rho, v1, v2, p), equations) + # add inflow for t>0 at x=-0.5 + # domain size is [-0.5,+0.5]^2 + if (t > 0) && (x[1] ≈ -0.5) && (abs(x[2]) < 0.05) + rho = 5 + v1 = 800 # about Mach number Ma = 2000 + v2 = 0 + p = 0.4127 + end + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_astro_jet -boundary_conditions = ( - x_neg=BoundaryConditionDirichlet(initial_condition_astro_jet), - x_pos=BoundaryConditionDirichlet(initial_condition_astro_jet), - y_neg=boundary_condition_periodic, - y_pos=boundary_condition_periodic, - ) +boundary_conditions = (x_neg = BoundaryConditionDirichlet(initial_condition_astro_jet), + x_pos = BoundaryConditionDirichlet(initial_condition_astro_jet), + y_neg = boundary_condition_periodic, + y_pos = boundary_condition_periodic) surface_flux = flux_lax_friedrichs # HLLC needs more shock capturing (alpha_max) -volume_flux = flux_ranocha # works with Chandrashekar flux as well +volume_flux = flux_ranocha # works with Chandrashekar flux as well polydeg = 3 basis = LobattoLegendreBasis(polydeg) # shock capturing necessary for this tough example indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.3, - alpha_min=0.0001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.3, + alpha_min = 0.0001, + alpha_smooth = true, + variable = density_pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-0.5, -0.5) -coordinates_max = ( 0.5, 0.5) +coordinates_max = (0.5, 0.5) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - periodicity=(false,true), - n_cells_max=100_000) -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions=boundary_conditions) + initial_refinement_level = 6, + periodicity = (false, true), + n_cells_max = 100_000) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -72,43 +71,43 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 5000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) - -alive_callback = AliveCallback(analysis_interval=analysis_interval) - -save_solution = SaveSolutionCallback(interval=5000, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) - -amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=1.0, - alpha_min=0.0001, - alpha_smooth=false, - variable=Trixi.density) - -amr_controller = ControllerThreeLevelCombined(semi, amr_indicator, indicator_sc, - base_level=2, - med_level =0, med_threshold=0.0003, # med_level = current level - max_level =8, max_threshold=0.003, - max_threshold_secondary=indicator_sc.alpha_max) - -amr_callback = AMRCallback(semi, amr_controller, - interval=1, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 5000, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +amr_indicator = IndicatorHennemannGassner(semi, + alpha_max = 1.0, + alpha_min = 0.0001, + alpha_smooth = false, + variable = Trixi.density) + +amr_controller = ControllerThreeLevelCombined(semi, amr_indicator, indicator_sc, + base_level = 2, + med_level = 0, med_threshold = 0.0003, # med_level = current level + max_level = 8, max_threshold = 0.003, + max_threshold_secondary = indicator_sc.alpha_max) + +amr_callback = AMRCallback(semi, amr_controller, + interval = 1, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) callbacks = CallbackSet(summary_callback, - analysis_callback, alive_callback, + analysis_callback, alive_callback, amr_callback, save_solution) # positivity limiter necessary for this tough example -stage_limiter! = PositivityPreservingLimiterZhangShu(thresholds=(5.0e-6, 5.0e-6), - variables=(Trixi.density, pressure)) +stage_limiter! = PositivityPreservingLimiterZhangShu(thresholds = (5.0e-6, 5.0e-6), + variables = (Trixi.density, pressure)) ############################################################################### # run the simulation # use adaptive time stepping based on error estimates, time step roughly dt = 1e-7 sol = solve(ode, SSPRK43(stage_limiter!); - ode_default_options()..., callback=callbacks); + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_euler_blast_wave.jl b/examples/tree_2d_dgsem/elixir_euler_blast_wave.jl index 0da18b7120d..ccd7b54086b 100644 --- a/examples/tree_2d_dgsem/elixir_euler_blast_wave.jl +++ b/examples/tree_2d_dgsem/elixir_euler_blast_wave.jl @@ -16,48 +16,46 @@ A medium blast wave taken from [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) """ function initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations2D) - # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" - # 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) - phi = atan(y_norm, x_norm) - sin_phi, cos_phi = sincos(phi) - - # 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 - p = r > 0.5 ? 1.0E-3 : 1.245 - - return prim2cons(SVector(rho, v1, v2, p), equations) + # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" + # 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) + phi = atan(y_norm, x_norm) + sin_phi, cos_phi = sincos(phi) + + # 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 + p = r > 0.5 ? 1.0E-3 : 1.245 + + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_ranocha +volume_flux = flux_ranocha basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - n_cells_max=10_000) - + initial_refinement_level = 6, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -67,27 +65,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.9) +stepsize_callback = StepsizeCallback(cfl = 0.9) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_euler_blast_wave_amr.jl b/examples/tree_2d_dgsem/elixir_euler_blast_wave_amr.jl index 6ce9268486c..d32c2e51b06 100644 --- a/examples/tree_2d_dgsem/elixir_euler_blast_wave_amr.jl +++ b/examples/tree_2d_dgsem/elixir_euler_blast_wave_amr.jl @@ -16,48 +16,46 @@ A medium blast wave taken from [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) """ function initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations2D) - # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" - # 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) - phi = atan(y_norm, x_norm) - sin_phi, cos_phi = sincos(phi) - - # 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 - p = r > 0.5 ? 1.0E-3 : 1.245 - - return prim2cons(SVector(rho, v1, v2, p), equations) + # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" + # 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) + phi = atan(y_norm, x_norm) + sin_phi, cos_phi = sincos(phi) + + # 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 + p = r > 0.5 ? 1.0E-3 : 1.245 + + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_ranocha +volume_flux = flux_ranocha basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - n_cells_max=10_000) - + initial_refinement_level = 6, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -67,40 +65,39 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = density_pressure) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=4, - max_level =6, max_threshold=0.01) + base_level = 4, + max_level = 6, max_threshold = 0.01) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=0.9) +stepsize_callback = StepsizeCallback(cfl = 0.9) 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); +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/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_cnn.jl b/examples/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_cnn.jl index 659788f2f5c..79d7474dc66 100644 --- a/examples/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_cnn.jl +++ b/examples/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_cnn.jl @@ -2,7 +2,8 @@ using Downloads: download using Flux using BSON: load network = joinpath(@__DIR__, "modelcnn-0.964-0.001.bson") -download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelcnn-0.964-0.001.bson", network) +download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelcnn-0.964-0.001.bson", + network) model2dcnn = load(network, @__MODULE__)[:model2dcnn] using OrdinaryDiffEq @@ -28,52 +29,50 @@ A medium blast wave taken from [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) """ function initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations2D) - # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" - # 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) - phi = atan(y_norm, x_norm) - sin_phi, cos_phi = sincos(phi) - - # 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 - p = r > 0.5 ? 1.0E-3 : 1.245 - - return prim2cons(SVector(rho, v1, v2, p), equations) + # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" + # 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) + phi = atan(y_norm, x_norm) + sin_phi, cos_phi = sincos(phi) + + # 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 + p = r > 0.5 ? 1.0E-3 : 1.245 + + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_chandrashekar +volume_flux = flux_chandrashekar basis = LobattoLegendreBasis(3) indicator_sc = IndicatorNeuralNetwork(equations, basis, - indicator_type=NeuralNetworkCNN(), - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - alpha_continuous=true, - alpha_amr=false, - variable=density_pressure, - network=model2dcnn) + indicator_type = NeuralNetworkCNN(), + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + alpha_continuous = true, + alpha_amr = false, + variable = density_pressure, + network = model2dcnn) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - n_cells_max=10_000) - + initial_refinement_level = 6, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -83,27 +82,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.9) +stepsize_callback = StepsizeCallback(cfl = 0.9) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl b/examples/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl index 3f4862674d2..27398593efd 100644 --- a/examples/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl +++ b/examples/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl @@ -2,7 +2,8 @@ using Downloads: download using Flux using BSON: load network = joinpath(@__DIR__, "modelnnpp-0.904-0.0005.bson") -download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelnnpp-0.904-0.0005.bson", network) +download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelnnpp-0.904-0.0005.bson", + network) model2d = load(network, @__MODULE__)[:model2d] using OrdinaryDiffEq @@ -28,52 +29,50 @@ A medium blast wave taken from [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) """ function initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations2D) - # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" - # 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) - phi = atan(y_norm, x_norm) - sin_phi, cos_phi = sincos(phi) - - # 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 - p = r > 0.5 ? 1.0E-3 : 1.245 - - return prim2cons(SVector(rho, v1, v2, p), equations) + # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" + # 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) + phi = atan(y_norm, x_norm) + sin_phi, cos_phi = sincos(phi) + + # 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 + p = r > 0.5 ? 1.0E-3 : 1.245 + + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_chandrashekar +volume_flux = flux_chandrashekar basis = LobattoLegendreBasis(3) indicator_sc = IndicatorNeuralNetwork(equations, basis, - indicator_type=NeuralNetworkPerssonPeraire(), - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - alpha_continuous=true, - alpha_amr=false, - variable=density_pressure, - network=model2d) + indicator_type = NeuralNetworkPerssonPeraire(), + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + alpha_continuous = true, + alpha_amr = false, + variable = density_pressure, + network = model2d) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - n_cells_max=10_000) - + initial_refinement_level = 6, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -83,27 +82,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.9) +stepsize_callback = StepsizeCallback(cfl = 0.9) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl b/examples/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl index db2fffacb36..6c67f948636 100644 --- a/examples/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl +++ b/examples/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl @@ -3,7 +3,8 @@ using Flux using Random using BSON: load network = joinpath(@__DIR__, "modelnnrhs-0.973-0.001.bson") -download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelnnrhs-0.973-0.001.bson", network) +download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelnnrhs-0.973-0.001.bson", + network) model2d = load(network, @__MODULE__)[:model2d] using OrdinaryDiffEq @@ -29,54 +30,52 @@ A medium blast wave taken from [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) """ function initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations2D) - # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" - # 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) - phi = atan(y_norm, x_norm) - sin_phi, cos_phi = sincos(phi) - - # 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 - p = r > 0.5 ? 1.0E-3 : 1.245 - - return prim2cons(SVector(rho, v1, v2, p), equations) + # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" + # 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) + phi = atan(y_norm, x_norm) + sin_phi, cos_phi = sincos(phi) + + # 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 + p = r > 0.5 ? 1.0E-3 : 1.245 + + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_chandrashekar +volume_flux = flux_chandrashekar basis = LobattoLegendreBasis(3) indicator_sc = IndicatorNeuralNetwork(equations, basis, - indicator_type=NeuralNetworkRayHesthaven(), - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - alpha_continuous=true, - alpha_amr=false, - variable=density_pressure, - network=model2d) + indicator_type = NeuralNetworkRayHesthaven(), + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + alpha_continuous = true, + alpha_amr = false, + variable = density_pressure, + network = model2d) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) refinement_patches = () # To allow for specifying them via `trixi_include` mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - refinement_patches=refinement_patches, - n_cells_max=10_000) - + initial_refinement_level = 6, + refinement_patches = refinement_patches, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -86,27 +85,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.9) +stepsize_callback = StepsizeCallback(cfl = 0.9) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_euler_blast_wave_pure_fv.jl b/examples/tree_2d_dgsem/elixir_euler_blast_wave_pure_fv.jl index a0fc9349696..a2392d05e5a 100644 --- a/examples/tree_2d_dgsem/elixir_euler_blast_wave_pure_fv.jl +++ b/examples/tree_2d_dgsem/elixir_euler_blast_wave_pure_fv.jl @@ -16,40 +16,38 @@ A medium blast wave taken from [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) """ function initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations2D) - # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" - # 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) - phi = atan(y_norm, x_norm) - sin_phi, cos_phi = sincos(phi) - - # 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 - p = r > 0.5 ? 1.0E-3 : 1.245 - - return prim2cons(SVector(rho, v1, v2, p), equations) + # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" + # 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) + phi = atan(y_norm, x_norm) + sin_phi, cos_phi = sincos(phi) + + # 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 + p = r > 0.5 ? 1.0E-3 : 1.245 + + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_blast_wave -surface_flux = flux_hllc +surface_flux = flux_hllc basis = LobattoLegendreBasis(3) volume_integral = VolumeIntegralPureLGLFiniteVolume(flux_hllc) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - n_cells_max=10_000) - + initial_refinement_level = 6, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -59,27 +57,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.9) +stepsize_callback = StepsizeCallback(cfl = 0.9) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_euler_blob_amr.jl b/examples/tree_2d_dgsem/elixir_euler_blob_amr.jl index f4040732667..2b3659017a3 100644 --- a/examples/tree_2d_dgsem/elixir_euler_blob_amr.jl +++ b/examples/tree_2d_dgsem/elixir_euler_blob_amr.jl @@ -4,7 +4,7 @@ using Trixi ############################################################################### # semidiscretization of the compressible Euler equations -gamma = 5/3 +gamma = 5 / 3 equations = CompressibleEulerEquations2D(gamma) """ @@ -16,67 +16,67 @@ The blob test case taken from [arXiv: astro-ph/0610051](https://arxiv.org/abs/astro-ph/0610051) """ function initial_condition_blob(x, t, equations::CompressibleEulerEquations2D) - # blob test case, see Agertz et al. https://arxiv.org/pdf/astro-ph/0610051.pdf - # other reference: https://arxiv.org/pdf/astro-ph/0610051.pdf - # change discontinuity to tanh - # typical domain is rectangular, we change it to a square - # resolution 128^2, 256^2 - # domain size is [-20.0,20.0]^2 - # gamma = 5/3 for this test case - R = 1.0 # radius of the blob - # background density - dens0 = 1.0 - Chi = 10.0 # density contrast - # reference time of characteristic growth of KH instability equal to 1.0 - tau_kh = 1.0 - tau_cr = tau_kh/1.6 # crushing time - # determine background velocity - velx0 = 2*R*sqrt(Chi)/tau_cr - vely0 = 0.0 - Ma0 = 2.7 # background flow Mach number Ma=v/c - c = velx0/Ma0 # sound speed - # use perfect gas assumption to compute background pressure via the sound speed c^2 = gamma * pressure/density - p0 = c*c*dens0/equations.gamma - # initial center of the blob - inicenter = [-15,0] - x_rel = x-inicenter - r = sqrt(x_rel[1]^2 + x_rel[2]^2) - # steepness of the tanh transition zone - slope = 2 - # density blob - dens = dens0 + (Chi-1) * 0.5*(1+(tanh(slope*(r+R)) - (tanh(slope*(r-R)) + 1))) - # velocity blob is zero - velx = velx0 - velx0 * 0.5*(1+(tanh(slope*(r+R)) - (tanh(slope*(r-R)) + 1))) - return prim2cons(SVector(dens, velx, vely0, p0), equations) + # blob test case, see Agertz et al. https://arxiv.org/pdf/astro-ph/0610051.pdf + # other reference: https://arxiv.org/pdf/astro-ph/0610051.pdf + # change discontinuity to tanh + # typical domain is rectangular, we change it to a square + # resolution 128^2, 256^2 + # domain size is [-20.0,20.0]^2 + # gamma = 5/3 for this test case + R = 1.0 # radius of the blob + # background density + dens0 = 1.0 + Chi = 10.0 # density contrast + # reference time of characteristic growth of KH instability equal to 1.0 + tau_kh = 1.0 + tau_cr = tau_kh / 1.6 # crushing time + # determine background velocity + velx0 = 2 * R * sqrt(Chi) / tau_cr + vely0 = 0.0 + Ma0 = 2.7 # background flow Mach number Ma=v/c + c = velx0 / Ma0 # sound speed + # use perfect gas assumption to compute background pressure via the sound speed c^2 = gamma * pressure/density + p0 = c * c * dens0 / equations.gamma + # initial center of the blob + inicenter = [-15, 0] + x_rel = x - inicenter + r = sqrt(x_rel[1]^2 + x_rel[2]^2) + # steepness of the tanh transition zone + slope = 2 + # density blob + dens = dens0 + + (Chi - 1) * 0.5 * (1 + (tanh(slope * (r + R)) - (tanh(slope * (r - R)) + 1))) + # velocity blob is zero + velx = velx0 - velx0 * 0.5 * (1 + (tanh(slope * (r + R)) - (tanh(slope * (r - R)) + 1))) + return prim2cons(SVector(dens, velx, vely0, p0), equations) end initial_condition = initial_condition_blob surface_flux = flux_lax_friedrichs -volume_flux = flux_ranocha +volume_flux = flux_ranocha basis = LobattoLegendreBasis(4) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.4, - alpha_min=0.0001, - alpha_smooth=true, - variable=pressure) + alpha_max = 0.4, + alpha_min = 0.0001, + alpha_smooth = true, + variable = pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-20.0, -20.0) -coordinates_max = ( 20.0, 20.0) +coordinates_max = (20.0, 20.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - n_cells_max=100_000,) + initial_refinement_level = 6, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -86,42 +86,41 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=1.0, - alpha_min=0.0001, - alpha_smooth=false, - variable=Trixi.density) + alpha_max = 1.0, + alpha_min = 0.0001, + alpha_smooth = false, + variable = Trixi.density) amr_controller = ControllerThreeLevelCombined(semi, amr_indicator, indicator_sc, - base_level=4, - med_level =0, med_threshold=0.0003, # med_level = current level - max_level =7, max_threshold=0.003, - max_threshold_secondary=indicator_sc.alpha_max) + base_level = 4, + med_level = 0, med_threshold = 0.0003, # med_level = current level + max_level = 7, max_threshold = 0.003, + max_threshold_secondary = indicator_sc.alpha_max) amr_callback = AMRCallback(semi, amr_controller, - interval=1, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 1, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=0.25) +stepsize_callback = StepsizeCallback(cfl = 0.25) 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); +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/tree_2d_dgsem/elixir_euler_blob_mortar.jl b/examples/tree_2d_dgsem/elixir_euler_blob_mortar.jl index 5b7365f860f..8bd5db00c9a 100644 --- a/examples/tree_2d_dgsem/elixir_euler_blob_mortar.jl +++ b/examples/tree_2d_dgsem/elixir_euler_blob_mortar.jl @@ -4,7 +4,7 @@ using Trixi ############################################################################### # semidiscretization of the compressible Euler equations -gamma = 5/3 +gamma = 5 / 3 equations = CompressibleEulerEquations2D(gamma) """ @@ -16,71 +16,71 @@ The blob test case taken from [arXiv: astro-ph/0610051](https://arxiv.org/abs/astro-ph/0610051) """ function initial_condition_blob(x, t, equations::CompressibleEulerEquations2D) - # blob test case, see Agertz et al. https://arxiv.org/pdf/astro-ph/0610051.pdf - # other reference: https://arxiv.org/pdf/astro-ph/0610051.pdf - # change discontinuity to tanh - # typical domain is rectangular, we change it to a square - # resolution 128^2, 256^2 - # domain size is [-20.0,20.0]^2 - # gamma = 5/3 for this test case - R = 1.0 # radius of the blob - # background density - dens0 = 1.0 - Chi = 10.0 # density contrast - # reference time of characteristic growth of KH instability equal to 1.0 - tau_kh = 1.0 - tau_cr = tau_kh/1.6 # crushing time - # determine background velocity - velx0 = 2*R*sqrt(Chi)/tau_cr - vely0 = 0.0 - Ma0 = 2.7 # background flow Mach number Ma=v/c - c = velx0/Ma0 # sound speed - # use perfect gas assumption to compute background pressure via the sound speed c^2 = gamma * pressure/density - p0 = c*c*dens0/equations.gamma - # initial center of the blob - inicenter = [-15,0] - x_rel = x-inicenter - r = sqrt(x_rel[1]^2 + x_rel[2]^2) - # steepness of the tanh transition zone - slope = 2 - # density blob - dens = dens0 + (Chi-1) * 0.5*(1+(tanh(slope*(r+R)) - (tanh(slope*(r-R)) + 1))) - # velocity blob is zero - velx = velx0 - velx0 * 0.5*(1+(tanh(slope*(r+R)) - (tanh(slope*(r-R)) + 1))) - return prim2cons(SVector(dens, velx, vely0, p0), equations) + # blob test case, see Agertz et al. https://arxiv.org/pdf/astro-ph/0610051.pdf + # other reference: https://arxiv.org/pdf/astro-ph/0610051.pdf + # change discontinuity to tanh + # typical domain is rectangular, we change it to a square + # resolution 128^2, 256^2 + # domain size is [-20.0,20.0]^2 + # gamma = 5/3 for this test case + R = 1.0 # radius of the blob + # background density + dens0 = 1.0 + Chi = 10.0 # density contrast + # reference time of characteristic growth of KH instability equal to 1.0 + tau_kh = 1.0 + tau_cr = tau_kh / 1.6 # crushing time + # determine background velocity + velx0 = 2 * R * sqrt(Chi) / tau_cr + vely0 = 0.0 + Ma0 = 2.7 # background flow Mach number Ma=v/c + c = velx0 / Ma0 # sound speed + # use perfect gas assumption to compute background pressure via the sound speed c^2 = gamma * pressure/density + p0 = c * c * dens0 / equations.gamma + # initial center of the blob + inicenter = [-15, 0] + x_rel = x - inicenter + r = sqrt(x_rel[1]^2 + x_rel[2]^2) + # steepness of the tanh transition zone + slope = 2 + # density blob + dens = dens0 + + (Chi - 1) * 0.5 * (1 + (tanh(slope * (r + R)) - (tanh(slope * (r - R)) + 1))) + # velocity blob is zero + velx = velx0 - velx0 * 0.5 * (1 + (tanh(slope * (r + R)) - (tanh(slope * (r - R)) + 1))) + return prim2cons(SVector(dens, velx, vely0, p0), equations) end initial_condition = initial_condition_blob surface_flux = flux_lax_friedrichs -volume_flux = flux_ranocha +volume_flux = flux_ranocha basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.05, - alpha_min=0.0001, - alpha_smooth=true, - variable=pressure) + alpha_max = 0.05, + alpha_min = 0.0001, + alpha_smooth = true, + variable = pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-32.0, -32.0) -coordinates_max = ( 32.0, 32.0) -refinement_patches = ( - (type="box", coordinates_min=(-40.0, -5.0), coordinates_max=(40.0, 5.0)), - (type="box", coordinates_min=(-40.0, -5.0), coordinates_max=(40.0, 5.0)), -) +coordinates_max = (32.0, 32.0) +refinement_patches = ((type = "box", coordinates_min = (-40.0, -5.0), + coordinates_max = (40.0, 5.0)), + (type = "box", coordinates_min = (-40.0, -5.0), + coordinates_max = (40.0, 5.0))) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - refinement_patches=refinement_patches, - n_cells_max=100_000,) + initial_refinement_level = 4, + refinement_patches = refinement_patches, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -90,27 +90,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.7) +stepsize_callback = StepsizeCallback(cfl = 0.7) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_euler_colliding_flow.jl b/examples/tree_2d_dgsem/elixir_euler_colliding_flow.jl index cb2a5b16816..984ac3ff1f6 100644 --- a/examples/tree_2d_dgsem/elixir_euler_colliding_flow.jl +++ b/examples/tree_2d_dgsem/elixir_euler_colliding_flow.jl @@ -10,71 +10,71 @@ equations = CompressibleEulerEquations2D(gamma) # This is a hand made colliding flow setup without reference. Features Mach=70 inflow from both # sides, with relative low temperature, such that pressure keeps relatively small # Computed with gamma close to 1, to simulate isothermal gas -function initial_condition_colliding_flow_astro(x, t, equations::CompressibleEulerEquations2D) - # change discontinuity to tanh - # resolution 128^2 elements (refined close to the interface) and polydeg=3 (total of 512^2 DOF) - # domain size is [-64,+64]^2 - @unpack gamma = equations - # the quantities are chosen such, that they are as close as possible to the astro examples - # keep in mind, that in the astro example, the physical units are weird (parsec, mega years, ...) - rho = 0.0247 - c = 0.2 - p = c^2 / gamma * rho - vel = 13.907432274789372 - slope = 1.0 - v1 = -vel*tanh(slope * x[1]) - # add small initial disturbance to the field, but only close to the interface - if abs(x[1]) < 10 - v1 = v1 * (1 + 0.01 * sin(pi * x[2])) - end - v2 = 0.0 - return prim2cons(SVector(rho, v1, v2, p), equations) +function initial_condition_colliding_flow_astro(x, t, + equations::CompressibleEulerEquations2D) + # change discontinuity to tanh + # resolution 128^2 elements (refined close to the interface) and polydeg=3 (total of 512^2 DOF) + # domain size is [-64,+64]^2 + @unpack gamma = equations + # the quantities are chosen such, that they are as close as possible to the astro examples + # keep in mind, that in the astro example, the physical units are weird (parsec, mega years, ...) + rho = 0.0247 + c = 0.2 + p = c^2 / gamma * rho + vel = 13.907432274789372 + slope = 1.0 + v1 = -vel * tanh(slope * x[1]) + # add small initial disturbance to the field, but only close to the interface + if abs(x[1]) < 10 + v1 = v1 * (1 + 0.01 * sin(pi * x[2])) + end + v2 = 0.0 + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_colliding_flow_astro - -boundary_conditions = ( - x_neg=BoundaryConditionDirichlet(initial_condition_colliding_flow_astro), - x_pos=BoundaryConditionDirichlet(initial_condition_colliding_flow_astro), - y_neg=boundary_condition_periodic, - y_pos=boundary_condition_periodic, - ) - - +boundary_conditions = (x_neg = BoundaryConditionDirichlet(initial_condition_colliding_flow_astro), + x_pos = BoundaryConditionDirichlet(initial_condition_colliding_flow_astro), + y_neg = boundary_condition_periodic, + y_pos = boundary_condition_periodic) surface_flux = flux_lax_friedrichs # HLLC needs more shock capturing (alpha_max) -volume_flux = flux_ranocha # works with Chandrashekar flux as well +volume_flux = flux_ranocha # works with Chandrashekar flux as well polydeg = 3 basis = LobattoLegendreBasis(polydeg) # shock capturing necessary for this tough example, however alpha_max = 0.5 is fine indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.0001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.5, + alpha_min = 0.0001, + alpha_smooth = true, + variable = density_pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-64.0, -64.0) -coordinates_max = ( 64.0, 64.0) +coordinates_max = (64.0, 64.0) # only refinement in a patch. Needs x=-17/+17 to trigger refinement due to coarse base mesh -refinement_patches = ( - (type="box", coordinates_min=(-17, -64), coordinates_max=(17, 64)), - (type="box", coordinates_min=(-17, -64), coordinates_max=(17, 64)), - (type="box", coordinates_min=(-17, -64), coordinates_max=(17, 64)), - (type="box", coordinates_min=(-17, -64), coordinates_max=(17, 64)), - #(type="box", coordinates_min=(-17, -64), coordinates_max=(17, 64)), # very high resolution, takes about 1000s on 2 cores -) +refinement_patches = ((type = "box", coordinates_min = (-17, -64), + coordinates_max = (17, 64)), + (type = "box", coordinates_min = (-17, -64), + coordinates_max = (17, 64)), + (type = "box", coordinates_min = (-17, -64), + coordinates_max = (17, 64)), + (type = "box", coordinates_min = (-17, -64), + coordinates_max = (17, 64)) + #(type="box", coordinates_min=(-17, -64), coordinates_max=(17, 64)), # very high resolution, takes about 1000s on 2 cores + ) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - refinement_patches=refinement_patches, - periodicity=(false,true), - n_cells_max=100_000) -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions=boundary_conditions) + initial_refinement_level = 3, + refinement_patches = refinement_patches, + periodicity = (false, true), + n_cells_max = 100_000) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -85,26 +85,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) callbacks = CallbackSet(summary_callback, - analysis_callback, alive_callback, + analysis_callback, alive_callback, save_solution) # positivity limiter necessary for this tough example -stage_limiter! = PositivityPreservingLimiterZhangShu(thresholds=(5.0e-6, 5.0e-6), - variables=(Trixi.density, pressure)) +stage_limiter! = PositivityPreservingLimiterZhangShu(thresholds = (5.0e-6, 5.0e-6), + variables = (Trixi.density, pressure)) ############################################################################### # run the simulation # use adaptive time stepping based on error estimates, time step roughly dt = 5e-3 sol = solve(ode, SSPRK43(stage_limiter!); - ode_default_options()..., callback=callbacks); + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_euler_colliding_flow_amr.jl b/examples/tree_2d_dgsem/elixir_euler_colliding_flow_amr.jl index 21de07147ca..a9eb671929f 100644 --- a/examples/tree_2d_dgsem/elixir_euler_colliding_flow_amr.jl +++ b/examples/tree_2d_dgsem/elixir_euler_colliding_flow_amr.jl @@ -10,62 +10,59 @@ equations = CompressibleEulerEquations2D(gamma) # This is a hand made colliding flow setup without reference. Features Mach=70 inflow from both # sides, with relative low temperature, such that pressure keeps relatively small # Computed with gamma close to 1, to simulate isothermal gas -function initial_condition_colliding_flow_astro(x, t, equations::CompressibleEulerEquations2D) - # change discontinuity to tanh - # resolution 128^2 elements (refined close to the interface) and polydeg=3 (total of 512^2 DOF) - # domain size is [-64,+64]^2 - @unpack gamma = equations - # the quantities are chosen such, that they are as close as possible to the astro examples - # keep in mind, that in the astro example, the physical units are weird (parsec, mega years, ...) - rho = 0.0247 - c = 0.2 - p = c^2 / gamma * rho - vel = 13.907432274789372 - slope = 1.0 - v1 = -vel*tanh(slope * x[1]) - # add small initial disturbance to the field, but only close to the interface - if abs(x[1]) < 10 - v1 = v1 * (1 + 0.01 * sin(pi*x[2])) - end - v2 = 0.0 - return prim2cons(SVector(rho, v1, v2, p), equations) +function initial_condition_colliding_flow_astro(x, t, + equations::CompressibleEulerEquations2D) + # change discontinuity to tanh + # resolution 128^2 elements (refined close to the interface) and polydeg=3 (total of 512^2 DOF) + # domain size is [-64,+64]^2 + @unpack gamma = equations + # the quantities are chosen such, that they are as close as possible to the astro examples + # keep in mind, that in the astro example, the physical units are weird (parsec, mega years, ...) + rho = 0.0247 + c = 0.2 + p = c^2 / gamma * rho + vel = 13.907432274789372 + slope = 1.0 + v1 = -vel * tanh(slope * x[1]) + # add small initial disturbance to the field, but only close to the interface + if abs(x[1]) < 10 + v1 = v1 * (1 + 0.01 * sin(pi * x[2])) + end + v2 = 0.0 + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_colliding_flow_astro - -boundary_conditions = ( - x_neg=BoundaryConditionDirichlet(initial_condition_colliding_flow_astro), - x_pos=BoundaryConditionDirichlet(initial_condition_colliding_flow_astro), - y_neg=boundary_condition_periodic, - y_pos=boundary_condition_periodic, - ) - - +boundary_conditions = (x_neg = BoundaryConditionDirichlet(initial_condition_colliding_flow_astro), + x_pos = BoundaryConditionDirichlet(initial_condition_colliding_flow_astro), + y_neg = boundary_condition_periodic, + y_pos = boundary_condition_periodic) surface_flux = flux_lax_friedrichs # HLLC needs more shock capturing (alpha_max) -volume_flux = flux_ranocha # works with Chandrashekar flux as well +volume_flux = flux_ranocha # works with Chandrashekar flux as well polydeg = 3 basis = LobattoLegendreBasis(polydeg) # shock capturing necessary for this tough example, however alpha_max = 0.5 is fine indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.0001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.5, + alpha_min = 0.0001, + alpha_smooth = true, + variable = density_pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-64.0, -64.0) -coordinates_max = ( 64.0, 64.0) +coordinates_max = (64.0, 64.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - periodicity=(false,true), - n_cells_max=100_000) -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions=boundary_conditions) + initial_refinement_level = 4, + periodicity = (false, true), + n_cells_max = 100_000) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -76,44 +73,44 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) # Simulation also feasible without AMR: AMR reduces CPU time by a factor of about 2 amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=1.0, - alpha_min=0.0001, - alpha_smooth=false, - variable=Trixi.density) + alpha_max = 1.0, + alpha_min = 0.0001, + alpha_smooth = false, + variable = Trixi.density) amr_controller = ControllerThreeLevelCombined(semi, amr_indicator, indicator_sc, - base_level=2, - med_level =0, med_threshold=0.0003, # med_level = current level - max_level =8, max_threshold=0.003, - max_threshold_secondary=indicator_sc.alpha_max) + base_level = 2, + med_level = 0, med_threshold = 0.0003, # med_level = current level + max_level = 8, max_threshold = 0.003, + max_threshold_secondary = indicator_sc.alpha_max) amr_callback = AMRCallback(semi, amr_controller, - interval=1, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 1, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) callbacks = CallbackSet(summary_callback, - analysis_callback, alive_callback, + analysis_callback, alive_callback, amr_callback, save_solution) # positivity limiter necessary for this tough example -stage_limiter! = PositivityPreservingLimiterZhangShu(thresholds=(5.0e-6, 5.0e-6), - variables=(Trixi.density, pressure)) +stage_limiter! = PositivityPreservingLimiterZhangShu(thresholds = (5.0e-6, 5.0e-6), + variables = (Trixi.density, pressure)) ############################################################################### # run the simulation # use adaptive time stepping based on error estimates, time step roughly dt = 5e-3 sol = solve(ode, SSPRK43(stage_limiter!); - ode_default_options()..., callback=callbacks); + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_euler_convergence_pure_fv.jl b/examples/tree_2d_dgsem/elixir_euler_convergence_pure_fv.jl index 89d7422cfe6..96184b5ba47 100644 --- a/examples/tree_2d_dgsem/elixir_euler_convergence_pure_fv.jl +++ b/examples/tree_2d_dgsem/elixir_euler_convergence_pure_fv.jl @@ -18,13 +18,11 @@ solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (0.0, 0.0) coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -35,16 +33,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -54,7 +52,7 @@ callbacks = CallbackSet(summary_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); +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/tree_2d_dgsem/elixir_euler_density_wave.jl b/examples/tree_2d_dgsem/elixir_euler_density_wave.jl index a5e9d30e389..0f9e232fa14 100644 --- a/examples/tree_2d_dgsem/elixir_euler_density_wave.jl +++ b/examples/tree_2d_dgsem/elixir_euler_density_wave.jl @@ -9,18 +9,16 @@ equations = CompressibleEulerEquations2D(gamma) initial_condition = initial_condition_density_wave -solver = DGSEM(polydeg=5, surface_flux=flux_central) +solver = DGSEM(polydeg = 5, surface_flux = flux_central) coordinates_min = (-1.0, -1.0) -coordinates_max = ( 1.0, 1.0) +coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=30_000) - + initial_refinement_level = 2, + n_cells_max = 30_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -30,27 +28,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_euler_ec.jl b/examples/tree_2d_dgsem/elixir_euler_ec.jl index 88f65c3d689..e634a383cdf 100644 --- a/examples/tree_2d_dgsem/elixir_euler_ec.jl +++ b/examples/tree_2d_dgsem/elixir_euler_ec.jl @@ -9,20 +9,18 @@ equations = CompressibleEulerEquations2D(1.4) initial_condition = initial_condition_weak_blast_wave volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_ranocha, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_ranocha, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=5, - n_cells_max=10_000, - periodicity=true) - + initial_refinement_level = 5, + n_cells_max = 10_000, + periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_condition_periodic) - + boundary_conditions = boundary_condition_periodic) ############################################################################### # ODE solvers, callbacks etc. @@ -33,27 +31,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability.jl b/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability.jl index 4fdedf516ef..5e6b1e0cc0d 100644 --- a/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability.jl +++ b/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability.jl @@ -16,40 +16,41 @@ A version of the classical Kelvin-Helmholtz instability based on of the Euler Equations [arXiv: 2102.06017](https://arxiv.org/abs/2102.06017) """ -function initial_condition_kelvin_helmholtz_instability(x, t, equations::CompressibleEulerEquations2D) - # change discontinuity to tanh - # typical resolution 128^2, 256^2 - # domain size is [-1,+1]^2 - slope = 15 - amplitude = 0.02 - B = tanh(slope * x[2] + 7.5) - tanh(slope * x[2] - 7.5) - rho = 0.5 + 0.75 * B - v1 = 0.5 * (B - 1) - v2 = 0.1 * sin(2 * pi * x[1]) - p = 1.0 - return prim2cons(SVector(rho, v1, v2, p), equations) +function initial_condition_kelvin_helmholtz_instability(x, t, + equations::CompressibleEulerEquations2D) + # change discontinuity to tanh + # typical resolution 128^2, 256^2 + # domain size is [-1,+1]^2 + slope = 15 + amplitude = 0.02 + B = tanh(slope * x[2] + 7.5) - tanh(slope * x[2] - 7.5) + rho = 0.5 + 0.75 * B + v1 = 0.5 * (B - 1) + v2 = 0.1 * sin(2 * pi * x[1]) + p = 1.0 + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_kelvin_helmholtz_instability surface_flux = flux_lax_friedrichs -volume_flux = flux_ranocha +volume_flux = flux_ranocha polydeg = 3 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.002, - alpha_min=0.0001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.002, + alpha_min = 0.0001, + alpha_smooth = true, + variable = density_pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-1.0, -1.0) -coordinates_max = ( 1.0, 1.0) +coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=5, - n_cells_max=100_000) + initial_refinement_level = 5, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) ############################################################################### @@ -61,27 +62,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=20, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 20, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.3) +stepsize_callback = StepsizeCallback(cfl = 1.3) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_amr.jl b/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_amr.jl index b8927c3fd6b..5c237835cc5 100644 --- a/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_amr.jl +++ b/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_amr.jl @@ -16,45 +16,44 @@ A version of the classical Kelvin-Helmholtz instability based on of the Euler Equations [arXiv: 2102.06017](https://arxiv.org/abs/2102.06017) """ -function initial_condition_kelvin_helmholtz_instability(x, t, equations::CompressibleEulerEquations2D) - # change discontinuity to tanh - # typical resolution 128^2, 256^2 - # domain size is [-1,+1]^2 - slope = 15 - amplitude = 0.02 - B = tanh(slope * x[2] + 7.5) - tanh(slope * x[2] - 7.5) - rho = 0.5 + 0.75 * B - v1 = 0.5 * (B - 1) - v2 = 0.1 * sin(2 * pi * x[1]) - p = 1.0 - return prim2cons(SVector(rho, v1, v2, p), equations) +function initial_condition_kelvin_helmholtz_instability(x, t, + equations::CompressibleEulerEquations2D) + # change discontinuity to tanh + # typical resolution 128^2, 256^2 + # domain size is [-1,+1]^2 + slope = 15 + amplitude = 0.02 + B = tanh(slope * x[2] + 7.5) - tanh(slope * x[2] - 7.5) + rho = 0.5 + 0.75 * B + v1 = 0.5 * (B - 1) + v2 = 0.1 * sin(2 * pi * x[1]) + p = 1.0 + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_kelvin_helmholtz_instability surface_flux = flux_lax_friedrichs -volume_flux = flux_ranocha +volume_flux = flux_ranocha polydeg = 3 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.002, - alpha_min=0.0001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.002, + alpha_min = 0.0001, + alpha_smooth = true, + variable = density_pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-1.0, -1.0) -coordinates_max = ( 1.0, 1.0) +coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=5, - n_cells_max=100_000) - + initial_refinement_level = 5, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -64,41 +63,40 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=1.0, - alpha_min=0.0001, - alpha_smooth=false, - variable=Trixi.density) + alpha_max = 1.0, + alpha_min = 0.0001, + alpha_smooth = false, + variable = Trixi.density) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=4, - med_level=0, med_threshold=0.0003, # med_level = current level - max_level=6, max_threshold=0.003) + base_level = 4, + med_level = 0, med_threshold = 0.0003, # med_level = current level + max_level = 6, max_threshold = 0.003) amr_callback = AMRCallback(semi, amr_controller, - interval=1, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 1, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.3) +stepsize_callback = StepsizeCallback(cfl = 1.3) 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); +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/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_amr_neuralnetwork_perssonperaire.jl b/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_amr_neuralnetwork_perssonperaire.jl index 952fa372696..d2cab04223e 100644 --- a/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_amr_neuralnetwork_perssonperaire.jl +++ b/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_amr_neuralnetwork_perssonperaire.jl @@ -2,7 +2,8 @@ using Downloads: download using Flux using BSON: load network = joinpath(@__DIR__, "modelnnpp-0.904-0.0005.bson") -download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelnnpp-0.904-0.0005.bson", network) +download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelnnpp-0.904-0.0005.bson", + network) model2d = load(network, @__MODULE__)[:model2d] using Random: seed! @@ -28,55 +29,59 @@ equations = CompressibleEulerEquations2D(gamma) A version of the classical Kelvin-Helmholtz instability based on https://rsaa.anu.edu.au/research/established-projects/fyris/2-d-kelvin-helmholtz-test. """ -function initial_condition_kelvin_helmholtz_instability(x, t, equations::CompressibleEulerEquations2D) - # change discontinuity to tanh - # typical resolution 128^2, 256^2 - # domain size is [-0.5,0.5]^2 - dens0 = 1.0 # outside density - dens1 = 2.0 # inside density - velx0 = -0.5 # outside velocity - velx1 = 0.5 # inside velocity - slope = 50 # used for tanh instead of discontinuous initial condition - # pressure equilibrium - p = 2.5 - # y velocity v2 is only white noise - v2 = 0.01*(rand(Float64,1)[1]-0.5) - # density - rho = dens0 + (dens1-dens0) * 0.5*(1+(tanh(slope*(x[2]+0.25)) - (tanh(slope*(x[2]-0.25)) + 1))) - # x velocity is also augmented with noise - v1 = velx0 + (velx1-velx0) * 0.5*(1+(tanh(slope*(x[2]+0.25)) - (tanh(slope*(x[2]-0.25)) + 1)))+0.01*(rand(Float64,1)[1]-0.5) - return prim2cons(SVector(rho, v1, v2, p), equations) +function initial_condition_kelvin_helmholtz_instability(x, t, + equations::CompressibleEulerEquations2D) + # change discontinuity to tanh + # typical resolution 128^2, 256^2 + # domain size is [-0.5,0.5]^2 + dens0 = 1.0 # outside density + dens1 = 2.0 # inside density + velx0 = -0.5 # outside velocity + velx1 = 0.5 # inside velocity + slope = 50 # used for tanh instead of discontinuous initial condition + # pressure equilibrium + p = 2.5 + # y velocity v2 is only white noise + v2 = 0.01 * (rand(Float64, 1)[1] - 0.5) + # density + rho = dens0 + + (dens1 - dens0) * 0.5 * + (1 + (tanh(slope * (x[2] + 0.25)) - (tanh(slope * (x[2] - 0.25)) + 1))) + # x velocity is also augmented with noise + v1 = velx0 + + (velx1 - velx0) * 0.5 * + (1 + (tanh(slope * (x[2] + 0.25)) - (tanh(slope * (x[2] - 0.25)) + 1))) + + 0.01 * (rand(Float64, 1)[1] - 0.5) + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_kelvin_helmholtz_instability surface_flux = flux_lax_friedrichs -volume_flux = flux_chandrashekar +volume_flux = flux_chandrashekar polydeg = 3 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorNeuralNetwork(equations, basis, - indicator_type=NeuralNetworkPerssonPeraire(), - alpha_max=0.002, - alpha_min=0.0001, - alpha_smooth=true, - alpha_continuous=true, - alpha_amr=false, - variable=density_pressure, - network=model2d) + indicator_type = NeuralNetworkPerssonPeraire(), + alpha_max = 0.002, + alpha_min = 0.0001, + alpha_smooth = true, + alpha_continuous = true, + alpha_amr = false, + variable = density_pressure, + network = model2d) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-0.5, -0.5) -coordinates_max = ( 0.5, 0.5) +coordinates_max = (0.5, 0.5) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=5, - n_cells_max=100_000) - + initial_refinement_level = 5, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -86,45 +91,44 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorNeuralNetwork(semi, - indicator_type=NeuralNetworkPerssonPeraire(), - alpha_max=1.0, - alpha_min=0.0001, - alpha_smooth=false, - alpha_continuous=true, - alpha_amr=true, - variable=density_pressure, - network=model2d) + indicator_type = NeuralNetworkPerssonPeraire(), + alpha_max = 1.0, + alpha_min = 0.0001, + alpha_smooth = false, + alpha_continuous = true, + alpha_amr = true, + variable = density_pressure, + network = model2d) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=4, - med_level=6, med_threshold=0.3, # med_level = current level - max_level=7, max_threshold=0.5) + base_level = 4, + med_level = 6, med_threshold = 0.3, # med_level = current level + max_level = 7, max_threshold = 0.5) amr_callback = AMRCallback(semi, amr_controller, - interval=1, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 1, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.3) +stepsize_callback = StepsizeCallback(cfl = 1.3) 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); +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/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_fjordholm_etal.jl b/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_fjordholm_etal.jl index 8e7484a96d4..5b2b80d84f3 100644 --- a/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_fjordholm_etal.jl +++ b/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_fjordholm_etal.jl @@ -1,7 +1,6 @@ using OrdinaryDiffEq using Trixi - ############################################################################### # semidiscretization of the compressible Euler equations gamma = 1.4 @@ -16,83 +15,86 @@ A version of the classical Kelvin-Helmholtz instability based on solutions for hyperbolic systems of conservation laws [arXiv: 1402.0909](https://arxiv.org/abs/1402.0909) """ -function initial_condition_kelvin_helmholtz_instability_fjordholm_etal(x, t, equations::CompressibleEulerEquations2D) - # typical resolution 128^2, 256^2 - # domain size is [0,+1]^2 - # interface is sharp, but randomly perturbed - # The random numbers used in the initial conditions have been generated as follows: - # - # using StableRNGs - # - # rng = StableRNG(100) - # - # a1 = rand(rng, m) - # a2 = rand(rng, m) - # a1 .= a1 / sum(a1) - # a2 .= a2 / sum(a2) - # b1 = (rand(rng, m) .- 0.5) .* pi - # b2 = (rand(rng, m) .- 0.5) .* pi - - m = 10 - a1 = [0.04457096674422902, 0.03891512410182607, 0.0030191053979293433, 0.0993913172320319, +function initial_condition_kelvin_helmholtz_instability_fjordholm_etal(x, t, + equations::CompressibleEulerEquations2D) + # typical resolution 128^2, 256^2 + # domain size is [0,+1]^2 + # interface is sharp, but randomly perturbed + # The random numbers used in the initial conditions have been generated as follows: + # + # using StableRNGs + # + # rng = StableRNG(100) + # + # a1 = rand(rng, m) + # a2 = rand(rng, m) + # a1 .= a1 / sum(a1) + # a2 .= a2 / sum(a2) + # b1 = (rand(rng, m) .- 0.5) .* pi + # b2 = (rand(rng, m) .- 0.5) .* pi + + m = 10 + a1 = [0.04457096674422902, 0.03891512410182607, 0.0030191053979293433, + 0.0993913172320319, 0.1622302137588842, 0.1831383653456182, 0.11758003014101702, 0.07964318348142958, 0.0863245324711805, 0.18518716132585408] - a2 = [0.061688440856337096, 0.23000237877135882, 0.04453793881833177, 0.19251530387370916, + a2 = [0.061688440856337096, 0.23000237877135882, 0.04453793881833177, + 0.19251530387370916, 0.11107917357941084, 0.05898041974649702, 0.09949312336096268, 0.07022276346006465, 0.10670366489014596, 0.02477679264318211] - b1 = [0.06582340543754152, 0.9857886297001535, 0.8450452205037154, -1.279648120993805, + b1 = [0.06582340543754152, 0.9857886297001535, 0.8450452205037154, -1.279648120993805, 0.45454198915209526, -0.13359370986823993, 0.07062615913363897, -1.0097986278512623, 1.0810669017430343, -0.14207309803877177] - b2 = [-1.1376882185131414, -1.4798197129947765, 0.6139290513283818, -0.3319087388365522, + b2 = [-1.1376882185131414, -1.4798197129947765, 0.6139290513283818, -0.3319087388365522, 0.14633328999192285, -0.06373231463100072, -0.6270101051216724, 0.13941252226261905, -1.0337526453303645, 1.0441408867083155] - Y1 = 0.0 - Y2 = 0.0 - for n = 1:m - Y1 += a1[n] * cos(b1[n] + 2 * n * pi * x[1]) - Y2 += a2[n] * cos(b2[n] + 2 * n * pi * x[1]) - end - - J1 = 0.25 - J2 = 0.75 - epsilon = 0.01 - I1 = J1 + epsilon * Y1 - I2 = J2 + epsilon * Y2 - - if (x[2] > I1) && (x[2] < I2) - rho = 2 - v1 = -0.5 - else - rho = 1 - v1 = 0.5 - end - v2 = 0 - p = 2.5 - - return prim2cons(SVector(rho, v1, v2, p), equations) + Y1 = 0.0 + Y2 = 0.0 + for n in 1:m + Y1 += a1[n] * cos(b1[n] + 2 * n * pi * x[1]) + Y2 += a2[n] * cos(b2[n] + 2 * n * pi * x[1]) + end + + J1 = 0.25 + J2 = 0.75 + epsilon = 0.01 + I1 = J1 + epsilon * Y1 + I2 = J2 + epsilon * Y2 + + if (x[2] > I1) && (x[2] < I2) + rho = 2 + v1 = -0.5 + else + rho = 1 + v1 = 0.5 + end + v2 = 0 + p = 2.5 + + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_kelvin_helmholtz_instability_fjordholm_etal surface_flux = flux_hllc -volume_flux = flux_ranocha +volume_flux = flux_ranocha polydeg = 3 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.001, - alpha_min=0.0001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.001, + alpha_min = 0.0001, + alpha_smooth = true, + variable = density_pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (0.0, 0.0) coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - n_cells_max=100_000) + initial_refinement_level = 6, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -105,14 +107,14 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 400 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=400, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 400, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -121,5 +123,5 @@ callbacks = CallbackSet(summary_callback, ############################################################################### # run the simulation sol = solve(ode, SSPRK43(); - ode_default_options()..., callback=callbacks); + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_euler_positivity.jl b/examples/tree_2d_dgsem/elixir_euler_positivity.jl index 4c7dd7eb6cf..6fec4c1bf9b 100644 --- a/examples/tree_2d_dgsem/elixir_euler_positivity.jl +++ b/examples/tree_2d_dgsem/elixir_euler_positivity.jl @@ -14,53 +14,51 @@ The Sedov blast wave setup based on Flash - https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_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) - - # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 - r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) - # r0 = 0.5 # = more reasonable setup - E = 1.0 - p0_inner = 3 * (equations.gamma - 1) * E / (3 * pi * r0^2) - p0_outer = 1.0e-5 # = true Sedov setup - # p0_outer = 1.0e-3 # = more reasonable setup - - # Calculate primitive variables - rho = 1.0 - v1 = 0.0 - v2 = 0.0 - p = r > r0 ? p0_outer : p0_inner - - return prim2cons(SVector(rho, v1, v2, p), equations) + # 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) + + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 + r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) + # r0 = 0.5 # = more reasonable setup + E = 1.0 + p0_inner = 3 * (equations.gamma - 1) * E / (3 * pi * r0^2) + p0_outer = 1.0e-5 # = true Sedov setup + # p0_outer = 1.0e-3 # = more reasonable setup + + # Calculate primitive variables + rho = 1.0 + 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_sedov_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_ranocha +volume_flux = flux_ranocha basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - n_cells_max=100_000) - + initial_refinement_level = 6, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -70,42 +68,40 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 500 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorLöhner(semi, - variable=density_pressure) + variable = density_pressure) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=4, - med_level =0, med_threshold=0.1, # med_level = current level - max_level =6, max_threshold=0.3) + base_level = 4, + med_level = 0, med_threshold = 0.1, # med_level = current level + max_level = 6, max_threshold = 0.3) amr_callback = AMRCallback(semi, amr_controller, - interval=2, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 2, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, amr_callback, stepsize_callback) - -stage_limiter! = PositivityPreservingLimiterZhangShu(thresholds=(5.0e-6, 5.0e-6), - variables=(Trixi.density, pressure)) - +stage_limiter! = PositivityPreservingLimiterZhangShu(thresholds = (5.0e-6, 5.0e-6), + variables = (Trixi.density, pressure)) ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(stage_limiter!, 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); +sol = solve(ode, CarpenterKennedy2N54(stage_limiter!, 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/tree_2d_dgsem/elixir_euler_sedov_blast_wave.jl b/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave.jl index 512e5822374..5b8959b97d1 100644 --- a/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave.jl +++ b/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave.jl @@ -14,53 +14,51 @@ The Sedov blast wave setup based on Flash - https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_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) - - # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 - r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) - # r0 = 0.5 # = more reasonable setup - E = 1.0 - p0_inner = 3 * (equations.gamma - 1) * E / (3 * pi * r0^2) - p0_outer = 1.0e-5 # = true Sedov setup - # p0_outer = 1.0e-3 # = more reasonable setup - - # Calculate primitive variables - rho = 1.0 - v1 = 0.0 - v2 = 0.0 - p = r > r0 ? p0_outer : p0_inner - - return prim2cons(SVector(rho, v1, v2, p), equations) + # 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) + + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 + r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) + # r0 = 0.5 # = more reasonable setup + E = 1.0 + p0_inner = 3 * (equations.gamma - 1) * E / (3 * pi * r0^2) + p0_outer = 1.0e-5 # = true Sedov setup + # p0_outer = 1.0e-3 # = more reasonable setup + + # Calculate primitive variables + rho = 1.0 + 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_sedov_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_chandrashekar +volume_flux = flux_chandrashekar basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - n_cells_max=100_000) - + initial_refinement_level = 6, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -70,29 +68,29 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = density_pressure) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=4, - max_level =6, max_threshold=0.01) + base_level = 4, + max_level = 6, max_threshold = 0.01) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -101,7 +99,7 @@ callbacks = CallbackSet(summary_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); +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/tree_2d_dgsem/elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl b/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl index 5fd32da2e5c..39ea947f872 100644 --- a/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl +++ b/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl @@ -2,7 +2,8 @@ using Downloads: download using Flux using BSON: load network = joinpath(@__DIR__, "modelnnpp-0.904-0.0005.bson") -download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelnnpp-0.904-0.0005.bson", network) +download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelnnpp-0.904-0.0005.bson", + network) model2d = load(network, @__MODULE__)[:model2d] using OrdinaryDiffEq @@ -26,57 +27,55 @@ The Sedov blast wave setup based on Flash - https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_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) - - # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 - r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) - # r0 = 0.5 # = more reasonable setup - E = 1.0 - p0_inner = 3 * (equations.gamma - 1) * E / (3 * pi * r0^2) - p0_outer = 1.0e-5 # = true Sedov setup - # p0_outer = 1.0e-3 # = more reasonable setup - - # Calculate primitive variables - rho = 1.0 - v1 = 0.0 - v2 = 0.0 - p = r > r0 ? p0_outer : p0_inner - - return prim2cons(SVector(rho, v1, v2, p), equations) + # 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) + + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 + r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) + # r0 = 0.5 # = more reasonable setup + E = 1.0 + p0_inner = 3 * (equations.gamma - 1) * E / (3 * pi * r0^2) + p0_outer = 1.0e-5 # = true Sedov setup + # p0_outer = 1.0e-3 # = more reasonable setup + + # Calculate primitive variables + rho = 1.0 + 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_sedov_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_chandrashekar +volume_flux = flux_chandrashekar basis = LobattoLegendreBasis(3) indicator_sc = IndicatorNeuralNetwork(equations, basis, - indicator_type=NeuralNetworkPerssonPeraire(), - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - alpha_continuous=true, - alpha_amr=false, - variable=density_pressure, - network=model2d) + indicator_type = NeuralNetworkPerssonPeraire(), + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + alpha_continuous = true, + alpha_amr = false, + variable = density_pressure, + network = model2d) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - n_cells_max=100_000) - + initial_refinement_level = 6, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -86,33 +85,33 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorNeuralNetwork(semi, - indicator_type=NeuralNetworkPerssonPeraire(), - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - alpha_continuous=true, - alpha_amr=true, - variable=density_pressure, - network=model2d) + indicator_type = NeuralNetworkPerssonPeraire(), + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + alpha_continuous = true, + alpha_amr = true, + variable = density_pressure, + network = model2d) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=4, - max_level =6, max_threshold=0.22) + base_level = 4, + max_level = 6, max_threshold = 0.22) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=0.9) +stepsize_callback = StepsizeCallback(cfl = 0.9) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -121,7 +120,7 @@ callbacks = CallbackSet(summary_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); +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/tree_2d_dgsem/elixir_euler_shockcapturing.jl b/examples/tree_2d_dgsem/elixir_euler_shockcapturing.jl index f0a7ed0b953..40f19cbd4e2 100644 --- a/examples/tree_2d_dgsem/elixir_euler_shockcapturing.jl +++ b/examples/tree_2d_dgsem/elixir_euler_shockcapturing.jl @@ -10,28 +10,26 @@ equations = CompressibleEulerEquations2D(1.4) initial_condition = initial_condition_weak_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_shima_etal +volume_flux = flux_shima_etal basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=5, - n_cells_max=10_000) - + initial_refinement_level = 5, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -41,26 +39,25 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, stepsize_callback, save_solution, analysis_callback, alive_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); +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/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl b/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl index c696e2de416..3fea48b30da 100644 --- a/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl +++ b/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl @@ -16,45 +16,44 @@ A medium blast wave (modified to lower density and higher pressure) taken from [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) """ function initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations2D) - # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> modified to lower density, higher pressure - # 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) - phi = atan(y_norm, x_norm) - sin_phi, cos_phi = sincos(phi) - - # Calculate primitive variables "normal" medium blast wave - rho = r > 0.5 ? 0.1 : 0.2691 # rho = r > 0.5 ? 1 : 1.1691 - v1 = r > 0.5 ? 0.0 : 0.1882 * cos_phi - v2 = r > 0.5 ? 0.0 : 0.1882 * sin_phi - p = r > 0.5 ? 1.0E-1 : 1.245 # p = r > 0.5 ? 1.0E-3 : 1.245 - - return prim2cons(SVector(rho, v1, v2, p), equations) + # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> modified to lower density, higher pressure + # 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) + phi = atan(y_norm, x_norm) + sin_phi, cos_phi = sincos(phi) + + # Calculate primitive variables "normal" medium blast wave + rho = r > 0.5 ? 0.1 : 0.2691 # rho = r > 0.5 ? 1 : 1.1691 + v1 = r > 0.5 ? 0.0 : 0.1882 * cos_phi + v2 = r > 0.5 ? 0.0 : 0.1882 * sin_phi + p = r > 0.5 ? 1.0E-1 : 1.245 # p = r > 0.5 ? 1.0E-3 : 1.245 + + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_blast_wave surface_flux = flux_lax_friedrichs -volume_flux = flux_ranocha +volume_flux = flux_ranocha basis = LobattoLegendreBasis(3) limiter_idp = SubcellLimiterIDP(equations, basis; - positivity_variables_cons=[1], - positivity_correction_factor=0.5) + positivity_variables_cons = [1], + positivity_correction_factor = 0.5) volume_integral = VolumeIntegralSubcellLimiting(limiter_idp; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=5, - n_cells_max=100_000) + initial_refinement_level = 5, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -64,29 +63,28 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.6) +stepsize_callback = StepsizeCallback(cfl = 0.6) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) - ############################################################################### # run the simulation -stage_callbacks = (SubcellLimiterIDPCorrection(), BoundsCheckCallback(save_errors=false)) +stage_callbacks = (SubcellLimiterIDPCorrection(), BoundsCheckCallback(save_errors = false)) -sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks=stage_callbacks); - dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks = stage_callbacks); + 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/tree_2d_dgsem/elixir_euler_source_terms.jl b/examples/tree_2d_dgsem/elixir_euler_source_terms.jl index 36d93147289..ec230145537 100644 --- a/examples/tree_2d_dgsem/elixir_euler_source_terms.jl +++ b/examples/tree_2d_dgsem/elixir_euler_source_terms.jl @@ -8,18 +8,16 @@ using Trixi equations = CompressibleEulerEquations2D(1.4) initial_condition = initial_condition_convergence_test -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0, 0.0) coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -30,16 +28,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -49,7 +47,7 @@ callbacks = CallbackSet(summary_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); +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/tree_2d_dgsem/elixir_euler_source_terms_amr_refine_coarsen.jl b/examples/tree_2d_dgsem/elixir_euler_source_terms_amr_refine_coarsen.jl index 231486b11c9..28ab4cec1d3 100644 --- a/examples/tree_2d_dgsem/elixir_euler_source_terms_amr_refine_coarsen.jl +++ b/examples/tree_2d_dgsem/elixir_euler_source_terms_amr_refine_coarsen.jl @@ -10,60 +10,57 @@ module TrixiExtensionEulerAMR using Trixi -struct IndicatorRefineCoarsen{Cache<:NamedTuple} <: Trixi.AbstractIndicator - cache::Cache +struct IndicatorRefineCoarsen{Cache <: NamedTuple} <: Trixi.AbstractIndicator + cache::Cache end function IndicatorRefineCoarsen(semi) - basis = semi.solver.basis - alpha = Vector{real(basis)}() - cache = (; semi.mesh, alpha) + basis = semi.solver.basis + alpha = Vector{real(basis)}() + cache = (; semi.mesh, alpha) - return IndicatorRefineCoarsen{typeof(cache)}(cache) + return IndicatorRefineCoarsen{typeof(cache)}(cache) end -function (indicator::IndicatorRefineCoarsen)(u::AbstractArray{<:Any,4}, +function (indicator::IndicatorRefineCoarsen)(u::AbstractArray{<:Any, 4}, mesh, equations, dg, cache; t, kwargs...) - alpha = indicator.cache.alpha - resize!(alpha, nelements(dg, cache)) - - if t >= 0.7 && t < 1.0 - # Refine to max level - alpha .= 1.0 - elseif t >= 1.0 - # Coarsen to base level - alpha .= -1.0 - else - alpha .= 0.0 - end - - return alpha + alpha = indicator.cache.alpha + resize!(alpha, nelements(dg, cache)) + + if t >= 0.7 && t < 1.0 + # Refine to max level + alpha .= 1.0 + elseif t >= 1.0 + # Coarsen to base level + alpha .= -1.0 + else + alpha .= 0.0 + end + + return alpha end end # module TrixiExtensionEulerAMR import .TrixiExtensionEulerAMR - ############################################################################### # semidiscretization of the compressible Euler equations equations = CompressibleEulerEquations2D(1.4) initial_condition = initial_condition_convergence_test -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0, 0.0) coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=10_000) - + initial_refinement_level = 3, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -74,25 +71,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -amr_controller = ControllerThreeLevel(semi, TrixiExtensionEulerAMR.IndicatorRefineCoarsen(semi), - base_level=3, max_level=6, - med_threshold=0.1, max_threshold=0.6) +amr_controller = ControllerThreeLevel(semi, + TrixiExtensionEulerAMR.IndicatorRefineCoarsen(semi), + base_level = 3, max_level = 6, + med_threshold = 0.1, max_threshold = 0.6) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -102,7 +100,7 @@ callbacks = CallbackSet(summary_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); +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/tree_2d_dgsem/elixir_euler_source_terms_nonperiodic.jl b/examples/tree_2d_dgsem/elixir_euler_source_terms_nonperiodic.jl index 9826a53d3d5..05ed7ba78cc 100644 --- a/examples/tree_2d_dgsem/elixir_euler_source_terms_nonperiodic.jl +++ b/examples/tree_2d_dgsem/elixir_euler_source_terms_nonperiodic.jl @@ -12,26 +12,23 @@ initial_condition = initial_condition_convergence_test # you can either use a single function to impose the BCs weakly in all # 2*ndims == 4 directions or you can pass a tuple containing BCs for each direction boundary_condition = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = (x_neg=boundary_condition, - x_pos=boundary_condition, - y_neg=boundary_condition, - y_pos=boundary_condition,) - -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +boundary_conditions = (x_neg = boundary_condition, + x_pos = boundary_condition, + y_neg = boundary_condition, + y_pos = boundary_condition) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0, 0.0) coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000, - periodicity=false) - + initial_refinement_level = 4, + n_cells_max = 10_000, + periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test, - boundary_conditions=boundary_conditions) - + source_terms = source_terms_convergence_test, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -42,19 +39,19 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -63,7 +60,7 @@ callbacks = CallbackSet(summary_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); +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/tree_2d_dgsem/elixir_euler_vortex.jl b/examples/tree_2d_dgsem/elixir_euler_vortex.jl index 14e46ce7540..c87d6f49ba8 100644 --- a/examples/tree_2d_dgsem/elixir_euler_vortex.jl +++ b/examples/tree_2d_dgsem/elixir_euler_vortex.jl @@ -17,46 +17,45 @@ The classical isentropic vortex test case of [NASA/CR-97-206253](https://ntrs.nasa.gov/citations/19980007543) """ function initial_condition_isentropic_vortex(x, t, equations::CompressibleEulerEquations2D) - # needs appropriate mesh size, e.g. [-10,-10]x[10,10] - # for error convergence: make sure that the end time is such that the vortex is back at the initial state!! - # for the current velocity and domain size: t_end should be a multiple of 20s - # initial center of the vortex - inicenter = SVector(0.0, 0.0) - # size and strength of the vortex - iniamplitude = 5.0 - # base flow - rho = 1.0 - v1 = 1.0 - v2 = 1.0 - vel = SVector(v1, v2) - p = 25.0 - rt = p / rho # ideal gas equation - t_loc = 0.0 - cent = inicenter + vel*t_loc # advection of center - # ATTENTION: handle periodic BC, but only for v1 = v2 = 1.0 (!!!!) - cent = x - cent # distance to center point - # cent = cross(iniaxis, cent) # distance to axis, tangent vector, length r - # cross product with iniaxis = [0, 0, 1] - cent = SVector(-cent[2], cent[1]) - r2 = cent[1]^2 + cent[2]^2 - du = iniamplitude / (2*π) * exp(0.5 * (1 - r2)) # vel. perturbation - dtemp = -(equations.gamma - 1) / (2 * equations.gamma * rt) * du^2 # isentropic - rho = rho * (1 + dtemp)^(1 / (equations.gamma - 1)) - vel = vel + du * cent - v1, v2 = vel - p = p * (1 + dtemp)^(equations.gamma / (equations.gamma - 1)) - prim = SVector(rho, v1, v2, p) - return prim2cons(prim, equations) + # needs appropriate mesh size, e.g. [-10,-10]x[10,10] + # for error convergence: make sure that the end time is such that the vortex is back at the initial state!! + # for the current velocity and domain size: t_end should be a multiple of 20s + # initial center of the vortex + inicenter = SVector(0.0, 0.0) + # size and strength of the vortex + iniamplitude = 5.0 + # base flow + rho = 1.0 + v1 = 1.0 + v2 = 1.0 + vel = SVector(v1, v2) + p = 25.0 + rt = p / rho # ideal gas equation + t_loc = 0.0 + cent = inicenter + vel * t_loc # advection of center + # ATTENTION: handle periodic BC, but only for v1 = v2 = 1.0 (!!!!) + cent = x - cent # distance to center point + # cent = cross(iniaxis, cent) # distance to axis, tangent vector, length r + # cross product with iniaxis = [0, 0, 1] + cent = SVector(-cent[2], cent[1]) + r2 = cent[1]^2 + cent[2]^2 + du = iniamplitude / (2 * π) * exp(0.5 * (1 - r2)) # vel. perturbation + dtemp = -(equations.gamma - 1) / (2 * equations.gamma * rt) * du^2 # isentropic + rho = rho * (1 + dtemp)^(1 / (equations.gamma - 1)) + vel = vel + du * cent + v1, v2 = vel + p = p * (1 + dtemp)^(equations.gamma / (equations.gamma - 1)) + prim = SVector(rho, v1, v2, p) + return prim2cons(prim, equations) end initial_condition = initial_condition_isentropic_vortex -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-10.0, -10.0) -coordinates_max = ( 10.0, 10.0) +coordinates_max = (10.0, 10.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -69,30 +68,31 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=true, - extra_analysis_errors=(:conservation_error,), - extra_analysis_integrals=(entropy, energy_total, - energy_kinetic, energy_internal)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_errors = (:conservation_error,), + extra_analysis_integrals = (entropy, energy_total, + energy_kinetic, + energy_internal)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.1) +stepsize_callback = StepsizeCallback(cfl = 1.1) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_euler_vortex_amr.jl b/examples/tree_2d_dgsem/elixir_euler_vortex_amr.jl index 6f6eb25efa4..e9831c95526 100644 --- a/examples/tree_2d_dgsem/elixir_euler_vortex_amr.jl +++ b/examples/tree_2d_dgsem/elixir_euler_vortex_amr.jl @@ -7,55 +7,54 @@ module TrixiExtension using Trixi -struct IndicatorVortex{Cache<:NamedTuple} <: Trixi.AbstractIndicator - cache::Cache +struct IndicatorVortex{Cache <: NamedTuple} <: Trixi.AbstractIndicator + cache::Cache end function IndicatorVortex(semi) - basis = semi.solver.basis - alpha = Vector{real(basis)}() - A = Array{real(basis), 2} - indicator_threaded = [A(undef, nnodes(basis), nnodes(basis)) - for _ in 1:Threads.nthreads()] - cache = (; semi.mesh, alpha, indicator_threaded) - - return IndicatorVortex{typeof(cache)}(cache) + basis = semi.solver.basis + alpha = Vector{real(basis)}() + A = Array{real(basis), 2} + indicator_threaded = [A(undef, nnodes(basis), nnodes(basis)) + for _ in 1:Threads.nthreads()] + cache = (; semi.mesh, alpha, indicator_threaded) + + return IndicatorVortex{typeof(cache)}(cache) end -function (indicator_vortex::IndicatorVortex)(u::AbstractArray{<:Any,4}, +function (indicator_vortex::IndicatorVortex)(u::AbstractArray{<:Any, 4}, mesh, equations, dg, cache; t, kwargs...) - mesh = indicator_vortex.cache.mesh - alpha = indicator_vortex.cache.alpha - indicator_threaded = indicator_vortex.cache.indicator_threaded - resize!(alpha, nelements(dg, cache)) - - - # get analytical vortex center (based on assumption that center=[0.0,0.0] - # at t=0.0 and that we stop after one period) - domain_length = mesh.tree.length_level_0 - if t < 0.5 * domain_length - center = (t, t) - else - center = (t-domain_length, t-domain_length) - end - - Threads.@threads for element in eachelement(dg, cache) - cell_id = cache.elements.cell_ids[element] - coordinates = (mesh.tree.coordinates[1, cell_id], mesh.tree.coordinates[2, cell_id]) - # use the negative radius as indicator since the AMR controller increases - # the level with increasing value of the indicator and we want to use - # high levels near the vortex center - alpha[element] = -periodic_distance_2d(coordinates, center, domain_length) - end - - return alpha + mesh = indicator_vortex.cache.mesh + alpha = indicator_vortex.cache.alpha + indicator_threaded = indicator_vortex.cache.indicator_threaded + resize!(alpha, nelements(dg, cache)) + + # get analytical vortex center (based on assumption that center=[0.0,0.0] + # at t=0.0 and that we stop after one period) + domain_length = mesh.tree.length_level_0 + if t < 0.5 * domain_length + center = (t, t) + else + center = (t - domain_length, t - domain_length) + end + + Threads.@threads for element in eachelement(dg, cache) + cell_id = cache.elements.cell_ids[element] + coordinates = (mesh.tree.coordinates[1, cell_id], mesh.tree.coordinates[2, cell_id]) + # use the negative radius as indicator since the AMR controller increases + # the level with increasing value of the indicator and we want to use + # high levels near the vortex center + alpha[element] = -periodic_distance_2d(coordinates, center, domain_length) + end + + return alpha end function periodic_distance_2d(coordinates, center, domain_length) - dx = @. abs(coordinates - center) - dx_periodic = @. min(dx, domain_length - dx) - return sqrt(sum(abs2, dx_periodic)) + dx = @. abs(coordinates - center) + dx_periodic = @. min(dx, domain_length - dx) + return sqrt(sum(abs2, dx_periodic)) end end # module TrixiExtension @@ -77,48 +76,47 @@ The classical isentropic vortex test case of [NASA/CR-97-206253](https://ntrs.nasa.gov/citations/19980007543) """ function initial_condition_isentropic_vortex(x, t, equations::CompressibleEulerEquations2D) - # needs appropriate mesh size, e.g. [-10,-10]x[10,10] - # for error convergence: make sure that the end time is such that the vortex is back at the initial state!! - # for the current velocity and domain size: t_end should be a multiple of 20s - # initial center of the vortex - inicenter = SVector(0.0, 0.0) - # size and strength of the vortex - iniamplitude = 5.0 - # base flow - rho = 1.0 - v1 = 1.0 - v2 = 1.0 - vel = SVector(v1, v2) - p = 25.0 - rt = p / rho # ideal gas equation - t_loc = 0.0 - cent = inicenter + vel*t_loc # advection of center - # ATTENTION: handle periodic BC, but only for v1 = v2 = 1.0 (!!!!) - - cent = x - cent # distance to center point - - # cent = cross(iniaxis, cent) # distance to axis, tangent vector, length r - # cross product with iniaxis = [0, 0, 1] - cent = SVector(-cent[2], cent[1]) - r2 = cent[1]^2 + cent[2]^2 - du = iniamplitude / (2*π) * exp(0.5 * (1 - r2)) # vel. perturbation - dtemp = -(equations.gamma - 1) / (2 * equations.gamma * rt) * du^2 # isentropic - rho = rho * (1 + dtemp)^(1 / (equations.gamma - 1)) - vel = vel + du * cent - v1, v2 = vel - p = p * (1 + dtemp)^(equations.gamma / (equations.gamma - 1)) - prim = SVector(rho, v1, v2, p) - return prim2cons(prim, equations) + # needs appropriate mesh size, e.g. [-10,-10]x[10,10] + # for error convergence: make sure that the end time is such that the vortex is back at the initial state!! + # for the current velocity and domain size: t_end should be a multiple of 20s + # initial center of the vortex + inicenter = SVector(0.0, 0.0) + # size and strength of the vortex + iniamplitude = 5.0 + # base flow + rho = 1.0 + v1 = 1.0 + v2 = 1.0 + vel = SVector(v1, v2) + p = 25.0 + rt = p / rho # ideal gas equation + t_loc = 0.0 + cent = inicenter + vel * t_loc # advection of center + # ATTENTION: handle periodic BC, but only for v1 = v2 = 1.0 (!!!!) + + cent = x - cent # distance to center point + + # cent = cross(iniaxis, cent) # distance to axis, tangent vector, length r + # cross product with iniaxis = [0, 0, 1] + cent = SVector(-cent[2], cent[1]) + r2 = cent[1]^2 + cent[2]^2 + du = iniamplitude / (2 * π) * exp(0.5 * (1 - r2)) # vel. perturbation + dtemp = -(equations.gamma - 1) / (2 * equations.gamma * rt) * du^2 # isentropic + rho = rho * (1 + dtemp)^(1 / (equations.gamma - 1)) + vel = vel + du * cent + v1, v2 = vel + p = p * (1 + dtemp)^(equations.gamma / (equations.gamma - 1)) + prim = SVector(rho, v1, v2, p) + return prim2cons(prim, equations) end initial_condition = initial_condition_isentropic_vortex -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-10.0, -10.0) -coordinates_max = ( 10.0, 10.0) +coordinates_max = (10.0, 10.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=10_000) - + initial_refinement_level = 3, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -132,39 +130,40 @@ summary_callback = SummaryCallback() analysis_interval = 200 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=true, - extra_analysis_errors=(:conservation_error,), - extra_analysis_integrals=(entropy, energy_total, - energy_kinetic, energy_internal)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_errors = (:conservation_error,), + extra_analysis_integrals = (entropy, energy_total, + energy_kinetic, + energy_internal)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=50, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 50, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_controller = ControllerThreeLevel(semi, TrixiExtension.IndicatorVortex(semi), - base_level=3, - med_level=4, med_threshold=-3.0, - max_level=5, max_threshold=-2.0) + base_level = 3, + med_level = 4, med_threshold = -3.0, + max_level = 5, max_threshold = -2.0) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.1) +stepsize_callback = StepsizeCallback(cfl = 1.1) 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); +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/tree_2d_dgsem/elixir_euler_vortex_mortar.jl b/examples/tree_2d_dgsem/elixir_euler_vortex_mortar.jl index 637133b9b2f..858799d2d3d 100644 --- a/examples/tree_2d_dgsem/elixir_euler_vortex_mortar.jl +++ b/examples/tree_2d_dgsem/elixir_euler_vortex_mortar.jl @@ -17,49 +17,48 @@ The classical isentropic vortex test case of [NASA/CR-97-206253](https://ntrs.nasa.gov/citations/19980007543) """ function initial_condition_isentropic_vortex(x, t, equations::CompressibleEulerEquations2D) - # needs appropriate mesh size, e.g. [-10,-10]x[10,10] - # for error convergence: make sure that the end time is such that the vortex is back at the initial state!! - # for the current velocity and domain size: t_end should be a multiple of 20s - # initial center of the vortex - inicenter = SVector(0.0, 0.0) - # size and strength of the vortex - iniamplitude = 5.0 - # base flow - rho = 1.0 - v1 = 1.0 - v2 = 1.0 - vel = SVector(v1, v2) - p = 25.0 - rt = p / rho # ideal gas equation - t_loc = 0.0 - cent = inicenter + vel*t_loc # advection of center - # ATTENTION: handle periodic BC, but only for v1 = v2 = 1.0 (!!!!) - cent = x - cent # distance to center point - # cent = cross(iniaxis, cent) # distance to axis, tangent vector, length r - # cross product with iniaxis = [0, 0, 1] - cent = SVector(-cent[2], cent[1]) - r2 = cent[1]^2 + cent[2]^2 - du = iniamplitude / (2*π) * exp(0.5 * (1 - r2)) # vel. perturbation - dtemp = -(equations.gamma - 1) / (2 * equations.gamma * rt) * du^2 # isentropic - rho = rho * (1 + dtemp)^(1 / (equations.gamma - 1)) - vel = vel + du * cent - v1, v2 = vel - p = p * (1 + dtemp)^(equations.gamma / (equations.gamma - 1)) - prim = SVector(rho, v1, v2, p) - return prim2cons(prim, equations) + # needs appropriate mesh size, e.g. [-10,-10]x[10,10] + # for error convergence: make sure that the end time is such that the vortex is back at the initial state!! + # for the current velocity and domain size: t_end should be a multiple of 20s + # initial center of the vortex + inicenter = SVector(0.0, 0.0) + # size and strength of the vortex + iniamplitude = 5.0 + # base flow + rho = 1.0 + v1 = 1.0 + v2 = 1.0 + vel = SVector(v1, v2) + p = 25.0 + rt = p / rho # ideal gas equation + t_loc = 0.0 + cent = inicenter + vel * t_loc # advection of center + # ATTENTION: handle periodic BC, but only for v1 = v2 = 1.0 (!!!!) + cent = x - cent # distance to center point + # cent = cross(iniaxis, cent) # distance to axis, tangent vector, length r + # cross product with iniaxis = [0, 0, 1] + cent = SVector(-cent[2], cent[1]) + r2 = cent[1]^2 + cent[2]^2 + du = iniamplitude / (2 * π) * exp(0.5 * (1 - r2)) # vel. perturbation + dtemp = -(equations.gamma - 1) / (2 * equations.gamma * rt) * du^2 # isentropic + rho = rho * (1 + dtemp)^(1 / (equations.gamma - 1)) + vel = vel + du * cent + v1, v2 = vel + p = p * (1 + dtemp)^(equations.gamma / (equations.gamma - 1)) + prim = SVector(rho, v1, v2, p) + return prim2cons(prim, equations) end initial_condition = initial_condition_isentropic_vortex -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-10.0, -10.0) -coordinates_max = ( 10.0, 10.0) -refinement_patches = ( - (type="box", coordinates_min=(0.0, -10.0), coordinates_max=(10.0, 10.0)), -) +coordinates_max = (10.0, 10.0) +refinement_patches = ((type = "box", coordinates_min = (0.0, -10.0), + coordinates_max = (10.0, 10.0)),) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - refinement_patches=refinement_patches, - n_cells_max=10_000,) + initial_refinement_level = 4, + refinement_patches = refinement_patches, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -72,30 +71,31 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=true, - extra_analysis_errors=(:conservation_error,), - extra_analysis_integrals=(entropy, energy_total, - energy_kinetic, energy_internal)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_errors = (:conservation_error,), + extra_analysis_integrals = (entropy, energy_total, + energy_kinetic, + energy_internal)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.4) +stepsize_callback = StepsizeCallback(cfl = 1.4) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_euler_vortex_mortar_shockcapturing.jl b/examples/tree_2d_dgsem/elixir_euler_vortex_mortar_shockcapturing.jl index dc6a326c5d5..026f6d1462c 100644 --- a/examples/tree_2d_dgsem/elixir_euler_vortex_mortar_shockcapturing.jl +++ b/examples/tree_2d_dgsem/elixir_euler_vortex_mortar_shockcapturing.jl @@ -17,36 +17,36 @@ The classical isentropic vortex test case of [NASA/CR-97-206253](https://ntrs.nasa.gov/citations/19980007543) """ function initial_condition_isentropic_vortex(x, t, equations::CompressibleEulerEquations2D) - # needs appropriate mesh size, e.g. [-10,-10]x[10,10] - # for error convergence: make sure that the end time is such that the vortex is back at the initial state!! - # for the current velocity and domain size: t_end should be a multiple of 20s - # initial center of the vortex - inicenter = SVector(0.0, 0.0) - # size and strength of the vortex - iniamplitude = 5.0 - # base flow - rho = 1.0 - v1 = 1.0 - v2 = 1.0 - vel = SVector(v1, v2) - p = 25.0 - rt = p / rho # ideal gas equation - t_loc = 0.0 - cent = inicenter + vel*t_loc # advection of center - # ATTENTION: handle periodic BC, but only for v1 = v2 = 1.0 (!!!!) - cent = x - cent # distance to center point - # cent = cross(iniaxis, cent) # distance to axis, tangent vector, length r - # cross product with iniaxis = [0, 0, 1] - cent = SVector(-cent[2], cent[1]) - r2 = cent[1]^2 + cent[2]^2 - du = iniamplitude / (2*π) * exp(0.5 * (1 - r2)) # vel. perturbation - dtemp = -(equations.gamma - 1) / (2 * equations.gamma * rt) * du^2 # isentropic - rho = rho * (1 + dtemp)^(1 / (equations.gamma - 1)) - vel = vel + du * cent - v1, v2 = vel - p = p * (1 + dtemp)^(equations.gamma / (equations.gamma - 1)) - prim = SVector(rho, v1, v2, p) - return prim2cons(prim, equations) + # needs appropriate mesh size, e.g. [-10,-10]x[10,10] + # for error convergence: make sure that the end time is such that the vortex is back at the initial state!! + # for the current velocity and domain size: t_end should be a multiple of 20s + # initial center of the vortex + inicenter = SVector(0.0, 0.0) + # size and strength of the vortex + iniamplitude = 5.0 + # base flow + rho = 1.0 + v1 = 1.0 + v2 = 1.0 + vel = SVector(v1, v2) + p = 25.0 + rt = p / rho # ideal gas equation + t_loc = 0.0 + cent = inicenter + vel * t_loc # advection of center + # ATTENTION: handle periodic BC, but only for v1 = v2 = 1.0 (!!!!) + cent = x - cent # distance to center point + # cent = cross(iniaxis, cent) # distance to axis, tangent vector, length r + # cross product with iniaxis = [0, 0, 1] + cent = SVector(-cent[2], cent[1]) + r2 = cent[1]^2 + cent[2]^2 + du = iniamplitude / (2 * π) * exp(0.5 * (1 - r2)) # vel. perturbation + dtemp = -(equations.gamma - 1) / (2 * equations.gamma * rt) * du^2 # isentropic + rho = rho * (1 + dtemp)^(1 / (equations.gamma - 1)) + vel = vel + du * cent + v1, v2 = vel + p = p * (1 + dtemp)^(equations.gamma / (equations.gamma - 1)) + prim = SVector(rho, v1, v2, p) + return prim2cons(prim, equations) end initial_condition = initial_condition_isentropic_vortex @@ -56,24 +56,23 @@ volume_flux = flux_shima_etal polydeg = 3 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-10.0, -10.0) -coordinates_max = ( 10.0, 10.0) -refinement_patches = ( - (type="box", coordinates_min=(0.0, -10.0), coordinates_max=(10.0, 10.0)), -) +coordinates_max = (10.0, 10.0) +refinement_patches = ((type = "box", coordinates_min = (0.0, -10.0), + coordinates_max = (10.0, 10.0)),) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - refinement_patches=refinement_patches, - n_cells_max=10_000,) + initial_refinement_level = 4, + refinement_patches = refinement_patches, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -86,30 +85,31 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=true, - extra_analysis_errors=(:conservation_error,), - extra_analysis_integrals=(entropy, energy_total, - energy_kinetic, energy_internal)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_errors = (:conservation_error,), + extra_analysis_integrals = (entropy, energy_total, + energy_kinetic, + energy_internal)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.7) +stepsize_callback = StepsizeCallback(cfl = 0.7) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_euler_vortex_mortar_split.jl b/examples/tree_2d_dgsem/elixir_euler_vortex_mortar_split.jl index 99036c36451..d719e01fd7c 100644 --- a/examples/tree_2d_dgsem/elixir_euler_vortex_mortar_split.jl +++ b/examples/tree_2d_dgsem/elixir_euler_vortex_mortar_split.jl @@ -17,52 +17,51 @@ The classical isentropic vortex test case of [NASA/CR-97-206253](https://ntrs.nasa.gov/citations/19980007543) """ function initial_condition_isentropic_vortex(x, t, equations::CompressibleEulerEquations2D) - # needs appropriate mesh size, e.g. [-10,-10]x[10,10] - # for error convergence: make sure that the end time is such that the vortex is back at the initial state!! - # for the current velocity and domain size: t_end should be a multiple of 20s - # initial center of the vortex - inicenter = SVector(0.0, 0.0) - # size and strength of the vortex - iniamplitude = 5.0 - # base flow - rho = 1.0 - v1 = 1.0 - v2 = 1.0 - vel = SVector(v1, v2) - p = 25.0 - rt = p / rho # ideal gas equation - t_loc = 0.0 - cent = inicenter + vel*t_loc # advection of center - # ATTENTION: handle periodic BC, but only for v1 = v2 = 1.0 (!!!!) - cent = x - cent # distance to center point - # cent = cross(iniaxis, cent) # distance to axis, tangent vector, length r - # cross product with iniaxis = [0, 0, 1] - cent = SVector(-cent[2], cent[1]) - r2 = cent[1]^2 + cent[2]^2 - du = iniamplitude / (2*π) * exp(0.5 * (1 - r2)) # vel. perturbation - dtemp = -(equations.gamma - 1) / (2 * equations.gamma * rt) * du^2 # isentropic - rho = rho * (1 + dtemp)^(1 / (equations.gamma - 1)) - vel = vel + du * cent - v1, v2 = vel - p = p * (1 + dtemp)^(equations.gamma / (equations.gamma - 1)) - prim = SVector(rho, v1, v2, p) - return prim2cons(prim, equations) + # needs appropriate mesh size, e.g. [-10,-10]x[10,10] + # for error convergence: make sure that the end time is such that the vortex is back at the initial state!! + # for the current velocity and domain size: t_end should be a multiple of 20s + # initial center of the vortex + inicenter = SVector(0.0, 0.0) + # size and strength of the vortex + iniamplitude = 5.0 + # base flow + rho = 1.0 + v1 = 1.0 + v2 = 1.0 + vel = SVector(v1, v2) + p = 25.0 + rt = p / rho # ideal gas equation + t_loc = 0.0 + cent = inicenter + vel * t_loc # advection of center + # ATTENTION: handle periodic BC, but only for v1 = v2 = 1.0 (!!!!) + cent = x - cent # distance to center point + # cent = cross(iniaxis, cent) # distance to axis, tangent vector, length r + # cross product with iniaxis = [0, 0, 1] + cent = SVector(-cent[2], cent[1]) + r2 = cent[1]^2 + cent[2]^2 + du = iniamplitude / (2 * π) * exp(0.5 * (1 - r2)) # vel. perturbation + dtemp = -(equations.gamma - 1) / (2 * equations.gamma * rt) * du^2 # isentropic + rho = rho * (1 + dtemp)^(1 / (equations.gamma - 1)) + vel = vel + du * cent + v1, v2 = vel + p = p * (1 + dtemp)^(equations.gamma / (equations.gamma - 1)) + prim = SVector(rho, v1, v2, p) + return prim2cons(prim, equations) end initial_condition = initial_condition_isentropic_vortex volume_flux = flux_shima_etal -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-10.0, -10.0) -coordinates_max = ( 10.0, 10.0) -refinement_patches = ( - (type="box", coordinates_min=(0.0, -10.0), coordinates_max=(10.0, 10.0)), -) +coordinates_max = (10.0, 10.0) +refinement_patches = ((type = "box", coordinates_min = (0.0, -10.0), + coordinates_max = (10.0, 10.0)),) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - refinement_patches=refinement_patches, - n_cells_max=10_000,) + initial_refinement_level = 4, + refinement_patches = refinement_patches, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -75,30 +74,31 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=true, - extra_analysis_errors=(:conservation_error,), - extra_analysis_integrals=(entropy, energy_total, - energy_kinetic, energy_internal)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_errors = (:conservation_error,), + extra_analysis_integrals = (entropy, energy_total, + energy_kinetic, + energy_internal)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.4) +stepsize_callback = StepsizeCallback(cfl = 1.4) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_euler_vortex_shockcapturing.jl b/examples/tree_2d_dgsem/elixir_euler_vortex_shockcapturing.jl index 65a497374ed..99e4b090633 100644 --- a/examples/tree_2d_dgsem/elixir_euler_vortex_shockcapturing.jl +++ b/examples/tree_2d_dgsem/elixir_euler_vortex_shockcapturing.jl @@ -17,36 +17,36 @@ The classical isentropic vortex test case of [NASA/CR-97-206253](https://ntrs.nasa.gov/citations/19980007543) """ function initial_condition_isentropic_vortex(x, t, equations::CompressibleEulerEquations2D) - # needs appropriate mesh size, e.g. [-10,-10]x[10,10] - # for error convergence: make sure that the end time is such that the vortex is back at the initial state!! - # for the current velocity and domain size: t_end should be a multiple of 20s - # initial center of the vortex - inicenter = SVector(0.0, 0.0) - # size and strength of the vortex - iniamplitude = 5.0 - # base flow - rho = 1.0 - v1 = 1.0 - v2 = 1.0 - vel = SVector(v1, v2) - p = 25.0 - rt = p / rho # ideal gas equation - t_loc = 0.0 - cent = inicenter + vel*t_loc # advection of center - # ATTENTION: handle periodic BC, but only for v1 = v2 = 1.0 (!!!!) - cent = x - cent # distance to center point - # cent = cross(iniaxis, cent) # distance to axis, tangent vector, length r - # cross product with iniaxis = [0, 0, 1] - cent = SVector(-cent[2], cent[1]) - r2 = cent[1]^2 + cent[2]^2 - du = iniamplitude / (2*π) * exp(0.5 * (1 - r2)) # vel. perturbation - dtemp = -(equations.gamma - 1) / (2 * equations.gamma * rt) * du^2 # isentropic - rho = rho * (1 + dtemp)^(1 / (equations.gamma - 1)) - vel = vel + du * cent - v1, v2 = vel - p = p * (1 + dtemp)^(equations.gamma / (equations.gamma - 1)) - prim = SVector(rho, v1, v2, p) - return prim2cons(prim, equations) + # needs appropriate mesh size, e.g. [-10,-10]x[10,10] + # for error convergence: make sure that the end time is such that the vortex is back at the initial state!! + # for the current velocity and domain size: t_end should be a multiple of 20s + # initial center of the vortex + inicenter = SVector(0.0, 0.0) + # size and strength of the vortex + iniamplitude = 5.0 + # base flow + rho = 1.0 + v1 = 1.0 + v2 = 1.0 + vel = SVector(v1, v2) + p = 25.0 + rt = p / rho # ideal gas equation + t_loc = 0.0 + cent = inicenter + vel * t_loc # advection of center + # ATTENTION: handle periodic BC, but only for v1 = v2 = 1.0 (!!!!) + cent = x - cent # distance to center point + # cent = cross(iniaxis, cent) # distance to axis, tangent vector, length r + # cross product with iniaxis = [0, 0, 1] + cent = SVector(-cent[2], cent[1]) + r2 = cent[1]^2 + cent[2]^2 + du = iniamplitude / (2 * π) * exp(0.5 * (1 - r2)) # vel. perturbation + dtemp = -(equations.gamma - 1) / (2 * equations.gamma * rt) * du^2 # isentropic + rho = rho * (1 + dtemp)^(1 / (equations.gamma - 1)) + vel = vel + du * cent + v1, v2 = vel + p = p * (1 + dtemp)^(equations.gamma / (equations.gamma - 1)) + prim = SVector(rho, v1, v2, p) + return prim2cons(prim, equations) end initial_condition = initial_condition_isentropic_vortex @@ -56,20 +56,20 @@ volume_flux = flux_shima_etal polydeg = 3 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-10.0, -10.0) -coordinates_max = ( 10.0, 10.0) +coordinates_max = (10.0, 10.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000,) + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -82,22 +82,24 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=true, - extra_analysis_errors=(:conservation_error,), - extra_analysis_integrals=(entropy, energy_total, - energy_kinetic, energy_internal)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_errors = (:conservation_error,), + extra_analysis_integrals = (entropy, energy_total, + energy_kinetic, + energy_internal)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.7) +stepsize_callback = StepsizeCallback(cfl = 0.7) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -107,7 +109,7 @@ callbacks = CallbackSet(summary_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); +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/tree_2d_dgsem/elixir_euleracoustics_co-rotating_vortex_pair.jl b/examples/tree_2d_dgsem/elixir_euleracoustics_co-rotating_vortex_pair.jl index 38b48b5d537..ea81bd049e4 100644 --- a/examples/tree_2d_dgsem/elixir_euleracoustics_co-rotating_vortex_pair.jl +++ b/examples/tree_2d_dgsem/elixir_euleracoustics_co-rotating_vortex_pair.jl @@ -19,203 +19,199 @@ module VortexPairSetup using LinearAlgebra: norm using Trixi - # Parameters that describe the co-rotating vortex pair -struct VortexPair{RealT<:Real} - r0::RealT # Distance between origin and each vortex center - rc::RealT # Vortex core radius - c0::RealT # Speed of sound - circulation::RealT # Circulation of the vortices - rho0::RealT # Density +struct VortexPair{RealT <: Real} + r0::RealT # Distance between origin and each vortex center + rc::RealT # Vortex core radius + c0::RealT # Speed of sound + circulation::RealT # Circulation of the vortices + rho0::RealT # Density end - # Analytical flow solution, used for the initial condition of the flow simulation function velocity(x, t, vortex_pair::VortexPair) - @unpack r0, rc, circulation = vortex_pair + @unpack r0, rc, circulation = vortex_pair - omega = circulation / (4 * pi * r0^2) - si, co = sincos(omega * t) - b = SVector(r0 * co, r0 * si) # vortex centers are b and -b - z_plus = x - b - z_minus = x + b + omega = circulation / (4 * pi * r0^2) + si, co = sincos(omega * t) + b = SVector(r0 * co, r0 * si) # vortex centers are b and -b + z_plus = x - b + z_minus = x + b - # Transform to polar coordinates - r_plus = norm(z_plus) - r_minus = norm(z_minus) - theta_plus = atan(z_plus[2], z_plus[1]) - theta_minus = atan(z_minus[2], z_minus[1]) + # Transform to polar coordinates + r_plus = norm(z_plus) + r_minus = norm(z_minus) + theta_plus = atan(z_plus[2], z_plus[1]) + theta_minus = atan(z_minus[2], z_minus[1]) - si_plus, co_plus = sincos(theta_plus) - si_minus, co_minus = sincos(theta_minus) + si_plus, co_plus = sincos(theta_plus) + si_minus, co_minus = sincos(theta_minus) - v1 = -circulation/(2 * pi) * ( r_plus /(rc^2 + r_plus^2) * si_plus + - r_minus/(rc^2 + r_minus^2) * si_minus) - v2 = circulation/(2 * pi) * ( r_plus /(rc^2 + r_plus^2) * co_plus + - r_minus/(rc^2 + r_minus^2) * co_minus ) + v1 = -circulation / (2 * pi) * (r_plus / (rc^2 + r_plus^2) * si_plus + + r_minus / (rc^2 + r_minus^2) * si_minus) + v2 = circulation / (2 * pi) * (r_plus / (rc^2 + r_plus^2) * co_plus + + r_minus / (rc^2 + r_minus^2) * co_minus) - return SVector(v1, v2) + return SVector(v1, v2) end - # Initial condition of the flow simulation. Uses constant density rho0 and analytical velocities. # The pressure is calculated using the given speed of sound c0 and Bernoulli's principle -struct InitialCondition{RealT<:Real} - vortex_pair::VortexPair{RealT} +struct InitialCondition{RealT <: Real} + vortex_pair::VortexPair{RealT} end -function (initial_condition::InitialCondition)(x, t, equations::CompressibleEulerEquations2D) - @unpack vortex_pair = initial_condition - @unpack rho0, c0 = vortex_pair - gamma = equations.gamma +function (initial_condition::InitialCondition)(x, t, + equations::CompressibleEulerEquations2D) + @unpack vortex_pair = initial_condition + @unpack rho0, c0 = vortex_pair + gamma = equations.gamma - v = velocity(x, t, vortex_pair) - p0 = rho0 * c0^2 / gamma - p = p0 - 0.5 * (gamma-1)/gamma * sum(v.^2) # Bernoulli's principle + v = velocity(x, t, vortex_pair) + p0 = rho0 * c0^2 / gamma + p = p0 - 0.5 * (gamma - 1) / gamma * sum(v .^ 2) # Bernoulli's principle - prim = SVector(rho0, v[1], v[2], p) - return prim2cons(prim, equations) + prim = SVector(rho0, v[1], v[2], p) + return prim2cons(prim, equations) end - # For both the flow and acoustics solvers, a sponge layer is used to dampen the density # and pressure towards the freestream values (for the flow solver) and the perturbed pressure # to zero (for the acoustics solver). -struct SpongeLayer{RealT<:Real, uEltype<:Real, N, SourceTerms} - sponge_layer_min::NTuple{4, RealT} # (-x,+x,-y,+y) min coordinates of sponge layer per direction - sponge_layer_max::NTuple{4, RealT} # (-x,+x,-y,+y) max coordinates of sponge layer per direction - reference_values::NTuple{N, uEltype} # reference values for variables affected by sponge layer - source_terms::SourceTerms # source terms to be used outside the sponge zone +struct SpongeLayer{RealT <: Real, uEltype <: Real, N, SourceTerms} + sponge_layer_min::NTuple{4, RealT} # (-x,+x,-y,+y) min coordinates of sponge layer per direction + sponge_layer_max::NTuple{4, RealT} # (-x,+x,-y,+y) max coordinates of sponge layer per direction + reference_values::NTuple{N, uEltype} # reference values for variables affected by sponge layer + source_terms::SourceTerms # source terms to be used outside the sponge zone end -function SpongeLayer(; sponge_layer_min, sponge_layer_max, reference_values, source_terms=nothing) - return SpongeLayer(sponge_layer_min, sponge_layer_max, reference_values, source_terms) +function SpongeLayer(; sponge_layer_min, sponge_layer_max, reference_values, + source_terms = nothing) + return SpongeLayer(sponge_layer_min, sponge_layer_max, reference_values, source_terms) end function (sponge_layer::SpongeLayer)(u, x, t, equations) - @unpack sponge_layer_min, sponge_layer_max, reference_values, source_terms = sponge_layer - - if lies_in_sponge_layer(x, sponge_layer_min, sponge_layer_max) - return source_term_sponge_layer(u, x, t, equations, sponge_layer_min, sponge_layer_max, - reference_values) - elseif source_terms !== nothing - return source_terms(u, x, t, equations) - else - return SVector(ntuple(v -> zero(eltype(u)), Val(nvariables(equations)))) - end + @unpack sponge_layer_min, sponge_layer_max, reference_values, source_terms = sponge_layer + + if lies_in_sponge_layer(x, sponge_layer_min, sponge_layer_max) + return source_term_sponge_layer(u, x, t, equations, sponge_layer_min, + sponge_layer_max, + reference_values) + elseif source_terms !== nothing + return source_terms(u, x, t, equations) + else + return SVector(ntuple(v -> zero(eltype(u)), Val(nvariables(equations)))) + end end function lies_in_sponge_layer(x, sponge_layer_min, sponge_layer_max) - return (sponge_layer_min[1] <= x[1] <= sponge_layer_max[1]) || # -x direction - (sponge_layer_min[2] <= x[1] <= sponge_layer_max[2]) || # +x direction - (sponge_layer_min[3] <= x[2] <= sponge_layer_max[3]) || # -y direction - (sponge_layer_min[4] <= x[2] <= sponge_layer_max[4]) # +y direction + return (sponge_layer_min[1] <= x[1] <= sponge_layer_max[1]) || # -x direction + (sponge_layer_min[2] <= x[1] <= sponge_layer_max[2]) || # +x direction + (sponge_layer_min[3] <= x[2] <= sponge_layer_max[3]) || # -y direction + (sponge_layer_min[4] <= x[2] <= sponge_layer_max[4]) # +y direction end function source_term_sponge_layer(u, x, t, equations::AcousticPerturbationEquations2D, sponge_layer_min::NTuple{4}, sponge_layer_max::NTuple{4}, reference_values) - # Perturbed pressure source is -alpha^2 * (u - reference_value) where alpha in [0,1] is a damping - # factor depending on the position inside the sponge layer + # Perturbed pressure source is -alpha^2 * (u - reference_value) where alpha in [0,1] is a damping + # factor depending on the position inside the sponge layer - # Calculate the damping factors for each direction (=0 if x is not in the corresponding sponge - # zone) and take the maximum. This ensures proper damping if x lies in a corner where the sponge - # zones for two directions overlap - alphas = ntuple(i -> calc_damping_factor(x, i, sponge_layer_min, sponge_layer_max), - Val(2*ndims(equations))) - alpha_square = maximum(alphas)^2 + # Calculate the damping factors for each direction (=0 if x is not in the corresponding sponge + # zone) and take the maximum. This ensures proper damping if x lies in a corner where the sponge + # zones for two directions overlap + alphas = ntuple(i -> calc_damping_factor(x, i, sponge_layer_min, sponge_layer_max), + Val(2 * ndims(equations))) + alpha_square = maximum(alphas)^2 - return SVector(0, 0, -alpha_square*(u[3] - reference_values[1]/u[6]^2), 0, 0, 0, 0) + return SVector(0, 0, -alpha_square * (u[3] - reference_values[1] / u[6]^2), 0, 0, 0, 0) end function source_term_sponge_layer(u, x, t, equations::CompressibleEulerEquations2D, sponge_layer_min::NTuple{4}, sponge_layer_max::NTuple{4}, reference_values) - # Calculate the damping factors for each direction (=0 if x is not in the corresponding sponge - # zone) and take the maximum. This ensures proper damping if x lies in a corner where the sponge - # zones for two directions overlap - alphas = ntuple(i -> calc_damping_factor(x, i, sponge_layer_min, sponge_layer_max), - Val(2*ndims(equations))) - alpha_square = maximum(alphas)^2 - - u_prim = cons2prim(u, equations) - s = SVector(-alpha_square*(u_prim[1] - reference_values[1]), 0, 0, - -alpha_square*(u_prim[4] - reference_values[2])) - - return prim2cons(s, equations) + # Calculate the damping factors for each direction (=0 if x is not in the corresponding sponge + # zone) and take the maximum. This ensures proper damping if x lies in a corner where the sponge + # zones for two directions overlap + alphas = ntuple(i -> calc_damping_factor(x, i, sponge_layer_min, sponge_layer_max), + Val(2 * ndims(equations))) + alpha_square = maximum(alphas)^2 + + u_prim = cons2prim(u, equations) + s = SVector(-alpha_square * (u_prim[1] - reference_values[1]), 0, 0, + -alpha_square * (u_prim[4] - reference_values[2])) + + return prim2cons(s, equations) end function calc_damping_factor(x, direction, sponge_layer_min, sponge_layer_max) - # Damping factor alpha grows linearly from 0 to 1 depending on how deep x lies in the sponge layer - # If x does not lie in the sponge layer, this returns 0 - - # Get the coordinate that determines how deep we are in the sponge zone - if direction in (1, 2) - pos = x[1] - else - pos = x[2] - end - - # Determine where the sponge layer begins/ends to allow calculating the damping factor - if iseven(direction) - sponge_begin = sponge_layer_min[direction] - sponge_end = sponge_layer_max[direction] - else - sponge_begin = sponge_layer_max[direction] - sponge_end = sponge_layer_min[direction] - end - - alpha = (pos - sponge_begin) / (sponge_end - sponge_begin) - - # alpha lies in [0, 1] if and only if x lies in the sponge zone - if 0 <= alpha <= 1 - return alpha - else - return zero(alpha) - end + # Damping factor alpha grows linearly from 0 to 1 depending on how deep x lies in the sponge layer + # If x does not lie in the sponge layer, this returns 0 + + # Get the coordinate that determines how deep we are in the sponge zone + if direction in (1, 2) + pos = x[1] + else + pos = x[2] + end + + # Determine where the sponge layer begins/ends to allow calculating the damping factor + if iseven(direction) + sponge_begin = sponge_layer_min[direction] + sponge_end = sponge_layer_max[direction] + else + sponge_begin = sponge_layer_max[direction] + sponge_end = sponge_layer_min[direction] + end + + alpha = (pos - sponge_begin) / (sponge_end - sponge_begin) + + # alpha lies in [0, 1] if and only if x lies in the sponge zone + if 0 <= alpha <= 1 + return alpha + else + return zero(alpha) + end end - # Boundary condition for the flow problem: The sponge layer dampens density and pressure towards the # freestream values. The freestream values (converted into conservative variables) are therefore # used as a Dirichlet boundary struct BoundaryCondition{uEltype} - rho::uEltype - rho_e::uEltype + rho::uEltype + rho_e::uEltype end function (bc::BoundaryCondition)(u_inner, orientation, direction, x, t, surface_flux_function, equations::CompressibleEulerEquations2D) - u_boundary = SVector(bc.rho, zero(bc.rho), zero(bc.rho), bc.rho_e) + u_boundary = SVector(bc.rho, zero(bc.rho), zero(bc.rho), bc.rho_e) - # Calculate boundary flux - if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary - flux = surface_flux_function(u_inner, u_boundary, orientation, equations) - else # u_boundary is "left" of boundary, u_inner is "right" of boundary - flux = surface_flux_function(u_boundary, u_inner, orientation, equations) - end + # Calculate boundary flux + if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary + flux = surface_flux_function(u_inner, u_boundary, orientation, equations) + else # u_boundary is "left" of boundary, u_inner is "right" of boundary + flux = surface_flux_function(u_boundary, u_inner, orientation, equations) + end - return flux + return flux end end # module - import .VortexPairSetup - ############################################################################### # shared parameters, mesh and solver for both semidiscretizations # Parameters of the vortex pair -Mach = 1/9 +Mach = 1 / 9 c0 = 1.0 r0 = 1.0 circulation = 4 * pi * r0 * c0 * Mach rho = 1.0 -rc = 2/9 * r0 * 1.0 +rc = 2 / 9 * r0 * 1.0 T_r = 8 * pi^2 * r0^2 / circulation # Rotational period of the vortex pair T_a = T_r / 2 # Acoustic period of the vortex pair @@ -223,24 +219,22 @@ T_a = T_r / 2 # Acoustic period of the vortex pair vortex_pair = VortexPairSetup.VortexPair(r0, rc, c0, circulation, rho) # Shared mesh for both semidiscretizations -coordinates_min = (-135*r0, -135*r0) # minimum coordinates (min(x), min(y)) -coordinates_max = ( 135*r0, 135*r0) # maximum coordinates (max(x), max(y)) -refinement_patches = ( - (type="sphere", center=(0.0, 0.0), radius=85.0*r0), - (type="sphere", center=(0.0, 0.0), radius=20.0*r0), - (type="sphere", center=(0.0, 0.0), radius=10.0*r0), - (type="sphere", center=(0.0, 0.0), radius=5.0*r0) -) -initial_refinement_level=7 -n_cells_max=500_000 +coordinates_min = (-135 * r0, -135 * r0) # minimum coordinates (min(x), min(y)) +coordinates_max = (135 * r0, 135 * r0) # maximum coordinates (max(x), max(y)) +refinement_patches = ((type = "sphere", center = (0.0, 0.0), radius = 85.0 * r0), + (type = "sphere", center = (0.0, 0.0), radius = 20.0 * r0), + (type = "sphere", center = (0.0, 0.0), radius = 10.0 * r0), + (type = "sphere", center = (0.0, 0.0), radius = 5.0 * r0)) +initial_refinement_level = 7 +n_cells_max = 500_000 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=initial_refinement_level, - refinement_patches=refinement_patches, - n_cells_max=n_cells_max, # set maximum capacity of tree data structure - periodicity=false) + initial_refinement_level = initial_refinement_level, + refinement_patches = refinement_patches, + n_cells_max = n_cells_max, # set maximum capacity of tree data structure + periodicity = false) # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) ############################################################################### # semidiscretization Euler equations @@ -250,24 +244,37 @@ equations_euler = CompressibleEulerEquations2D(gamma) initial_condition_euler = VortexPairSetup.InitialCondition(vortex_pair) -sponge_layer_euler = VortexPairSetup.SpongeLayer(sponge_layer_min=(-135*r0, 115*r0, -135*r0, 115*r0), - sponge_layer_max=(-115*r0, 135*r0, -115*r0, 135*r0), - reference_values=(rho, rho * c0^2 / gamma)) # (rho0, p0) +sponge_layer_euler = VortexPairSetup.SpongeLayer(sponge_layer_min = (-135 * r0, 115 * r0, + -135 * r0, 115 * r0), + sponge_layer_max = (-115 * r0, 135 * r0, + -115 * r0, 135 * r0), + reference_values = (rho, + rho * c0^2 / gamma)) # (rho0, p0) -boundary_condition_euler = VortexPairSetup.BoundaryCondition(rho, (rho * c0^2 / gamma) / (gamma-1)) +boundary_condition_euler = VortexPairSetup.BoundaryCondition(rho, + (rho * c0^2 / gamma) / + (gamma - 1)) -semi_euler = SemidiscretizationHyperbolic(mesh, equations_euler, initial_condition_euler, solver, - boundary_conditions=boundary_condition_euler, - source_terms=sponge_layer_euler) +semi_euler = SemidiscretizationHyperbolic(mesh, equations_euler, initial_condition_euler, + solver, + boundary_conditions = boundary_condition_euler, + source_terms = sponge_layer_euler) ############################################################################### # semidiscretization acoustic perturbation equations -equations_acoustics = AcousticPerturbationEquations2D(v_mean_global=(13.0, 26.0), c_mean_global=39.0, - rho_mean_global=52.0) # global mean values will be overwritten - -sponge_layer_acoustics = VortexPairSetup.SpongeLayer(sponge_layer_min=(-135*r0, 100*r0, -135*r0, 100*r0), - sponge_layer_max=(-100*r0, 135*r0, -100*r0, 135*r0), - reference_values=(0.0,)) +equations_acoustics = AcousticPerturbationEquations2D(v_mean_global = (13.0, 26.0), + c_mean_global = 39.0, + rho_mean_global = 52.0) # global mean values will be overwritten + +sponge_layer_acoustics = VortexPairSetup.SpongeLayer(sponge_layer_min = (-135 * r0, + 100 * r0, + -135 * r0, + 100 * r0), + sponge_layer_max = (-100 * r0, + 135 * r0, + -100 * r0, + 135 * r0), + reference_values = (0.0,)) """ boundary_condition_zero(u_inner, orientation, direction, x, t, surface_flux_function, @@ -276,24 +283,27 @@ sponge_layer_acoustics = VortexPairSetup.SpongeLayer(sponge_layer_min=(-135*r0, Boundary condition that uses a boundary state where the state variables are zero and the mean variables are the same as in `u_inner`. """ -function boundary_condition_zero(u_inner, orientation, direction, x, t, surface_flux_function, +function boundary_condition_zero(u_inner, orientation, direction, x, t, + surface_flux_function, equations::AcousticPerturbationEquations2D) - value = zero(eltype(u_inner)) - u_boundary = SVector(value, value, value, cons2mean(u_inner, equations)...) + value = zero(eltype(u_inner)) + u_boundary = SVector(value, value, value, cons2mean(u_inner, equations)...) - # Calculate boundary flux - if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary - flux = surface_flux_function(u_inner, u_boundary, orientation, equations) - else # u_boundary is "left" of boundary, u_inner is "right" of boundary - flux = surface_flux_function(u_boundary, u_inner, orientation, equations) - end + # Calculate boundary flux + if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary + flux = surface_flux_function(u_inner, u_boundary, orientation, equations) + else # u_boundary is "left" of boundary, u_inner is "right" of boundary + flux = surface_flux_function(u_boundary, u_inner, orientation, equations) + end - return flux + return flux end -semi_acoustics = SemidiscretizationHyperbolic(mesh, equations_acoustics, initial_condition_constant, - solver, boundary_conditions=boundary_condition_zero, - source_terms=sponge_layer_acoustics) +semi_acoustics = SemidiscretizationHyperbolic(mesh, equations_acoustics, + initial_condition_constant, + solver, + boundary_conditions = boundary_condition_zero, + source_terms = sponge_layer_acoustics) ############################################################################### # ODE solvers, callbacks etc. for averaging the flow field @@ -307,12 +317,12 @@ ode_averaging = semidiscretize(semi_euler, tspan1) summary_callback = SummaryCallback() analysis_interval = 5000 -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) tspan_averaging = (50.0, 400.0) averaging_callback = AveragingCallback(semi_euler, tspan_averaging) -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) callbacks_averaging = CallbackSet(summary_callback, alive_callback, averaging_callback, stepsize_callback) @@ -321,14 +331,13 @@ callbacks_averaging = CallbackSet(summary_callback, alive_callback, averaging_ca # run simulation for averaging the flow field # OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks -sol_averaging = solve(ode_averaging, 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_averaging); +sol_averaging = solve(ode_averaging, 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_averaging); # Print the timer summary summary_callback() - ############################################################################### # set up coupled semidiscretization @@ -337,13 +346,13 @@ source_region(x) = sum(abs2, x) < 6.0^2 # calculate sources within radius 6 arou weights(x) = sum(abs2, x) < 5.0^2 ? 1.0 : cospi(0.5 * (norm(x) - 5.0)) semi = SemidiscretizationEulerAcoustics(semi_acoustics, semi_euler, - source_region=source_region, weights=weights) + source_region = source_region, weights = weights) ############################################################################### # ODE solvers, callbacks etc. for the coupled simulation # Create ODE problem -tspan = (0.0, 7.0*T_a) +tspan = (0.0, 7.0 * T_a) ode = semidiscretize(semi, tspan) # We need an additional ODE for the pure flow problem ode_euler = semidiscretize(semi.semi_euler, tspan) @@ -351,28 +360,30 @@ ode_euler = semidiscretize(semi.semi_euler, tspan) # Set up coupling callback cfl_acoustics = 0.8 cfl_euler = 0.8 -euler_acoustics_coupling = EulerAcousticsCouplingCallback( - ode_euler, "out/averaging.h5", CarpenterKennedy2N54(williamson_condition=false), - cfl_acoustics, cfl_euler, callback=SaveRestartCallback(interval=2300, output_directory="out/euler/")) +euler_acoustics_coupling = EulerAcousticsCouplingCallback(ode_euler, "out/averaging.h5", + CarpenterKennedy2N54(williamson_condition = false), + cfl_acoustics, cfl_euler, + callback = SaveRestartCallback(interval = 2300, + output_directory = "out/euler/")) # At the beginning of the main loop, the SummaryCallback prints a summary of the simulation setup # and resets the timers summary_callback = SummaryCallback() analysis_interval = 5000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) output_directory = "out/" -save_solution = SaveSolutionCallback(interval=2300, output_directory=output_directory) -save_restart = SaveRestartCallback(interval=2300, output_directory=output_directory) +save_solution = SaveSolutionCallback(interval = 2300, output_directory = output_directory) +save_restart = SaveRestartCallback(interval = 2300, output_directory = output_directory) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback, save_solution, save_restart, euler_acoustics_coupling) -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); +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); # Print the timer summary -summary_callback() \ No newline at end of file +summary_callback() diff --git a/examples/tree_2d_dgsem/elixir_eulermulti_convergence_ec.jl b/examples/tree_2d_dgsem/elixir_eulermulti_convergence_ec.jl index d423b800fd0..bc4859e5760 100644 --- a/examples/tree_2d_dgsem/elixir_eulermulti_convergence_ec.jl +++ b/examples/tree_2d_dgsem/elixir_eulermulti_convergence_ec.jl @@ -4,25 +4,23 @@ using Trixi ############################################################################### # semidiscretization of the compressible Euler multicomponent equations -equations = CompressibleEulerMulticomponentEquations2D(gammas = (1.4, 1.4), +equations = CompressibleEulerMulticomponentEquations2D(gammas = (1.4, 1.4), gas_constants = (0.4, 0.4)) initial_condition = initial_condition_convergence_test volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_ranocha, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_ranocha, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-1.0, -1.0) -coordinates_max = ( 1.0, 1.0) +coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=30_000) - + initial_refinement_level = 3, + n_cells_max = 30_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -33,27 +31,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_eulermulti_convergence_es.jl b/examples/tree_2d_dgsem/elixir_eulermulti_convergence_es.jl index 62c5bab51ea..771343937a4 100644 --- a/examples/tree_2d_dgsem/elixir_eulermulti_convergence_es.jl +++ b/examples/tree_2d_dgsem/elixir_eulermulti_convergence_es.jl @@ -4,25 +4,23 @@ using Trixi ############################################################################### # semidiscretization of the compressible Euler multicomponent equations -equations = CompressibleEulerMulticomponentEquations2D(gammas = (1.4, 1.4), +equations = CompressibleEulerMulticomponentEquations2D(gammas = (1.4, 1.4), gas_constants = (0.4, 0.4)) initial_condition = initial_condition_convergence_test volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-1.0, -1.0) -coordinates_max = ( 1.0, 1.0) +coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=30_000) - + initial_refinement_level = 4, + n_cells_max = 30_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -33,27 +31,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_eulermulti_ec.jl b/examples/tree_2d_dgsem/elixir_eulermulti_ec.jl index 0715dfe35d6..d912a280e49 100644 --- a/examples/tree_2d_dgsem/elixir_eulermulti_ec.jl +++ b/examples/tree_2d_dgsem/elixir_eulermulti_ec.jl @@ -4,26 +4,23 @@ using Trixi ############################################################################### # semidiscretization of the compressible Euler multicomponent equations -equations = CompressibleEulerMulticomponentEquations2D(gammas = 1.4, +equations = CompressibleEulerMulticomponentEquations2D(gammas = 1.4, gas_constants = 0.4) - initial_condition = initial_condition_weak_blast_wave volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_ranocha, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_ranocha, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=5, - n_cells_max=10_000) - + initial_refinement_level = 5, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -34,28 +31,27 @@ summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(Trixi.density,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (Trixi.density,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_eulermulti_es.jl b/examples/tree_2d_dgsem/elixir_eulermulti_es.jl index a3e5580b572..470e533ab8d 100644 --- a/examples/tree_2d_dgsem/elixir_eulermulti_es.jl +++ b/examples/tree_2d_dgsem/elixir_eulermulti_es.jl @@ -4,25 +4,23 @@ using Trixi ############################################################################### # semidiscretization of the compressible Euler multicomponent equations -equations = CompressibleEulerMulticomponentEquations2D(gammas = (1.4, 1.4, 1.4, 1.4), +equations = CompressibleEulerMulticomponentEquations2D(gammas = (1.4, 1.4, 1.4, 1.4), gas_constants = (0.4, 0.4, 0.4, 0.4)) initial_condition = initial_condition_weak_blast_wave volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=5, - n_cells_max=10_000) - + initial_refinement_level = 5, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -32,30 +30,29 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_restart, save_solution, 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); +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/tree_2d_dgsem/elixir_eulermulti_shock_bubble.jl b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble.jl index 38510446cb1..f5ef51c108a 100644 --- a/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble.jl +++ b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble.jl @@ -5,7 +5,7 @@ using Trixi # semidiscretization of the compressible Euler multicomponent equations # 1) Dry Air 2) Helium + 28% Air -equations = CompressibleEulerMulticomponentEquations2D(gammas = (1.4, 1.648), +equations = CompressibleEulerMulticomponentEquations2D(gammas = (1.4, 1.648), gas_constants = (0.287, 1.578)) """ @@ -16,124 +16,126 @@ A shock-bubble testcase for multicomponent Euler equations Formulation of Entropy-Stable schemes for the multicomponent compressible Euler equations [arXiv: 1904.00972](https://arxiv.org/abs/1904.00972) """ -function initial_condition_shock_bubble(x, t, equations::CompressibleEulerMulticomponentEquations2D{5, 2}) - # bubble test case, see Gouasmi et al. https://arxiv.org/pdf/1904.00972 - # other reference: https://www.researchgate.net/profile/Pep_Mulet/publication/222675930_A_flux-split_algorithm_applied_to_conservative_models_for_multicomponent_compressible_flows/links/568da54508aeaa1481ae7af0.pdf - # typical domain is rectangular, we change it to a square, as Trixi can only do squares - @unpack gas_constants = equations - - # Positivity Preserving Parameter, can be set to zero if scheme is positivity preserving - delta = 0.03 - - # Region I - rho1_1 = delta - rho2_1 = 1.225 * gas_constants[1]/gas_constants[2] - delta - v1_1 = zero(delta) - v2_1 = zero(delta) - p_1 = 101325 - - # Region II - rho1_2 = 1.225-delta - rho2_2 = delta - v1_2 = zero(delta) - v2_2 = zero(delta) - p_2 = 101325 - - # Region III - rho1_3 = 1.6861 - delta - rho2_3 = delta - v1_3 = -113.5243 - v2_3 = zero(delta) - p_3 = 159060 - - # Set up Region I & II: - inicenter = SVector(zero(delta), zero(delta)) - x_norm = x[1] - inicenter[1] - y_norm = x[2] - inicenter[2] - r = sqrt(x_norm^2 + y_norm^2) - - if (x[1] > 0.50) - # Set up Region III - rho1 = rho1_3 - rho2 = rho2_3 - v1 = v1_3 - v2 = v2_3 - p = p_3 - elseif (r < 0.25) - # Set up Region I - rho1 = rho1_1 - rho2 = rho2_1 - v1 = v1_1 - v2 = v2_1 - p = p_1 - else - # Set up Region II - rho1 = rho1_2 - rho2 = rho2_2 - v1 = v1_2 - v2 = v2_2 - p = p_2 - end - - return prim2cons(SVector(v1, v2, p, rho1, rho2), equations) +function initial_condition_shock_bubble(x, t, + equations::CompressibleEulerMulticomponentEquations2D{ + 5, + 2 + }) + # bubble test case, see Gouasmi et al. https://arxiv.org/pdf/1904.00972 + # other reference: https://www.researchgate.net/profile/Pep_Mulet/publication/222675930_A_flux-split_algorithm_applied_to_conservative_models_for_multicomponent_compressible_flows/links/568da54508aeaa1481ae7af0.pdf + # typical domain is rectangular, we change it to a square, as Trixi can only do squares + @unpack gas_constants = equations + + # Positivity Preserving Parameter, can be set to zero if scheme is positivity preserving + delta = 0.03 + + # Region I + rho1_1 = delta + rho2_1 = 1.225 * gas_constants[1] / gas_constants[2] - delta + v1_1 = zero(delta) + v2_1 = zero(delta) + p_1 = 101325 + + # Region II + rho1_2 = 1.225 - delta + rho2_2 = delta + v1_2 = zero(delta) + v2_2 = zero(delta) + p_2 = 101325 + + # Region III + rho1_3 = 1.6861 - delta + rho2_3 = delta + v1_3 = -113.5243 + v2_3 = zero(delta) + p_3 = 159060 + + # Set up Region I & II: + inicenter = SVector(zero(delta), zero(delta)) + x_norm = x[1] - inicenter[1] + y_norm = x[2] - inicenter[2] + r = sqrt(x_norm^2 + y_norm^2) + + if (x[1] > 0.50) + # Set up Region III + rho1 = rho1_3 + rho2 = rho2_3 + v1 = v1_3 + v2 = v2_3 + p = p_3 + elseif (r < 0.25) + # Set up Region I + rho1 = rho1_1 + rho2 = rho2_1 + v1 = v1_1 + v2 = v2_1 + p = p_1 + else + # Set up Region II + rho1 = rho1_2 + rho2 = rho2_2 + v1 = v1_2 + v2 = v2_2 + p = p_2 + end + + return prim2cons(SVector(v1, v2, p, rho1, rho2), equations) end initial_condition = initial_condition_shock_bubble -surface_flux = flux_lax_friedrichs -volume_flux = flux_ranocha -basis = LobattoLegendreBasis(3) -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(basis, surface_flux, volume_integral) - -coordinates_min = (-2.25, -2.225) -coordinates_max = ( 2.20, 2.225) -mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=1_000_000) - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - +surface_flux = flux_lax_friedrichs +volume_flux = flux_ranocha +basis = LobattoLegendreBasis(3) +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(basis, surface_flux, volume_integral) + +coordinates_min = (-2.25, -2.225) +coordinates_max = (2.20, 2.225) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 3, + n_cells_max = 1_000_000) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 0.01) -ode = semidiscretize(semi, tspan) - -summary_callback = SummaryCallback() +tspan = (0.0, 0.01) +ode = semidiscretize(semi, tspan) -analysis_interval = 300 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(Trixi.density,)) +summary_callback = SummaryCallback() -alive_callback = AliveCallback(analysis_interval=analysis_interval) +analysis_interval = 300 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (Trixi.density,)) -save_solution = SaveSolutionCallback(interval=300, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -stepsize_callback = StepsizeCallback(cfl=0.3) +save_solution = SaveSolutionCallback(interval = 300, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -callbacks = CallbackSet(summary_callback, - analysis_callback, - alive_callback, - save_solution, - stepsize_callback) +stepsize_callback = StepsizeCallback(cfl = 0.3) +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + 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=1e5); -summary_callback() # print the timer summary \ No newline at end of file +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 = 1e5); +summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl index c5a7a5932e6..6241ca30938 100644 --- a/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl +++ b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl @@ -5,7 +5,7 @@ using Trixi # semidiscretization of the compressible Euler multicomponent equations # 1) Dry Air 2) Helium + 28% Air -equations = CompressibleEulerMulticomponentEquations2D(gammas = (1.4, 1.648), +equations = CompressibleEulerMulticomponentEquations2D(gammas = (1.4, 1.648), gas_constants = (0.287, 1.578)) """ @@ -16,127 +16,132 @@ A shock-bubble testcase for multicomponent Euler equations Formulation of Entropy-Stable schemes for the multicomponent compressible Euler equations [arXiv: 1904.00972](https://arxiv.org/abs/1904.00972) """ -function initial_condition_shock_bubble(x, t, equations::CompressibleEulerMulticomponentEquations2D{5, 2}) - # bubble test case, see Gouasmi et al. https://arxiv.org/pdf/1904.00972 - # other reference: https://www.researchgate.net/profile/Pep_Mulet/publication/222675930_A_flux-split_algorithm_applied_to_conservative_models_for_multicomponent_compressible_flows/links/568da54508aeaa1481ae7af0.pdf - # typical domain is rectangular, we change it to a square, as Trixi can only do squares - @unpack gas_constants = equations - - # Positivity Preserving Parameter, can be set to zero if scheme is positivity preserving - delta = 0.03 - - # Region I - rho1_1 = delta - rho2_1 = 1.225 * gas_constants[1]/gas_constants[2] - delta - v1_1 = zero(delta) - v2_1 = zero(delta) - p_1 = 101325 - - # Region II - rho1_2 = 1.225-delta - rho2_2 = delta - v1_2 = zero(delta) - v2_2 = zero(delta) - p_2 = 101325 - - # Region III - rho1_3 = 1.6861 - delta - rho2_3 = delta - v1_3 = -113.5243 - v2_3 = zero(delta) - p_3 = 159060 - - # Set up Region I & II: - inicenter = SVector(zero(delta), zero(delta)) - x_norm = x[1] - inicenter[1] - y_norm = x[2] - inicenter[2] - r = sqrt(x_norm^2 + y_norm^2) - - if (x[1] > 0.50) - # Set up Region III - rho1 = rho1_3 - rho2 = rho2_3 - v1 = v1_3 - v2 = v2_3 - p = p_3 - elseif (r < 0.25) - # Set up Region I - rho1 = rho1_1 - rho2 = rho2_1 - v1 = v1_1 - v2 = v2_1 - p = p_1 - else - # Set up Region II - rho1 = rho1_2 - rho2 = rho2_2 - v1 = v1_2 - v2 = v2_2 - p = p_2 - end - - return prim2cons(SVector(v1, v2, p, rho1, rho2), equations) +function initial_condition_shock_bubble(x, t, + equations::CompressibleEulerMulticomponentEquations2D{ + 5, + 2 + }) + # bubble test case, see Gouasmi et al. https://arxiv.org/pdf/1904.00972 + # other reference: https://www.researchgate.net/profile/Pep_Mulet/publication/222675930_A_flux-split_algorithm_applied_to_conservative_models_for_multicomponent_compressible_flows/links/568da54508aeaa1481ae7af0.pdf + # typical domain is rectangular, we change it to a square, as Trixi can only do squares + @unpack gas_constants = equations + + # Positivity Preserving Parameter, can be set to zero if scheme is positivity preserving + delta = 0.03 + + # Region I + rho1_1 = delta + rho2_1 = 1.225 * gas_constants[1] / gas_constants[2] - delta + v1_1 = zero(delta) + v2_1 = zero(delta) + p_1 = 101325 + + # Region II + rho1_2 = 1.225 - delta + rho2_2 = delta + v1_2 = zero(delta) + v2_2 = zero(delta) + p_2 = 101325 + + # Region III + rho1_3 = 1.6861 - delta + rho2_3 = delta + v1_3 = -113.5243 + v2_3 = zero(delta) + p_3 = 159060 + + # Set up Region I & II: + inicenter = SVector(zero(delta), zero(delta)) + x_norm = x[1] - inicenter[1] + y_norm = x[2] - inicenter[2] + r = sqrt(x_norm^2 + y_norm^2) + + if (x[1] > 0.50) + # Set up Region III + rho1 = rho1_3 + rho2 = rho2_3 + v1 = v1_3 + v2 = v2_3 + p = p_3 + elseif (r < 0.25) + # Set up Region I + rho1 = rho1_1 + rho2 = rho2_1 + v1 = v1_1 + v2 = v2_1 + p = p_1 + else + # Set up Region II + rho1 = rho1_2 + rho2 = rho2_2 + v1 = v1_2 + v2 = v2_2 + p = p_2 + end + + return prim2cons(SVector(v1, v2, p, rho1, rho2), equations) end initial_condition = initial_condition_shock_bubble -surface_flux = flux_lax_friedrichs -volume_flux = flux_ranocha -basis = LobattoLegendreBasis(3) +surface_flux = flux_lax_friedrichs +volume_flux = flux_ranocha +basis = LobattoLegendreBasis(3) limiter_idp = SubcellLimiterIDP(equations, basis; - positivity_variables_cons=[(i+3 for i in eachcomponent(equations))...]) + positivity_variables_cons = [ + (i + 3 for i in eachcomponent(equations))..., + ]) volume_integral = VolumeIntegralSubcellLimiting(limiter_idp; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) -coordinates_min = (-2.25, -2.225) -coordinates_max = ( 2.20, 2.225) -mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=1_000_000) - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) +coordinates_min = (-2.25, -2.225) +coordinates_max = (2.20, 2.225) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 3, + n_cells_max = 1_000_000) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 0.01) -ode = semidiscretize(semi, tspan) - -summary_callback = SummaryCallback() +tspan = (0.0, 0.01) +ode = semidiscretize(semi, tspan) -analysis_interval = 300 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(Trixi.density,)) +summary_callback = SummaryCallback() -alive_callback = AliveCallback(analysis_interval=analysis_interval) +analysis_interval = 300 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (Trixi.density,)) -save_solution = SaveSolutionCallback(interval=300, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -stepsize_callback = StepsizeCallback(cfl=0.9) +save_solution = SaveSolutionCallback(interval = 300, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -callbacks = CallbackSet(summary_callback, - analysis_callback, - alive_callback, - save_solution, - stepsize_callback) +stepsize_callback = StepsizeCallback(cfl = 0.9) +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) ############################################################################### # run the simulation output_directory = "out" stage_callbacks = (SubcellLimiterIDPCorrection(), - BoundsCheckCallback(save_errors=true, interval=100, output_directory=output_directory)) + BoundsCheckCallback(save_errors = true, interval = 100, + output_directory = output_directory)) -sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks=stage_callbacks); - 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 \ No newline at end of file +sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks = stage_callbacks); + 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/tree_2d_dgsem/elixir_hypdiff_godunov.jl b/examples/tree_2d_dgsem/elixir_hypdiff_godunov.jl index abf9735fd28..1700957d900 100644 --- a/examples/tree_2d_dgsem/elixir_hypdiff_godunov.jl +++ b/examples/tree_2d_dgsem/elixir_hypdiff_godunov.jl @@ -8,51 +8,50 @@ using Trixi equations = HyperbolicDiffusionEquations2D() function initial_condition_poisson_periodic(x, t, equations::HyperbolicDiffusionEquations2D) - # elliptic equation: -νΔϕ = f - # depending on initial constant state, c, for phi this converges to the solution ϕ + c - if iszero(t) - phi = 0.0 - q1 = 0.0 - q2 = 0.0 - else - phi = sin(2.0*pi*x[1])*sin(2.0*pi*x[2]) - q1 = 2*pi*cos(2.0*pi*x[1])*sin(2.0*pi*x[2]) - q2 = 2*pi*sin(2.0*pi*x[1])*cos(2.0*pi*x[2]) - end - return SVector(phi, q1, q2) + # elliptic equation: -νΔϕ = f + # depending on initial constant state, c, for phi this converges to the solution ϕ + c + if iszero(t) + phi = 0.0 + q1 = 0.0 + q2 = 0.0 + else + phi = sin(2.0 * pi * x[1]) * sin(2.0 * pi * x[2]) + q1 = 2 * pi * cos(2.0 * pi * x[1]) * sin(2.0 * pi * x[2]) + q2 = 2 * pi * sin(2.0 * pi * x[1]) * cos(2.0 * pi * x[2]) + end + return SVector(phi, q1, q2) end initial_condition = initial_condition_poisson_periodic -@inline function source_terms_poisson_periodic(u, x, t, equations::HyperbolicDiffusionEquations2D) - # elliptic equation: -νΔϕ = f - # analytical solution: phi = sin(2πx)*sin(2πy) and f = -8νπ^2 sin(2πx)*sin(2πy) - @unpack inv_Tr = equations - C = -8 * equations.nu * pi^2 - - x1, x2 = x - tmp1 = sinpi(2 * x1) - tmp2 = sinpi(2 * x2) - du1 = -C*tmp1*tmp2 - du2 = -inv_Tr * u[2] - du3 = -inv_Tr * u[3] - - return SVector(du1, du2, du3) +@inline function source_terms_poisson_periodic(u, x, t, + equations::HyperbolicDiffusionEquations2D) + # elliptic equation: -νΔϕ = f + # analytical solution: phi = sin(2πx)*sin(2πy) and f = -8νπ^2 sin(2πx)*sin(2πy) + @unpack inv_Tr = equations + C = -8 * equations.nu * pi^2 + + x1, x2 = x + tmp1 = sinpi(2 * x1) + tmp2 = sinpi(2 * x2) + du1 = -C * tmp1 * tmp2 + du2 = -inv_Tr * u[2] + du3 = -inv_Tr * u[3] + + return SVector(du1, du2, du3) end volume_flux = flux_central -solver = DGSEM(polydeg=4, surface_flux=flux_godunov, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 4, surface_flux = flux_godunov, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (0.0, 0.0) coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=30_000) - + initial_refinement_level = 3, + n_cells_max = 30_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_poisson_periodic) - + source_terms = source_terms_poisson_periodic) ############################################################################### # ODE solvers, callbacks etc. @@ -63,30 +62,29 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() resid_tol = 5.0e-12 -steady_state_callback = SteadyStateCallback(abstol=resid_tol, reltol=0.0) +steady_state_callback = SteadyStateCallback(abstol = resid_tol, reltol = 0.0) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, steady_state_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_hypdiff_harmonic_nonperiodic.jl b/examples/tree_2d_dgsem/elixir_hypdiff_harmonic_nonperiodic.jl index c144ef47a63..e70b91906b1 100644 --- a/examples/tree_2d_dgsem/elixir_hypdiff_harmonic_nonperiodic.jl +++ b/examples/tree_2d_dgsem/elixir_hypdiff_harmonic_nonperiodic.jl @@ -7,44 +7,43 @@ using Trixi equations = HyperbolicDiffusionEquations2D() -@inline function initial_condition_harmonic_nonperiodic(x, t, equations::HyperbolicDiffusionEquations2D) - # elliptic equation: -ν Δϕ = 0 in Ω, u = g on ∂Ω - if t == 0.0 - phi = 1.0 - q1 = 1.0 - q2 = 1.0 - else - C = inv(sinh(pi)) - sinpi_x1, cospi_x1 = sincos(pi*x[1]) - sinpi_x2, cospi_x2 = sincos(pi*x[2]) - sinh_pix1 = sinh(pi*x[1]) - cosh_pix1 = cosh(pi*x[1]) - sinh_pix2 = sinh(pi*x[2]) - cosh_pix2 = cosh(pi*x[2]) - phi = C * (sinh_pix1 * sinpi_x2 + sinh_pix2 * sinpi_x1) - q1 = C * pi * (cosh_pix1 * sinpi_x2 + sinh_pix2 * cospi_x1) - q2 = C * pi * (sinh_pix1 * cospi_x2 + cosh_pix2 * sinpi_x1) - end - return SVector(phi, q1, q2) +@inline function initial_condition_harmonic_nonperiodic(x, t, + equations::HyperbolicDiffusionEquations2D) + # elliptic equation: -ν Δϕ = 0 in Ω, u = g on ∂Ω + if t == 0.0 + phi = 1.0 + q1 = 1.0 + q2 = 1.0 + else + C = inv(sinh(pi)) + sinpi_x1, cospi_x1 = sincos(pi * x[1]) + sinpi_x2, cospi_x2 = sincos(pi * x[2]) + sinh_pix1 = sinh(pi * x[1]) + cosh_pix1 = cosh(pi * x[1]) + sinh_pix2 = sinh(pi * x[2]) + cosh_pix2 = cosh(pi * x[2]) + phi = C * (sinh_pix1 * sinpi_x2 + sinh_pix2 * sinpi_x1) + q1 = C * pi * (cosh_pix1 * sinpi_x2 + sinh_pix2 * cospi_x1) + q2 = C * pi * (sinh_pix1 * cospi_x2 + cosh_pix2 * sinpi_x1) + end + return SVector(phi, q1, q2) end initial_condition = initial_condition_harmonic_nonperiodic boundary_conditions = BoundaryConditionDirichlet(initial_condition) -solver = DGSEM(polydeg=4, surface_flux=flux_godunov) +solver = DGSEM(polydeg = 4, surface_flux = flux_godunov) coordinates_min = (0.0, 0.0) coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=30_000, - periodicity=false) - + initial_refinement_level = 3, + n_cells_max = 30_000, + periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions, - source_terms=source_terms_harmonic) - + boundary_conditions = boundary_conditions, + source_terms = source_terms_harmonic) ############################################################################### # ODE solvers, callbacks etc. @@ -55,30 +54,29 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() resid_tol = 5.0e-12 -steady_state_callback = SteadyStateCallback(abstol=resid_tol, reltol=0.0) +steady_state_callback = SteadyStateCallback(abstol = resid_tol, reltol = 0.0) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, steady_state_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_hypdiff_lax_friedrichs.jl b/examples/tree_2d_dgsem/elixir_hypdiff_lax_friedrichs.jl index d0d706981a2..a1a0397a46c 100644 --- a/examples/tree_2d_dgsem/elixir_hypdiff_lax_friedrichs.jl +++ b/examples/tree_2d_dgsem/elixir_hypdiff_lax_friedrichs.jl @@ -8,49 +8,48 @@ using Trixi equations = HyperbolicDiffusionEquations2D() function initial_condition_poisson_periodic(x, t, equations::HyperbolicDiffusionEquations2D) - # elliptic equation: -νΔϕ = f - # depending on initial constant state, c, for phi this converges to the solution ϕ + c - if iszero(t) - phi = 0.0 - q1 = 0.0 - q2 = 0.0 - else - phi = sin(2.0*pi*x[1])*sin(2.0*pi*x[2]) - q1 = 2*pi*cos(2.0*pi*x[1])*sin(2.0*pi*x[2]) - q2 = 2*pi*sin(2.0*pi*x[1])*cos(2.0*pi*x[2]) - end - return SVector(phi, q1, q2) + # elliptic equation: -νΔϕ = f + # depending on initial constant state, c, for phi this converges to the solution ϕ + c + if iszero(t) + phi = 0.0 + q1 = 0.0 + q2 = 0.0 + else + phi = sin(2.0 * pi * x[1]) * sin(2.0 * pi * x[2]) + q1 = 2 * pi * cos(2.0 * pi * x[1]) * sin(2.0 * pi * x[2]) + q2 = 2 * pi * sin(2.0 * pi * x[1]) * cos(2.0 * pi * x[2]) + end + return SVector(phi, q1, q2) end initial_condition = initial_condition_poisson_periodic -@inline function source_terms_poisson_periodic(u, x, t, equations::HyperbolicDiffusionEquations2D) - # elliptic equation: -νΔϕ = f - # analytical solution: phi = sin(2πx)*sin(2πy) and f = -8νπ^2 sin(2πx)*sin(2πy) - @unpack inv_Tr = equations - C = -8 * equations.nu * pi^2 - - x1, x2 = x - tmp1 = sinpi(2 * x1) - tmp2 = sinpi(2 * x2) - du1 = -C*tmp1*tmp2 - du2 = -inv_Tr * u[2] - du3 = -inv_Tr * u[3] - - return SVector(du1, du2, du3) +@inline function source_terms_poisson_periodic(u, x, t, + equations::HyperbolicDiffusionEquations2D) + # elliptic equation: -νΔϕ = f + # analytical solution: phi = sin(2πx)*sin(2πy) and f = -8νπ^2 sin(2πx)*sin(2πy) + @unpack inv_Tr = equations + C = -8 * equations.nu * pi^2 + + x1, x2 = x + tmp1 = sinpi(2 * x1) + tmp2 = sinpi(2 * x2) + du1 = -C * tmp1 * tmp2 + du2 = -inv_Tr * u[2] + du3 = -inv_Tr * u[3] + + return SVector(du1, du2, du3) end -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0, 0.0) coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=30_000) - + initial_refinement_level = 3, + n_cells_max = 30_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_poisson_periodic) - + source_terms = source_terms_poisson_periodic) ############################################################################### # ODE solvers, callbacks etc. @@ -61,31 +60,30 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() resid_tol = 5.0e-12 -steady_state_callback = SteadyStateCallback(abstol=resid_tol, reltol=0.0) +steady_state_callback = SteadyStateCallback(abstol = resid_tol, reltol = 0.0) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy, energy_total)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy, energy_total)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.2) +stepsize_callback = StepsizeCallback(cfl = 1.2) callbacks = CallbackSet(summary_callback, steady_state_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) - ############################################################################### # run the simulation sol = Trixi.solve(ode, Trixi.HypDiffN3Erk3Sstar52(), - dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); + 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/tree_2d_dgsem/elixir_hypdiff_nonperiodic.jl b/examples/tree_2d_dgsem/elixir_hypdiff_nonperiodic.jl index fc825660f1e..1396481a3f1 100644 --- a/examples/tree_2d_dgsem/elixir_hypdiff_nonperiodic.jl +++ b/examples/tree_2d_dgsem/elixir_hypdiff_nonperiodic.jl @@ -9,25 +9,23 @@ equations = HyperbolicDiffusionEquations2D() initial_condition = initial_condition_poisson_nonperiodic # 1 => -x, 2 => +x, 3 => -y, 4 => +y as usual for orientations -boundary_conditions = (x_neg=boundary_condition_poisson_nonperiodic, - x_pos=boundary_condition_poisson_nonperiodic, - y_neg=boundary_condition_periodic, - y_pos=boundary_condition_periodic) +boundary_conditions = (x_neg = boundary_condition_poisson_nonperiodic, + x_pos = boundary_condition_poisson_nonperiodic, + y_neg = boundary_condition_periodic, + y_pos = boundary_condition_periodic) -solver = DGSEM(polydeg=4, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 4, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0, 0.0) coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=30_000, - periodicity=(false, true)) - + initial_refinement_level = 3, + n_cells_max = 30_000, + periodicity = (false, true)) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions, - source_terms=source_terms_poisson_nonperiodic) - + boundary_conditions = boundary_conditions, + source_terms = source_terms_poisson_nonperiodic) ############################################################################### # ODE solvers, callbacks etc. @@ -38,30 +36,29 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() resid_tol = 5.0e-12 -steady_state_callback = SteadyStateCallback(abstol=resid_tol, reltol=0.0) +steady_state_callback = SteadyStateCallback(abstol = resid_tol, reltol = 0.0) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, steady_state_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_2d_dgsem/elixir_kpp.jl b/examples/tree_2d_dgsem/elixir_kpp.jl index f3cbc1cb664..b48bde0d155 100644 --- a/examples/tree_2d_dgsem/elixir_kpp.jl +++ b/examples/tree_2d_dgsem/elixir_kpp.jl @@ -25,22 +25,25 @@ end @inline function Trixi.flux_ec(u_ll, u_rr, orientation::Integer, ::KPPEquation2D) # The tolerance of 1e-12 is based on experience and somewhat arbitrarily chosen if abs(u_ll[1] - u_rr[1]) < 1e-12 - return 0.5 * (flux(u_ll, orientation, KPPEquation2D()) + flux(u_rr, orientation, KPPEquation2D())) + return 0.5 * (flux(u_ll, orientation, KPPEquation2D()) + + flux(u_rr, orientation, KPPEquation2D())) else factor = 1.0 / (u_rr[1] - u_ll[1]) if orientation == 1 - return SVector(factor*(-cos(u_rr[1]) + cos(u_ll[1]))) + return SVector(factor * (-cos(u_rr[1]) + cos(u_ll[1]))) else - return SVector(factor*(sin(u_rr[1]) - sin(u_ll[1]))) + return SVector(factor * (sin(u_rr[1]) - sin(u_ll[1]))) end end end # Wavespeeds @inline wavespeed(::KPPEquation2D) = 1.0 -@inline Trixi.max_abs_speeds(u, equation::KPPEquation2D) = (wavespeed(equation), wavespeed(equation)) +@inline Trixi.max_abs_speeds(u, equation::KPPEquation2D) = (wavespeed(equation), + wavespeed(equation)) @inline Trixi.max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equation::KPPEquation2D) = wavespeed(equation) -@inline Trixi.max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, equation::KPPEquation2D) = wavespeed(equation) * norm(normal_direction) +@inline Trixi.max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, equation::KPPEquation2D) = wavespeed(equation) * + norm(normal_direction) # Compute entropy: we use the square entropy @inline Trixi.entropy(u::Real, ::KPPEquation2D) = 0.5 * u^2 @@ -74,24 +77,25 @@ volume_flux = flux_ec polydeg = 3 basis = LobattoLegendreBasis(polydeg) shock_indicator = IndicatorHennemannGassner(equation, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=first) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = first) volume_integral = VolumeIntegralShockCapturingHG(shock_indicator; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) -solver = DGSEM(polydeg=polydeg, surface_flux=surface_flux, volume_integral=volume_integral) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral) ############################################################################### # Set up the tree mesh (initially a Cartesian grid of [-2,2]^2) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=6, - periodicity=true, - n_cells_max=500_000) + initial_refinement_level = 6, + periodicity = true, + n_cells_max = 500_000) ############################################################################### # Create the semi discretization object @@ -100,23 +104,24 @@ semi = SemidiscretizationHyperbolic(mesh, equation, initial_condition_kpp, solve ############################################################################### # Set up adaptive mesh refinement amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=1.0, - alpha_min=0.0001, - alpha_smooth=false, - variable=first) + alpha_max = 1.0, + alpha_min = 0.0001, + alpha_smooth = false, + variable = first) max_refinement_level = 8 amr_controller = ControllerThreeLevelCombined(semi, amr_indicator, shock_indicator, - base_level=2, - med_level=0, med_threshold=0.0003, - max_level=max_refinement_level, max_threshold=0.003, - max_threshold_secondary=shock_indicator.alpha_max) + base_level = 2, + med_level = 0, med_threshold = 0.0003, + max_level = max_refinement_level, + max_threshold = 0.003, + max_threshold_secondary = shock_indicator.alpha_max) amr_callback = AMRCallback(semi, amr_controller, - interval=1, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 1, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) ############################################################################### # ODE solvers, callbacks etc. @@ -125,14 +130,14 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -analysis_callback = AnalysisCallback(semi, interval=200) +analysis_callback = AnalysisCallback(semi, interval = 200) -alive_callback = AliveCallback(analysis_interval=200) +alive_callback = AliveCallback(analysis_interval = 200) -save_solution = SaveSolutionCallback(interval=200, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2cons) +save_solution = SaveSolutionCallback(interval = 200, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2cons) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -140,6 +145,6 @@ callbacks = CallbackSet(summary_callback, ############################################################################### # run the simulation -sol = solve(ode, SSPRK43(); ode_default_options()..., callback=callbacks) +sol = solve(ode, SSPRK43(); ode_default_options()..., callback = callbacks) summary_callback() # Print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_lbm_constant.jl b/examples/tree_2d_dgsem/elixir_lbm_constant.jl index 40b16f41ef6..5a4f3074e4e 100644 --- a/examples/tree_2d_dgsem/elixir_lbm_constant.jl +++ b/examples/tree_2d_dgsem/elixir_lbm_constant.jl @@ -5,22 +5,20 @@ using Trixi ############################################################################### # semidiscretization of the Lattice-Boltzmann equations for the D2Q9 scheme -equations = LatticeBoltzmannEquations2D(Ma=0.1, Re=Inf) +equations = LatticeBoltzmannEquations2D(Ma = 0.1, Re = Inf) initial_condition = initial_condition_constant -solver = DGSEM(polydeg=3, surface_flux=flux_godunov) +solver = DGSEM(polydeg = 3, surface_flux = flux_godunov) coordinates_min = (-1.0, -1.0) -coordinates_max = ( 1.0, 1.0) +coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000,) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -30,19 +28,19 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2macroscopic) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2macroscopic) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) collision_callback = LBMCollisionCallback() @@ -52,11 +50,10 @@ callbacks = CallbackSet(summary_callback, stepsize_callback, collision_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); +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/tree_2d_dgsem/elixir_lbm_couette.jl b/examples/tree_2d_dgsem/elixir_lbm_couette.jl index 6a33b2fb0ee..1ba040405d1 100644 --- a/examples/tree_2d_dgsem/elixir_lbm_couette.jl +++ b/examples/tree_2d_dgsem/elixir_lbm_couette.jl @@ -5,7 +5,7 @@ using Trixi ############################################################################### # semidiscretization of the Lattice-Boltzmann equations for the D2Q9 scheme -equations = LatticeBoltzmannEquations2D(Ma=0.05, Re=2000) +equations = LatticeBoltzmannEquations2D(Ma = 0.05, Re = 2000) """ initial_condition_couette_unsteady(x, t, equations::LatticeBoltzmannEquations2D) @@ -16,19 +16,20 @@ incompressible Navier-Stokes equations. To be used in combination with this setup will converge to the state set in [`initial_condition_couette_steady`](@ref). """ function initial_condition_couette_unsteady(x, t, equations::LatticeBoltzmannEquations2D) - @unpack L, u0, rho0, nu = equations + @unpack L, u0, rho0, nu = equations - x1, x2 = x - v1 = u0*x2/L - for m in 1:100 - lambda_m = m * pi / L - v1 += 2 * u0 * (-1)^m/(lambda_m * L) * exp(-nu * lambda_m^2 * t) * sin(lambda_m * x2) - end + x1, x2 = x + v1 = u0 * x2 / L + for m in 1:100 + lambda_m = m * pi / L + v1 += 2 * u0 * (-1)^m / (lambda_m * L) * exp(-nu * lambda_m^2 * t) * + sin(lambda_m * x2) + end - rho = 1 - v2 = 0 + rho = 1 + v2 = 0 - return equilibrium_distribution(rho, v1, v2, equations) + return equilibrium_distribution(rho, v1, v2, equations) end initial_condition = initial_condition_couette_unsteady @@ -44,53 +45,49 @@ Moving *upper* wall boundary condition for a Couette flow setup. To be used in c function boundary_condition_couette(u_inner, orientation, direction, x, t, surface_flux_function, equations::LatticeBoltzmannEquations2D) - return boundary_condition_moving_wall_ypos(u_inner, orientation, direction, x, t, - surface_flux_function, equations) + return boundary_condition_moving_wall_ypos(u_inner, orientation, direction, x, t, + surface_flux_function, equations) end function boundary_condition_moving_wall_ypos(u_inner, orientation, direction, x, t, surface_flux_function, equations::LatticeBoltzmannEquations2D) - @assert direction == 4 "moving wall assumed in +y direction" + @assert direction==4 "moving wall assumed in +y direction" - @unpack rho0, u0, weights, c_s = equations - cs_squared = c_s^2 + @unpack rho0, u0, weights, c_s = equations + cs_squared = c_s^2 - pdf1 = u_inner[3] + 2 * weights[1] * rho0 * u0 / cs_squared - pdf2 = u_inner[2] # outgoing - pdf3 = u_inner[1] + 2 * weights[3] * rho0 * (-u0) / cs_squared - pdf4 = u_inner[2] - pdf5 = u_inner[5] # outgoing - pdf6 = u_inner[6] # outgoing - pdf7 = u_inner[5] + 2 * weights[7] * rho0 * (-u0) / cs_squared - pdf8 = u_inner[6] + 2 * weights[8] * rho0 * u0 / cs_squared - pdf9 = u_inner[9] + pdf1 = u_inner[3] + 2 * weights[1] * rho0 * u0 / cs_squared + pdf2 = u_inner[2] # outgoing + pdf3 = u_inner[1] + 2 * weights[3] * rho0 * (-u0) / cs_squared + pdf4 = u_inner[2] + pdf5 = u_inner[5] # outgoing + pdf6 = u_inner[6] # outgoing + pdf7 = u_inner[5] + 2 * weights[7] * rho0 * (-u0) / cs_squared + pdf8 = u_inner[6] + 2 * weights[8] * rho0 * u0 / cs_squared + pdf9 = u_inner[9] - u_boundary = SVector(pdf1, pdf2, pdf3, pdf4, pdf5, pdf6, pdf7, pdf8, pdf9) + u_boundary = SVector(pdf1, pdf2, pdf3, pdf4, pdf5, pdf6, pdf7, pdf8, pdf9) - # Calculate boundary flux (u_inner is "left" of boundary, u_boundary is "right" of boundary) - return surface_flux_function(u_inner, u_boundary, orientation, equations) + # Calculate boundary flux (u_inner is "left" of boundary, u_boundary is "right" of boundary) + return surface_flux_function(u_inner, u_boundary, orientation, equations) end -boundary_conditions = ( - x_neg=boundary_condition_periodic, - x_pos=boundary_condition_periodic, - y_neg=boundary_condition_noslip_wall, - y_pos=boundary_condition_couette, - ) +boundary_conditions = (x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_noslip_wall, + y_pos = boundary_condition_couette) -solver = DGSEM(polydeg=3, surface_flux=flux_godunov) +solver = DGSEM(polydeg = 3, surface_flux = flux_godunov) coordinates_min = (0.0, 0.0) coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - periodicity=(true, false), - n_cells_max=10_000,) - + initial_refinement_level = 3, + periodicity = (true, false), + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -101,26 +98,29 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) # Custom solution variables: normalize velocities by reference speed `u0` @inline function macroscopic_normalized(u, equations::LatticeBoltzmannEquations2D) - macroscopic = cons2macroscopic(u, equations) - rho, v1, v2, p = macroscopic + macroscopic = cons2macroscopic(u, equations) + rho, v1, v2, p = macroscopic - # Use `typeof(macroscopic)` to avoid having to explicitly add `using StaticArrays` - convert(typeof(macroscopic), (rho, v1/equations.u0, v2/equations.u0, p)) + # Use `typeof(macroscopic)` to avoid having to explicitly add `using StaticArrays` + convert(typeof(macroscopic), (rho, v1 / equations.u0, v2 / equations.u0, p)) +end +function Trixi.varnames(::typeof(macroscopic_normalized), + equations::LatticeBoltzmannEquations2D) + ("rho", "v1_normalized", "v2_normalized", "p") end -Trixi.varnames(::typeof(macroscopic_normalized), equations::LatticeBoltzmannEquations2D) = ("rho", "v1_normalized", "v2_normalized", "p") -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true, - solution_variables=macroscopic_normalized) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + solution_variables = macroscopic_normalized) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) collision_callback = LBMCollisionCallback() @@ -130,11 +130,10 @@ callbacks = CallbackSet(summary_callback, stepsize_callback, collision_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); +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/tree_2d_dgsem/elixir_lbm_lid_driven_cavity.jl b/examples/tree_2d_dgsem/elixir_lbm_lid_driven_cavity.jl index a34e784e7ac..d00926cafad 100644 --- a/examples/tree_2d_dgsem/elixir_lbm_lid_driven_cavity.jl +++ b/examples/tree_2d_dgsem/elixir_lbm_lid_driven_cavity.jl @@ -5,7 +5,7 @@ using Trixi ############################################################################### # semidiscretization of the Lattice-Boltzmann equations for the D2Q9 scheme -equations = LatticeBoltzmannEquations2D(Ma=0.1, Re=1000) +equations = LatticeBoltzmannEquations2D(Ma = 0.1, Re = 1000) """ initial_condition_lid_driven_cavity(x, t, equations::LatticeBoltzmannEquations2D) @@ -14,13 +14,13 @@ Initial state for a lid-driven cavity flow setup. To be used in combination with [`boundary_condition_lid_driven_cavity`](@ref) and [`boundary_condition_noslip_wall`](@ref). """ function initial_condition_lid_driven_cavity(x, t, equations::LatticeBoltzmannEquations2D) - @unpack L, u0, nu = equations + @unpack L, u0, nu = equations - rho = 1 - v1 = 0 - v2 = 0 + rho = 1 + v1 = 0 + v2 = 0 - return equilibrium_distribution(rho, v1, v2, equations) + return equilibrium_distribution(rho, v1, v2, equations) end initial_condition = initial_condition_lid_driven_cavity @@ -35,53 +35,49 @@ no-slip wall. To be used in combination with [`initial_condition_lid_driven_cavi function boundary_condition_lid_driven_cavity(u_inner, orientation, direction, x, t, surface_flux_function, equations::LatticeBoltzmannEquations2D) - return boundary_condition_moving_wall_ypos(u_inner, orientation, direction, x, t, - surface_flux_function, equations) + return boundary_condition_moving_wall_ypos(u_inner, orientation, direction, x, t, + surface_flux_function, equations) end function boundary_condition_moving_wall_ypos(u_inner, orientation, direction, x, t, surface_flux_function, equations::LatticeBoltzmannEquations2D) - @assert direction == 4 "moving wall assumed in +y direction" + @assert direction==4 "moving wall assumed in +y direction" - @unpack rho0, u0, weights, c_s = equations - cs_squared = c_s^2 + @unpack rho0, u0, weights, c_s = equations + cs_squared = c_s^2 - pdf1 = u_inner[3] + 2 * weights[1] * rho0 * u0 / cs_squared - pdf2 = u_inner[2] # outgoing - pdf3 = u_inner[1] + 2 * weights[3] * rho0 * (-u0) / cs_squared - pdf4 = u_inner[2] - pdf5 = u_inner[5] # outgoing - pdf6 = u_inner[6] # outgoing - pdf7 = u_inner[5] + 2 * weights[7] * rho0 * (-u0) / cs_squared - pdf8 = u_inner[6] + 2 * weights[8] * rho0 * u0 / cs_squared - pdf9 = u_inner[9] + pdf1 = u_inner[3] + 2 * weights[1] * rho0 * u0 / cs_squared + pdf2 = u_inner[2] # outgoing + pdf3 = u_inner[1] + 2 * weights[3] * rho0 * (-u0) / cs_squared + pdf4 = u_inner[2] + pdf5 = u_inner[5] # outgoing + pdf6 = u_inner[6] # outgoing + pdf7 = u_inner[5] + 2 * weights[7] * rho0 * (-u0) / cs_squared + pdf8 = u_inner[6] + 2 * weights[8] * rho0 * u0 / cs_squared + pdf9 = u_inner[9] - u_boundary = SVector(pdf1, pdf2, pdf3, pdf4, pdf5, pdf6, pdf7, pdf8, pdf9) + u_boundary = SVector(pdf1, pdf2, pdf3, pdf4, pdf5, pdf6, pdf7, pdf8, pdf9) - # Calculate boundary flux (u_inner is "left" of boundary, u_boundary is "right" of boundary) - return surface_flux_function(u_inner, u_boundary, orientation, equations) + # Calculate boundary flux (u_inner is "left" of boundary, u_boundary is "right" of boundary) + return surface_flux_function(u_inner, u_boundary, orientation, equations) end -boundary_conditions = ( - x_neg=boundary_condition_noslip_wall, - x_pos=boundary_condition_noslip_wall, - y_neg=boundary_condition_noslip_wall, - y_pos=boundary_condition_lid_driven_cavity, - ) +boundary_conditions = (x_neg = boundary_condition_noslip_wall, + x_pos = boundary_condition_noslip_wall, + y_neg = boundary_condition_noslip_wall, + y_pos = boundary_condition_lid_driven_cavity) -solver = DGSEM(polydeg=5, surface_flux=flux_godunov) +solver = DGSEM(polydeg = 5, surface_flux = flux_godunov) coordinates_min = (0.0, 0.0) coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - periodicity=false, - n_cells_max=10_000,) - + initial_refinement_level = 4, + periodicity = false, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -92,16 +88,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2macroscopic) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2macroscopic) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) collision_callback = LBMCollisionCallback() @@ -111,11 +107,10 @@ callbacks = CallbackSet(summary_callback, stepsize_callback, collision_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); +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/tree_2d_dgsem/elixir_linearizedeuler_convergence.jl b/examples/tree_2d_dgsem/elixir_linearizedeuler_convergence.jl index 14459fa4cb8..93272833b74 100644 --- a/examples/tree_2d_dgsem/elixir_linearizedeuler_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_linearizedeuler_convergence.jl @@ -4,25 +4,25 @@ using Trixi ############################################################################### # semidiscretization of the linearized Euler equations -equations = LinearizedEulerEquations2D(v_mean_global=(0.0, 0.0), c_mean_global=1.0, rho_mean_global=1.0) +equations = LinearizedEulerEquations2D(v_mean_global = (0.0, 0.0), c_mean_global = 1.0, + rho_mean_global = 1.0) initial_condition = initial_condition_convergence_test # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) -coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) +coordinates_max = (1.0, 1.0) # maximum coordinates (max(x), max(y)) # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=30_000) + initial_refinement_level = 4, + n_cells_max = 30_000) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -37,28 +37,29 @@ summary_callback = SummaryCallback() analysis_interval = 100 # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) # The SaveSolutionCallback allows to save the solution to a file in regular intervals -save_solution = SaveSolutionCallback(interval=analysis_interval, solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = analysis_interval, + solution_variables = cons2prim) # The AliveCallback prints short status information in regular intervals -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) # The StepsizeCallback handles the re-calculation of the maximum Δt after each time step -stepsize_callback = StepsizeCallback(cfl=0.8) +stepsize_callback = StepsizeCallback(cfl = 0.8) # 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, alive_callback, stepsize_callback) - +callbacks = CallbackSet(summary_callback, analysis_callback, save_solution, alive_callback, + 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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # print the timer summary summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_linearizedeuler_gauss_wall.jl b/examples/tree_2d_dgsem/elixir_linearizedeuler_gauss_wall.jl index 14fe201a291..fad03fab6ef 100644 --- a/examples/tree_2d_dgsem/elixir_linearizedeuler_gauss_wall.jl +++ b/examples/tree_2d_dgsem/elixir_linearizedeuler_gauss_wall.jl @@ -5,33 +5,32 @@ using Trixi ############################################################################### # semidiscretization of the linearized Euler equations -equations = LinearizedEulerEquations2D(v_mean_global=(0.5, 0.0), c_mean_global=1.0, - rho_mean_global=1.0) +equations = LinearizedEulerEquations2D(v_mean_global = (0.5, 0.0), c_mean_global = 1.0, + rho_mean_global = 1.0) # Create DG solver with polynomial degree = 5 and upwind flux as surface flux -solver = DGSEM(polydeg=5, surface_flux=flux_godunov) +solver = DGSEM(polydeg = 5, surface_flux = flux_godunov) coordinates_min = (-100.0, 0.0) # minimum coordinates (min(x), min(y)) coordinates_max = (100.0, 200.0) # maximum coordinates (max(x), max(y)) # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=100_000, - periodicity=false) + initial_refinement_level = 4, + n_cells_max = 100_000, + periodicity = false) function initial_condition_gauss_wall(x, t, equations::LinearizedEulerEquations2D) - v1_prime = 0.0 - v2_prime = 0.0 - rho_prime = p_prime = exp(-log(2) * (x[1]^2 + (x[2] - 25)^2) / 25) - return SVector(rho_prime, v1_prime, v2_prime, p_prime) + v1_prime = 0.0 + v2_prime = 0.0 + rho_prime = p_prime = exp(-log(2) * (x[1]^2 + (x[2] - 25)^2) / 25) + return SVector(rho_prime, v1_prime, v2_prime, p_prime) end initial_condition = initial_condition_gauss_wall # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_condition_wall) - + boundary_conditions = boundary_condition_wall) ############################################################################### # ODE solvers, callbacks etc. @@ -45,24 +44,25 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +analysis_callback = AnalysisCallback(semi, interval = 100) # The SaveSolutionCallback allows to save the solution to a file in regular intervals -save_solution = SaveSolutionCallback(interval=100) +save_solution = SaveSolutionCallback(interval = 100) # The StepsizeCallback handles the re-calculation of the maximum Δt after each time step -stepsize_callback = StepsizeCallback(cfl=0.7) +stepsize_callback = StepsizeCallback(cfl = 0.7) # 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) +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks) +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) # Print the timer summary summary_callback() diff --git a/examples/tree_2d_dgsem/elixir_mhd_alfven_wave.jl b/examples/tree_2d_dgsem/elixir_mhd_alfven_wave.jl index d9e59160e7d..377a07e947e 100644 --- a/examples/tree_2d_dgsem/elixir_mhd_alfven_wave.jl +++ b/examples/tree_2d_dgsem/elixir_mhd_alfven_wave.jl @@ -4,25 +4,24 @@ using Trixi ############################################################################### # semidiscretization of the compressible ideal GLM-MHD equations -gamma = 5/3 +gamma = 5 / 3 equations = IdealGlmMhdEquations2D(gamma) initial_condition = initial_condition_convergence_test volume_flux = (flux_central, flux_nonconservative_powell) -solver = DGSEM(polydeg=3, surface_flux=(flux_lax_friedrichs, flux_nonconservative_powell), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, + surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (0.0, 0.0) coordinates_max = (sqrt(2.0), sqrt(2.0)) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -32,22 +31,25 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=true, - extra_analysis_integrals=(entropy, energy_total, - energy_kinetic, energy_internal, - energy_magnetic, cross_helicity)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_integrals = (entropy, energy_total, + energy_kinetic, + energy_internal, + energy_magnetic, + cross_helicity)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=10, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 10, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) cfl = 1.5 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -56,11 +58,10 @@ callbacks = CallbackSet(summary_callback, stepsize_callback, glm_speed_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); +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/tree_2d_dgsem/elixir_mhd_alfven_wave_mortar.jl b/examples/tree_2d_dgsem/elixir_mhd_alfven_wave_mortar.jl index 11dfeacde6a..229360f266e 100644 --- a/examples/tree_2d_dgsem/elixir_mhd_alfven_wave_mortar.jl +++ b/examples/tree_2d_dgsem/elixir_mhd_alfven_wave_mortar.jl @@ -4,25 +4,23 @@ using Trixi ############################################################################### # semidiscretization of the compressible ideal GLM-MHD equations -gamma = 5/3 +gamma = 5 / 3 equations = IdealGlmMhdEquations2D(gamma) initial_condition = initial_condition_convergence_test volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -solver = DGSEM(polydeg=3, surface_flux=(flux_hll, flux_nonconservative_powell), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = (flux_hll, flux_nonconservative_powell), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (0.0, 0.0) coordinates_max = (sqrt(2.0), sqrt(2.0)) -refinement_patches = ( - (type="box", coordinates_min=0.25 .* coordinates_max, - coordinates_max=0.75 .* coordinates_max), -) +refinement_patches = ((type = "box", coordinates_min = 0.25 .* coordinates_max, + coordinates_max = 0.75 .* coordinates_max),) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - refinement_patches=refinement_patches, - n_cells_max=10_000,) + initial_refinement_level = 4, + refinement_patches = refinement_patches, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -35,22 +33,25 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=true, - extra_analysis_integrals=(entropy, energy_total, - energy_kinetic, energy_internal, - energy_magnetic, cross_helicity)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_integrals = (entropy, energy_total, + energy_kinetic, + energy_internal, + energy_magnetic, + cross_helicity)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=10, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 10, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) cfl = 1.0 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -62,7 +63,7 @@ callbacks = CallbackSet(summary_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); +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/tree_2d_dgsem/elixir_mhd_blast_wave.jl b/examples/tree_2d_dgsem/elixir_mhd_blast_wave.jl index af05fffaf54..a0909ca7580 100644 --- a/examples/tree_2d_dgsem/elixir_mhd_blast_wave.jl +++ b/examples/tree_2d_dgsem/elixir_mhd_blast_wave.jl @@ -16,52 +16,50 @@ An MHD blast wave taken from [doi: 10.1365/s13291-018-0178-9](https://doi.org/10.1365/s13291-018-0178-9) """ function initial_condition_blast_wave(x, t, equations::IdealGlmMhdEquations2D) - # setup taken from Derigs et al. DMV article (2018) - # domain must be [-0.5, 0.5] x [-0.5, 0.5], γ = 1.4 - r = sqrt(x[1]^2 + x[2]^2) - f = (0.1 - r)/0.01 - if r <= 0.09 - p = 1000.0 - elseif r >= 0.1 - p = 0.1 - else - p = 0.1 + 999.9*f - end - rho = 1.0 - v1 = 0.0 - v2 = 0.0 - v3 = 0.0 - B1 = 100.0/sqrt(4.0*pi) - B2 = 0.0 - B3 = 0.0 - psi = 0.0 - return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3, psi), equations) + # setup taken from Derigs et al. DMV article (2018) + # domain must be [-0.5, 0.5] x [-0.5, 0.5], γ = 1.4 + r = sqrt(x[1]^2 + x[2]^2) + f = (0.1 - r) / 0.01 + if r <= 0.09 + p = 1000.0 + elseif r >= 0.1 + p = 0.1 + else + p = 0.1 + 999.9 * f + end + rho = 1.0 + v1 = 0.0 + v2 = 0.0 + v3 = 0.0 + B1 = 100.0 / sqrt(4.0 * pi) + B2 = 0.0 + B3 = 0.0 + psi = 0.0 + return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3, psi), equations) end initial_condition = initial_condition_blast_wave surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell) -volume_flux = (flux_central, flux_nonconservative_powell) +volume_flux = (flux_central, flux_nonconservative_powell) basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-0.5, -0.5) -coordinates_max = ( 0.5, 0.5) +coordinates_max = (0.5, 0.5) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -71,32 +69,32 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=false, - variable=density_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = false, + variable = density_pressure) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=4, - max_level =6, max_threshold=0.01) + base_level = 4, + max_level = 6, max_threshold = 0.01) amr_callback = AMRCallback(semi, amr_controller, - interval=7, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 7, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) cfl = 0.8 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -109,7 +107,7 @@ callbacks = CallbackSet(summary_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); +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/tree_2d_dgsem/elixir_mhd_ec.jl b/examples/tree_2d_dgsem/elixir_mhd_ec.jl index 5873388f798..173d3ed448f 100644 --- a/examples/tree_2d_dgsem/elixir_mhd_ec.jl +++ b/examples/tree_2d_dgsem/elixir_mhd_ec.jl @@ -10,19 +10,18 @@ equations = IdealGlmMhdEquations2D(1.4) initial_condition = initial_condition_weak_blast_wave volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -solver = DGSEM(polydeg=3, surface_flux=(flux_hindenlang_gassner, flux_nonconservative_powell), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, + surface_flux = (flux_hindenlang_gassner, flux_nonconservative_powell), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -32,19 +31,19 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=10, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 10, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) cfl = 1.0 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -53,11 +52,10 @@ callbacks = CallbackSet(summary_callback, stepsize_callback, glm_speed_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); +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/tree_2d_dgsem/elixir_mhd_orszag_tang.jl b/examples/tree_2d_dgsem/elixir_mhd_orszag_tang.jl index 460b24e02b2..7f26f270d6e 100644 --- a/examples/tree_2d_dgsem/elixir_mhd_orszag_tang.jl +++ b/examples/tree_2d_dgsem/elixir_mhd_orszag_tang.jl @@ -4,7 +4,7 @@ using Trixi ############################################################################### # semidiscretization of the compressible ideal GLM-MHD equations -gamma = 5/3 +gamma = 5 / 3 equations = IdealGlmMhdEquations2D(gamma) """ @@ -16,44 +16,42 @@ The classical Orszag-Tang vortex test case. Here, the setup is taken from [doi: 10.1365/s13291-018-0178-9](https://doi.org/10.1365/s13291-018-0178-9) """ function initial_condition_orszag_tang(x, t, equations::IdealGlmMhdEquations2D) - # setup taken from Derigs et al. DMV article (2018) - # domain must be [0, 1] x [0, 1], γ = 5/3 - rho = 1.0 - v1 = -sin(2.0*pi*x[2]) - v2 = sin(2.0*pi*x[1]) - v3 = 0.0 - p = 1.0 / equations.gamma - B1 = -sin(2.0*pi*x[2]) / equations.gamma - B2 = sin(4.0*pi*x[1]) / equations.gamma - B3 = 0.0 - psi = 0.0 - return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3, psi), equations) + # setup taken from Derigs et al. DMV article (2018) + # domain must be [0, 1] x [0, 1], γ = 5/3 + rho = 1.0 + v1 = -sin(2.0 * pi * x[2]) + v2 = sin(2.0 * pi * x[1]) + v3 = 0.0 + p = 1.0 / equations.gamma + B1 = -sin(2.0 * pi * x[2]) / equations.gamma + B2 = sin(4.0 * pi * x[1]) / equations.gamma + B3 = 0.0 + psi = 0.0 + return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3, psi), equations) end initial_condition = initial_condition_orszag_tang surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell) -volume_flux = (flux_central, flux_nonconservative_powell) +volume_flux = (flux_central, flux_nonconservative_powell) basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (0.0, 0.0) coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -63,32 +61,32 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=false, - variable=density_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = false, + variable = density_pressure) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=4, - max_level =6, max_threshold=0.01) + base_level = 4, + max_level = 6, max_threshold = 0.01) amr_callback = AMRCallback(semi, amr_controller, - interval=6, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 6, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) cfl = 1.25 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -101,7 +99,7 @@ callbacks = CallbackSet(summary_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); +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/tree_2d_dgsem/elixir_mhd_rotor.jl b/examples/tree_2d_dgsem/elixir_mhd_rotor.jl index c6d880e9e9d..3109b1ce303 100644 --- a/examples/tree_2d_dgsem/elixir_mhd_rotor.jl +++ b/examples/tree_2d_dgsem/elixir_mhd_rotor.jl @@ -2,7 +2,6 @@ using OrdinaryDiffEq using Trixi - ############################################################################### # semidiscretization of the compressible ideal GLM-MHD equations equations = IdealGlmMhdEquations2D(1.4) @@ -16,59 +15,57 @@ The classical MHD rotor test case. Here, the setup is taken from [doi: 10.1365/s13291-018-0178-9](https://doi.org/10.1365/s13291-018-0178-9) """ function initial_condition_rotor(x, t, equations::IdealGlmMhdEquations2D) - # setup taken from Derigs et al. DMV article (2018) - # domain must be [0, 1] x [0, 1], γ = 1.4 - dx = x[1] - 0.5 - dy = x[2] - 0.5 - r = sqrt(dx^2 + dy^2) - f = (0.115 - r)/0.015 - if r <= 0.1 - rho = 10.0 - v1 = -20.0*dy - v2 = 20.0*dx - elseif r >= 0.115 - rho = 1.0 - v1 = 0.0 - v2 = 0.0 - else - rho = 1.0 + 9.0*f - v1 = -20.0*f*dy - v2 = 20.0*f*dx - end - v3 = 0.0 - p = 1.0 - B1 = 5.0/sqrt(4.0*pi) - B2 = 0.0 - B3 = 0.0 - psi = 0.0 - return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3, psi), equations) + # setup taken from Derigs et al. DMV article (2018) + # domain must be [0, 1] x [0, 1], γ = 1.4 + dx = x[1] - 0.5 + dy = x[2] - 0.5 + r = sqrt(dx^2 + dy^2) + f = (0.115 - r) / 0.015 + if r <= 0.1 + rho = 10.0 + v1 = -20.0 * dy + v2 = 20.0 * dx + elseif r >= 0.115 + rho = 1.0 + v1 = 0.0 + v2 = 0.0 + else + rho = 1.0 + 9.0 * f + v1 = -20.0 * f * dy + v2 = 20.0 * f * dx + end + v3 = 0.0 + p = 1.0 + B1 = 5.0 / sqrt(4.0 * pi) + B2 = 0.0 + B3 = 0.0 + psi = 0.0 + return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3, psi), equations) end initial_condition = initial_condition_rotor surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell) -volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) +volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) polydeg = 4 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (0.0, 0.0) coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -78,32 +75,32 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=false, - variable=density_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = false, + variable = density_pressure) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=4, - max_level =6, max_threshold=0.01) + base_level = 4, + max_level = 6, max_threshold = 0.01) amr_callback = AMRCallback(semi, amr_controller, - interval=6, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 6, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) cfl = 0.35 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -116,7 +113,7 @@ callbacks = CallbackSet(summary_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); +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/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl b/examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl index f40da6676c2..b2cdff2ab53 100644 --- a/examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl +++ b/examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl @@ -17,57 +17,55 @@ An MHD blast wave modified from: This setup needs a positivity limiter for the density. """ function initial_condition_blast_wave(x, t, equations::IdealGlmMhdEquations2D) - # setup taken from Derigs et al. DMV article (2018) - # domain must be [-0.5, 0.5] x [-0.5, 0.5], γ = 1.4 - r = sqrt(x[1]^2 + x[2]^2) - - pmax = 10.0 - pmin = 1.0 - rhomax = 1.0 - rhomin = 0.01 - if r <= 0.09 - p = pmax - rho = rhomax - elseif r >= 0.1 - p = pmin - rho = rhomin - else - p = pmin + (0.1 - r) * (pmax - pmin) / 0.01 - rho = rhomin + (0.1 - r) * (rhomax - rhomin) / 0.01 - end - v1 = 0.0 - v2 = 0.0 - v3 = 0.0 - B1 = 1.0/sqrt(4.0*pi) - B2 = 0.0 - B3 = 0.0 - psi = 0.0 - return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3, psi), equations) + # setup taken from Derigs et al. DMV article (2018) + # domain must be [-0.5, 0.5] x [-0.5, 0.5], γ = 1.4 + r = sqrt(x[1]^2 + x[2]^2) + + pmax = 10.0 + pmin = 1.0 + rhomax = 1.0 + rhomin = 0.01 + if r <= 0.09 + p = pmax + rho = rhomax + elseif r >= 0.1 + p = pmin + rho = rhomin + else + p = pmin + (0.1 - r) * (pmax - pmin) / 0.01 + rho = rhomin + (0.1 - r) * (rhomax - rhomin) / 0.01 + end + v1 = 0.0 + v2 = 0.0 + v3 = 0.0 + B1 = 1.0 / sqrt(4.0 * pi) + B2 = 0.0 + B3 = 0.0 + psi = 0.0 + return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3, psi), equations) end initial_condition = initial_condition_blast_wave surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell_local_symmetric) -volume_flux = (flux_derigs_etal, flux_nonconservative_powell_local_symmetric) +volume_flux = (flux_derigs_etal, flux_nonconservative_powell_local_symmetric) basis = LobattoLegendreBasis(3) limiter_idp = SubcellLimiterIDP(equations, basis; - positivity_variables_cons=[1], - positivity_correction_factor=0.5) + positivity_variables_cons = [1], + positivity_correction_factor = 0.5) volume_integral = VolumeIntegralSubcellLimiting(limiter_idp; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-0.5, -0.5) -coordinates_max = ( 0.5, 0.5) +coordinates_max = (0.5, 0.5) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -77,19 +75,19 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) cfl = 0.5 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -102,7 +100,7 @@ callbacks = CallbackSet(summary_callback, # run the simulation stage_callbacks = (SubcellLimiterIDPCorrection(), BoundsCheckCallback()) -sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks=stage_callbacks); - dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks = stage_callbacks); + 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/tree_2d_dgsem/elixir_mhdmulti_convergence.jl b/examples/tree_2d_dgsem/elixir_mhdmulti_convergence.jl index a7551f48937..4f1f8c5f2b7 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmulti_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmulti_convergence.jl @@ -5,25 +5,24 @@ using Trixi ############################################################################### # semidiscretization of the compressible ideal GLM-MHD equations -equations = IdealGlmMhdMulticomponentEquations2D(gammas = (5/3, 5/3, 5/3), - gas_constants = (2.08, 2.08, 2.08)) +equations = IdealGlmMhdMulticomponentEquations2D(gammas = (5 / 3, 5 / 3, 5 / 3), + gas_constants = (2.08, 2.08, 2.08)) initial_condition = initial_condition_convergence_test volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -solver = DGSEM(polydeg=3, surface_flux=(flux_lax_friedrichs, flux_nonconservative_powell), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, + surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (0.0, 0.0) coordinates_max = (sqrt(2), sqrt(2)) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=10_000) - + initial_refinement_level = 2, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -33,19 +32,20 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=true) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=10, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 10, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) cfl = 1.0 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -54,11 +54,10 @@ callbacks = CallbackSet(summary_callback, stepsize_callback, glm_speed_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); +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/tree_2d_dgsem/elixir_mhdmulti_ec.jl b/examples/tree_2d_dgsem/elixir_mhdmulti_ec.jl index ec2f3c21cdd..a7db9eeee96 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmulti_ec.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmulti_ec.jl @@ -5,25 +5,24 @@ using Trixi ############################################################################### # semidiscretization of the compressible ideal GLM-MHD equations -equations = IdealGlmMhdMulticomponentEquations2D(gammas = (1.4, 1.4), - gas_constants = (1.0, 1.0)) +equations = IdealGlmMhdMulticomponentEquations2D(gammas = (1.4, 1.4), + gas_constants = (1.0, 1.0)) initial_condition = initial_condition_weak_blast_wave volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -solver = DGSEM(polydeg=3, surface_flux=(flux_hindenlang_gassner, flux_nonconservative_powell), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, + surface_flux = (flux_hindenlang_gassner, flux_nonconservative_powell), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -33,19 +32,19 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=10, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 10, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) cfl = 1.0 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -54,11 +53,10 @@ callbacks = CallbackSet(summary_callback, stepsize_callback, glm_speed_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); +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/tree_2d_dgsem/elixir_mhdmulti_es.jl b/examples/tree_2d_dgsem/elixir_mhdmulti_es.jl index 3cd9c621ae3..fcaabdc7a58 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmulti_es.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmulti_es.jl @@ -5,25 +5,24 @@ using Trixi ############################################################################### # semidiscretization of the compressible ideal GLM-MHD equations -equations = IdealGlmMhdMulticomponentEquations2D(gammas = (5/3, 5/3), - gas_constants = (0.2, 0.2)) +equations = IdealGlmMhdMulticomponentEquations2D(gammas = (5 / 3, 5 / 3), + gas_constants = (0.2, 0.2)) initial_condition = initial_condition_weak_blast_wave volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -solver = DGSEM(polydeg=3, surface_flux=(flux_lax_friedrichs, flux_nonconservative_powell), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, + surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -33,19 +32,19 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=10, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 10, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) cfl = 1.0 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -54,11 +53,10 @@ callbacks = CallbackSet(summary_callback, stepsize_callback, glm_speed_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); +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/tree_2d_dgsem/elixir_mhdmulti_rotor.jl b/examples/tree_2d_dgsem/elixir_mhdmulti_rotor.jl index 55a4004f794..5ca21cc5e9c 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmulti_rotor.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmulti_rotor.jl @@ -2,10 +2,9 @@ using OrdinaryDiffEq using Trixi - ############################################################################### # semidiscretization of the compressible ideal GLM-MHD equations -equations = IdealGlmMhdMulticomponentEquations2D(gammas = (1.4, 1.4), +equations = IdealGlmMhdMulticomponentEquations2D(gammas = (1.4, 1.4), gas_constants = (1.0, 1.0)) """ @@ -14,62 +13,60 @@ equations = IdealGlmMhdMulticomponentEquations2D(gammas = (1.4, 1.4), The classical MHD rotor test case adapted to two density components. """ function initial_condition_rotor(x, t, equations::IdealGlmMhdMulticomponentEquations2D) - # setup taken from Derigs et al. DMV article (2018) - # domain must be [0, 1] x [0, 1], γ = 1.4 - dx = x[1] - 0.5 - dy = x[2] - 0.5 - r = sqrt(dx^2 + dy^2) - f = (0.115 - r)/0.015 - if r <= 0.1 - rho1 = 10.0 - rho2 = 5.0 - v1 = -20.0*dy - v2 = 20.0*dx - elseif r >= 0.115 - rho1 = 1.0 - rho2 = 0.5 - v1 = 0.0 - v2 = 0.0 - else - rho1 = 1.0 + 9.0*f - rho2 = 0.5 + 4.5*f - v1 = -20.0*f*dy - v2 = 20.0*f*dx - end - v3 = 0.0 - p = 1.0 - B1 = 5.0/sqrt(4.0*pi) - B2 = 0.0 - B3 = 0.0 - psi = 0.0 - return prim2cons(SVector(v1, v2, v3, p, B1, B2, B3, psi, rho1, rho2), equations) + # setup taken from Derigs et al. DMV article (2018) + # domain must be [0, 1] x [0, 1], γ = 1.4 + dx = x[1] - 0.5 + dy = x[2] - 0.5 + r = sqrt(dx^2 + dy^2) + f = (0.115 - r) / 0.015 + if r <= 0.1 + rho1 = 10.0 + rho2 = 5.0 + v1 = -20.0 * dy + v2 = 20.0 * dx + elseif r >= 0.115 + rho1 = 1.0 + rho2 = 0.5 + v1 = 0.0 + v2 = 0.0 + else + rho1 = 1.0 + 9.0 * f + rho2 = 0.5 + 4.5 * f + v1 = -20.0 * f * dy + v2 = 20.0 * f * dx + end + v3 = 0.0 + p = 1.0 + B1 = 5.0 / sqrt(4.0 * pi) + B2 = 0.0 + B3 = 0.0 + psi = 0.0 + return prim2cons(SVector(v1, v2, v3, p, B1, B2, B3, psi, rho1, rho2), equations) end initial_condition = initial_condition_rotor surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell) -volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) +volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) polydeg = 3 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.8, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.8, + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (0.0, 0.0) coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -79,32 +76,32 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=false, - variable=density_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = false, + variable = density_pressure) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=4, - max_level =6, max_threshold=0.01) + base_level = 4, + max_level = 6, max_threshold = 0.01) amr_callback = AMRCallback(semi, amr_controller, - interval=6, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 6, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) cfl = 1.0 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -117,7 +114,7 @@ callbacks = CallbackSet(summary_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); +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/tree_2d_dgsem/elixir_navierstokes_convergence.jl b/examples/tree_2d_dgsem/elixir_navierstokes_convergence.jl index b68e9e6c97e..57558224854 100644 --- a/examples/tree_2d_dgsem/elixir_navierstokes_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_navierstokes_convergence.jl @@ -8,163 +8,170 @@ prandtl_number() = 0.72 mu() = 0.01 equations = CompressibleEulerEquations2D(1.4) -equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu=mu(), Prandtl=prandtl_number(), - gradient_variables=GradientVariablesPrimitive()) +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu = mu(), + Prandtl = prandtl_number(), + gradient_variables = GradientVariablesPrimitive()) # 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, - volume_integral=VolumeIntegralWeakForm()) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralWeakForm()) coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) -coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) +coordinates_max = (1.0, 1.0) # maximum coordinates (max(x), max(y)) # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - periodicity=(true, false), - n_cells_max=30_000) # set maximum capacity of tree data structure + initial_refinement_level = 4, + periodicity = (true, false), + n_cells_max = 30_000) # set maximum capacity of tree data structure # Note: the initial condition cannot be specialized to `CompressibleNavierStokesDiffusion2D` # since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesDiffusion2D`) # and by the initial condition (which passes in `CompressibleEulerEquations2D`). # This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) function initial_condition_navier_stokes_convergence_test(x, t, equations) - # Amplitude and shift - A = 0.5 - c = 2.0 + # Amplitude and shift + A = 0.5 + c = 2.0 - # convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_t = pi * t + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t - rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) - v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0)) ) * cos(pi_t) - v2 = v1 - p = rho^2 + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0))) * cos(pi_t) + v2 = v1 + p = rho^2 - return prim2cons(SVector(rho, v1, v2, p), equations) + return prim2cons(SVector(rho, v1, v2, p), equations) end @inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) - y = x[2] - - # TODO: parabolic - # we currently need to hardcode these parameters until we fix the "combined equation" issue - # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 - inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = prandtl_number() - mu_ = mu() - - # Same settings as in `initial_condition` - # Amplitude and shift - A = 0.5 - c = 2.0 - - # convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_t = pi * t - - # compute the manufactured solution and all necessary derivatives - rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) - rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) - rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) - rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) - rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) - rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) - - v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) - v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_y = sin(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) - v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_xy = pi * cos(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) - v1_yy = (sin(pi_x) * ( 2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) - - A * A * log(y + 2.0) * exp(-A * (y - 1.0)) - - (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) - v2 = v1 - v2_t = v1_t - v2_x = v1_x - v2_y = v1_y - v2_xx = v1_xx - v2_xy = v1_xy - v2_yy = v1_yy - - p = rho * rho - p_t = 2.0 * rho * rho_t - p_x = 2.0 * rho * rho_x - p_y = 2.0 * rho * rho_y - p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x - p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y - - # Note this simplifies slightly because the ansatz assumes that v1 = v2 - E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) - E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t - E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x - E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y - - # Some convenience constants - T_const = equations.gamma * inv_gamma_minus_one / Pr - inv_rho_cubed = 1.0 / (rho^3) - - # compute the source terms - # density equation - du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y - - # x-momentum equation - du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 - + 2.0 * rho * v1 * v1_x - + rho_y * v1 * v2 - + rho * v1_y * v2 - + rho * v1 * v2_y - # stress tensor from x-direction - - 4.0 / 3.0 * v1_xx * mu_ - + 2.0 / 3.0 * v2_xy * mu_ - - v1_yy * mu_ - - v2_xy * mu_ ) - # y-momentum equation - du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 - + rho * v1_x * v2 - + rho * v1 * v2_x - + rho_y * v2^2 - + 2.0 * rho * v2 * v2_y - # stress tensor from y-direction - - v1_xy * mu_ - - v2_xx * mu_ - - 4.0 / 3.0 * v2_yy * mu_ - + 2.0 / 3.0 * v1_xy * mu_ ) - # total energy equation - du4 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) - + v2_y * (E + p) + v2 * (E_y + p_y) - # stress tensor and temperature gradient terms from x-direction - - 4.0 / 3.0 * v1_xx * v1 * mu_ - + 2.0 / 3.0 * v2_xy * v1 * mu_ - - 4.0 / 3.0 * v1_x * v1_x * mu_ - + 2.0 / 3.0 * v2_y * v1_x * mu_ - - v1_xy * v2 * mu_ - - v2_xx * v2 * mu_ - - v1_y * v2_x * mu_ - - v2_x * v2_x * mu_ - - T_const * inv_rho_cubed * ( p_xx * rho * rho - - 2.0 * p_x * rho * rho_x - + 2.0 * p * rho_x * rho_x - - p * rho * rho_xx ) * mu_ - # stress tensor and temperature gradient terms from y-direction - - v1_yy * v1 * mu_ - - v2_xy * v1 * mu_ - - v1_y * v1_y * mu_ - - v2_x * v1_y * mu_ - - 4.0 / 3.0 * v2_yy * v2 * mu_ - + 2.0 / 3.0 * v1_xy * v2 * mu_ - - 4.0 / 3.0 * v2_y * v2_y * mu_ - + 2.0 / 3.0 * v1_x * v2_y * mu_ - - T_const * inv_rho_cubed * ( p_yy * rho * rho - - 2.0 * p_y * rho * rho_y - + 2.0 * p * rho_y * rho_y - - p * rho * rho_yy ) * mu_ ) - - return SVector(du1, du2, du3, du4) + y = x[2] + + # TODO: parabolic + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + mu_ = mu() + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) + rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) + rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) + rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + + v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) + v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_y = sin(pi_x) * + (A * log(y + 2.0) * exp(-A * (y - 1.0)) + + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_xy = pi * cos(pi_x) * + (A * log(y + 2.0) * exp(-A * (y - 1.0)) + + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_yy = (sin(pi_x) * + (2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) - + A * A * log(y + 2.0) * exp(-A * (y - 1.0)) - + (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_xx = v1_xx + v2_xy = v1_xy + v2_yy = v1_yy + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y + + # Note this simplifies slightly because the ansatz assumes that v1 = v2 + E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) + E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x + E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one / Pr + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y + + # x-momentum equation + du2 = (rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y - + # stress tensor from x-direction + 4.0 / 3.0 * v1_xx * mu_ + + 2.0 / 3.0 * v2_xy * mu_ - + v1_yy * mu_ - + v2_xy * mu_) + # y-momentum equation + du3 = (rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y - + # stress tensor from y-direction + v1_xy * mu_ - + v2_xx * mu_ - + 4.0 / 3.0 * v2_yy * mu_ + + 2.0 / 3.0 * v1_xy * mu_) + # total energy equation + du4 = (E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) - + # stress tensor and temperature gradient terms from x-direction + 4.0 / 3.0 * v1_xx * v1 * mu_ + + 2.0 / 3.0 * v2_xy * v1 * mu_ - + 4.0 / 3.0 * v1_x * v1_x * mu_ + + 2.0 / 3.0 * v2_y * v1_x * mu_ - + v1_xy * v2 * mu_ - + v2_xx * v2 * mu_ - + v1_y * v2_x * mu_ - + v2_x * v2_x * mu_ - + T_const * inv_rho_cubed * + (p_xx * rho * rho - + 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x - + p * rho * rho_xx) * mu_ - + # stress tensor and temperature gradient terms from y-direction + v1_yy * v1 * mu_ - + v2_xy * v1 * mu_ - + v2_x * v1_y * mu_ - + 4.0 / 3.0 * v2_yy * v2 * mu_ + + 2.0 / 3.0 * v1_xy - + 4.0 / 3.0 * v2_y * v2_y * mu_ + + 2.0 / 3.0 * v1_x * v2_y * mu_ + - + - + (p_yy * rho * rho - + 2.0 * p_y * rho * rho_y + - - + p * rho * rho_yy) * mu_) + + return SVector(du1, du2, du3, du4) end initial_condition = initial_condition_navier_stokes_convergence_test @@ -175,23 +182,26 @@ velocity_bc_top_bottom = NoSlip() do x, t, equations return SVector(u[2], u[3]) end heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) -boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, heat_bc_top_bottom) +boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, + heat_bc_top_bottom) # define inviscid boundary conditions boundary_conditions = (; x_neg = boundary_condition_periodic, - x_pos = boundary_condition_periodic, - y_neg = boundary_condition_slip_wall, - y_pos = boundary_condition_slip_wall) + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_slip_wall, + y_pos = boundary_condition_slip_wall) # define viscous boundary conditions boundary_conditions_parabolic = (; x_neg = boundary_condition_periodic, - x_pos = boundary_condition_periodic, - y_neg = boundary_condition_top_bottom, - y_pos = boundary_condition_top_bottom) + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_top_bottom, + y_pos = boundary_condition_top_bottom) -semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; - boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), - source_terms=source_terms_navier_stokes_convergence_test) +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic), + source_terms = source_terms_navier_stokes_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -201,16 +211,15 @@ tspan = (0.0, 0.5) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, dt = 1e-5, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary - diff --git a/examples/tree_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl b/examples/tree_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl index 3314343ccca..7bd1ec0c647 100644 --- a/examples/tree_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl +++ b/examples/tree_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl @@ -9,28 +9,27 @@ prandtl_number() = 0.72 mu() = 0.001 equations = CompressibleEulerEquations2D(1.4) -equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu=mu(), - Prandtl=prandtl_number()) +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu = mu(), + Prandtl = prandtl_number()) # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) -coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) +coordinates_max = (1.0, 1.0) # maximum coordinates (max(x), max(y)) # Create a uniformly refined mesh mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - periodicity=false, - n_cells_max=30_000) # set maximum capacity of tree data structure - + initial_refinement_level = 4, + periodicity = false, + n_cells_max = 30_000) # set maximum capacity of tree data structure function initial_condition_cavity(x, t, equations::CompressibleEulerEquations2D) - Ma = 0.1 - rho = 1.0 - u, v = 0.0, 0.0 - p = 1.0 / (Ma^2 * equations.gamma) - return prim2cons(SVector(rho, u, v, p), equations) + Ma = 0.1 + rho = 1.0 + u, v = 0.0, 0.0 + p = 1.0 / (Ma^2 * equations.gamma) + return prim2cons(SVector(rho, u, v, p), equations) end initial_condition = initial_condition_cavity @@ -45,15 +44,15 @@ boundary_condition_cavity = BoundaryConditionNavierStokesWall(velocity_bc_cavity boundary_conditions = boundary_condition_slip_wall boundary_conditions_parabolic = (; x_neg = boundary_condition_cavity, - y_neg = boundary_condition_cavity, - y_pos = boundary_condition_lid, - x_pos = boundary_condition_cavity) + y_neg = boundary_condition_cavity, + y_pos = boundary_condition_lid, + x_pos = boundary_condition_cavity) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; - boundary_conditions=(boundary_conditions, - boundary_conditions_parabolic)) + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic)) ############################################################################### # ODE solvers, callbacks etc. @@ -63,17 +62,15 @@ tspan = (0.0, 25.0) ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=100) +alive_callback = AliveCallback(alive_interval = 100) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary - - diff --git a/examples/tree_2d_dgsem/elixir_navierstokes_shearlayer_amr.jl b/examples/tree_2d_dgsem/elixir_navierstokes_shearlayer_amr.jl index 06e8f06d3ca..4d92ea261e9 100644 --- a/examples/tree_2d_dgsem/elixir_navierstokes_shearlayer_amr.jl +++ b/examples/tree_2d_dgsem/elixir_navierstokes_shearlayer_amr.jl @@ -7,11 +7,11 @@ using Trixi # TODO: parabolic; unify names of these accessor functions prandtl_number() = 0.72 -mu() = 1.0/3.0 * 10^(-5) # equivalent to Re = 30,000 +mu() = 1.0 / 3.0 * 10^(-5) # equivalent to Re = 30,000 equations = CompressibleEulerEquations2D(1.4) -equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu=mu(), - Prandtl=prandtl_number()) +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu = mu(), + Prandtl = prandtl_number()) """ A compressible version of the double shear layer initial condition. Adapted from @@ -22,32 +22,31 @@ Brown and Minion (1995). [DOI: 10.1006/jcph.1995.1205](https://doi.org/10.1006/jcph.1995.1205) """ function initial_condition_shear_layer(x, t, equations::CompressibleEulerEquations2D) - # Shear layer parameters - k = 80 - delta = 0.05 - u0 = 1.0 - - Ms = 0.1 # maximum Mach number - - rho = 1.0 - v1 = x[2] <= 0.5 ? u0 * tanh(k*(x[2] - 0.25)) : u0 * tanh(k*(0.75 -x[2])) - v2 = u0 * delta * sin(2*pi*(x[1]+ 0.25)) - p = (u0 / Ms)^2 * rho / equations.gamma # scaling to get Ms - - return prim2cons(SVector(rho, v1, v2, p), equations) + # Shear layer parameters + k = 80 + delta = 0.05 + u0 = 1.0 + + Ms = 0.1 # maximum Mach number + + rho = 1.0 + v1 = x[2] <= 0.5 ? u0 * tanh(k * (x[2] - 0.25)) : u0 * tanh(k * (0.75 - x[2])) + v2 = u0 * delta * sin(2 * pi * (x[1] + 0.25)) + p = (u0 / Ms)^2 * rho / equations.gamma # scaling to get Ms + + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_shear_layer volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_hllc, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_hllc, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (0.0, 0.0) coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=100_000) - + initial_refinement_level = 4, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver) @@ -61,26 +60,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 2000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval,) +alive_callback = AliveCallback(analysis_interval = analysis_interval) # This uses velocity-based AMR @inline function v1(u, equations::CompressibleEulerEquations2D) - rho, rho_v1, _, _ = u - return rho_v1 / rho + rho, rho_v1, _, _ = u + return rho_v1 / rho end -amr_indicator = IndicatorLöhner(semi, variable=v1) +amr_indicator = IndicatorLöhner(semi, variable = v1) amr_controller = ControllerThreeLevel(semi, amr_indicator, base_level = 3, - med_level = 5, med_threshold=0.2, - max_level = 7, max_threshold=0.5) + med_level = 5, med_threshold = 0.2, + max_level = 7, max_threshold = 0.5) amr_callback = AMRCallback(semi, amr_controller, - interval=50, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 50, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.3) +stepsize_callback = StepsizeCallback(cfl = 1.3) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -91,7 +90,7 @@ callbacks = CallbackSet(summary_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 \ No newline at end of file +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/tree_2d_dgsem/elixir_navierstokes_taylor_green_vortex.jl b/examples/tree_2d_dgsem/elixir_navierstokes_taylor_green_vortex.jl index c3cbc858f7b..a3e38bf6d92 100644 --- a/examples/tree_2d_dgsem/elixir_navierstokes_taylor_green_vortex.jl +++ b/examples/tree_2d_dgsem/elixir_navierstokes_taylor_green_vortex.jl @@ -10,8 +10,8 @@ prandtl_number() = 0.72 mu() = 6.25e-4 # equivalent to Re = 1600 equations = CompressibleEulerEquations2D(1.4) -equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu=mu(), - Prandtl=prandtl_number()) +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu = mu(), + Prandtl = prandtl_number()) """ initial_condition_taylor_green_vortex(x, t, equations::CompressibleEulerEquations2D) @@ -22,30 +22,30 @@ This forms the basis behind the 3D case found for instance in Simulation of the Compressible Taylor Green Vortex using High-Order Flux Reconstruction Schemes [DOI: 10.2514/6.2014-3210](https://doi.org/10.2514/6.2014-3210) """ -function initial_condition_taylor_green_vortex(x, t, equations::CompressibleEulerEquations2D) - A = 1.0 # magnitude of speed - Ms = 0.1 # maximum Mach number - - rho = 1.0 - v1 = A * sin(x[1]) * cos(x[2]) - v2 = -A * cos(x[1]) * sin(x[2]) - p = (A / Ms)^2 * rho / equations.gamma # scaling to get Ms - p = p + 1.0/4.0 * A^2 * rho * (cos(2*x[1]) + cos(2*x[2])) - - return prim2cons(SVector(rho, v1, v2, p), equations) +function initial_condition_taylor_green_vortex(x, t, + equations::CompressibleEulerEquations2D) + A = 1.0 # magnitude of speed + Ms = 0.1 # maximum Mach number + + rho = 1.0 + v1 = A * sin(x[1]) * cos(x[2]) + v2 = -A * cos(x[1]) * sin(x[2]) + p = (A / Ms)^2 * rho / equations.gamma # scaling to get Ms + p = p + 1.0 / 4.0 * A^2 * rho * (cos(2 * x[1]) + cos(2 * x[2])) + + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_taylor_green_vortex volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_hllc, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_hllc, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-1.0, -1.0) .* pi -coordinates_max = ( 1.0, 1.0) .* pi +coordinates_max = (1.0, 1.0) .* pi mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=100_000) - + initial_refinement_level = 4, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver) @@ -59,11 +59,12 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=true, - extra_analysis_integrals=(energy_kinetic, - energy_internal)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_integrals = (energy_kinetic, + energy_internal)) -alive_callback = AliveCallback(analysis_interval=analysis_interval,) +alive_callback = AliveCallback(analysis_interval = analysis_interval) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -73,6 +74,6 @@ callbacks = CallbackSet(summary_callback, # run the simulation time_int_tol = 1e-9 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) -summary_callback() # print the timer summary \ No newline at end of file +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) +summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_shallowwater_conical_island.jl b/examples/tree_2d_dgsem/elixir_shallowwater_conical_island.jl index 7c60e35b03e..349b3741869 100644 --- a/examples/tree_2d_dgsem/elixir_shallowwater_conical_island.jl +++ b/examples/tree_2d_dgsem/elixir_shallowwater_conical_island.jl @@ -7,7 +7,7 @@ using Trixi # # TODO: TrixiShallowWater: wet/dry example elixir -equations = ShallowWaterEquations2D(gravity_constant=9.81, H0=1.4) +equations = ShallowWaterEquations2D(gravity_constant = 9.81, H0 = 1.4) """ initial_condition_conical_island(x, t, equations::ShallowWaterEquations2D) @@ -21,29 +21,29 @@ boundary condition with the initial values. Due to the dry cells at the boundary effect of an outflow which can be seen in the simulation. """ function initial_condition_conical_island(x, t, equations::ShallowWaterEquations2D) - # Set the background values + # Set the background values - v1 = 0.0 - v2 = 0.0 + v1 = 0.0 + v2 = 0.0 - x1, x2 = x - b = max(0.1, 1.0 - 4.0 * sqrt(x1^2 + x2^2)) + x1, x2 = x + b = max(0.1, 1.0 - 4.0 * sqrt(x1^2 + x2^2)) - # use a logistic function to transfer water height value smoothly - L = equations.H0 # maximum of function - x0 = 0.3 # center point of function - k = -25.0 # sharpness of transfer + # use a logistic function to transfer water height value smoothly + L = equations.H0 # maximum of function + x0 = 0.3 # center point of function + k = -25.0 # sharpness of transfer - H = max(b, L/(1.0 + exp(-k*(sqrt(x1^2+x2^2) - x0)))) + H = max(b, L / (1.0 + exp(-k * (sqrt(x1^2 + x2^2) - x0)))) - # It is mandatory to shift the water level at dry areas to make sure the water height h - # stays positive. The system would not be stable for h set to a hard 0 due to division by h in - # the computation of velocity, e.g., (h v1) / h. Therefore, a small dry state threshold - # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above - # for the ShallowWaterEquations and added to the initial condition if h = 0. - # This default value can be changed within the constructor call depending on the simulation setup. - H = max(H, b + equations.threshold_limiter) - return prim2cons(SVector(H, v1, v2, b), equations) + # It is mandatory to shift the water level at dry areas to make sure the water height h + # stays positive. The system would not be stable for h set to a hard 0 due to division by h in + # the computation of velocity, e.g., (h v1) / h. Therefore, a small dry state threshold + # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above + # for the ShallowWaterEquations and added to the initial condition if h = 0. + # This default value can be changed within the constructor call depending on the simulation setup. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v1, v2, b), equations) end initial_condition = initial_condition_conical_island @@ -53,19 +53,20 @@ boundary_conditions = BoundaryConditionDirichlet(initial_condition) # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, + hydrostatic_reconstruction_chen_noelle), flux_nonconservative_chen_noelle) basis = LobattoLegendreBasis(4) indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=waterheight_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = waterheight_pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) @@ -75,13 +76,13 @@ solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-1.0, -1.0) coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000, - periodicity=false) + initial_refinement_level = 4, + n_cells_max = 10_000, + periodicity = false) # Create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) + boundary_conditions = boundary_conditions) ############################################################################### # ODE solver @@ -95,22 +96,22 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) ############################################################################### # run the simulation -stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) +stage_limiter! = PositivityPreservingLimiterShallowWater(variables = (Trixi.waterheight,)) sol = solve(ode, SSPRK43(stage_limiter!); - ode_default_options()..., callback=callbacks); + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_shallowwater_ec.jl b/examples/tree_2d_dgsem/elixir_shallowwater_ec.jl index eed0a350e7e..bc528ae7756 100644 --- a/examples/tree_2d_dgsem/elixir_shallowwater_ec.jl +++ b/examples/tree_2d_dgsem/elixir_shallowwater_ec.jl @@ -6,7 +6,7 @@ using Trixi # semidiscretization of the shallow water equations with a discontinuous # bottom topography function -equations = ShallowWaterEquations2D(gravity_constant=9.81) +equations = ShallowWaterEquations2D(gravity_constant = 9.81) # 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. @@ -16,17 +16,18 @@ initial_condition = initial_condition_weak_blast_wave # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -solver = DGSEM(polydeg=4, surface_flux=(flux_fjordholm_etal, flux_nonconservative_fjordholm_etal), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 4, + surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the TreeMesh and setup a periodic mesh coordinates_min = (-1.0, -1.0) -coordinates_max = ( 1.0, 1.0) +coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=10_000) + initial_refinement_level = 2, + n_cells_max = 10_000) # Create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -46,45 +47,48 @@ ode = semidiscretize(semi, tspan) # 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 TreeMesh2D with initial_refinement_level=2. -function initial_condition_ec_discontinuous_bottom(x, t, element_id, equations::ShallowWaterEquations2D) - # Set up polar coordinates - inicenter = SVector(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 = 4.25 - v1 = 0.0 - v2 = 0.0 - b = 0.0 - - # setup the discontinuous water height and velocities - if element_id == 10 - H = 5.0 - v1 = 0.1882 * cos_phi - v2 = 0.1882 * sin_phi - end - - # Setup a discontinuous bottom topography using the element id number - if element_id == 7 - b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) + 0.5 * cos(2.0 * pi * x[2]) - end - - return prim2cons(SVector(H, v1, v2, b), equations) +function initial_condition_ec_discontinuous_bottom(x, t, element_id, + equations::ShallowWaterEquations2D) + # Set up polar coordinates + inicenter = SVector(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 = 4.25 + v1 = 0.0 + v2 = 0.0 + b = 0.0 + + # setup the discontinuous water height and velocities + if element_id == 10 + H = 5.0 + v1 = 0.1882 * cos_phi + v2 = 0.1882 * sin_phi + end + + # Setup a discontinuous bottom topography using the element id number + if element_id == 7 + b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) + 0.5 * cos(2.0 * pi * 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 + 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 ############################################################################### @@ -93,15 +97,15 @@ end summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(dt=0.2, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(dt = 0.2, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=3.0) +stepsize_callback = StepsizeCallback(cfl = 3.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) @@ -109,7 +113,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav ############################################################################### # 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); +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/tree_2d_dgsem/elixir_shallowwater_parabolic_bowl.jl b/examples/tree_2d_dgsem/elixir_shallowwater_parabolic_bowl.jl index 03dcf017266..2008019cc31 100644 --- a/examples/tree_2d_dgsem/elixir_shallowwater_parabolic_bowl.jl +++ b/examples/tree_2d_dgsem/elixir_shallowwater_parabolic_bowl.jl @@ -7,7 +7,7 @@ using Trixi # # TODO: TrixiShallowWater: wet/dry example elixir -equations = ShallowWaterEquations2D(gravity_constant=9.81) +equations = ShallowWaterEquations2D(gravity_constant = 9.81) """ initial_condition_parabolic_bowl(x, t, equations:: ShallowWaterEquations2D) @@ -28,27 +28,27 @@ The particular setup below is taken from Section 6.2 of curvilinear meshes with wet/dry fronts accelerated by GPUs [DOI: 10.1016/j.jcp.2018.08.038](https://doi.org/10.1016/j.jcp.2018.08.038). """ -function initial_condition_parabolic_bowl(x, t, equations:: ShallowWaterEquations2D) - a = 1.0 - h_0 = 0.1 - sigma = 0.5 - ω = sqrt(2 * equations.gravity * h_0) / a - - v1 = -sigma * ω * sin(ω * t) - v2 = sigma * ω * cos(ω * t) - - b = h_0 * ((x[1])^2 + (x[2])^2) / a^2 - - H = sigma * h_0 / a^2 * (2 * x[1] * cos(ω * t) + 2 * x[2] * sin(ω * t) - sigma) + h_0 - - # It is mandatory to shift the water level at dry areas to make sure the water height h - # stays positive. The system would not be stable for h set to a hard 0 due to division by h in - # the computation of velocity, e.g., (h v1) / h. Therefore, a small dry state threshold - # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above - # for the ShallowWaterEquations and added to the initial condition if h = 0. - # This default value can be changed within the constructor call depending on the simulation setup. - H = max(H, b + equations.threshold_limiter) - return prim2cons(SVector(H, v1, v2, b), equations) +function initial_condition_parabolic_bowl(x, t, equations::ShallowWaterEquations2D) + a = 1.0 + h_0 = 0.1 + sigma = 0.5 + ω = sqrt(2 * equations.gravity * h_0) / a + + v1 = -sigma * ω * sin(ω * t) + v2 = sigma * ω * cos(ω * t) + + b = h_0 * ((x[1])^2 + (x[2])^2) / a^2 + + H = sigma * h_0 / a^2 * (2 * x[1] * cos(ω * t) + 2 * x[2] * sin(ω * t) - sigma) + h_0 + + # It is mandatory to shift the water level at dry areas to make sure the water height h + # stays positive. The system would not be stable for h set to a hard 0 due to division by h in + # the computation of velocity, e.g., (h v1) / h. Therefore, a small dry state threshold + # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above + # for the ShallowWaterEquations and added to the initial condition if h = 0. + # This default value can be changed within the constructor call depending on the simulation setup. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v1, v2, b), equations) end initial_condition = initial_condition_parabolic_bowl @@ -56,23 +56,23 @@ initial_condition = initial_condition_parabolic_bowl # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, + hydrostatic_reconstruction_chen_noelle), flux_nonconservative_chen_noelle) basis = LobattoLegendreBasis(7) indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, - alpha_max=0.6, - alpha_min=0.001, - alpha_smooth=true, - variable=waterheight_pressure) + alpha_max = 0.6, + alpha_min = 0.001, + alpha_smooth = true, + variable = waterheight_pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) - ############################################################################### # Create the TreeMesh for the domain [-2, 2]^2 @@ -80,8 +80,8 @@ coordinates_min = (-2.0, -2.0) coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=5, - n_cells_max=10_000) + initial_refinement_level = 5, + n_cells_max = 10_000) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -95,19 +95,20 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false, - extra_analysis_integrals=(energy_kinetic, - energy_internal)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = false, + extra_analysis_integrals = (energy_kinetic, + energy_internal)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) -stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) +stage_limiter! = PositivityPreservingLimiterShallowWater(variables = (Trixi.waterheight,)) ############################################################################### # run the simulation @@ -115,6 +116,6 @@ stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterh callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) sol = solve(ode, SSPRK43(stage_limiter!); - ode_default_options()..., callback=callbacks); + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_shallowwater_source_terms.jl b/examples/tree_2d_dgsem/elixir_shallowwater_source_terms.jl index 6d4f6fe518c..c92e885c161 100644 --- a/examples/tree_2d_dgsem/elixir_shallowwater_source_terms.jl +++ b/examples/tree_2d_dgsem/elixir_shallowwater_source_terms.jl @@ -5,17 +5,17 @@ using Trixi ############################################################################### # semidiscretization of the shallow water equations -equations = ShallowWaterEquations2D(gravity_constant=9.81) +equations = ShallowWaterEquations2D(gravity_constant = 9.81) initial_condition = initial_condition_convergence_test # MMS EOC test - ############################################################################### # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -solver = DGSEM(polydeg=3, surface_flux=(flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, + surface_flux = (flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the TreeMesh and setup a periodic mesh @@ -23,13 +23,13 @@ solver = DGSEM(polydeg=3, surface_flux=(flux_lax_friedrichs, flux_nonconservativ coordinates_min = (0.0, 0.0) coordinates_max = (sqrt(2.0), sqrt(2.0)) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=10_000, - periodicity=true) + initial_refinement_level = 3, + n_cells_max = 10_000, + periodicity = true) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -40,13 +40,13 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 500 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=200, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 200, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) @@ -54,6 +54,6 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav # run the simulation # use a Runge-Kutta method with automatic (error based) time step size control -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-8, reltol=1.0e-8, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-8, reltol = 1.0e-8, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_shallowwater_source_terms_dirichlet.jl b/examples/tree_2d_dgsem/elixir_shallowwater_source_terms_dirichlet.jl index c3da957b764..f7544b1e32e 100644 --- a/examples/tree_2d_dgsem/elixir_shallowwater_source_terms_dirichlet.jl +++ b/examples/tree_2d_dgsem/elixir_shallowwater_source_terms_dirichlet.jl @@ -5,7 +5,7 @@ using Trixi ############################################################################### # Semidiscretization of the shallow water equations -equations = ShallowWaterEquations2D(gravity_constant=9.81) +equations = ShallowWaterEquations2D(gravity_constant = 9.81) initial_condition = initial_condition_convergence_test @@ -15,8 +15,9 @@ boundary_condition = BoundaryConditionDirichlet(initial_condition) # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -solver = DGSEM(polydeg=3, surface_flux=(flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, + surface_flux = (flux_lax_friedrichs, flux_nonconservative_fjordholm_etal), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the TreeMesh and setup a periodic mesh @@ -24,14 +25,14 @@ solver = DGSEM(polydeg=3, surface_flux=(flux_lax_friedrichs, flux_nonconservativ coordinates_min = (0.0, 0.0) coordinates_max = (sqrt(2.0), sqrt(2.0)) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=10_000, - periodicity=false) + initial_refinement_level = 3, + n_cells_max = 10_000, + periodicity = false) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions = boundary_condition, - source_terms=source_terms_convergence_test) + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -42,13 +43,13 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 500 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=200, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 200, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) @@ -56,6 +57,6 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav # run the simulation # use a Runge-Kutta method with automatic (error based) time step size control -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-8, reltol=1.0e-8, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-8, reltol = 1.0e-8, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl b/examples/tree_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl index 402361c8823..f7c8ab3a249 100644 --- a/examples/tree_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl @@ -5,7 +5,8 @@ using Trixi ############################################################################### # Semidiscretization of the two-layer shallow water equations -equations = ShallowWaterTwoLayerEquations2D(gravity_constant=10.0, rho_upper=0.9, rho_lower=1.0) +equations = ShallowWaterTwoLayerEquations2D(gravity_constant = 10.0, rho_upper = 0.9, + rho_lower = 1.0) initial_condition = initial_condition_convergence_test @@ -13,9 +14,9 @@ initial_condition = initial_condition_convergence_test # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -solver = DGSEM(polydeg=3, surface_flux=(flux_fjordholm_etal, flux_nonconservative_fjordholm_etal), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) - +solver = DGSEM(polydeg = 3, + surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the TreeMesh and setup a periodic mesh @@ -23,13 +24,13 @@ solver = DGSEM(polydeg=3, surface_flux=(flux_fjordholm_etal, flux_nonconservativ coordinates_min = (0.0, 0.0) coordinates_max = (sqrt(2.0), sqrt(2.0)) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=20_000, - periodicity=true) + initial_refinement_level = 3, + n_cells_max = 20_000, + periodicity = true) # Create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -40,13 +41,13 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 500 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=500, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 500, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) @@ -54,6 +55,6 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav # run the simulation # use a Runge-Kutta method with automatic (error based) time step size control -sol = solve(ode, RDPK3SpFSAL49(), abstol=1.0e-8, reltol=1.0e-8, -save_everystep=false, callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(), abstol = 1.0e-8, reltol = 1.0e-8, + save_everystep = false, callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl b/examples/tree_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl index ba4bcd25774..1495e6d8568 100644 --- a/examples/tree_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl +++ b/examples/tree_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl @@ -6,21 +6,24 @@ using Trixi # Semidiscretization of the two-layer shallow water equations with a bottom topography function # to test well-balancedness -equations = ShallowWaterTwoLayerEquations2D(gravity_constant=9.81, H0=0.6, rho_upper=0.9, rho_lower=1.0) +equations = ShallowWaterTwoLayerEquations2D(gravity_constant = 9.81, H0 = 0.6, + rho_upper = 0.9, rho_lower = 1.0) # An initial condition with constant total water height, zero velocities and a bottom topography to # test well-balancedness function initial_condition_well_balanced(x, t, equations::ShallowWaterTwoLayerEquations2D) - H_lower = 0.5 - H_upper = 0.6 - v1_upper = 0.0 - v2_upper = 0.0 - v1_lower = 0.0 - v2_lower = 0.0 - b = (((x[1] - 0.5)^2 + (x[2] - 0.5)^2) < 0.04 ? 0.2 * (cos(4 * pi * sqrt((x[1] - 0.5)^2 + (x[2] + - -0.5)^2)) + 1) : 0.0) - - return prim2cons(SVector(H_upper, v1_upper, v2_upper, H_lower, v1_lower, v2_lower, b), equations) + H_lower = 0.5 + H_upper = 0.6 + v1_upper = 0.0 + v2_upper = 0.0 + v1_lower = 0.0 + v2_lower = 0.0 + b = (((x[1] - 0.5)^2 + (x[2] - 0.5)^2) < 0.04 ? + 0.2 * (cos(4 * pi * sqrt((x[1] - 0.5)^2 + (x[2] + + -0.5)^2)) + 1) : 0.0) + + return prim2cons(SVector(H_upper, v1_upper, v2_upper, H_lower, v1_lower, v2_lower, b), + equations) end initial_condition = initial_condition_well_balanced @@ -30,8 +33,8 @@ initial_condition = initial_condition_well_balanced volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) surface_flux = (flux_es_fjordholm_etal, flux_nonconservative_fjordholm_etal) -solver = DGSEM(polydeg=3, surface_flux=surface_flux, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the TreeMesh and setup a periodic mesh @@ -39,9 +42,9 @@ solver = DGSEM(polydeg=3, surface_flux=surface_flux, coordinates_min = (0.0, 0.0) coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=10_000, - periodicity=true) + initial_refinement_level = 3, + n_cells_max = 10_000, + periodicity = true) # Create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -55,16 +58,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(lake_at_rest_error,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (lake_at_rest_error,)) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) @@ -72,7 +75,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav ############################################################################### # 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); +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/tree_2d_dgsem/elixir_shallowwater_well_balanced.jl b/examples/tree_2d_dgsem/elixir_shallowwater_well_balanced.jl index 23efdcb7366..13023dfaba2 100644 --- a/examples/tree_2d_dgsem/elixir_shallowwater_well_balanced.jl +++ b/examples/tree_2d_dgsem/elixir_shallowwater_well_balanced.jl @@ -6,21 +6,21 @@ using Trixi # semidiscretization of the shallow water equations with a discontinuous # bottom topography function -equations = ShallowWaterEquations2D(gravity_constant=9.81, H0=3.25) +equations = ShallowWaterEquations2D(gravity_constant = 9.81, H0 = 3.25) # An initial condition with constant total water height and zero velocities to test well-balancedness. # Note, this routine is used to compute errors in the analysis callback but the initialization is # overwritten by `initial_condition_discontinuous_well_balancedness` below. function initial_condition_well_balancedness(x, t, equations::ShallowWaterEquations2D) - # Set the background values - H = equations.H0 - v1 = 0.0 - v2 = 0.0 - # bottom topography taken from Pond.control in [HOHQMesh](https://github.com/trixi-framework/HOHQMesh) - x1, x2 = x - b = ( 1.5 / exp( 0.5 * ((x1 - 1.0)^2 + (x2 - 1.0)^2) ) - + 0.75 / exp( 0.5 * ((x1 + 1.0)^2 + (x2 + 1.0)^2) ) ) - return prim2cons(SVector(H, v1, v2, b), equations) + # Set the background values + H = equations.H0 + v1 = 0.0 + v2 = 0.0 + # bottom topography taken from Pond.control in [HOHQMesh](https://github.com/trixi-framework/HOHQMesh) + x1, x2 = x + b = (1.5 / exp(0.5 * ((x1 - 1.0)^2 + (x2 - 1.0)^2)) + + 0.75 / exp(0.5 * ((x1 + 1.0)^2 + (x2 + 1.0)^2))) + return prim2cons(SVector(H, v1, v2, b), equations) end initial_condition = initial_condition_well_balancedness @@ -30,17 +30,17 @@ initial_condition = initial_condition_well_balancedness volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal) -solver = DGSEM(polydeg=4, surface_flux=surface_flux, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 4, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the TreeMesh and setup a periodic mesh coordinates_min = (-1.0, -1.0) -coordinates_max = ( 1.0, 1.0) +coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=10_000) + initial_refinement_level = 2, + n_cells_max = 10_000) # Create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -61,30 +61,33 @@ ode = semidiscretize(semi, tspan) # 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 TreeMesh2D with initial_refinement_level=2. -function initial_condition_discontinuous_well_balancedness(x, t, element_id, equations::ShallowWaterEquations2D) - # Set the background values - H = equations.H0 - v1 = 0.0 - v2 = 0.0 - b = 0.0 - - # Setup a discontinuous bottom topography using the element id number - if element_id == 7 - b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) + 0.5 * cos(2.0 * pi * x[2]) - end - - return prim2cons(SVector(H, v1, v2, b), equations) +function initial_condition_discontinuous_well_balancedness(x, t, element_id, + equations::ShallowWaterEquations2D) + # Set the background values + H = equations.H0 + v1 = 0.0 + v2 = 0.0 + b = 0.0 + + # Setup a discontinuous bottom topography using the element id number + if element_id == 7 + b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) + 0.5 * cos(2.0 * pi * 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_discontinuous_well_balancedness(x_node, first(tspan), element, equations) - Trixi.set_node_vars!(u, u_node, equations, semi.solver, i, j, element) - end + 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_discontinuous_well_balancedness(x_node, first(tspan), + element, equations) + Trixi.set_node_vars!(u, u_node, equations, semi.solver, i, j, element) + end end ############################################################################### @@ -93,16 +96,16 @@ end summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(lake_at_rest_error,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (lake_at_rest_error,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=3.0) +stepsize_callback = StepsizeCallback(cfl = 3.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) @@ -110,7 +113,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav ############################################################################### # 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); +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/tree_2d_dgsem/elixir_shallowwater_well_balanced_wall.jl b/examples/tree_2d_dgsem/elixir_shallowwater_well_balanced_wall.jl index 66cd27f6864..f50bd4e4f65 100644 --- a/examples/tree_2d_dgsem/elixir_shallowwater_well_balanced_wall.jl +++ b/examples/tree_2d_dgsem/elixir_shallowwater_well_balanced_wall.jl @@ -5,21 +5,21 @@ using Trixi # semidiscretization of the shallow water equations with a discontinuous # bottom topography function -equations = ShallowWaterEquations2D(gravity_constant=9.81, H0=3.25) +equations = ShallowWaterEquations2D(gravity_constant = 9.81, H0 = 3.25) # An initial condition with constant total water height and zero velocities to test well-balancedness. # Note, this routine is used to compute errors in the analysis callback but the initialization is # overwritten by `initial_condition_discontinuous_well_balancedness` below. function initial_condition_well_balancedness(x, t, equations::ShallowWaterEquations2D) - # Set the background values - H = equations.H0 - v1 = 0.0 - v2 = 0.0 - # bottom topography taken from Pond.control in [HOHQMesh](https://github.com/trixi-framework/HOHQMesh) - x1, x2 = x - b = ( 1.5 / exp( 0.5 * ((x1 - 1.0)^2 + (x2 - 1.0)^2) ) - + 0.75 / exp( 0.5 * ((x1 + 1.0)^2 + (x2 + 1.0)^2) ) ) - return prim2cons(SVector(H, v1, v2, b), equations) + # Set the background values + H = equations.H0 + v1 = 0.0 + v2 = 0.0 + # bottom topography taken from Pond.control in [HOHQMesh](https://github.com/trixi-framework/HOHQMesh) + x1, x2 = x + b = (1.5 / exp(0.5 * ((x1 - 1.0)^2 + (x2 - 1.0)^2)) + + 0.75 / exp(0.5 * ((x1 + 1.0)^2 + (x2 + 1.0)^2))) + return prim2cons(SVector(H, v1, v2, b), equations) end initial_condition = initial_condition_well_balancedness @@ -31,8 +31,8 @@ boundary_condition = boundary_condition_slip_wall volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal) -solver = DGSEM(polydeg=4, surface_flux=surface_flux, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 4, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the TreeMesh and setup a periodic mesh @@ -40,8 +40,8 @@ solver = DGSEM(polydeg=4, surface_flux=surface_flux, coordinates_min = (-1.0, -1.0) coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=10_000, + initial_refinement_level = 2, + n_cells_max = 10_000, periodicity = false) # create the semi discretization object @@ -64,30 +64,33 @@ ode = semidiscretize(semi, tspan) # 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 TreeMesh2D with initial_refinement_level=2. -function initial_condition_discontinuous_well_balancedness(x, t, element_id, equations::ShallowWaterEquations2D) - # Set the background values - H = equations.H0 - v1 = 0.0 - v2 = 0.0 - b = 0.0 - - # Setup a discontinuous bottom topography using the element id number - if element_id == 7 - b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) + 0.5 * cos(2.0 * pi * x[2]) - end - - return prim2cons(SVector(H, v1, v2, b), equations) +function initial_condition_discontinuous_well_balancedness(x, t, element_id, + equations::ShallowWaterEquations2D) + # Set the background values + H = equations.H0 + v1 = 0.0 + v2 = 0.0 + b = 0.0 + + # Setup a discontinuous bottom topography using the element id number + if element_id == 7 + b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) + 0.5 * cos(2.0 * pi * 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_discontinuous_well_balancedness(x_node, first(tspan), element, equations) - Trixi.set_node_vars!(u, u_node, equations, semi.solver, i, j, element) - end + 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_discontinuous_well_balancedness(x_node, first(tspan), + element, equations) + Trixi.set_node_vars!(u, u_node, equations, semi.solver, i, j, element) + end end ############################################################################### @@ -96,16 +99,16 @@ end summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(lake_at_rest_error,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (lake_at_rest_error,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=3.0) +stepsize_callback = StepsizeCallback(cfl = 3.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) @@ -113,7 +116,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav ############################################################################### # 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 \ No newline at end of file +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/tree_2d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl b/examples/tree_2d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl index 6fede2fa4ea..034411c2b54 100644 --- a/examples/tree_2d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl +++ b/examples/tree_2d_dgsem/elixir_shallowwater_well_balanced_wet_dry.jl @@ -8,7 +8,7 @@ using Printf: @printf, @sprintf # # TODO: TrixiShallowWater: wet/dry example elixir -equations = ShallowWaterEquations2D(gravity_constant=9.812) +equations = ShallowWaterEquations2D(gravity_constant = 9.812) """ initial_condition_well_balanced_chen_noelle(x, t, equations:: ShallowWaterEquations2D) @@ -23,28 +23,29 @@ The initial condition is taken from Section 5.2 of the paper: A new hydrostatic reconstruction scheme based on subcell reconstructions [DOI:10.1137/15M1053074](https://dx.doi.org/10.1137/15M1053074) """ -function initial_condition_complex_bottom_well_balanced(x, t, equations::ShallowWaterEquations2D) - v1 = 0 - v2 = 0 - b = sin(4 * pi * x[1]) + 3 - - if x[1] >= 0.5 - b = sin(4 * pi * x[1]) + 1 - end - - H = max(b, 2.5) - if x[1] >= 0.5 - H = max(b, 1.5) - end - - # It is mandatory to shift the water level at dry areas to make sure the water height h - # stays positive. The system would not be stable for h set to a hard 0 due to division by h in - # the computation of velocity, e.g., (h v1) / h. Therefore, a small dry state threshold - # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above - # for the ShallowWaterEquations and added to the initial condition if h = 0. - # This default value can be changed within the constructor call depending on the simulation setup. - H = max(H, b + equations.threshold_limiter) - return prim2cons(SVector(H, v1, v2, b), equations) +function initial_condition_complex_bottom_well_balanced(x, t, + equations::ShallowWaterEquations2D) + v1 = 0 + v2 = 0 + b = sin(4 * pi * x[1]) + 3 + + if x[1] >= 0.5 + b = sin(4 * pi * x[1]) + 1 + end + + H = max(b, 2.5) + if x[1] >= 0.5 + H = max(b, 1.5) + end + + # It is mandatory to shift the water level at dry areas to make sure the water height h + # stays positive. The system would not be stable for h set to a hard 0 due to division by h in + # the computation of velocity, e.g., (h v1) / h. Therefore, a small dry state threshold + # with a default value of 500*eps() ≈ 1e-13 in double precision, is set in the constructor above + # for the ShallowWaterEquations and added to the initial condition if h = 0. + # This default value can be changed within the constructor call depending on the simulation setup. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v1, v2, b), equations) end initial_condition = initial_condition_complex_bottom_well_balanced @@ -53,19 +54,20 @@ initial_condition = initial_condition_complex_bottom_well_balanced # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, + hydrostatic_reconstruction_chen_noelle), flux_nonconservative_chen_noelle) basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=waterheight_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = waterheight_pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) @@ -76,8 +78,8 @@ coordinates_min = (0.0, 0.0) coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=10_000) + initial_refinement_level = 3, + n_cells_max = 10_000) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -102,18 +104,20 @@ ode = semidiscretize(semi, tspan) 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) - # We know that the discontinuity is a vertical line. Slightly augment the x value by a factor - # of unit roundoff to avoid the repeted value from the LGL nodes at at interface. - if i == 1 - x_node = SVector(nextfloat(x_node[1]) , x_node[2]) - elseif i == nnodes(semi.solver) - x_node = SVector(prevfloat(x_node[1]) , x_node[2]) + 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) + # We know that the discontinuity is a vertical line. Slightly augment the x value by a factor + # of unit roundoff to avoid the repeted value from the LGL nodes at at interface. + if i == 1 + x_node = SVector(nextfloat(x_node[1]), x_node[2]) + elseif i == nnodes(semi.solver) + x_node = SVector(prevfloat(x_node[1]), x_node[2]) + end + u_node = initial_condition_complex_bottom_well_balanced(x_node, first(tspan), + equations) + Trixi.set_node_vars!(u, u_node, equations, semi.solver, i, j, element) end - u_node = initial_condition_complex_bottom_well_balanced(x_node, first(tspan), equations) - Trixi.set_node_vars!(u, u_node, equations, semi.solver, i, j, element) - end end ############################################################################### @@ -122,27 +126,27 @@ end summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = false) -alive_callback = AliveCallback(analysis_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=2.0) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true) +stepsize_callback = StepsizeCallback(cfl = 2.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) -stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) +stage_limiter! = PositivityPreservingLimiterShallowWater(variables = (Trixi.waterheight,)) ############################################################################### # run the simulation -sol = solve(ode, SSPRK43(stage_limiter!); dt=1.0, - ode_default_options()..., callback=callbacks, adaptive=false); +sol = solve(ode, SSPRK43(stage_limiter!); dt = 1.0, + ode_default_options()..., callback = callbacks, adaptive = false); summary_callback() # print the timer summary @@ -157,34 +161,38 @@ summary_callback() # print the timer summary function lake_at_rest_error_two_level(u, x, equations::ShallowWaterEquations2D) h, _, _, b = u - # For well-balancedness testing with possible wet/dry regions the reference - # water height `H0` accounts for the possibility that the bottom topography - # can emerge out of the water as well as for the threshold offset to avoid - # division by a "hard" zero water heights as well. + # For well-balancedness testing with possible wet/dry regions the reference + # water height `H0` accounts for the possibility that the bottom topography + # can emerge out of the water as well as for the threshold offset to avoid + # division by a "hard" zero water heights as well. - if x[1] < 0.5 - H0_wet_dry = max( 2.5 , b + equations.threshold_limiter ) - else - H0_wet_dry = max( 1.5 , b + equations.threshold_limiter ) - end + if x[1] < 0.5 + H0_wet_dry = max(2.5, b + equations.threshold_limiter) + else + H0_wet_dry = max(1.5, b + equations.threshold_limiter) + end - return abs(H0_wet_dry - (h + b)) + return abs(H0_wet_dry - (h + b)) end # point to the data we want to analyze u = Trixi.wrap_array(sol[end], semi) # Perform the actual integration of the well-balancedness error over the domain -l1_well_balance_error = Trixi.integrate_via_indices(u, mesh, equations, semi.solver, semi.cache; normalize=true) do u, i, j, element, equations, solver - x_node = Trixi.get_node_coords(semi.cache.elements.node_coordinates, equations, solver, i, j, element) - # We know that the discontinuity is a vertical line. Slightly augment the x value by a factor - # of unit roundoff to avoid the repeted value from the LGL nodes at at interface. - if i == 1 - x_node = SVector(nextfloat(x_node[1]) , x_node[2]) - elseif i == nnodes(semi.solver) - x_node = SVector(prevfloat(x_node[1]) , x_node[2]) - end - u_local = Trixi.get_node_vars(u, equations, solver, i, j, element) - return lake_at_rest_error_two_level(u_local, x_node, equations) +l1_well_balance_error = Trixi.integrate_via_indices(u, mesh, equations, semi.solver, + semi.cache; + normalize = true) do u, i, j, element, + equations, solver + x_node = Trixi.get_node_coords(semi.cache.elements.node_coordinates, equations, solver, + i, j, element) + # We know that the discontinuity is a vertical line. Slightly augment the x value by a factor + # of unit roundoff to avoid the repeted value from the LGL nodes at at interface. + if i == 1 + x_node = SVector(nextfloat(x_node[1]), x_node[2]) + elseif i == nnodes(semi.solver) + x_node = SVector(prevfloat(x_node[1]), x_node[2]) + end + u_local = Trixi.get_node_vars(u, equations, solver, i, j, element) + return lake_at_rest_error_two_level(u_local, x_node, equations) end # report the well-balancedness lake-at-rest error to the screen diff --git a/examples/tree_2d_fdsbp/elixir_advection_extended.jl b/examples/tree_2d_fdsbp/elixir_advection_extended.jl index 6e599d9f42d..8716a9a6b78 100644 --- a/examples/tree_2d_fdsbp/elixir_advection_extended.jl +++ b/examples/tree_2d_fdsbp/elixir_advection_extended.jl @@ -13,22 +13,21 @@ equations = LinearScalarAdvectionEquation2D(advection_velocity) initial_condition = initial_condition_convergence_test D_SBP = derivative_operator(SummationByPartsOperators.MattssonNordström2004(), - derivative_order=1, accuracy_order=4, - xmin=0.0, xmax=1.0, N=100) + derivative_order = 1, accuracy_order = 4, + xmin = 0.0, xmax = 1.0, N = 100) solver = FDSBP(D_SBP, - surface_integral=SurfaceIntegralStrongForm(flux_lax_friedrichs), - volume_integral=VolumeIntegralStrongForm()) + surface_integral = SurfaceIntegralStrongForm(flux_lax_friedrichs), + volume_integral = VolumeIntegralStrongForm()) coordinates_min = (-1.0, -1.0) -coordinates_max = ( 1.0, 1.0) +coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=1, - n_cells_max=30_000, - periodicity=true) + initial_refinement_level = 1, + n_cells_max = 30_000, + periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -38,19 +37,18 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(energy_total,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (energy_total,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) - ############################################################################### # run the simulation -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-9, reltol=1.0e-9, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-9, reltol = 1.0e-9, + ode_default_options()..., callback = callbacks) summary_callback() diff --git a/examples/tree_2d_fdsbp/elixir_euler_convergence.jl b/examples/tree_2d_fdsbp/elixir_euler_convergence.jl index 2a6c291f0bf..123be02bd17 100644 --- a/examples/tree_2d_fdsbp/elixir_euler_convergence.jl +++ b/examples/tree_2d_fdsbp/elixir_euler_convergence.jl @@ -13,23 +13,24 @@ initial_condition = initial_condition_convergence_test source_terms = source_terms_convergence_test D_upw = upwind_operators(SummationByPartsOperators.Mattsson2017, - derivative_order=1, - accuracy_order=4, - xmin=-1.0, xmax=1.0, - N=16) + derivative_order = 1, + accuracy_order = 4, + xmin = -1.0, xmax = 1.0, + N = 16) flux_splitting = splitting_steger_warming solver = FDSBP(D_upw, - surface_integral=SurfaceIntegralUpwind(flux_splitting), - volume_integral=VolumeIntegralUpwind(flux_splitting)) + surface_integral = SurfaceIntegralUpwind(flux_splitting), + volume_integral = VolumeIntegralUpwind(flux_splitting)) coordinates_min = (-1.0, -1.0) -coordinates_max = ( 1.0, 1.0) +coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=30_000, - periodicity=true) + initial_refinement_level = 3, + n_cells_max = 30_000, + periodicity = true) -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, source_terms = source_terms_convergence_test) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -40,15 +41,15 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(energy_total,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (energy_total,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -58,6 +59,6 @@ callbacks = CallbackSet(summary_callback, ############################################################################### # run the simulation -sol = solve(ode, SSPRK43(); abstol=1.0e-9, reltol=1.0e-9, - ode_default_options()..., callback=callbacks) +sol = solve(ode, SSPRK43(); abstol = 1.0e-9, reltol = 1.0e-9, + ode_default_options()..., callback = callbacks) summary_callback() diff --git a/examples/tree_2d_fdsbp/elixir_euler_kelvin_helmholtz_instability.jl b/examples/tree_2d_fdsbp/elixir_euler_kelvin_helmholtz_instability.jl index e63343852ab..4c41b84af33 100644 --- a/examples/tree_2d_fdsbp/elixir_euler_kelvin_helmholtz_instability.jl +++ b/examples/tree_2d_fdsbp/elixir_euler_kelvin_helmholtz_instability.jl @@ -9,42 +9,42 @@ using Trixi equations = CompressibleEulerEquations2D(1.4) -function initial_condition_kelvin_helmholtz_instability(x, t, equations::CompressibleEulerEquations2D) - # change discontinuity to tanh - # typical resolution 128^2, 256^2 - # domain size is [-1,+1]^2 - slope = 15 - amplitude = 0.02 - B = tanh(slope * x[2] + 7.5) - tanh(slope * x[2] - 7.5) - rho = 0.5 + 0.75 * B - v1 = 0.5 * (B - 1) - v2 = 0.1 * sin(2 * pi * x[1]) - p = 1.0 - return prim2cons(SVector(rho, v1, v2, p), equations) +function initial_condition_kelvin_helmholtz_instability(x, t, + equations::CompressibleEulerEquations2D) + # change discontinuity to tanh + # typical resolution 128^2, 256^2 + # domain size is [-1,+1]^2 + slope = 15 + amplitude = 0.02 + B = tanh(slope * x[2] + 7.5) - tanh(slope * x[2] - 7.5) + rho = 0.5 + 0.75 * B + v1 = 0.5 * (B - 1) + v2 = 0.1 * sin(2 * pi * x[1]) + p = 1.0 + return prim2cons(SVector(rho, v1, v2, p), equations) end initial_condition = initial_condition_kelvin_helmholtz_instability D_upw = upwind_operators(SummationByPartsOperators.Mattsson2017, - derivative_order=1, - accuracy_order=4, - xmin=-1.0, xmax=1.0, - N=16) + derivative_order = 1, + accuracy_order = 4, + xmin = -1.0, xmax = 1.0, + N = 16) flux_splitting = splitting_vanleer_haenel solver = FDSBP(D_upw, - surface_integral=SurfaceIntegralUpwind(flux_splitting), - volume_integral=VolumeIntegralUpwind(flux_splitting)) + surface_integral = SurfaceIntegralUpwind(flux_splitting), + volume_integral = VolumeIntegralUpwind(flux_splitting)) coordinates_min = (-1.0, -1.0) -coordinates_max = ( 1.0, 1.0) +coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=30_000, - periodicity=true) + initial_refinement_level = 4, + n_cells_max = 30_000, + periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -54,27 +54,26 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - save_analysis=true, - extra_analysis_integrals=(entropy, - energy_total,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_integrals = (entropy, + energy_total)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) callbacks = CallbackSet(summary_callback, analysis_callback, save_solution, alive_callback) - ############################################################################### # run the simulation -sol = solve(ode, SSPRK43(); abstol=1.0e-6, reltol=1.0e-6, dt=1e-3, - ode_default_options()..., callback=callbacks) +sol = solve(ode, SSPRK43(); abstol = 1.0e-6, reltol = 1.0e-6, dt = 1e-3, + ode_default_options()..., callback = callbacks) summary_callback() diff --git a/examples/tree_2d_fdsbp/elixir_euler_vortex.jl b/examples/tree_2d_fdsbp/elixir_euler_vortex.jl index c1bee8f9c4d..d0847cc8016 100644 --- a/examples/tree_2d_fdsbp/elixir_euler_vortex.jl +++ b/examples/tree_2d_fdsbp/elixir_euler_vortex.jl @@ -19,62 +19,61 @@ The classical isentropic vortex test case of [NASA/CR-97-206253](https://ntrs.nasa.gov/citations/19980007543) """ function initial_condition_isentropic_vortex(x, t, equations::CompressibleEulerEquations2D) - # needs appropriate mesh size, e.g. [-10,-10]x[10,10] - # for error convergence: make sure that the end time is such that the is back at the initial state!! - # for the current velocity and domain size: t_end should be a multiple of 20s - # initial center of the vortex - inicenter = SVector(0.0, 0.0) - # size and strength of the vortex - iniamplitude = 5.0 - # base flow - rho = 1.0 - v1 = 1.0 - v2 = 1.0 - vel = SVector(v1, v2) - p = 25.0 - rt = p / rho # ideal gas equation - t_loc = 0.0 - cent = inicenter + vel*t_loc # advection of center - # ATTENTION: handle periodic BC, but only for v1 = v2 = 1.0 (!!!!) - - cent = x - cent # distance to center point - - #cent=cross(iniaxis,cent) # distance to axis, tangent vector, length r - # cross product with iniaxis = [0, 0, 1] - cent = SVector(-cent[2], cent[1]) - r2 = cent[1]^2 + cent[2]^2 - du = iniamplitude/(2*π)*exp(0.5*(1-r2)) # vel. perturbation - dtemp = -(equations.gamma-1)/(2*equations.gamma*rt)*du^2 # isentropic - rho = rho * (1+dtemp)^(1/(equations.gamma-1)) - vel = vel + du*cent - v1, v2 = vel - p = p * (1+dtemp)^(equations.gamma/(equations.gamma-1)) - prim = SVector(rho, v1, v2, p) - return prim2cons(prim, equations) + # needs appropriate mesh size, e.g. [-10,-10]x[10,10] + # for error convergence: make sure that the end time is such that the is back at the initial state!! + # for the current velocity and domain size: t_end should be a multiple of 20s + # initial center of the vortex + inicenter = SVector(0.0, 0.0) + # size and strength of the vortex + iniamplitude = 5.0 + # base flow + rho = 1.0 + v1 = 1.0 + v2 = 1.0 + vel = SVector(v1, v2) + p = 25.0 + rt = p / rho # ideal gas equation + t_loc = 0.0 + cent = inicenter + vel * t_loc # advection of center + # ATTENTION: handle periodic BC, but only for v1 = v2 = 1.0 (!!!!) + + cent = x - cent # distance to center point + + #cent=cross(iniaxis,cent) # distance to axis, tangent vector, length r + # cross product with iniaxis = [0, 0, 1] + cent = SVector(-cent[2], cent[1]) + r2 = cent[1]^2 + cent[2]^2 + du = iniamplitude / (2 * π) * exp(0.5 * (1 - r2)) # vel. perturbation + dtemp = -(equations.gamma - 1) / (2 * equations.gamma * rt) * du^2 # isentropic + rho = rho * (1 + dtemp)^(1 / (equations.gamma - 1)) + vel = vel + du * cent + v1, v2 = vel + p = p * (1 + dtemp)^(equations.gamma / (equations.gamma - 1)) + prim = SVector(rho, v1, v2, p) + return prim2cons(prim, equations) end initial_condition = initial_condition_isentropic_vortex D_upw = upwind_operators(SummationByPartsOperators.Mattsson2017, - derivative_order=1, - accuracy_order=4, - xmin=-1.0, xmax=1.0, - N=16) + derivative_order = 1, + accuracy_order = 4, + xmin = -1.0, xmax = 1.0, + N = 16) flux_splitting = splitting_steger_warming solver = FDSBP(D_upw, - surface_integral=SurfaceIntegralUpwind(flux_splitting), - volume_integral=VolumeIntegralUpwind(flux_splitting)) + surface_integral = SurfaceIntegralUpwind(flux_splitting), + volume_integral = VolumeIntegralUpwind(flux_splitting)) coordinates_min = (-10.0, -10.0) -coordinates_max = ( 10.0, 10.0) +coordinates_max = (10.0, 10.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=30_000, - periodicity=true) + initial_refinement_level = 3, + n_cells_max = 30_000, + periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -84,24 +83,23 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) callbacks = CallbackSet(summary_callback, analysis_callback, save_solution, alive_callback) - ############################################################################### # run the simulation -sol = solve(ode, SSPRK43(); abstol=1.0e-6, reltol=1.0e-6, dt=1e-3, - ode_default_options()..., callback=callbacks) +sol = solve(ode, SSPRK43(); abstol = 1.0e-6, reltol = 1.0e-6, dt = 1e-3, + ode_default_options()..., callback = callbacks) summary_callback() diff --git a/examples/tree_3d_dgsem/elixir_advection_amr.jl b/examples/tree_3d_dgsem/elixir_advection_amr.jl index 67664eed563..19a9bd18a8a 100644 --- a/examples/tree_3d_dgsem/elixir_advection_amr.jl +++ b/examples/tree_3d_dgsem/elixir_advection_amr.jl @@ -9,18 +9,16 @@ advection_velocity = (0.2, -0.7, 0.5) equations = LinearScalarAdvectionEquation3D(advection_velocity) initial_condition = initial_condition_gauss -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-5.0, -5.0, -5.0) -coordinates_max = ( 5.0, 5.0, 5.0) +coordinates_max = (5.0, 5.0, 5.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=30_000) - + initial_refinement_level = 4, + n_cells_max = 30_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -30,26 +28,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable=first), - base_level=4, - med_level=5, med_threshold=0.1, - max_level=6, max_threshold=0.6) +amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first), + base_level = 4, + med_level = 5, med_threshold = 0.1, + max_level = 6, max_threshold = 0.6) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.2) +stepsize_callback = StepsizeCallback(cfl = 1.2) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -61,7 +59,7 @@ callbacks = CallbackSet(summary_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); +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/tree_3d_dgsem/elixir_advection_basic.jl b/examples/tree_3d_dgsem/elixir_advection_basic.jl index da91a70fe6d..3ea50423be7 100644 --- a/examples/tree_3d_dgsem/elixir_advection_basic.jl +++ b/examples/tree_3d_dgsem/elixir_advection_basic.jl @@ -9,19 +9,19 @@ advection_velocity = (0.2, -0.7, 0.5) equations = LinearScalarAdvectionEquation3D(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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -1.0, -1.0) # minimum coordinates (min(x), min(y), min(z)) -coordinates_max = ( 1.0, 1.0, 1.0) # maximum coordinates (max(x), max(y), max(z)) +coordinates_max = (1.0, 1.0, 1.0) # maximum coordinates (max(x), max(y), max(z)) # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=30_000) # set maximum capacity of tree data structure + initial_refinement_level = 3, + n_cells_max = 30_000) # set maximum capacity of tree data structure # A semidiscretization collects data structures and functions for the spatial discretization -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, solver) - +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, + solver) ############################################################################### # ODE solvers, callbacks etc. @@ -34,26 +34,26 @@ ode = semidiscretize(semi, (0.0, 1.0)); summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +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.2) +stepsize_callback = StepsizeCallback(cfl = 1.2) # 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) - +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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/tree_3d_dgsem/elixir_advection_diffusion_amr.jl b/examples/tree_3d_dgsem/elixir_advection_diffusion_amr.jl index 0fab685b642..6a8f8d02590 100644 --- a/examples/tree_3d_dgsem/elixir_advection_diffusion_amr.jl +++ b/examples/tree_3d_dgsem/elixir_advection_diffusion_amr.jl @@ -11,27 +11,28 @@ equations = LinearScalarAdvectionEquation3D(advection_velocity) diffusivity() = 5.0e-4 equations_parabolic = LaplaceDiffusion3D(diffusivity(), equations) -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -1.0, -1.0) -coordinates_max = ( 1.0, 1.0, 1.0) +coordinates_max = (1.0, 1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=80_000) + initial_refinement_level = 4, + n_cells_max = 80_000) # Define initial condition -function initial_condition_diffusive_convergence_test(x, t, equation::LinearScalarAdvectionEquation3D) - # Store translated coordinate for easy use of exact solution - x_trans = x - equation.advection_velocity * t - - nu = diffusivity() - c = 1.0 - A = 0.5 - L = 2 - f = 1/L - omega = 2 * pi * f - scalar = c + A * sin(omega * sum(x_trans)) * exp(-2 * nu * omega^2 * t) - return SVector(scalar) +function initial_condition_diffusive_convergence_test(x, t, + equation::LinearScalarAdvectionEquation3D) + # Store translated coordinate for easy use of exact solution + x_trans = x - equation.advection_velocity * t + + nu = diffusivity() + c = 1.0 + A = 0.5 + L = 2 + f = 1 / L + omega = 2 * pi * f + scalar = c + A * sin(omega * sum(x_trans)) * exp(-2 * nu * omega^2 * t) + return SVector(scalar) end initial_condition = initial_condition_diffusive_convergence_test @@ -43,9 +44,8 @@ boundary_conditions_parabolic = boundary_condition_periodic semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; - boundary_conditions=(boundary_conditions, - boundary_conditions_parabolic)) - + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic)) ############################################################################### # ODE solvers, callbacks etc. @@ -56,26 +56,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable=first), - base_level=3, - med_level=4, med_threshold=1.2, - max_level=5, max_threshold=1.45) +amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first), + base_level = 3, + med_level = 4, med_threshold = 1.2, + max_level = 5, max_threshold = 1.45) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -87,7 +87,7 @@ callbacks = CallbackSet(summary_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 \ No newline at end of file +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/tree_3d_dgsem/elixir_advection_diffusion_nonperiodic.jl b/examples/tree_3d_dgsem/elixir_advection_diffusion_nonperiodic.jl index 5dc6e6338a7..4c30406680a 100644 --- a/examples/tree_3d_dgsem/elixir_advection_diffusion_nonperiodic.jl +++ b/examples/tree_3d_dgsem/elixir_advection_diffusion_nonperiodic.jl @@ -10,16 +10,16 @@ equations = LinearScalarAdvectionEquation3D(advection_velocity) equations_parabolic = LaplaceDiffusion3D(diffusivity(), equations) # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -0.5, -0.25) # minimum coordinates (min(x), min(y), min(z)) -coordinates_max = ( 0.0, 0.5, 0.25) # maximum coordinates (max(x), max(y), max(z)) +coordinates_max = (0.0, 0.5, 0.25) # maximum coordinates (max(x), max(y), max(z)) # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - periodicity=false, - n_cells_max=30_000) # set maximum capacity of tree data structure + initial_refinement_level = 3, + periodicity = false, + n_cells_max = 30_000) # set maximum capacity of tree data structure # Example setup taken from # - Truman Ellis, Jesse Chan, and Leszek Demkowicz (2016). @@ -28,24 +28,24 @@ mesh = TreeMesh(coordinates_min, coordinates_max, # to numerical partial differential equations. # [DOI](https://doi.org/10.1007/978-3-319-41640-3_6). function initial_condition_eriksson_johnson(x, t, equations) - l = 4 - epsilon = diffusivity() # TODO: this requires epsilon < .6 due to sqrt - lambda_1 = (-1 + sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) - lambda_2 = (-1 - sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) - r1 = (1 + sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) - s1 = (1 - sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) - u = exp(-l * t) * (exp(lambda_1 * x[1]) - exp(lambda_2 * x[1])) + - cos(pi * x[2]) * (exp(s1 * x[1]) - exp(r1 * x[1])) / (exp(-s1) - exp(-r1)) - return SVector{1}(u) + l = 4 + epsilon = diffusivity() # TODO: this requires epsilon < .6 due to sqrt + lambda_1 = (-1 + sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + lambda_2 = (-1 - sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + r1 = (1 + sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + s1 = (1 - sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + u = exp(-l * t) * (exp(lambda_1 * x[1]) - exp(lambda_2 * x[1])) + + cos(pi * x[2]) * (exp(s1 * x[1]) - exp(r1 * x[1])) / (exp(-s1) - exp(-r1)) + return SVector{1}(u) end initial_condition = initial_condition_eriksson_johnson boundary_conditions = (; x_neg = BoundaryConditionDirichlet(initial_condition), - y_neg = BoundaryConditionDirichlet(initial_condition), - z_neg = boundary_condition_do_nothing, - y_pos = BoundaryConditionDirichlet(initial_condition), - x_pos = boundary_condition_do_nothing, - z_pos = boundary_condition_do_nothing) + y_neg = BoundaryConditionDirichlet(initial_condition), + z_neg = boundary_condition_do_nothing, + y_pos = BoundaryConditionDirichlet(initial_condition), + x_pos = boundary_condition_do_nothing, + z_pos = boundary_condition_do_nothing) boundary_conditions_parabolic = BoundaryConditionDirichlet(initial_condition) @@ -53,9 +53,8 @@ boundary_conditions_parabolic = BoundaryConditionDirichlet(initial_condition) semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; - boundary_conditions=(boundary_conditions, - boundary_conditions_parabolic)) - + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic)) ############################################################################### # ODE solvers, callbacks etc. @@ -70,22 +69,21 @@ summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) # The AliveCallback prints short status information in regular intervals -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) - ############################################################################### # run the simulation # OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks time_int_tol = 1.0e-11 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) # Print the timer summary summary_callback() diff --git a/examples/tree_3d_dgsem/elixir_advection_extended.jl b/examples/tree_3d_dgsem/elixir_advection_extended.jl index d820f47f25c..efc20c64f6d 100644 --- a/examples/tree_3d_dgsem/elixir_advection_extended.jl +++ b/examples/tree_3d_dgsem/elixir_advection_extended.jl @@ -18,21 +18,20 @@ initial_condition = initial_condition_convergence_test boundary_conditions = boundary_condition_periodic # 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) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -1.0, -1.0) # minimum coordinates (min(x), min(y), min(z)) -coordinates_max = ( 1.0, 1.0, 1.0) # maximum coordinates (max(x), max(y), max(z)) +coordinates_max = (1.0, 1.0, 1.0) # maximum coordinates (max(x), max(y), max(z)) # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=30_000, # set maximum capacity of tree data structure - periodicity=true) + initial_refinement_level = 3, + n_cells_max = 30_000, # set maximum capacity of tree data structure + periodicity = true) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -47,24 +46,24 @@ summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy, energy_total)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy, energy_total)) # The AliveCallback prints short status information in regular intervals -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) # The SaveRestartCallback allows to save a file from which a Trixi simulation can be restarted -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) # The SaveSolutionCallback allows to save the solution to a file in regular intervals -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) # The StepsizeCallback handles the re-calculation of the maximum Δt after each time step -stepsize_callback = StepsizeCallback(cfl=1.2) +stepsize_callback = StepsizeCallback(cfl = 1.2) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver callbacks = CallbackSet(summary_callback, @@ -72,14 +71,13 @@ callbacks = CallbackSet(summary_callback, save_restart, 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.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +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); # Print the timer summary summary_callback() diff --git a/examples/tree_3d_dgsem/elixir_advection_mortar.jl b/examples/tree_3d_dgsem/elixir_advection_mortar.jl index 7b24f152b6a..d27a19c7dcf 100644 --- a/examples/tree_3d_dgsem/elixir_advection_mortar.jl +++ b/examples/tree_3d_dgsem/elixir_advection_mortar.jl @@ -9,23 +9,21 @@ advection_velocity = (0.2, -0.7, 0.5) equations = LinearScalarAdvectionEquation3D(advection_velocity) initial_condition = initial_condition_convergence_test -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -1.0, -1.0) -coordinates_max = ( 1.0, 1.0, 1.0) -refinement_patches = ( - (type="box", coordinates_min=(0.0, -1.0, -1.0), coordinates_max=(1.0, 1.0, 1.0)), - (type="box", coordinates_min=(0.0, -0.5, -0.5), coordinates_max=(0.5, 0.5, 0.5)), -) +coordinates_max = (1.0, 1.0, 1.0) +refinement_patches = ((type = "box", coordinates_min = (0.0, -1.0, -1.0), + coordinates_max = (1.0, 1.0, 1.0)), + (type = "box", coordinates_min = (0.0, -0.5, -0.5), + coordinates_max = (0.5, 0.5, 0.5))) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - refinement_patches=refinement_patches, - n_cells_max=10_000,) - + initial_refinement_level = 2, + refinement_patches = refinement_patches, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -35,17 +33,17 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.2) +stepsize_callback = StepsizeCallback(cfl = 1.2) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -53,11 +51,10 @@ callbacks = CallbackSet(summary_callback, save_solution, 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); +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/tree_3d_dgsem/elixir_advection_restart.jl b/examples/tree_3d_dgsem/elixir_advection_restart.jl index b7835ed061f..f81e013fc0a 100644 --- a/examples/tree_3d_dgsem/elixir_advection_restart.jl +++ b/examples/tree_3d_dgsem/elixir_advection_restart.jl @@ -7,7 +7,6 @@ using Trixi trixi_include(@__MODULE__, joinpath(@__DIR__, "elixir_advection_extended.jl")) - ############################################################################### # adapt the parameters that have changed compared to "elixir_advection_extended.jl" @@ -26,14 +25,13 @@ ode = semidiscretize(semi, tspan, restart_filename); # Do not overwrite the initial snapshot written by elixir_advection_extended.jl. save_solution.condition.save_initial_solution = false -integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=dt, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +integrator = init(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); # Get the last time index and work with that. load_timestep!(integrator, restart_filename) - ############################################################################### # run the simulation diff --git a/examples/tree_3d_dgsem/elixir_euler_amr.jl b/examples/tree_3d_dgsem/elixir_euler_amr.jl index f226a6b446d..9bd7f74c688 100644 --- a/examples/tree_3d_dgsem/elixir_euler_amr.jl +++ b/examples/tree_3d_dgsem/elixir_euler_amr.jl @@ -14,30 +14,28 @@ A Gaussian pulse in the density with constant velocity and pressure; reduces the compressible Euler equations to the linear advection equations. """ function initial_condition_density_pulse(x, t, equations::CompressibleEulerEquations3D) - rho = 1 + exp(-(x[1]^2 + x[2]^2 + x[3]^2))/2 - v1 = 1 - v2 = 1 - v3 = 1 - rho_v1 = rho * v1 - rho_v2 = rho * v2 - rho_v3 = rho * v3 - p = 1 - rho_e = p/(equations.gamma - 1) + 1/2 * rho * (v1^2 + v2^2 + v3^2) - return SVector(rho, rho_v1, rho_v2, rho_v3, rho_e) + rho = 1 + exp(-(x[1]^2 + x[2]^2 + x[3]^2)) / 2 + v1 = 1 + v2 = 1 + v3 = 1 + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_v3 = rho * v3 + p = 1 + rho_e = p / (equations.gamma - 1) + 1 / 2 * rho * (v1^2 + v2^2 + v3^2) + return SVector(rho, rho_v1, rho_v2, rho_v3, rho_e) end initial_condition = initial_condition_density_pulse -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-5.0, -5.0, -5.0) -coordinates_max = ( 5.0, 5.0, 5.0) +coordinates_max = (5.0, 5.0, 5.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -47,40 +45,39 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable=first), - base_level=4, - med_level=5, med_threshold=1.05, - max_level=6, max_threshold=1.3) +amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first), + base_level = 4, + med_level = 5, med_threshold = 1.05, + max_level = 6, max_threshold = 1.3) amr_callback = AMRCallback(semi, amr_controller, - interval=5, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=0.9) +stepsize_callback = StepsizeCallback(cfl = 0.9) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_restart, 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); +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/tree_3d_dgsem/elixir_euler_blob_amr.jl b/examples/tree_3d_dgsem/elixir_euler_blob_amr.jl index a8d112f5b05..0ce886620cc 100644 --- a/examples/tree_3d_dgsem/elixir_euler_blob_amr.jl +++ b/examples/tree_3d_dgsem/elixir_euler_blob_amr.jl @@ -4,7 +4,7 @@ using Trixi ############################################################################### # semidiscretization of the compressible Euler equations -gamma = 5/3 +gamma = 5 / 3 equations = CompressibleEulerEquations3D(gamma) """ @@ -16,63 +16,65 @@ The blob test case taken from [arXiv: astro-ph/0610051](https://arxiv.org/abs/astro-ph/0610051) """ function initial_condition_blob(x, t, equations::CompressibleEulerEquations3D) - # blob test case, see Agertz et al. https://arxiv.org/pdf/astro-ph/0610051.pdf - # other reference: https://arxiv.org/pdf/astro-ph/0610051.pdf - # change discontinuity to tanh - # typical domain is rectangular, we change it to a square - # resolution 128^3, 256^3 - # domain size is [-20.0,20.0]^3 - # gamma = 5/3 for this test case - R = 1.0 # radius of the blob - # background density - rho = 1.0 - Chi = 10.0 # density contrast - # reference time of characteristic growth of KH instability equal to 1.0 - tau_kh = 1.0 - tau_cr = tau_kh / 1.6 # crushing time - # determine background velocity - v1 = 2 * R * sqrt(Chi) / tau_cr - v2 = 0.0 - v3 = 0.0 - Ma0 = 2.7 # background flow Mach number Ma=v/c - c = v1 / Ma0 # sound speed - # use perfect gas assumption to compute background pressure via the sound speed c^2 = gamma * pressure/density - p = c * c * rho / equations.gamma - # initial center of the blob - inicenter = [-15, 0, 0] - x_rel = x - inicenter - r = sqrt(x_rel[1]^2 + x_rel[2]^2 + x_rel[3]^2) - # steepness of the tanh transition zone - slope = 2 - # density blob - rho = rho + (Chi - 1) * 0.5 * (1 + (tanh(slope * (r + R)) - (tanh(slope *(r - R)) + 1))) - # velocity blob is zero - v1 = v1 - v1 * 0.5 * (1 + (tanh(slope *(r + R)) - (tanh(slope *(r - R)) + 1))) - return prim2cons(SVector(rho, v1, v2, v3, p), equations) + # blob test case, see Agertz et al. https://arxiv.org/pdf/astro-ph/0610051.pdf + # other reference: https://arxiv.org/pdf/astro-ph/0610051.pdf + # change discontinuity to tanh + # typical domain is rectangular, we change it to a square + # resolution 128^3, 256^3 + # domain size is [-20.0,20.0]^3 + # gamma = 5/3 for this test case + R = 1.0 # radius of the blob + # background density + rho = 1.0 + Chi = 10.0 # density contrast + # reference time of characteristic growth of KH instability equal to 1.0 + tau_kh = 1.0 + tau_cr = tau_kh / 1.6 # crushing time + # determine background velocity + v1 = 2 * R * sqrt(Chi) / tau_cr + v2 = 0.0 + v3 = 0.0 + Ma0 = 2.7 # background flow Mach number Ma=v/c + c = v1 / Ma0 # sound speed + # use perfect gas assumption to compute background pressure via the sound speed c^2 = gamma * pressure/density + p = c * c * rho / equations.gamma + # initial center of the blob + inicenter = [-15, 0, 0] + x_rel = x - inicenter + r = sqrt(x_rel[1]^2 + x_rel[2]^2 + x_rel[3]^2) + # steepness of the tanh transition zone + slope = 2 + # density blob + rho = rho + + (Chi - 1) * 0.5 * (1 + (tanh(slope * (r + R)) - (tanh(slope * (r - R)) + 1))) + # velocity blob is zero + v1 = v1 - v1 * 0.5 * (1 + (tanh(slope * (r + R)) - (tanh(slope * (r - R)) + 1))) + return prim2cons(SVector(rho, v1, v2, v3, p), equations) end initial_condition = initial_condition_blob volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_hllc, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_hllc, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-20.0, -20.0, -20.0) -coordinates_max = ( 20.0, 20.0, 20.0) - -refinement_patches = ( - (type="box", coordinates_min=(-20.0, -10.0, -10.0), coordinates_max=(-10.0, 10.0, 10.0)), - (type="box", coordinates_min=(-20.0, -5.0, -5.0), coordinates_max=(-10.0, 5.0, 5.0)), - (type="box", coordinates_min=(-17.0, -2.0, -2.0), coordinates_max=(-13.0, 2.0, 2.0)), - (type="box", coordinates_min=(-17.0, -2.0, -2.0), coordinates_max=(-13.0, 2.0, 2.0)), -) +coordinates_max = (20.0, 20.0, 20.0) + +refinement_patches = ((type = "box", coordinates_min = (-20.0, -10.0, -10.0), + coordinates_max = (-10.0, 10.0, 10.0)), + (type = "box", coordinates_min = (-20.0, -5.0, -5.0), + coordinates_max = (-10.0, 5.0, 5.0)), + (type = "box", coordinates_min = (-17.0, -2.0, -2.0), + coordinates_max = (-13.0, 2.0, 2.0)), + (type = "box", coordinates_min = (-17.0, -2.0, -2.0), + coordinates_max = (-13.0, 2.0, 2.0))) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - refinement_patches=refinement_patches, - n_cells_max=100_000,) + initial_refinement_level = 2, + refinement_patches = refinement_patches, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -82,41 +84,40 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 200 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=200, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 200, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorLöhner(semi, - variable=Trixi.density) + variable = Trixi.density) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=1, - med_level =0, med_threshold=0.1, # med_level = current level - max_level =6, max_threshold=0.3) + base_level = 1, + med_level = 0, med_threshold = 0.1, # med_level = current level + max_level = 6, max_threshold = 0.3) amr_callback = AMRCallback(semi, amr_controller, - interval=3, - adapt_initial_condition=false, - adapt_initial_condition_only_refine=true) + interval = 3, + adapt_initial_condition = false, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.7) +stepsize_callback = StepsizeCallback(cfl = 1.7) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, amr_callback, stepsize_callback) - -stage_limiter! = PositivityPreservingLimiterZhangShu(thresholds=(1.0e-4, 1.0e-4), - variables=(Trixi.density, pressure)) +stage_limiter! = PositivityPreservingLimiterZhangShu(thresholds = (1.0e-4, 1.0e-4), + variables = (Trixi.density, pressure)) ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(stage_limiter!, 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); +sol = solve(ode, CarpenterKennedy2N54(stage_limiter!, 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/tree_3d_dgsem/elixir_euler_convergence.jl b/examples/tree_3d_dgsem/elixir_euler_convergence.jl index 2eeb280ae1f..170b292a42f 100644 --- a/examples/tree_3d_dgsem/elixir_euler_convergence.jl +++ b/examples/tree_3d_dgsem/elixir_euler_convergence.jl @@ -9,19 +9,17 @@ equations = CompressibleEulerEquations3D(2.0) initial_condition = initial_condition_eoc_test_coupled_euler_gravity -solver = DGSEM(polydeg=3, surface_flux=flux_hll, - volume_integral=VolumeIntegralWeakForm()) +solver = DGSEM(polydeg = 3, surface_flux = flux_hll, + volume_integral = VolumeIntegralWeakForm()) coordinates_min = (0.0, 0.0, 0.0) coordinates_max = (2.0, 2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=10_000) - + initial_refinement_level = 2, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_eoc_test_euler) - + source_terms = source_terms_eoc_test_euler) ############################################################################### # ODE solvers, callbacks etc. @@ -32,27 +30,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.1) +stepsize_callback = StepsizeCallback(cfl = 1.1) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_3d_dgsem/elixir_euler_convergence_pure_fv.jl b/examples/tree_3d_dgsem/elixir_euler_convergence_pure_fv.jl index dbf5747784c..4789b46dacc 100644 --- a/examples/tree_3d_dgsem/elixir_euler_convergence_pure_fv.jl +++ b/examples/tree_3d_dgsem/elixir_euler_convergence_pure_fv.jl @@ -9,19 +9,17 @@ equations = CompressibleEulerEquations3D(1.4) initial_condition = initial_condition_convergence_test -solver = DGSEM(polydeg=3, surface_flux=flux_hllc, - volume_integral=VolumeIntegralPureLGLFiniteVolume(flux_hllc)) +solver = DGSEM(polydeg = 3, surface_flux = flux_hllc, + volume_integral = VolumeIntegralPureLGLFiniteVolume(flux_hllc)) coordinates_min = (0.0, 0.0, 0.0) coordinates_max = (2.0, 2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=10_000) - + initial_refinement_level = 2, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -32,27 +30,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.6) +stepsize_callback = StepsizeCallback(cfl = 0.6) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_3d_dgsem/elixir_euler_density_pulse.jl b/examples/tree_3d_dgsem/elixir_euler_density_pulse.jl index ee788321c66..cad8fc578c8 100644 --- a/examples/tree_3d_dgsem/elixir_euler_density_pulse.jl +++ b/examples/tree_3d_dgsem/elixir_euler_density_pulse.jl @@ -14,33 +14,31 @@ A Gaussian pulse in the density with constant velocity and pressure; reduces the compressible Euler equations to the linear advection equations. """ function initial_condition_density_pulse(x, t, equations::CompressibleEulerEquations3D) - rho = 1 + exp(-(x[1]^2 + x[2]^2 + x[3]^2))/2 - v1 = 1 - v2 = 1 - v3 = 1 - rho_v1 = rho * v1 - rho_v2 = rho * v2 - rho_v3 = rho * v3 - p = 1 - rho_e = p/(equations.gamma - 1) + 1/2 * rho * (v1^2 + v2^2 + v3^2) - return SVector(rho, rho_v1, rho_v2, rho_v3, rho_e) + rho = 1 + exp(-(x[1]^2 + x[2]^2 + x[3]^2)) / 2 + v1 = 1 + v2 = 1 + v3 = 1 + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_v3 = rho * v3 + p = 1 + rho_e = p / (equations.gamma - 1) + 1 / 2 * rho * (v1^2 + v2^2 + v3^2) + return SVector(rho, rho_v1, rho_v2, rho_v3, rho_e) end initial_condition = initial_condition_density_pulse volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_ranocha, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_ranocha, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-2.0, -2.0, -2.0) -coordinates_max = ( 2.0, 2.0, 2.0) +coordinates_max = (2.0, 2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=100_000) - + initial_refinement_level = 3, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -50,30 +48,29 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.1) +stepsize_callback = StepsizeCallback(cfl = 1.1) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_restart, save_solution, 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); +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/tree_3d_dgsem/elixir_euler_ec.jl b/examples/tree_3d_dgsem/elixir_euler_ec.jl index 08fd1b998d5..88d7cbc7ba5 100644 --- a/examples/tree_3d_dgsem/elixir_euler_ec.jl +++ b/examples/tree_3d_dgsem/elixir_euler_ec.jl @@ -10,19 +10,17 @@ equations = CompressibleEulerEquations3D(1.4) initial_condition = initial_condition_weak_blast_wave volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_ranocha, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_ranocha, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-2.0, -2.0, -2.0) -coordinates_max = ( 2.0, 2.0, 2.0) +coordinates_max = (2.0, 2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=100_000) - + initial_refinement_level = 3, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -32,27 +30,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.3) +stepsize_callback = StepsizeCallback(cfl = 1.3) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_3d_dgsem/elixir_euler_mortar.jl b/examples/tree_3d_dgsem/elixir_euler_mortar.jl index c9fc2dfed50..cf103dc26cf 100644 --- a/examples/tree_3d_dgsem/elixir_euler_mortar.jl +++ b/examples/tree_3d_dgsem/elixir_euler_mortar.jl @@ -8,22 +8,19 @@ using Trixi equations = CompressibleEulerEquations3D(1.4) initial_condition = initial_condition_convergence_test -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0, 0.0, 0.0) coordinates_max = (2.0, 2.0, 2.0) -refinement_patches = ( - (type="box", coordinates_min=(0.5, 0.5, 0.5), coordinates_max=(1.5, 1.5, 1.5)), -) +refinement_patches = ((type = "box", coordinates_min = (0.5, 0.5, 0.5), + coordinates_max = (1.5, 1.5, 1.5)),) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - refinement_patches=refinement_patches, - n_cells_max=10_000) - + initial_refinement_level = 2, + refinement_patches = refinement_patches, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -34,16 +31,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.6) +stepsize_callback = StepsizeCallback(cfl = 0.6) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -53,7 +50,7 @@ callbacks = CallbackSet(summary_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); +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/tree_3d_dgsem/elixir_euler_sedov_blast_wave.jl b/examples/tree_3d_dgsem/elixir_euler_sedov_blast_wave.jl index 3641878149a..87774ada266 100644 --- a/examples/tree_3d_dgsem/elixir_euler_sedov_blast_wave.jl +++ b/examples/tree_3d_dgsem/elixir_euler_sedov_blast_wave.jl @@ -19,34 +19,34 @@ based on Should be used together with [`boundary_condition_sedov_self_gravity`](@ref). """ function initial_condition_sedov_self_gravity(x, t, equations::CompressibleEulerEquations3D) - # Calculate radius as distance from origin - r = sqrt(x[1]^2 + x[2]^2 + x[3]^2) - - # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 - r0 = 0.25 # = 4.0 * smallest dx (for domain length=8 and max-ref=7) - E = 1.0 - p_inner = (equations.gamma - 1) * E / (4/3 * pi * r0^3) - p_ambient = 1e-5 # = true Sedov setup - - # Calculate primitive variables - # use a logistic function to transfer density value smoothly - L = 1.0 # maximum of function - x0 = 1.0 # center point of function - k = -50.0 # sharpness of transfer - logistic_function_rho = L/(1.0 + exp(-k*(r - x0))) - rho_ambient = 1e-5 - rho = max(logistic_function_rho, rho_ambient) # clip background density to not be so tiny - - # velocities are zero - v1 = 0.0 - v2 = 0.0 - v3 = 0.0 - - # use a logistic function to transfer pressure value smoothly - logistic_function_p = p_inner/(1.0 + exp(-k*(r - r0))) - p = max(logistic_function_p, p_ambient) - - return prim2cons(SVector(rho, v1, v2, v3, p), equations) + # Calculate radius as distance from origin + r = sqrt(x[1]^2 + x[2]^2 + x[3]^2) + + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 + r0 = 0.25 # = 4.0 * smallest dx (for domain length=8 and max-ref=7) + E = 1.0 + p_inner = (equations.gamma - 1) * E / (4 / 3 * pi * r0^3) + p_ambient = 1e-5 # = true Sedov setup + + # Calculate primitive variables + # use a logistic function to transfer density value smoothly + L = 1.0 # maximum of function + x0 = 1.0 # center point of function + k = -50.0 # sharpness of transfer + logistic_function_rho = L / (1.0 + exp(-k * (r - x0))) + rho_ambient = 1e-5 + rho = max(logistic_function_rho, rho_ambient) # clip background density to not be so tiny + + # velocities are zero + v1 = 0.0 + v2 = 0.0 + v3 = 0.0 + + # use a logistic function to transfer pressure value smoothly + logistic_function_p = p_inner / (1.0 + exp(-k * (r - r0))) + p = max(logistic_function_p, p_ambient) + + return prim2cons(SVector(rho, v1, v2, v3, p), equations) end initial_condition = initial_condition_sedov_self_gravity @@ -64,26 +64,26 @@ based on Should be used together with [`initial_condition_sedov_self_gravity`](@ref). """ function boundary_condition_sedov_self_gravity(u_inner, orientation, direction, x, t, - surface_flux_function, - equations::CompressibleEulerEquations3D) - # velocities are zero, density/pressure are ambient values according to - # initial_condition_sedov_self_gravity - rho = 1e-5 - v1 = 0.0 - v2 = 0.0 - v3 = 0.0 - p = 1e-5 - - u_boundary = prim2cons(SVector(rho, v1, v2, v3, p), equations) - - # Calculate boundary flux - if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary - flux = surface_flux_function(u_inner, u_boundary, orientation, equations) - else # u_boundary is "left" of boundary, u_inner is "right" of boundary - flux = surface_flux_function(u_boundary, u_inner, orientation, equations) - end - - return flux + surface_flux_function, + equations::CompressibleEulerEquations3D) + # velocities are zero, density/pressure are ambient values according to + # initial_condition_sedov_self_gravity + rho = 1e-5 + v1 = 0.0 + v2 = 0.0 + v3 = 0.0 + p = 1e-5 + + u_boundary = prim2cons(SVector(rho, v1, v2, v3, p), equations) + + # Calculate boundary flux + if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary + flux = surface_flux_function(u_inner, u_boundary, orientation, equations) + else # u_boundary is "left" of boundary, u_inner is "right" of boundary + flux = surface_flux_function(u_boundary, u_inner, orientation, equations) + end + + return flux end boundary_conditions = boundary_condition_sedov_self_gravity @@ -92,26 +92,24 @@ volume_flux = flux_ranocha polydeg = 3 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.7, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.7, + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-4.0, -4.0, -4.0) -coordinates_max = ( 4.0, 4.0, 4.0) +coordinates_max = (4.0, 4.0, 4.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=1_000_000, - periodicity=false) - + initial_refinement_level = 2, + n_cells_max = 1_000_000, + periodicity = false) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -122,42 +120,41 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=1.0, - alpha_min=0.0, - alpha_smooth=false, - variable=density_pressure) + alpha_max = 1.0, + alpha_min = 0.0, + alpha_smooth = false, + variable = density_pressure) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=2, - max_level =7, max_threshold=0.0003) + base_level = 2, + max_level = 7, max_threshold = 0.0003) amr_callback = AMRCallback(semi, amr_controller, - interval=1, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 1, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=0.35) +stepsize_callback = StepsizeCallback(cfl = 0.35) 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); +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/tree_3d_dgsem/elixir_euler_shockcapturing.jl b/examples/tree_3d_dgsem/elixir_euler_shockcapturing.jl index 3015f6c50a4..0a90615016c 100644 --- a/examples/tree_3d_dgsem/elixir_euler_shockcapturing.jl +++ b/examples/tree_3d_dgsem/elixir_euler_shockcapturing.jl @@ -10,30 +10,28 @@ equations = CompressibleEulerEquations3D(1.4) initial_condition = initial_condition_weak_blast_wave surface_flux = flux_ranocha # OBS! Using a non-dissipative flux is only sensible to test EC, - # but not for real shock simulations +# but not for real shock simulations volume_flux = flux_ranocha polydeg = 3 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-2.0, -2.0, -2.0) -coordinates_max = ( 2.0, 2.0, 2.0) +coordinates_max = (2.0, 2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=100_000) - + initial_refinement_level = 3, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -43,27 +41,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.4) +stepsize_callback = StepsizeCallback(cfl = 1.4) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_3d_dgsem/elixir_euler_shockcapturing_amr.jl b/examples/tree_3d_dgsem/elixir_euler_shockcapturing_amr.jl index 3d338cd7f01..be31fbbc42c 100644 --- a/examples/tree_3d_dgsem/elixir_euler_shockcapturing_amr.jl +++ b/examples/tree_3d_dgsem/elixir_euler_shockcapturing_amr.jl @@ -10,30 +10,28 @@ equations = CompressibleEulerEquations3D(1.4) initial_condition = initial_condition_weak_blast_wave surface_flux = flux_ranocha # OBS! Using a non-dissipative flux is only sensible to test EC, - # but not for real shock simulations +# but not for real shock simulations volume_flux = flux_ranocha polydeg = 3 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (-2.0, -2.0, -2.0) -coordinates_max = ( 2.0, 2.0, 2.0) +coordinates_max = (2.0, 2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=100_000) - + initial_refinement_level = 3, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -43,41 +41,39 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) amr_indicator = IndicatorHennemannGassner(semi, - alpha_smooth=false, - variable=density_pressure) + alpha_smooth = false, + variable = density_pressure) amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level=2, - max_level =4, max_threshold=0.0003) + base_level = 2, + max_level = 4, max_threshold = 0.0003) amr_callback = AMRCallback(semi, amr_controller, - interval=1, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 1, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -stepsize_callback = StepsizeCallback(cfl=1.3) +stepsize_callback = StepsizeCallback(cfl = 1.3) 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); +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/tree_3d_dgsem/elixir_euler_source_terms.jl b/examples/tree_3d_dgsem/elixir_euler_source_terms.jl index 3445e9fc433..f0246c30490 100644 --- a/examples/tree_3d_dgsem/elixir_euler_source_terms.jl +++ b/examples/tree_3d_dgsem/elixir_euler_source_terms.jl @@ -9,19 +9,17 @@ equations = CompressibleEulerEquations3D(1.4) initial_condition = initial_condition_convergence_test -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs, - volume_integral=VolumeIntegralWeakForm()) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralWeakForm()) coordinates_min = (0.0, 0.0, 0.0) coordinates_max = (2.0, 2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=10_000) - + initial_refinement_level = 2, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -32,27 +30,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.6) +stepsize_callback = StepsizeCallback(cfl = 0.6) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_3d_dgsem/elixir_euler_taylor_green_vortex.jl b/examples/tree_3d_dgsem/elixir_euler_taylor_green_vortex.jl index 693f9ce9049..135ee673e44 100644 --- a/examples/tree_3d_dgsem/elixir_euler_taylor_green_vortex.jl +++ b/examples/tree_3d_dgsem/elixir_euler_taylor_green_vortex.jl @@ -12,35 +12,37 @@ equations = CompressibleEulerEquations3D(1.4) The classical inviscid Taylor-Green vortex. """ -function initial_condition_taylor_green_vortex(x, t, equations::CompressibleEulerEquations3D) - A = 1.0 # magnitude of speed - Ms = 0.1 # maximum Mach number - - rho = 1.0 - v1 = A * sin(x[1]) * cos(x[2]) * cos(x[3]) - v2 = -A * cos(x[1]) * sin(x[2]) * cos(x[3]) - v3 = 0.0 - p = (A / Ms)^2 * rho / equations.gamma # scaling to get Ms - p = p + 1.0/16.0 * A^2 * rho * (cos(2*x[1])*cos(2*x[3]) + 2*cos(2*x[2]) + 2*cos(2*x[1]) + cos(2*x[2])*cos(2*x[3])) - - return prim2cons(SVector(rho, v1, v2, v3, p), equations) +function initial_condition_taylor_green_vortex(x, t, + equations::CompressibleEulerEquations3D) + A = 1.0 # magnitude of speed + Ms = 0.1 # maximum Mach number + + rho = 1.0 + v1 = A * sin(x[1]) * cos(x[2]) * cos(x[3]) + v2 = -A * cos(x[1]) * sin(x[2]) * cos(x[3]) + v3 = 0.0 + p = (A / Ms)^2 * rho / equations.gamma # scaling to get Ms + p = p + + 1.0 / 16.0 * A^2 * rho * + (cos(2 * x[1]) * cos(2 * x[3]) + 2 * cos(2 * x[2]) + 2 * cos(2 * x[1]) + + cos(2 * x[2]) * cos(2 * x[3])) + + return prim2cons(SVector(rho, v1, v2, v3, p), equations) end initial_condition = initial_condition_taylor_green_vortex volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-1.0, -1.0, -1.0) .* pi -coordinates_max = ( 1.0, 1.0, 1.0) .* pi +coordinates_max = (1.0, 1.0, 1.0) .* pi mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=100_000) - + initial_refinement_level = 3, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -50,27 +52,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.4) +stepsize_callback = StepsizeCallback(cfl = 1.4) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_3d_dgsem/elixir_eulergravity_convergence.jl b/examples/tree_3d_dgsem/elixir_eulergravity_convergence.jl index 6699ec9a4da..21ef661d0b6 100644 --- a/examples/tree_3d_dgsem/elixir_eulergravity_convergence.jl +++ b/examples/tree_3d_dgsem/elixir_eulergravity_convergence.jl @@ -15,12 +15,12 @@ solver_euler = DGSEM(polydeg, flux_hll) coordinates_min = (0.0, 0.0, 0.0) coordinates_max = (2.0, 2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=10_000) - -semi_euler = SemidiscretizationHyperbolic(mesh, equations_euler, initial_condition, solver_euler, - source_terms=source_terms_eoc_test_coupled_euler_gravity) + initial_refinement_level = 2, + n_cells_max = 10_000) +semi_euler = SemidiscretizationHyperbolic(mesh, equations_euler, initial_condition, + solver_euler, + source_terms = source_terms_eoc_test_coupled_euler_gravity) ############################################################################### # semidiscretization of the hyperbolic diffusion equations @@ -28,22 +28,21 @@ equations_gravity = HyperbolicDiffusionEquations3D() solver_gravity = DGSEM(polydeg, flux_lax_friedrichs) -semi_gravity = SemidiscretizationHyperbolic(mesh, equations_gravity, initial_condition, solver_gravity, - source_terms=source_terms_harmonic) - +semi_gravity = SemidiscretizationHyperbolic(mesh, equations_gravity, initial_condition, + solver_gravity, + source_terms = source_terms_harmonic) ############################################################################### # combining both semidiscretizations for Euler + self-gravity -parameters = ParametersEulerGravity(background_density=2.0, # aka rho0 - gravitational_constant=1.0, # aka G - cfl=1.5, - resid_tol=1.0e-10, - n_iterations_max=1000, - timestep_gravity=timestep_gravity_erk52_3Sstar!) +parameters = ParametersEulerGravity(background_density = 2.0, # aka rho0 + gravitational_constant = 1.0, # aka G + cfl = 1.5, + resid_tol = 1.0e-10, + n_iterations_max = 1000, + timestep_gravity = timestep_gravity_erk52_3Sstar!) semi = SemidiscretizationEulerGravity(semi_euler, semi_gravity, parameters) - ############################################################################### # ODE solvers, callbacks etc. tspan = (0.0, 0.5) @@ -52,20 +51,20 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi_euler, interval=analysis_interval, - save_analysis=true) +analysis_callback = AnalysisCallback(semi_euler, interval = analysis_interval, + save_analysis = true) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=10, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 10, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.1) +stepsize_callback = StepsizeCallback(cfl = 1.1) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -74,11 +73,10 @@ callbacks = CallbackSet(summary_callback, save_solution, 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); +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 println("Number of gravity subcycles: ", semi.gravity_counter.ncalls_since_readout) diff --git a/examples/tree_3d_dgsem/elixir_hypdiff_lax_friedrichs.jl b/examples/tree_3d_dgsem/elixir_hypdiff_lax_friedrichs.jl index c7744ce23bd..7bba154a925 100644 --- a/examples/tree_3d_dgsem/elixir_hypdiff_lax_friedrichs.jl +++ b/examples/tree_3d_dgsem/elixir_hypdiff_lax_friedrichs.jl @@ -8,53 +8,52 @@ using Trixi equations = HyperbolicDiffusionEquations3D() function initial_condition_poisson_periodic(x, t, equations::HyperbolicDiffusionEquations3D) - # elliptic equation: -νΔϕ = f - # depending on initial constant state, c, for phi this converges to the solution ϕ + c - if iszero(t) - phi = 0.0 - q1 = 0.0 - q2 = 0.0 - q3 = 0.0 - else - phi = sin(2 * pi * x[1]) * sin(2 * pi * x[2]) * sin(2 * pi * x[3]) - q1 = 2 * pi * cos(2 * pi * x[1]) * sin(2 * pi * x[2]) * sin(2 * pi * x[3]) - q2 = 2 * pi * sin(2 * pi * x[1]) * cos(2 * pi * x[2]) * sin(2 * pi * x[3]) - q3 = 2 * pi * sin(2 * pi * x[1]) * sin(2 * pi * x[2]) * cos(2 * pi * x[3]) - end - return SVector(phi, q1, q2, q3) + # elliptic equation: -νΔϕ = f + # depending on initial constant state, c, for phi this converges to the solution ϕ + c + if iszero(t) + phi = 0.0 + q1 = 0.0 + q2 = 0.0 + q3 = 0.0 + else + phi = sin(2 * pi * x[1]) * sin(2 * pi * x[2]) * sin(2 * pi * x[3]) + q1 = 2 * pi * cos(2 * pi * x[1]) * sin(2 * pi * x[2]) * sin(2 * pi * x[3]) + q2 = 2 * pi * sin(2 * pi * x[1]) * cos(2 * pi * x[2]) * sin(2 * pi * x[3]) + q3 = 2 * pi * sin(2 * pi * x[1]) * sin(2 * pi * x[2]) * cos(2 * pi * x[3]) + end + return SVector(phi, q1, q2, q3) end initial_condition = initial_condition_poisson_periodic -@inline function source_terms_poisson_periodic(u, x, t, equations::HyperbolicDiffusionEquations3D) - # elliptic equation: -νΔϕ = f - # analytical solution: phi = sin(2πx)*sin(2πy) and f = -8νπ^2 sin(2πx)*sin(2πy) - @unpack inv_Tr = equations - C = -12 * equations.nu * pi^2 - - x1, x2, x3 = x - tmp1 = sinpi(2 * x1) - tmp2 = sinpi(2 * x2) - tmp3 = sinpi(2 * x3) - du1 = -C*tmp1*tmp2*tmp3 - du2 = -inv_Tr * u[2] - du3 = -inv_Tr * u[3] - du4 = -inv_Tr * u[4] - - return SVector(du1, du2, du3, du4) +@inline function source_terms_poisson_periodic(u, x, t, + equations::HyperbolicDiffusionEquations3D) + # elliptic equation: -νΔϕ = f + # analytical solution: phi = sin(2πx)*sin(2πy) and f = -8νπ^2 sin(2πx)*sin(2πy) + @unpack inv_Tr = equations + C = -12 * equations.nu * pi^2 + + x1, x2, x3 = x + tmp1 = sinpi(2 * x1) + tmp2 = sinpi(2 * x2) + tmp3 = sinpi(2 * x3) + du1 = -C * tmp1 * tmp2 * tmp3 + du2 = -inv_Tr * u[2] + du3 = -inv_Tr * u[3] + du4 = -inv_Tr * u[4] + + return SVector(du1, du2, du3, du4) end -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0, 0.0, 0.0) coordinates_max = (1.0, 1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=30_000) - + initial_refinement_level = 3, + n_cells_max = 30_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_poisson_periodic) - + source_terms = source_terms_poisson_periodic) ############################################################################### # ODE solvers, callbacks etc. @@ -65,20 +64,20 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() resid_tol = 5.0e-12 -steady_state_callback = SteadyStateCallback(abstol=resid_tol, reltol=0.0) +steady_state_callback = SteadyStateCallback(abstol = resid_tol, reltol = 0.0) analysis_interval = 200 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy, energy_total)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy, energy_total)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=2.4) +stepsize_callback = StepsizeCallback(cfl = 2.4) callbacks = CallbackSet(summary_callback, steady_state_callback, analysis_callback, alive_callback, @@ -89,6 +88,6 @@ callbacks = CallbackSet(summary_callback, steady_state_callback, # run the simulation sol = Trixi.solve(ode, Trixi.HypDiffN3Erk3Sstar52(), - dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); + 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/tree_3d_dgsem/elixir_hypdiff_nonperiodic.jl b/examples/tree_3d_dgsem/elixir_hypdiff_nonperiodic.jl index beefb22ea1e..831e01519b6 100644 --- a/examples/tree_3d_dgsem/elixir_hypdiff_nonperiodic.jl +++ b/examples/tree_3d_dgsem/elixir_hypdiff_nonperiodic.jl @@ -8,27 +8,25 @@ using Trixi equations = HyperbolicDiffusionEquations3D() initial_condition = initial_condition_poisson_nonperiodic -boundary_conditions = (x_neg=boundary_condition_poisson_nonperiodic, - x_pos=boundary_condition_poisson_nonperiodic, - y_neg=boundary_condition_periodic, - y_pos=boundary_condition_periodic, - z_neg=boundary_condition_periodic, - z_pos=boundary_condition_periodic) +boundary_conditions = (x_neg = boundary_condition_poisson_nonperiodic, + x_pos = boundary_condition_poisson_nonperiodic, + y_neg = boundary_condition_periodic, + y_pos = boundary_condition_periodic, + z_neg = boundary_condition_periodic, + z_pos = boundary_condition_periodic) -solver = DGSEM(polydeg=4, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 4, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0, 0.0, 0.0) coordinates_max = (1.0, 1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=30_000, - periodicity=(false, true, true)) - + initial_refinement_level = 2, + n_cells_max = 30_000, + periodicity = (false, true, true)) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_poisson_nonperiodic, - boundary_conditions=boundary_conditions) - + source_terms = source_terms_poisson_nonperiodic, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -39,31 +37,30 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() resid_tol = 1.0e-5 -steady_state_callback = SteadyStateCallback(abstol=resid_tol, reltol=0.0) +steady_state_callback = SteadyStateCallback(abstol = resid_tol, reltol = 0.0) analysis_interval = 200 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(entropy, energy_total)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy, energy_total)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.8) +stepsize_callback = StepsizeCallback(cfl = 1.8) callbacks = CallbackSet(summary_callback, steady_state_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) - ############################################################################### # run the simulation sol = Trixi.solve(ode, Trixi.HypDiffN3Erk3Sstar52(), - dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); + 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/tree_3d_dgsem/elixir_lbm_constant.jl b/examples/tree_3d_dgsem/elixir_lbm_constant.jl index 269a0da2d50..ee38f62887d 100644 --- a/examples/tree_3d_dgsem/elixir_lbm_constant.jl +++ b/examples/tree_3d_dgsem/elixir_lbm_constant.jl @@ -5,22 +5,20 @@ using Trixi ############################################################################### # semidiscretization of the Lattice-Boltzmann equations for the D3Q27 scheme -equations = LatticeBoltzmannEquations3D(Ma=0.1, Re=Inf) +equations = LatticeBoltzmannEquations3D(Ma = 0.1, Re = Inf) initial_condition = initial_condition_constant -solver = DGSEM(polydeg=3, surface_flux=flux_godunov) +solver = DGSEM(polydeg = 3, surface_flux = flux_godunov) coordinates_min = (-1.0, -1.0, -1.0) -coordinates_max = ( 1.0, 1.0, 1.0) +coordinates_max = (1.0, 1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=10_000,) - + initial_refinement_level = 3, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -30,19 +28,19 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2macroscopic) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2macroscopic) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) collision_callback = LBMCollisionCallback() @@ -52,11 +50,10 @@ callbacks = CallbackSet(summary_callback, stepsize_callback, collision_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); +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/tree_3d_dgsem/elixir_lbm_taylor_green_vortex.jl b/examples/tree_3d_dgsem/elixir_lbm_taylor_green_vortex.jl index b3835eb1287..0980ee56be3 100644 --- a/examples/tree_3d_dgsem/elixir_lbm_taylor_green_vortex.jl +++ b/examples/tree_3d_dgsem/elixir_lbm_taylor_green_vortex.jl @@ -6,7 +6,7 @@ using Trixi # semidiscretization of the Lattice-Boltzmann equations for the D3Q27 scheme L = 1.0 # reference length -equations = LatticeBoltzmannEquations3D(Ma=0.1, Re=1600.0; L=L) +equations = LatticeBoltzmannEquations3D(Ma = 0.1, Re = 1600.0; L = L) """ initial_condition_taylor_green_vortex(x, t, equations::LatticeBoltzmannEquations3D) @@ -14,52 +14,51 @@ equations = LatticeBoltzmannEquations3D(Ma=0.1, Re=1600.0; L=L) Initialize the flow field to the Taylor-Green vortex setup """ function initial_condition_taylor_green_vortex(x, t, equations::LatticeBoltzmannEquations3D) - @unpack u0, rho0, L = equations + @unpack u0, rho0, L = equations - v1 = u0 * sin(x[1] / L) * cos(x[2] / L) * cos(x[3] / L) - v2 = -u0 * cos(x[1] / L) * sin(x[2] / L) * cos(x[3] / L) - v3 = 0 - p0 = (pressure(rho0, equations) + - rho0 * u0^2 / 16 * (cos(2 * x[1] / L) + cos(2 * x[2] / L)) * (cos(2 * x[3] / L) + 2)) - rho = density(p0, equations) + v1 = u0 * sin(x[1] / L) * cos(x[2] / L) * cos(x[3] / L) + v2 = -u0 * cos(x[1] / L) * sin(x[2] / L) * cos(x[3] / L) + v3 = 0 + p0 = (pressure(rho0, equations) + + rho0 * u0^2 / 16 * (cos(2 * x[1] / L) + cos(2 * x[2] / L)) * + (cos(2 * x[3] / L) + 2)) + rho = density(p0, equations) - return equilibrium_distribution(rho, v1, v2, v3, equations) + return equilibrium_distribution(rho, v1, v2, v3, equations) end initial_condition = initial_condition_taylor_green_vortex -solver = DGSEM(polydeg=3, surface_flux=flux_godunov) +solver = DGSEM(polydeg = 3, surface_flux = flux_godunov) -coordinates_min = (-pi*L, -pi*L, -pi*L) -coordinates_max = ( pi*L, pi*L, pi*L) +coordinates_min = (-pi * L, -pi * L, -pi * L) +coordinates_max = (pi * L, pi * L, pi * L) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=5, - n_cells_max=300_000,) - + initial_refinement_level = 5, + n_cells_max = 300_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 20*equations.L/equations.u0) # Final time is `20` in non-dimensional time +tspan = (0.0, 20 * equations.L / equations.u0) # Final time is `20` in non-dimensional time ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 20 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - save_analysis=true, - extra_analysis_integrals=(Trixi.energy_kinetic_nondimensional,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_integrals = (Trixi.energy_kinetic_nondimensional,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2macroscopic) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2macroscopic) -stepsize_callback = StepsizeCallback(cfl=0.3) +stepsize_callback = StepsizeCallback(cfl = 0.3) collision_callback = LBMCollisionCallback() @@ -69,12 +68,11 @@ callbacks = CallbackSet(summary_callback, stepsize_callback, collision_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, - save_start=false, alias_u0=true); +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, + save_start = false, alias_u0 = true); summary_callback() # print the timer summary diff --git a/examples/tree_3d_dgsem/elixir_mhd_alfven_wave.jl b/examples/tree_3d_dgsem/elixir_mhd_alfven_wave.jl index 191982bf2d6..9aab5e58788 100644 --- a/examples/tree_3d_dgsem/elixir_mhd_alfven_wave.jl +++ b/examples/tree_3d_dgsem/elixir_mhd_alfven_wave.jl @@ -5,24 +5,23 @@ using Trixi ############################################################################### # semidiscretization of the compressible ideal GLM-MHD equations -equations = IdealGlmMhdEquations3D(5/3) +equations = IdealGlmMhdEquations3D(5 / 3) initial_condition = initial_condition_convergence_test volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -solver = DGSEM(polydeg=3, surface_flux=(flux_lax_friedrichs, flux_nonconservative_powell), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, + surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-1.0, -1.0, -1.0) -coordinates_max = ( 1.0, 1.0, 1.0) +coordinates_max = (1.0, 1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=10_000) - + initial_refinement_level = 2, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -32,18 +31,18 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=10, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 10, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) cfl = 1.5 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -51,11 +50,10 @@ callbacks = CallbackSet(summary_callback, stepsize_callback, glm_speed_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); +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/tree_3d_dgsem/elixir_mhd_alfven_wave_mortar.jl b/examples/tree_3d_dgsem/elixir_mhd_alfven_wave_mortar.jl index e23f7ce5460..3ce166a7fa7 100644 --- a/examples/tree_3d_dgsem/elixir_mhd_alfven_wave_mortar.jl +++ b/examples/tree_3d_dgsem/elixir_mhd_alfven_wave_mortar.jl @@ -5,24 +5,22 @@ using Trixi ############################################################################### # semidiscretization of the compressible ideal GLM-MHD equations -equations = IdealGlmMhdEquations3D(5/3) +equations = IdealGlmMhdEquations3D(5 / 3) initial_condition = initial_condition_convergence_test volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -solver = DGSEM(polydeg=3, surface_flux=(flux_hll, flux_nonconservative_powell), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = (flux_hll, flux_nonconservative_powell), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-1.0, -1.0, -1.0) -coordinates_max = ( 1.0, 1.0, 1.0) -refinement_patches = ( - (type="box", coordinates_min=(-0.5, -0.5, -0.5), - coordinates_max=( 0.5, 0.5, 0.5)), -) +coordinates_max = (1.0, 1.0, 1.0) +refinement_patches = ((type = "box", coordinates_min = (-0.5, -0.5, -0.5), + coordinates_max = (0.5, 0.5, 0.5)),) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - refinement_patches=refinement_patches, - n_cells_max=10_000) + initial_refinement_level = 2, + refinement_patches = refinement_patches, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -35,18 +33,18 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) cfl = 1.0 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -54,11 +52,10 @@ callbacks = CallbackSet(summary_callback, stepsize_callback, glm_speed_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); +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/tree_3d_dgsem/elixir_mhd_ec.jl b/examples/tree_3d_dgsem/elixir_mhd_ec.jl index 057ffcb031f..1f0088e82c9 100644 --- a/examples/tree_3d_dgsem/elixir_mhd_ec.jl +++ b/examples/tree_3d_dgsem/elixir_mhd_ec.jl @@ -10,19 +10,18 @@ equations = IdealGlmMhdEquations3D(1.4) initial_condition = initial_condition_weak_blast_wave volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -solver = DGSEM(polydeg=3, surface_flux=(flux_hindenlang_gassner, flux_nonconservative_powell), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, + surface_flux = (flux_hindenlang_gassner, flux_nonconservative_powell), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-2.0, -2.0, -2.0) -coordinates_max = ( 2.0, 2.0, 2.0) +coordinates_max = (2.0, 2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=10_000) - + initial_refinement_level = 2, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -32,19 +31,19 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=10, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 10, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) cfl = 1.4 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, @@ -52,11 +51,10 @@ callbacks = CallbackSet(summary_callback, stepsize_callback, glm_speed_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); +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/tree_3d_dgsem/elixir_mhd_ec_shockcapturing.jl b/examples/tree_3d_dgsem/elixir_mhd_ec_shockcapturing.jl index 6b4f6e310ce..f8a72b6f452 100644 --- a/examples/tree_3d_dgsem/elixir_mhd_ec_shockcapturing.jl +++ b/examples/tree_3d_dgsem/elixir_mhd_ec_shockcapturing.jl @@ -10,25 +10,26 @@ equations = IdealGlmMhdEquations3D(1.4) initial_condition = initial_condition_weak_blast_wave surface_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) +volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) polydeg = 4 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) -solver = DGSEM(polydeg=polydeg, surface_flux=surface_flux, volume_integral=volume_integral) +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral) coordinates_min = (-2.0, -2.0, -2.0) -coordinates_max = ( 2.0, 2.0, 2.0) +coordinates_max = (2.0, 2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=10_000) + initial_refinement_level = 3, + n_cells_max = 10_000) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -42,25 +43,24 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) cfl = 1.4 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, stepsize_callback, glm_speed_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); +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/tree_3d_dgsem/elixir_navierstokes_convergence.jl b/examples/tree_3d_dgsem/elixir_navierstokes_convergence.jl index ebb0137a1bb..3ada9503c6a 100644 --- a/examples/tree_3d_dgsem/elixir_navierstokes_convergence.jl +++ b/examples/tree_3d_dgsem/elixir_navierstokes_convergence.jl @@ -8,213 +8,215 @@ prandtl_number() = 0.72 mu() = 0.01 equations = CompressibleEulerEquations3D(1.4) -equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu=mu(), Prandtl=prandtl_number(), - gradient_variables=GradientVariablesPrimitive()) +equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu = mu(), + Prandtl = prandtl_number(), + gradient_variables = GradientVariablesPrimitive()) # 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, - volume_integral=VolumeIntegralWeakForm()) +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralWeakForm()) coordinates_min = (-1.0, -1.0, -1.0) # minimum coordinates (min(x), min(y), min(z)) -coordinates_max = ( 1.0, 1.0, 1.0) # maximum coordinates (max(x), max(y), max(z)) +coordinates_max = (1.0, 1.0, 1.0) # maximum coordinates (max(x), max(y), max(z)) # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - periodicity=(true, false, true), - n_cells_max=50_000) # set maximum capacity of tree data structure + initial_refinement_level = 3, + periodicity = (true, false, true), + n_cells_max = 50_000) # set maximum capacity of tree data structure # Note: the initial condition cannot be specialized to `CompressibleNavierStokesDiffusion3D` # since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesDiffusion3D`) # and by the initial condition (which passes in `CompressibleEulerEquations3D`). # This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) function initial_condition_navier_stokes_convergence_test(x, t, equations) - # Constants. OBS! Must match those in `source_terms_navier_stokes_convergence_test` - c = 2.0 - A1 = 0.5 - A2 = 1.0 - A3 = 0.5 - - # Convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_z = pi * x[3] - pi_t = 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.0) * (1.0 - exp(-A3 * (x[2] - 1.0))) * sin(pi_z) * cos(pi_t) - v2 = v1 - v3 = v1 - p = rho^2 - - return prim2cons(SVector(rho, v1, v2, v3, p), equations) + # Constants. OBS! Must match those in `source_terms_navier_stokes_convergence_test` + c = 2.0 + A1 = 0.5 + A2 = 1.0 + A3 = 0.5 + + # Convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_z = pi * x[3] + pi_t = 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.0) * (1.0 - exp(-A3 * (x[2] - 1.0))) * sin(pi_z) * + cos(pi_t) + v2 = v1 + v3 = v1 + p = rho^2 + + return prim2cons(SVector(rho, v1, v2, v3, p), equations) end @inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) - # TODO: parabolic - # we currently need to hardcode these parameters until we fix the "combined equation" issue - # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 - inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = prandtl_number() - mu_ = mu() - - # Constants. OBS! Must match those in `initial_condition_navier_stokes_convergence_test` - c = 2.0 - A1 = 0.5 - A2 = 1.0 - A3 = 0.5 - - # Convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_z = pi * x[3] - pi_t = pi * t - - # Define auxiliary functions for the strange function of the y variable - # to make expressions easier to read - g = log(x[2] + 2.0) * (1.0 - exp(-A3 * (x[2] - 1.0))) - g_y = ( A3 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0)) - + (1.0 - exp(-A3 * (x[2] - 1.0))) / (x[2] + 2.0) ) - g_yy = ( 2.0 * A3 * exp(-A3 * (x[2] - 1.0)) / (x[2] + 2.0) - - (1.0 - exp(-A3 * (x[2] - 1.0))) / ((x[2] + 2.0)^2) - - A3^2 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0)) ) - - # Density and its derivatives - rho = c + A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t) - rho_t = -pi * A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * sin(pi_t) - rho_x = pi * A1 * cos(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t) - rho_y = -pi * A1 * sin(pi_x) * sin(pi_y) * sin(pi_z) * cos(pi_t) - rho_z = pi * A1 * sin(pi_x) * cos(pi_y) * cos(pi_z) * cos(pi_t) - rho_xx = -pi^2 * (rho - c) - rho_yy = -pi^2 * (rho - c) - rho_zz = -pi^2 * (rho - c) - - # Velocities and their derivatives - # v1 terms - v1 = A2 * sin(pi_x) * g * sin(pi_z) * cos(pi_t) - v1_t = -pi * A2 * sin(pi_x) * g * sin(pi_z) * sin(pi_t) - v1_x = pi * A2 * cos(pi_x) * g * sin(pi_z) * cos(pi_t) - v1_y = A2 * sin(pi_x) * g_y * sin(pi_z) * cos(pi_t) - v1_z = pi * A2 * sin(pi_x) * g * cos(pi_z) * cos(pi_t) - v1_xx = -pi^2 * v1 - v1_yy = A2 * sin(pi_x) * g_yy * sin(pi_z) * cos(pi_t) - v1_zz = -pi^2 * v1 - v1_xy = pi * A2 * cos(pi_x) * g_y * sin(pi_z) * cos(pi_t) - v1_xz = pi^2 * A2 * cos(pi_x) * g * cos(pi_z) * cos(pi_t) - v1_yz = pi * A2 * sin(pi_x) * g_y * cos(pi_z) * cos(pi_t) - # v2 terms (simplifies from ansatz) - v2 = v1 - v2_t = v1_t - v2_x = v1_x - v2_y = v1_y - v2_z = v1_z - v2_xx = v1_xx - v2_yy = v1_yy - v2_zz = v1_zz - v2_xy = v1_xy - v2_yz = v1_yz - # v3 terms (simplifies from ansatz) - v3 = v1 - v3_t = v1_t - v3_x = v1_x - v3_y = v1_y - v3_z = v1_z - v3_xx = v1_xx - v3_yy = v1_yy - v3_zz = v1_zz - v3_xz = v1_xz - v3_yz = v1_yz - - # Pressure and its derivatives - p = rho^2 - p_t = 2.0 * rho * rho_t - p_x = 2.0 * rho * rho_x - p_y = 2.0 * rho * rho_y - p_z = 2.0 * rho * rho_z - - # Total energy and its derivatives; simiplifies from ansatz that v2 = v1 and v3 = v1 - E = p * inv_gamma_minus_one + 1.5 * rho * v1^2 - E_t = p_t * inv_gamma_minus_one + 1.5 * rho_t * v1^2 + 3.0 * rho * v1 * v1_t - E_x = p_x * inv_gamma_minus_one + 1.5 * rho_x * v1^2 + 3.0 * rho * v1 * v1_x - E_y = p_y * inv_gamma_minus_one + 1.5 * rho_y * v1^2 + 3.0 * rho * v1 * v1_y - E_z = p_z * inv_gamma_minus_one + 1.5 * rho_z * v1^2 + 3.0 * rho * v1 * v1_z - - # Divergence of Fick's law ∇⋅∇q = kappa ∇⋅∇T; simplifies because p = rho², so T = p/rho = rho - kappa = equations.gamma * inv_gamma_minus_one / Pr - q_xx = kappa * rho_xx # kappa T_xx - q_yy = kappa * rho_yy # kappa T_yy - q_zz = kappa * rho_zz # kappa T_zz - - # Stress tensor and its derivatives (exploit symmetry) - tau11 = 4.0 / 3.0 * v1_x - 2.0 / 3.0 * (v2_y + v3_z) - tau12 = v1_y + v2_x - tau13 = v1_z + v3_x - tau22 = 4.0 / 3.0 * v2_y - 2.0 / 3.0 * (v1_x + v3_z) - tau23 = v2_z + v3_y - tau33 = 4.0 / 3.0 * v3_z - 2.0 / 3.0 * (v1_x + v2_y) - - tau11_x = 4.0 / 3.0 * v1_xx - 2.0 / 3.0 * (v2_xy + v3_xz) - tau12_x = v1_xy + v2_xx - tau13_x = v1_xz + v3_xx - - tau12_y = v1_yy + v2_xy - tau22_y = 4.0 / 3.0 * v2_yy - 2.0 / 3.0 * (v1_xy + v3_yz) - tau23_y = v2_yz + v3_yy - - tau13_z = v1_zz + v3_xz - tau23_z = v2_zz + v3_yz - tau33_z = 4.0 / 3.0 * v3_zz - 2.0 / 3.0 * (v1_xz + v2_yz) - - # Compute the source terms - # Density equation - du1 = ( rho_t + rho_x * v1 + rho * v1_x - + rho_y * v2 + rho * v2_y - + rho_z * v3 + rho * v3_z ) - # x-momentum equation - du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 - + 2.0 * rho * v1 * v1_x - + rho_y * v1 * v2 - + rho * v1_y * v2 - + rho * v1 * v2_y - + rho_z * v1 * v3 - + rho * v1_z * v3 - + rho * v1 * v3_z - - mu_ * (tau11_x + tau12_y + tau13_z) ) - # y-momentum equation - du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 - + rho * v1_x * v2 - + rho * v1 * v2_x - + rho_y * v2^2 - + 2.0 * rho * v2 * v2_y - + rho_z * v2 * v3 - + rho * v2_z * v3 - + rho * v2 * v3_z - - mu_ * (tau12_x + tau22_y + tau23_z) ) - # z-momentum equation - du4 = ( rho_t * v3 + rho * v3_t + p_z + rho_x * v1 * v3 - + rho * v1_x * v3 - + rho * v1 * v3_x - + rho_y * v2 * v3 - + rho * v2_y * v3 - + rho * v2 * v3_y - + rho_z * v3^2 - + 2.0 * rho * v3 * v3_z - - mu_ * (tau13_x + tau23_y + tau33_z) ) - # Total energy equation - du5 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) - + v2_y * (E + p) + v2 * (E_y + p_y) - + v3_z * (E + p) + v3 * (E_z + p_z) - # stress tensor and temperature gradient from x-direction - - mu_ * ( q_xx + v1_x * tau11 + v2_x * tau12 + v3_x * tau13 - + v1 * tau11_x + v2 * tau12_x + v3 * tau13_x) - # stress tensor and temperature gradient terms from y-direction - - mu_ * ( q_yy + v1_y * tau12 + v2_y * tau22 + v3_y * tau23 - + v1 * tau12_y + v2 * tau22_y + v3 * tau23_y) - # stress tensor and temperature gradient terms from z-direction - - mu_ * ( q_zz + v1_z * tau13 + v2_z * tau23 + v3_z * tau33 - + v1 * tau13_z + v2 * tau23_z + v3 * tau33_z) ) - - return SVector(du1, du2, du3, du4, du5) + # TODO: parabolic + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + mu_ = mu() + + # Constants. OBS! Must match those in `initial_condition_navier_stokes_convergence_test` + c = 2.0 + A1 = 0.5 + A2 = 1.0 + A3 = 0.5 + + # Convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_z = pi * x[3] + pi_t = pi * t + + # Define auxiliary functions for the strange function of the y variable + # to make expressions easier to read + g = log(x[2] + 2.0) * (1.0 - exp(-A3 * (x[2] - 1.0))) + g_y = (A3 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0)) + + (1.0 - exp(-A3 * (x[2] - 1.0))) / (x[2] + 2.0)) + g_yy = (2.0 * A3 * exp(-A3 * (x[2] - 1.0)) / (x[2] + 2.0) - + (1.0 - exp(-A3 * (x[2] - 1.0))) / ((x[2] + 2.0)^2) - + A3^2 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0))) + + # Density and its derivatives + rho = c + A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t) + rho_t = -pi * A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * sin(pi_t) + rho_x = pi * A1 * cos(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t) + rho_y = -pi * A1 * sin(pi_x) * sin(pi_y) * sin(pi_z) * cos(pi_t) + rho_z = pi * A1 * sin(pi_x) * cos(pi_y) * cos(pi_z) * cos(pi_t) + rho_xx = -pi^2 * (rho - c) + rho_yy = -pi^2 * (rho - c) + rho_zz = -pi^2 * (rho - c) + + # Velocities and their derivatives + # v1 terms + v1 = A2 * sin(pi_x) * g * sin(pi_z) * cos(pi_t) + v1_t = -pi * A2 * sin(pi_x) * g * sin(pi_z) * sin(pi_t) + v1_x = pi * A2 * cos(pi_x) * g * sin(pi_z) * cos(pi_t) + v1_y = A2 * sin(pi_x) * g_y * sin(pi_z) * cos(pi_t) + v1_z = pi * A2 * sin(pi_x) * g * cos(pi_z) * cos(pi_t) + v1_xx = -pi^2 * v1 + v1_yy = A2 * sin(pi_x) * g_yy * sin(pi_z) * cos(pi_t) + v1_zz = -pi^2 * v1 + v1_xy = pi * A2 * cos(pi_x) * g_y * sin(pi_z) * cos(pi_t) + v1_xz = pi^2 * A2 * cos(pi_x) * g * cos(pi_z) * cos(pi_t) + v1_yz = pi * A2 * sin(pi_x) * g_y * cos(pi_z) * cos(pi_t) + # v2 terms (simplifies from ansatz) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_z = v1_z + v2_xx = v1_xx + v2_yy = v1_yy + v2_zz = v1_zz + v2_xy = v1_xy + v2_yz = v1_yz + # v3 terms (simplifies from ansatz) + v3 = v1 + v3_t = v1_t + v3_x = v1_x + v3_y = v1_y + v3_z = v1_z + v3_xx = v1_xx + v3_yy = v1_yy + v3_zz = v1_zz + v3_xz = v1_xz + v3_yz = v1_yz + + # Pressure and its derivatives + p = rho^2 + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_z = 2.0 * rho * rho_z + + # Total energy and its derivatives; simiplifies from ansatz that v2 = v1 and v3 = v1 + E = p * inv_gamma_minus_one + 1.5 * rho * v1^2 + E_t = p_t * inv_gamma_minus_one + 1.5 * rho_t * v1^2 + 3.0 * rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + 1.5 * rho_x * v1^2 + 3.0 * rho * v1 * v1_x + E_y = p_y * inv_gamma_minus_one + 1.5 * rho_y * v1^2 + 3.0 * rho * v1 * v1_y + E_z = p_z * inv_gamma_minus_one + 1.5 * rho_z * v1^2 + 3.0 * rho * v1 * v1_z + + # Divergence of Fick's law ∇⋅∇q = kappa ∇⋅∇T; simplifies because p = rho², so T = p/rho = rho + kappa = equations.gamma * inv_gamma_minus_one / Pr + q_xx = kappa * rho_xx # kappa T_xx + q_yy = kappa * rho_yy # kappa T_yy + q_zz = kappa * rho_zz # kappa T_zz + + # Stress tensor and its derivatives (exploit symmetry) + tau11 = 4.0 / 3.0 * v1_x - 2.0 / 3.0 * (v2_y + v3_z) + tau12 = v1_y + v2_x + tau13 = v1_z + v3_x + tau22 = 4.0 / 3.0 * v2_y - 2.0 / 3.0 * (v1_x + v3_z) + tau23 = v2_z + v3_y + tau33 = 4.0 / 3.0 * v3_z - 2.0 / 3.0 * (v1_x + v2_y) + + tau11_x = 4.0 / 3.0 * v1_xx - 2.0 / 3.0 * (v2_xy + v3_xz) + tau12_x = v1_xy + v2_xx + tau13_x = v1_xz + v3_xx + + tau12_y = v1_yy + v2_xy + tau22_y = 4.0 / 3.0 * v2_yy - 2.0 / 3.0 * (v1_xy + v3_yz) + tau23_y = v2_yz + v3_yy + + tau13_z = v1_zz + v3_xz + tau23_z = v2_zz + v3_yz + tau33_z = 4.0 / 3.0 * v3_zz - 2.0 / 3.0 * (v1_xz + v2_yz) + + # Compute the source terms + # Density equation + du1 = (rho_t + rho_x * v1 + rho * v1_x + + rho_y * v2 + rho * v2_y + + rho_z * v3 + rho * v3_z) + # x-momentum equation + du2 = (rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y + + rho_z * v1 * v3 + + rho * v1_z * v3 + + rho * v1 * v3_z - + mu_ * (tau11_x + tau12_y + tau13_z)) + # y-momentum equation + du3 = (rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y + + rho_z * v2 * v3 + + rho * v2_z * v3 + + rho * v2 * v3_z - + mu_ * (tau12_x + tau22_y + tau23_z)) + # z-momentum equation + du4 = (rho_t * v3 + rho * v3_t + p_z + rho_x * v1 * v3 + + rho * v1_x * v3 + + rho * v1 * v3_x + + rho_y * v2 * v3 + + rho * v2_y * v3 + + rho * v2 * v3_y + + rho_z * v3^2 + + 2.0 * rho * v3 * v3_z - + mu_ * (tau13_x + tau23_y + tau33_z)) + # Total energy equation + du5 = (E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) + + v3_z * (E + p) + v3 * (E_z + p_z) - + # stress tensor and temperature gradient from x-direction + mu_ * (q_xx + v1_x * tau11 + v2_x * tau12 + v3_x * tau13 + + v1 * tau11_x + v2 * tau12_x + v3 * tau13_x) - + # stress tensor and temperature gradient terms from y-direction + mu_ * (q_yy + v1_y * tau12 + v2_y * tau22 + v3_y * tau23 + + v1 * tau12_y + v2 * tau22_y + v3 * tau23_y) - + # stress tensor and temperature gradient terms from z-direction + mu_ * (q_zz + v1_z * tau13 + v2_z * tau23 + v3_z * tau33 + + v1 * tau13_z + v2 * tau23_z + v3 * tau33_z)) + + return SVector(du1, du2, du3, du4, du5) end initial_condition = initial_condition_navier_stokes_convergence_test @@ -222,30 +224,33 @@ initial_condition = initial_condition_navier_stokes_convergence_test # BC types velocity_bc_top_bottom = NoSlip() do x, t, equations u = initial_condition_navier_stokes_convergence_test(x, t, equations) - return SVector(u[2], u[3], u[4]) + return SVector(u[2], u[3], u[4]) end heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) -boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, heat_bc_top_bottom) +boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, + heat_bc_top_bottom) # define inviscid boundary conditions boundary_conditions = (; x_neg = boundary_condition_periodic, - x_pos = boundary_condition_periodic, - y_neg = boundary_condition_slip_wall, - y_pos = boundary_condition_slip_wall, - z_neg = boundary_condition_periodic, - z_pos = boundary_condition_periodic) + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_slip_wall, + y_pos = boundary_condition_slip_wall, + z_neg = boundary_condition_periodic, + z_pos = boundary_condition_periodic) # define viscous boundary conditions boundary_conditions_parabolic = (; x_neg = boundary_condition_periodic, - x_pos = boundary_condition_periodic, - y_neg = boundary_condition_top_bottom, - y_pos = boundary_condition_top_bottom, - z_neg = boundary_condition_periodic, - z_pos = boundary_condition_periodic) - -semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; - boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), - source_terms=source_terms_navier_stokes_convergence_test) + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_top_bottom, + y_pos = boundary_condition_top_bottom, + z_neg = boundary_condition_periodic, + z_pos = boundary_condition_periodic) + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic), + source_terms = source_terms_navier_stokes_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -255,16 +260,15 @@ tspan = (0.0, 1.0) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval = 10) analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) ############################################################################### # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, dt = 1e-5, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary - diff --git a/examples/tree_3d_dgsem/elixir_navierstokes_taylor_green_vortex.jl b/examples/tree_3d_dgsem/elixir_navierstokes_taylor_green_vortex.jl index 5556831a59d..65bd9aa133d 100644 --- a/examples/tree_3d_dgsem/elixir_navierstokes_taylor_green_vortex.jl +++ b/examples/tree_3d_dgsem/elixir_navierstokes_taylor_green_vortex.jl @@ -10,8 +10,8 @@ prandtl_number() = 0.72 mu() = 6.25e-4 # equivalent to Re = 1600 equations = CompressibleEulerEquations3D(1.4) -equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu=mu(), - Prandtl=prandtl_number()) +equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu = mu(), + Prandtl = prandtl_number()) """ initial_condition_taylor_green_vortex(x, t, equations::CompressibleEulerEquations3D) @@ -22,31 +22,34 @@ The classical viscous Taylor-Green vortex, as found for instance in Simulation of the Compressible Taylor Green Vortex using High-Order Flux Reconstruction Schemes [DOI: 10.2514/6.2014-3210](https://doi.org/10.2514/6.2014-3210) """ -function initial_condition_taylor_green_vortex(x, t, equations::CompressibleEulerEquations3D) - A = 1.0 # magnitude of speed - Ms = 0.1 # maximum Mach number - - rho = 1.0 - v1 = A * sin(x[1]) * cos(x[2]) * cos(x[3]) - v2 = -A * cos(x[1]) * sin(x[2]) * cos(x[3]) - v3 = 0.0 - p = (A / Ms)^2 * rho / equations.gamma # scaling to get Ms - p = p + 1.0/16.0 * A^2 * rho * (cos(2*x[1])*cos(2*x[3]) + 2*cos(2*x[2]) + 2*cos(2*x[1]) + cos(2*x[2])*cos(2*x[3])) - - return prim2cons(SVector(rho, v1, v2, v3, p), equations) +function initial_condition_taylor_green_vortex(x, t, + equations::CompressibleEulerEquations3D) + A = 1.0 # magnitude of speed + Ms = 0.1 # maximum Mach number + + rho = 1.0 + v1 = A * sin(x[1]) * cos(x[2]) * cos(x[3]) + v2 = -A * cos(x[1]) * sin(x[2]) * cos(x[3]) + v3 = 0.0 + p = (A / Ms)^2 * rho / equations.gamma # scaling to get Ms + p = p + + 1.0 / 16.0 * A^2 * rho * + (cos(2 * x[1]) * cos(2 * x[3]) + 2 * cos(2 * x[2]) + 2 * cos(2 * x[1]) + + cos(2 * x[2]) * cos(2 * x[3])) + + return prim2cons(SVector(rho, v1, v2, v3, p), equations) end initial_condition = initial_condition_taylor_green_vortex volume_flux = flux_ranocha -solver = DGSEM(polydeg=3, surface_flux=flux_hllc, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = flux_hllc, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-1.0, -1.0, -1.0) .* pi -coordinates_max = ( 1.0, 1.0, 1.0) .* pi +coordinates_max = (1.0, 1.0, 1.0) .* pi mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=3, - n_cells_max=100_000) - + initial_refinement_level = 3, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver) @@ -60,12 +63,13 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 50 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=true, - extra_analysis_integrals=(energy_kinetic, - energy_internal, - enstrophy)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_integrals = (energy_kinetic, + energy_internal, + enstrophy)) -alive_callback = AliveCallback(analysis_interval=analysis_interval,) +alive_callback = AliveCallback(analysis_interval = analysis_interval) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -75,6 +79,6 @@ callbacks = CallbackSet(summary_callback, # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(); abstol=time_int_tol, reltol=time_int_tol, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary diff --git a/examples/tree_3d_fdsbp/elixir_advection_extended.jl b/examples/tree_3d_fdsbp/elixir_advection_extended.jl index 241e0698649..22085a63510 100644 --- a/examples/tree_3d_fdsbp/elixir_advection_extended.jl +++ b/examples/tree_3d_fdsbp/elixir_advection_extended.jl @@ -13,22 +13,21 @@ equations = LinearScalarAdvectionEquation3D(advection_velocity) initial_condition = initial_condition_convergence_test D_SBP = derivative_operator(SummationByPartsOperators.MattssonNordström2004(), - derivative_order=1, accuracy_order=4, - xmin=0.0, xmax=1.0, N=10) + derivative_order = 1, accuracy_order = 4, + xmin = 0.0, xmax = 1.0, N = 10) solver = FDSBP(D_SBP, - surface_integral=SurfaceIntegralStrongForm(flux_lax_friedrichs), - volume_integral=VolumeIntegralStrongForm()) + surface_integral = SurfaceIntegralStrongForm(flux_lax_friedrichs), + volume_integral = VolumeIntegralStrongForm()) coordinates_min = (-1.0, -1.0, -1.0) -coordinates_max = ( 1.0, 1.0, 1.0) +coordinates_max = (1.0, 1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=1, - n_cells_max=30_000, - periodicity=true) + initial_refinement_level = 1, + n_cells_max = 30_000, + periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -38,19 +37,18 @@ ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(energy_total,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (energy_total,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) - ############################################################################### # run the simulation -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-9, reltol=1.0e-9, - ode_default_options()..., callback=callbacks) +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-9, reltol = 1.0e-9, + ode_default_options()..., callback = callbacks) summary_callback() diff --git a/examples/tree_3d_fdsbp/elixir_euler_convergence.jl b/examples/tree_3d_fdsbp/elixir_euler_convergence.jl index 6aafa1b5cc1..aa5b231ee13 100644 --- a/examples/tree_3d_fdsbp/elixir_euler_convergence.jl +++ b/examples/tree_3d_fdsbp/elixir_euler_convergence.jl @@ -11,24 +11,23 @@ equations = CompressibleEulerEquations3D(1.4) initial_condition = initial_condition_convergence_test D_upw = upwind_operators(SummationByPartsOperators.Mattsson2017, - derivative_order=1, - accuracy_order=4, - xmin=-1.0, xmax=1.0, - N=16) + derivative_order = 1, + accuracy_order = 4, + xmin = -1.0, xmax = 1.0, + N = 16) flux_splitting = splitting_steger_warming solver = FDSBP(D_upw, - surface_integral=SurfaceIntegralUpwind(flux_splitting), - volume_integral=VolumeIntegralUpwind(flux_splitting)) + surface_integral = SurfaceIntegralUpwind(flux_splitting), + volume_integral = VolumeIntegralUpwind(flux_splitting)) coordinates_min = (0.0, 0.0, 0.0) coordinates_max = (2.0, 2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=10_000) + initial_refinement_level = 2, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) - + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -39,27 +38,26 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=1.1) +stepsize_callback = StepsizeCallback(cfl = 1.1) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, 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); +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/tree_3d_fdsbp/elixir_euler_taylor_green_vortex.jl b/examples/tree_3d_fdsbp/elixir_euler_taylor_green_vortex.jl index d2495cff5cd..0354200ae42 100644 --- a/examples/tree_3d_fdsbp/elixir_euler_taylor_green_vortex.jl +++ b/examples/tree_3d_fdsbp/elixir_euler_taylor_green_vortex.jl @@ -14,40 +14,43 @@ equations = CompressibleEulerEquations3D(1.4) The classical inviscid Taylor-Green vortex. """ -function initial_condition_taylor_green_vortex(x, t, equations::CompressibleEulerEquations3D) - A = 1.0 # magnitude of speed - Ms = 0.1 # maximum Mach number - - rho = 1.0 - v1 = A * sin(x[1]) * cos(x[2]) * cos(x[3]) - v2 = -A * cos(x[1]) * sin(x[2]) * cos(x[3]) - v3 = 0.0 - p = (A / Ms)^2 * rho / equations.gamma # scaling to get Ms - p = p + 1.0/16.0 * A^2 * rho * (cos(2*x[1])*cos(2*x[3]) + 2*cos(2*x[2]) + 2*cos(2*x[1]) + cos(2*x[2])*cos(2*x[3])) - - return prim2cons(SVector(rho, v1, v2, v3, p), equations) +function initial_condition_taylor_green_vortex(x, t, + equations::CompressibleEulerEquations3D) + A = 1.0 # magnitude of speed + Ms = 0.1 # maximum Mach number + + rho = 1.0 + v1 = A * sin(x[1]) * cos(x[2]) * cos(x[3]) + v2 = -A * cos(x[1]) * sin(x[2]) * cos(x[3]) + v3 = 0.0 + p = (A / Ms)^2 * rho / equations.gamma # scaling to get Ms + p = p + + 1.0 / 16.0 * A^2 * rho * + (cos(2 * x[1]) * cos(2 * x[3]) + 2 * cos(2 * x[2]) + 2 * cos(2 * x[1]) + + cos(2 * x[2]) * cos(2 * x[3])) + + return prim2cons(SVector(rho, v1, v2, v3, p), equations) end initial_condition = initial_condition_taylor_green_vortex D_upw = upwind_operators(SummationByPartsOperators.Mattsson2017, - derivative_order=1, - accuracy_order=4, - xmin=-1.0, xmax=1.0, - N=16) + derivative_order = 1, + accuracy_order = 4, + xmin = -1.0, xmax = 1.0, + N = 16) flux_splitting = splitting_steger_warming solver = FDSBP(D_upw, - surface_integral=SurfaceIntegralUpwind(flux_splitting), - volume_integral=VolumeIntegralUpwind(flux_splitting)) + surface_integral = SurfaceIntegralUpwind(flux_splitting), + volume_integral = VolumeIntegralUpwind(flux_splitting)) coordinates_min = (-1.0, -1.0, -1.0) .* pi -coordinates_max = ( 1.0, 1.0, 1.0) .* pi +coordinates_max = (1.0, 1.0, 1.0) .* pi mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=2, - n_cells_max=100_000) + initial_refinement_level = 2, + n_cells_max = 100_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - ############################################################################### # ODE solvers, callbacks etc. @@ -57,28 +60,27 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - save_analysis=true, - extra_analysis_integrals=(energy_total, - energy_kinetic, - energy_internal,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_integrals = (energy_total, + energy_kinetic, + energy_internal)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) - ############################################################################### # run the simulation -sol = solve(ode, SSPRK43(); abstol=1.0e-6, reltol=1.0e-6, - ode_default_options()..., callback=callbacks) +sol = solve(ode, SSPRK43(); abstol = 1.0e-6, reltol = 1.0e-6, + ode_default_options()..., callback = callbacks) summary_callback() # print the timer summary diff --git a/examples/unstructured_2d_dgsem/elixir_acoustics_gauss_wall.jl b/examples/unstructured_2d_dgsem/elixir_acoustics_gauss_wall.jl index 2f8228dffb8..8f8e867dca8 100644 --- a/examples/unstructured_2d_dgsem/elixir_acoustics_gauss_wall.jl +++ b/examples/unstructured_2d_dgsem/elixir_acoustics_gauss_wall.jl @@ -6,16 +6,18 @@ using Trixi ############################################################################### # semidiscretization of the acoustic perturbation equations -equations = AcousticPerturbationEquations2D(v_mean_global=(0.0, -0.5), c_mean_global=1.0, - rho_mean_global=1.0) +equations = AcousticPerturbationEquations2D(v_mean_global = (0.0, -0.5), + c_mean_global = 1.0, + rho_mean_global = 1.0) # Create DG solver with polynomial degree = 4 and (local) Lax-Friedrichs/Rusanov flux -solver = DGSEM(polydeg=4, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 4, surface_flux = flux_lax_friedrichs) # Create unstructured quadrilateral mesh from a file default_mesh_file = joinpath(@__DIR__, "mesh_five_circles_in_circle.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/3c79baad6b4d73bb26ec6420b5d16f45/raw/22aefc4ec2107cf0bffc40e81dfbc52240c625b1/mesh_five_circles_in_circle.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/3c79baad6b4d73bb26ec6420b5d16f45/raw/22aefc4ec2107cf0bffc40e81dfbc52240c625b1/mesh_five_circles_in_circle.mesh", + default_mesh_file) mesh_file = default_mesh_file mesh = UnstructuredMesh2D(mesh_file) @@ -27,27 +29,26 @@ A Gaussian pulse, used in the `gauss_wall` example elixir in combination with [`boundary_condition_wall`](@ref). Uses the global mean values from `equations`. """ function initial_condition_gauss_wall(x, t, equations::AcousticPerturbationEquations2D) - v1_prime = 0.0 - v2_prime = 0.0 - p_prime = exp(-log(2) * (x[1]^2 + (x[2] - 25)^2) / 25) + v1_prime = 0.0 + v2_prime = 0.0 + p_prime = exp(-log(2) * (x[1]^2 + (x[2] - 25)^2) / 25) - prim = SVector(v1_prime, v2_prime, p_prime, global_mean_vars(equations)...) + prim = SVector(v1_prime, v2_prime, p_prime, global_mean_vars(equations)...) - return prim2cons(prim, equations) + return prim2cons(prim, equations) end initial_condition = initial_condition_gauss_wall -boundary_conditions = Dict( :OuterCircle => boundary_condition_slip_wall, - :InnerCircle1 => boundary_condition_slip_wall, - :InnerCircle2 => boundary_condition_slip_wall, - :InnerCircle3 => boundary_condition_slip_wall, - :InnerCircle4 => boundary_condition_slip_wall, - :InnerCircle5 => boundary_condition_slip_wall ) +boundary_conditions = Dict(:OuterCircle => boundary_condition_slip_wall, + :InnerCircle1 => boundary_condition_slip_wall, + :InnerCircle2 => boundary_condition_slip_wall, + :InnerCircle3 => boundary_condition_slip_wall, + :InnerCircle4 => boundary_condition_slip_wall, + :InnerCircle5 => boundary_condition_slip_wall) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) - + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -61,10 +62,10 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +analysis_callback = AnalysisCallback(semi, interval = 100) # The SaveSolutionCallback allows to save the solution to a file in regular intervals -save_solution = SaveSolutionCallback(interval=50, solution_variables=cons2state) +save_solution = SaveSolutionCallback(interval = 50, solution_variables = cons2state) # 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) @@ -73,7 +74,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, save_solution) # run the simulation # use a Runge-Kutta method with automatic (error based) time step size control -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-6, reltol=1.0e-6, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-6, reltol = 1.0e-6, + ode_default_options()..., callback = callbacks); # Print the timer summary summary_callback() diff --git a/examples/unstructured_2d_dgsem/elixir_advection_basic.jl b/examples/unstructured_2d_dgsem/elixir_advection_basic.jl index 274978d48b0..afef6c2c38f 100644 --- a/examples/unstructured_2d_dgsem/elixir_advection_basic.jl +++ b/examples/unstructured_2d_dgsem/elixir_advection_basic.jl @@ -12,22 +12,24 @@ equations = LinearScalarAdvectionEquation2D(advection_velocity) ############################################################################### # Get the DG approximation space -solver = DGSEM(polydeg=6, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 6, surface_flux = flux_lax_friedrichs) ############################################################################### # Get the curved quad mesh from a file (downloads the file if not available locally) default_mesh_file = joinpath(@__DIR__, "mesh_periodic_square_with_twist.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", + default_mesh_file) mesh_file = default_mesh_file -mesh = UnstructuredMesh2D(mesh_file, periodicity=true) +mesh = UnstructuredMesh2D(mesh_file, periodicity = true) ############################################################################### # create the semi discretization object -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, solver) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, + solver) ############################################################################### # ODE solvers, callbacks etc. @@ -40,22 +42,23 @@ ode = semidiscretize(semi, (0.0, 1.0)); summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_callback = AnalysisCallback(semi, interval=100) +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) +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.6) +stepsize_callback = StepsizeCallback(cfl = 1.6) # 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) +callbacks = CallbackSet(summary_callback, analysis_callback, save_solution, + 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); +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/unstructured_2d_dgsem/elixir_euler_basic.jl b/examples/unstructured_2d_dgsem/elixir_euler_basic.jl index 9fbea47a9d5..cd6a1995757 100644 --- a/examples/unstructured_2d_dgsem/elixir_euler_basic.jl +++ b/examples/unstructured_2d_dgsem/elixir_euler_basic.jl @@ -12,23 +12,24 @@ initial_condition = initial_condition_convergence_test source_terms = source_terms_convergence_test boundary_condition_convergence_test = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = Dict( :Slant => boundary_condition_convergence_test, - :Bezier => boundary_condition_convergence_test, - :Right => boundary_condition_convergence_test, - :Bottom => boundary_condition_convergence_test, - :Top => boundary_condition_convergence_test ) +boundary_conditions = Dict(:Slant => boundary_condition_convergence_test, + :Bezier => boundary_condition_convergence_test, + :Right => boundary_condition_convergence_test, + :Bottom => boundary_condition_convergence_test, + :Top => boundary_condition_convergence_test) ############################################################################### # Get the DG approximation space -solver = DGSEM(polydeg=8, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg = 8, surface_flux = flux_lax_friedrichs) ############################################################################### # Get the curved quad mesh from a file (downloads the file if not available locally) default_mesh_file = joinpath(@__DIR__, "mesh_trixi_unstructured_mesh_docs.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/52056f1487853fab63b7f4ed7f171c80/raw/9d573387dfdbb8bce2a55db7246f4207663ac07f/mesh_trixi_unstructured_mesh_docs.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/52056f1487853fab63b7f4ed7f171c80/raw/9d573387dfdbb8bce2a55db7246f4207663ac07f/mesh_trixi_unstructured_mesh_docs.mesh", + default_mesh_file) mesh_file = default_mesh_file mesh = UnstructuredMesh2D(mesh_file) @@ -37,8 +38,8 @@ mesh = UnstructuredMesh2D(mesh_file) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms, - boundary_conditions=boundary_conditions) + source_terms = source_terms, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -49,18 +50,18 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_restart = SaveRestartCallback(interval=50, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 50, + save_final_restart = true) -save_solution = SaveSolutionCallback(interval=10, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 10, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=0.9) +stepsize_callback = StepsizeCallback(cfl = 0.9) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -72,7 +73,7 @@ callbacks = CallbackSet(summary_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); +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/unstructured_2d_dgsem/elixir_euler_ec.jl b/examples/unstructured_2d_dgsem/elixir_euler_ec.jl index 2725142fd17..0f53aa62a18 100644 --- a/examples/unstructured_2d_dgsem/elixir_euler_ec.jl +++ b/examples/unstructured_2d_dgsem/elixir_euler_ec.jl @@ -6,7 +6,7 @@ using Trixi ############################################################################### # semidiscretization of the compressible Euler equations -equations = CompressibleEulerEquations2D(5/3) +equations = CompressibleEulerEquations2D(5 / 3) initial_condition = initial_condition_weak_blast_wave @@ -14,18 +14,19 @@ initial_condition = initial_condition_weak_blast_wave # Get the DG approximation space volume_flux = flux_ranocha -solver = DGSEM(polydeg=6, surface_flux=flux_ranocha, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 6, surface_flux = flux_ranocha, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the curved quad mesh from a file default_mesh_file = joinpath(@__DIR__, "mesh_periodic_square_with_twist.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", + default_mesh_file) mesh_file = default_mesh_file -mesh = UnstructuredMesh2D(mesh_file, periodicity=true) +mesh = UnstructuredMesh2D(mesh_file, periodicity = true) ############################################################################### # create the semi discretization object @@ -41,15 +42,15 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -60,7 +61,7 @@ callbacks = CallbackSet(summary_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); +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/unstructured_2d_dgsem/elixir_euler_free_stream.jl b/examples/unstructured_2d_dgsem/elixir_euler_free_stream.jl index 36e119ab794..a2fec1a320a 100644 --- a/examples/unstructured_2d_dgsem/elixir_euler_free_stream.jl +++ b/examples/unstructured_2d_dgsem/elixir_euler_free_stream.jl @@ -11,25 +11,26 @@ equations = CompressibleEulerEquations2D(1.4) initial_condition = initial_condition_constant boundary_condition_free_stream = BoundaryConditionDirichlet(initial_condition) -boundary_conditions = Dict( :Body => boundary_condition_free_stream, - :Button1 => boundary_condition_free_stream, - :Button2 => boundary_condition_free_stream, - :Eye1 => boundary_condition_free_stream, - :Eye2 => boundary_condition_free_stream, - :Smile => boundary_condition_free_stream, - :Bowtie => boundary_condition_free_stream ) +boundary_conditions = Dict(:Body => boundary_condition_free_stream, + :Button1 => boundary_condition_free_stream, + :Button2 => boundary_condition_free_stream, + :Eye1 => boundary_condition_free_stream, + :Eye2 => boundary_condition_free_stream, + :Smile => boundary_condition_free_stream, + :Bowtie => boundary_condition_free_stream) ############################################################################### # Get the DG approximation space -solver = DGSEM(polydeg=6, surface_flux=flux_hll) +solver = DGSEM(polydeg = 6, surface_flux = flux_hll) ############################################################################### # Get the curved quad mesh from a file (downloads the file if not available locally) default_mesh_file = joinpath(@__DIR__, "mesh_gingerbread_man.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/2c6440b5f8a57db131061ad7aa78ee2b/raw/1f89fdf2c874ff678c78afb6fe8dc784bdfd421f/mesh_gingerbread_man.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/2c6440b5f8a57db131061ad7aa78ee2b/raw/1f89fdf2c874ff678c78afb6fe8dc784bdfd421f/mesh_gingerbread_man.mesh", + default_mesh_file) mesh_file = default_mesh_file mesh = UnstructuredMesh2D(mesh_file) @@ -38,7 +39,7 @@ mesh = UnstructuredMesh2D(mesh_file) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -49,15 +50,15 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) @@ -65,7 +66,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav ############################################################################### # 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); +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/unstructured_2d_dgsem/elixir_euler_periodic.jl b/examples/unstructured_2d_dgsem/elixir_euler_periodic.jl index 796c99987a2..afd177f0740 100644 --- a/examples/unstructured_2d_dgsem/elixir_euler_periodic.jl +++ b/examples/unstructured_2d_dgsem/elixir_euler_periodic.jl @@ -15,24 +15,25 @@ boundary_conditions = boundary_condition_periodic ############################################################################### # Get the DG approximation space -solver = DGSEM(polydeg=6, surface_flux=FluxRotated(flux_hll)) +solver = DGSEM(polydeg = 6, surface_flux = FluxRotated(flux_hll)) ############################################################################### # Get the curved quad mesh from a file (downloads the file if not available locally) default_mesh_file = joinpath(@__DIR__, "mesh_periodic_square_with_twist.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", + default_mesh_file) mesh_file = default_mesh_file -mesh = UnstructuredMesh2D(mesh_file, periodicity=true) +mesh = UnstructuredMesh2D(mesh_file, periodicity = true) ############################################################################### # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms, - boundary_conditions=boundary_conditions) + source_terms = source_terms, + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -43,14 +44,14 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) ############################################################################### # run the simulation -sol = solve(ode, SSPRK43(); ode_default_options()..., callback=callbacks); +sol = solve(ode, SSPRK43(); ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/unstructured_2d_dgsem/elixir_euler_restart.jl b/examples/unstructured_2d_dgsem/elixir_euler_restart.jl index 6653f8662d9..4d6af65b8a4 100644 --- a/examples/unstructured_2d_dgsem/elixir_euler_restart.jl +++ b/examples/unstructured_2d_dgsem/elixir_euler_restart.jl @@ -7,7 +7,6 @@ using Trixi trixi_include(@__MODULE__, joinpath(@__DIR__, "elixir_euler_basic.jl")) - ############################################################################### # adapt the parameters that have changed compared to "elixir_advection_extended.jl" @@ -18,8 +17,8 @@ restart_filename = joinpath("out", "restart_000050.h5") mesh = load_mesh(restart_filename) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms, - boundary_conditions=boundary_conditions) + source_terms = source_terms, + boundary_conditions = boundary_conditions) tspan = (load_time(restart_filename), 1.0) dt = load_dt(restart_filename) @@ -28,17 +27,15 @@ ode = semidiscretize(semi, tspan, restart_filename); # Do not overwrite the initial snapshot written by elixir_advection_extended.jl. save_solution.condition.save_initial_solution = false -integrator = init(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=dt, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +integrator = init(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); # Get the last time index and work with that. load_timestep!(integrator, restart_filename) - ############################################################################### # run the simulation sol = solve!(integrator) summary_callback() # print the timer summary - diff --git a/examples/unstructured_2d_dgsem/elixir_euler_sedov.jl b/examples/unstructured_2d_dgsem/elixir_euler_sedov.jl index 570a2084691..e1cc0932969 100644 --- a/examples/unstructured_2d_dgsem/elixir_euler_sedov.jl +++ b/examples/unstructured_2d_dgsem/elixir_euler_sedov.jl @@ -14,25 +14,25 @@ The Sedov blast wave setup based on Flash - https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 """ function initial_condition_sedov_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) - - # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 - r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) - E = 1.0 - p0_inner = 3 * (equations.gamma - 1) * E / (3 * pi * r0^2) - p0_outer = 1.0e-5 # = true Sedov setup - - # Calculate primitive variables - rho = 1.0 - v1 = 0.0 - v2 = 0.0 - p = r > r0 ? p0_outer : p0_inner - - return prim2cons(SVector(rho, v1, v2, p), equations) + # 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) + + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 + r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) + E = 1.0 + p0_inner = 3 * (equations.gamma - 1) * E / (3 * pi * r0^2) + p0_outer = 1.0e-5 # = true Sedov setup + + # Calculate primitive variables + rho = 1.0 + 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_sedov_blast_wave @@ -43,23 +43,25 @@ volume_flux = flux_ranocha polydeg = 6 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=1.0, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + 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) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) -solver = DGSEM(polydeg=polydeg, surface_flux=surface_flux, volume_integral=volume_integral) +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral) # Get the curved quad mesh from a file default_mesh_file = joinpath(@__DIR__, "mesh_periodic_square_with_twist.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", + default_mesh_file) mesh_file = default_mesh_file -mesh = UnstructuredMesh2D(mesh_file, periodicity=true) +mesh = UnstructuredMesh2D(mesh_file, periodicity = true) # create the semidiscretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -73,15 +75,15 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 300 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=300, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 300, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -92,7 +94,7 @@ callbacks = CallbackSet(summary_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); +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/unstructured_2d_dgsem/elixir_euler_wall_bc.jl b/examples/unstructured_2d_dgsem/elixir_euler_wall_bc.jl index 5bfe1ae4e0e..b2abefe7eeb 100644 --- a/examples/unstructured_2d_dgsem/elixir_euler_wall_bc.jl +++ b/examples/unstructured_2d_dgsem/elixir_euler_wall_bc.jl @@ -10,40 +10,41 @@ equations = CompressibleEulerEquations2D(1.4) @inline function uniform_flow_state(x, t, equations::CompressibleEulerEquations2D) - # set the freestream flow parameters - rho_freestream = 1.0 - u_freestream = 0.3 - p_freestream = inv(equations.gamma) - - theta = pi / 90.0 # analogous with a two degree angle of attack - si, co = sincos(theta) - v1 = u_freestream * co - v2 = u_freestream * si - - prim = SVector(rho_freestream, v1, v2, p_freestream) - return prim2cons(prim, equations) + # set the freestream flow parameters + rho_freestream = 1.0 + u_freestream = 0.3 + p_freestream = inv(equations.gamma) + + theta = pi / 90.0 # analogous with a two degree angle of attack + si, co = sincos(theta) + v1 = u_freestream * co + v2 = u_freestream * si + + prim = SVector(rho_freestream, v1, v2, p_freestream) + return prim2cons(prim, equations) end initial_condition = uniform_flow_state boundary_condition_uniform_flow = BoundaryConditionDirichlet(uniform_flow_state) -boundary_conditions = Dict( :Bottom => boundary_condition_uniform_flow, - :Top => boundary_condition_uniform_flow, - :Right => boundary_condition_uniform_flow, - :Left => boundary_condition_uniform_flow, - :Circle => boundary_condition_slip_wall ) +boundary_conditions = Dict(:Bottom => boundary_condition_uniform_flow, + :Top => boundary_condition_uniform_flow, + :Right => boundary_condition_uniform_flow, + :Left => boundary_condition_uniform_flow, + :Circle => boundary_condition_slip_wall) ############################################################################### # Get the DG approximation space -solver = DGSEM(polydeg=4, surface_flux=flux_hll) +solver = DGSEM(polydeg = 4, surface_flux = flux_hll) ############################################################################### # Get the curved quad mesh from a file default_mesh_file = joinpath(@__DIR__, "mesh_box_around_circle.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/8b9b11a1eedfa54b215c122c3d17b271/raw/0d2b5d98c87e67a6f384693a8b8e54b4c9fcbf3d/mesh_box_around_circle.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/8b9b11a1eedfa54b215c122c3d17b271/raw/0d2b5d98c87e67a6f384693a8b8e54b4c9fcbf3d/mesh_box_around_circle.mesh", + default_mesh_file) mesh_file = default_mesh_file mesh = UnstructuredMesh2D(mesh_file) @@ -52,7 +53,7 @@ mesh = UnstructuredMesh2D(mesh_file) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_conditions) + boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. @@ -63,22 +64,23 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=10, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 10, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) -callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, + 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); +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/unstructured_2d_dgsem/elixir_mhd_alfven_wave.jl b/examples/unstructured_2d_dgsem/elixir_mhd_alfven_wave.jl index 6b31776b297..fdafed98c8d 100644 --- a/examples/unstructured_2d_dgsem/elixir_mhd_alfven_wave.jl +++ b/examples/unstructured_2d_dgsem/elixir_mhd_alfven_wave.jl @@ -5,22 +5,23 @@ using Trixi ############################################################################### # semidiscretization of the compressible ideal GLM-MHD equations -gamma = 5/3 +gamma = 5 / 3 equations = IdealGlmMhdEquations2D(gamma) initial_condition = initial_condition_convergence_test volume_flux = (flux_central, flux_nonconservative_powell) -solver = DGSEM(polydeg=7, surface_flux=(flux_hll, flux_nonconservative_powell), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 7, surface_flux = (flux_hll, flux_nonconservative_powell), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) # Get the unstructured quad mesh from a file (downloads the file if not available locally) default_mesh_file = joinpath(@__DIR__, "mesh_alfven_wave_with_twist_and_flip.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", + default_mesh_file) mesh_file = default_mesh_file -mesh = UnstructuredMesh2D(mesh_file, periodicity=true) +mesh = UnstructuredMesh2D(mesh_file, periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -33,21 +34,24 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false, - extra_analysis_integrals=(entropy, energy_total, - energy_kinetic, energy_internal, - energy_magnetic, cross_helicity)) - -alive_callback = AliveCallback(analysis_interval=analysis_interval) - -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = false, + extra_analysis_integrals = (entropy, energy_total, + energy_kinetic, + energy_internal, + energy_magnetic, + cross_helicity)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) cfl = 0.9 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -56,11 +60,10 @@ callbacks = CallbackSet(summary_callback, stepsize_callback, glm_speed_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); +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/unstructured_2d_dgsem/elixir_mhd_ec.jl b/examples/unstructured_2d_dgsem/elixir_mhd_ec.jl index d75079bb8d7..a40f92cac02 100644 --- a/examples/unstructured_2d_dgsem/elixir_mhd_ec.jl +++ b/examples/unstructured_2d_dgsem/elixir_mhd_ec.jl @@ -6,40 +6,42 @@ using Trixi ############################################################################### # semidiscretization of the compressible ideal GLM-MHD equations -equations = IdealGlmMhdEquations2D(5/3) +equations = IdealGlmMhdEquations2D(5 / 3) function initial_condition_shifted_weak_blast_wave(x, t, equations::IdealGlmMhdEquations2D) - # Adapted MHD version of the weak blast wave from Hennemann & Gassner JCP paper 2020 (Sec. 6.3) - # Shift blastwave to center of domain - inicenter = (sqrt(2)/2, sqrt(2)/2) - 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) - - # 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) - p = r > 0.5 ? 1.0 : 1.245 - - return prim2cons(SVector(rho, v1, v2, 0.0, p, 1.0, 1.0, 1.0, 0.0), equations) + # Adapted MHD version of the weak blast wave from Hennemann & Gassner JCP paper 2020 (Sec. 6.3) + # Shift blastwave to center of domain + inicenter = (sqrt(2) / 2, sqrt(2) / 2) + 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) + + # 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) + p = r > 0.5 ? 1.0 : 1.245 + + return prim2cons(SVector(rho, v1, v2, 0.0, p, 1.0, 1.0, 1.0, 0.0), equations) end initial_condition = initial_condition_shifted_weak_blast_wave # Get the DG approximation space volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -solver = DGSEM(polydeg=6, surface_flux=(flux_hindenlang_gassner, flux_nonconservative_powell), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 6, + surface_flux = (flux_hindenlang_gassner, flux_nonconservative_powell), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) # Get the unstructured quad mesh from a file (downloads the file if not available locally) default_mesh_file = joinpath(@__DIR__, "mesh_alfven_wave_with_twist_and_flip.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", + default_mesh_file) mesh_file = default_mesh_file -mesh = UnstructuredMesh2D(mesh_file, periodicity=true) +mesh = UnstructuredMesh2D(mesh_file, periodicity = true) # create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -53,21 +55,24 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false, - extra_analysis_integrals=(entropy, energy_total, - energy_kinetic, energy_internal, - energy_magnetic, cross_helicity)) - -alive_callback = AliveCallback(analysis_interval=analysis_interval) - -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = false, + extra_analysis_integrals = (entropy, energy_total, + energy_kinetic, + energy_internal, + energy_magnetic, + cross_helicity)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) cfl = 1.0 -stepsize_callback = StepsizeCallback(cfl=cfl) +stepsize_callback = StepsizeCallback(cfl = cfl) -glm_speed_callback = GlmSpeedCallback(glm_scale=0.5, cfl=cfl) +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, @@ -79,7 +84,7 @@ callbacks = CallbackSet(summary_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); +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/unstructured_2d_dgsem/elixir_shallowwater_dirichlet.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_dirichlet.jl index 044b2549b01..1148f25fae3 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_dirichlet.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_dirichlet.jl @@ -7,47 +7,48 @@ using Trixi # semidiscretization of the shallow water equations with a continuous # bottom topography function (set in the initial conditions) -equations = ShallowWaterEquations2D(gravity_constant=1.0, H0=3.0) +equations = ShallowWaterEquations2D(gravity_constant = 1.0, H0 = 3.0) # An initial condition with constant total water height and zero velocities to test well-balancedness. function initial_condition_well_balancedness(x, t, equations::ShallowWaterEquations2D) - # Set the background values - H = equations.H0 - v1 = 0.0 - v2 = 0.0 - # bottom topography taken from Pond.control in [HOHQMesh](https://github.com/trixi-framework/HOHQMesh) - x1, x2 = x - b = ( 1.5 / exp( 0.5 * ((x1 - 1.0)^2 + (x2 - 1.0)^2) ) - + 0.75 / exp( 0.5 * ((x1 + 1.0)^2 + (x2 + 1.0)^2) ) ) - return prim2cons(SVector(H, v1, v2, b), equations) + # Set the background values + H = equations.H0 + v1 = 0.0 + v2 = 0.0 + # bottom topography taken from Pond.control in [HOHQMesh](https://github.com/trixi-framework/HOHQMesh) + x1, x2 = x + b = (1.5 / exp(0.5 * ((x1 - 1.0)^2 + (x2 - 1.0)^2)) + + 0.75 / exp(0.5 * ((x1 + 1.0)^2 + (x2 + 1.0)^2))) + return prim2cons(SVector(H, v1, v2, b), equations) end initial_condition = initial_condition_well_balancedness boundary_condition_constant = BoundaryConditionDirichlet(initial_condition) -boundary_condition = Dict( :OuterCircle => boundary_condition_constant ) +boundary_condition = Dict(:OuterCircle => boundary_condition_constant) ############################################################################### # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -solver = DGSEM(polydeg=4, surface_flux=(flux_hll, flux_nonconservative_fjordholm_etal), - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 4, surface_flux = (flux_hll, flux_nonconservative_fjordholm_etal), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # This setup is for the curved, split form well-balancedness testing # Get the unstructured quad mesh from a file (downloads the file if not available locally) default_mesh_file = joinpath(@__DIR__, "mesh_outer_circle.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/9beddd9cd00e2a0a15865129eeb24928/raw/be71e67fa48bc4e1e97f5f6cd77c3ed34c6ba9be/mesh_outer_circle.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/9beddd9cd00e2a0a15865129eeb24928/raw/be71e67fa48bc4e1e97f5f6cd77c3ed34c6ba9be/mesh_outer_circle.mesh", + default_mesh_file) mesh_file = default_mesh_file mesh = UnstructuredMesh2D(mesh_file) # Create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_condition) + boundary_conditions = boundary_condition) ############################################################################### # ODE solvers, callbacks, etc. @@ -58,15 +59,15 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - save_analysis=true, - extra_analysis_integrals=(lake_at_rest_error,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_integrals = (lake_at_rest_error,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) @@ -74,6 +75,6 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav # run the simulation # use a Runge-Kutta method with automatic (error based) time step size control -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-11, reltol=1.0e-11, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-11, reltol = 1.0e-11, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/unstructured_2d_dgsem/elixir_shallowwater_ec.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_ec.jl index 138b256c08b..8e9d396d826 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_ec.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_ec.jl @@ -7,7 +7,7 @@ using Trixi # semidiscretization of the shallow water equations with a discontinuous # bottom topography function -equations = ShallowWaterEquations2D(gravity_constant=9.81) +equations = ShallowWaterEquations2D(gravity_constant = 9.81) # 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. @@ -17,19 +17,21 @@ 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)) +solver = DGSEM(polydeg = 6, + surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # 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) default_mesh_file = joinpath(@__DIR__, "mesh_alfven_wave_with_twist_and_flip.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", + default_mesh_file) mesh_file = default_mesh_file -mesh = UnstructuredMesh2D(mesh_file, periodicity=true) +mesh = UnstructuredMesh2D(mesh_file, periodicity = true) # Create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -49,45 +51,48 @@ ode = semidiscretize(semi, tspan) # 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) - # Set up polar coordinates - inicenter = SVector(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.25 - v1 = 0.0 - v2 = 0.0 - b = 0.0 - - # setup the discontinuous water height and velocities - if element_id == 10 - H = 4.0 - v1 = 0.1882 * cos_phi - v2 = 0.1882 * sin_phi - end - - # Setup a discontinuous bottom topography using the element id number - if element_id == 7 - b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) + 0.5 * cos(2.0 * pi * x[2]) - end - - return prim2cons(SVector(H, v1, v2, b), equations) +function initial_condition_ec_discontinuous_bottom(x, t, element_id, + equations::ShallowWaterEquations2D) + # Set up polar coordinates + inicenter = SVector(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.25 + v1 = 0.0 + v2 = 0.0 + b = 0.0 + + # setup the discontinuous water height and velocities + if element_id == 10 + H = 4.0 + v1 = 0.1882 * cos_phi + v2 = 0.1882 * sin_phi + end + + # Setup a discontinuous bottom topography using the element id number + if element_id == 7 + b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) + 0.5 * cos(2.0 * pi * 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 + 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 ############################################################################### @@ -96,15 +101,15 @@ end summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=3.0) +stepsize_callback = StepsizeCallback(cfl = 3.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) @@ -112,7 +117,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav ############################################################################### # 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); +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/unstructured_2d_dgsem/elixir_shallowwater_ec_shockcapturing.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_ec_shockcapturing.jl index ee3650f3bb5..94202b81df0 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_ec_shockcapturing.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_ec_shockcapturing.jl @@ -7,7 +7,7 @@ using Trixi # semidiscretization of the shallow water equations with a discontinuous # bottom topography function -equations = ShallowWaterEquations2D(gravity_constant=9.81) +equations = ShallowWaterEquations2D(gravity_constant = 9.81) # 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. @@ -17,17 +17,17 @@ initial_condition = initial_condition_weak_blast_wave # Get the DG approximation space surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal) -volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) polydeg = 6 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=waterheight_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = waterheight_pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) ############################################################################### @@ -35,11 +35,12 @@ solver = DGSEM(basis, surface_flux, volume_integral) # Get the unstructured quad mesh from a file (downloads the file if not available locally) default_mesh_file = joinpath(@__DIR__, "mesh_alfven_wave_with_twist_and_flip.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", + default_mesh_file) mesh_file = default_mesh_file -mesh = UnstructuredMesh2D(mesh_file, periodicity=true) +mesh = UnstructuredMesh2D(mesh_file, periodicity = true) # Create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -59,45 +60,48 @@ ode = semidiscretize(semi, tspan) # 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) - # Set up polar coordinates - inicenter = SVector(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.25 - v1 = 0.0 - v2 = 0.0 - b = 0.0 - - # setup the discontinuous water height and velocities - if element_id == 10 - H = 4.0 - v1 = 0.1882 * cos_phi - v2 = 0.1882 * sin_phi - end - - # Setup a discontinuous bottom topography using the element id number - if element_id == 7 - b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) + 0.5 * cos(2.0 * pi * x[2]) - end - - return prim2cons(SVector(H, v1, v2, b), equations) +function initial_condition_ec_discontinuous_bottom(x, t, element_id, + equations::ShallowWaterEquations2D) + # Set up polar coordinates + inicenter = SVector(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.25 + v1 = 0.0 + v2 = 0.0 + b = 0.0 + + # setup the discontinuous water height and velocities + if element_id == 10 + H = 4.0 + v1 = 0.1882 * cos_phi + v2 = 0.1882 * sin_phi + end + + # Setup a discontinuous bottom topography using the element id number + if element_id == 7 + b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) + 0.5 * cos(2.0 * pi * 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 + 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 ############################################################################### @@ -106,11 +110,11 @@ end summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -stepsize_callback = StepsizeCallback(cfl=3.0) +stepsize_callback = StepsizeCallback(cfl = 3.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, stepsize_callback) @@ -118,7 +122,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_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); +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/unstructured_2d_dgsem/elixir_shallowwater_source_terms.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_source_terms.jl index e0b64802ff8..07668688406 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_source_terms.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_source_terms.jl @@ -7,7 +7,7 @@ using Trixi # semidiscretization of the shallow water equations with a periodic # bottom topography function (set in the initial conditions) -equations = ShallowWaterEquations2D(gravity_constant=9.81) +equations = ShallowWaterEquations2D(gravity_constant = 9.81) initial_condition = initial_condition_convergence_test @@ -16,23 +16,24 @@ initial_condition = initial_condition_convergence_test volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal) -solver = DGSEM(polydeg=6, surface_flux=surface_flux, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 6, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # This setup is for the curved, split form convergence test on a periodic domain # Get the unstructured quad mesh from a file (downloads the file if not available locally) default_mesh_file = joinpath(@__DIR__, "mesh_alfven_wave_with_twist_and_flip.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", + default_mesh_file) mesh_file = default_mesh_file -mesh = UnstructuredMesh2D(mesh_file, periodicity=true) +mesh = UnstructuredMesh2D(mesh_file, periodicity = true) # Create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -43,15 +44,15 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) @@ -59,7 +60,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav ############################################################################### # 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); +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/unstructured_2d_dgsem/elixir_shallowwater_three_mound_dam_break.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_three_mound_dam_break.jl index 65b0fcae462..6164f9d4a55 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_three_mound_dam_break.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_three_mound_dam_break.jl @@ -8,10 +8,8 @@ using Trixi # # TODO: TrixiShallowWater: wet/dry example elixir - -equations = ShallowWaterEquations2D(gravity_constant=9.81, H0=1.875, - threshold_limiter=1e-12, threshold_wet=1e-14) - +equations = ShallowWaterEquations2D(gravity_constant = 9.81, H0 = 1.875, + threshold_limiter = 1e-12, threshold_wet = 1e-14) """ initial_condition_three_mounds(x, t, equations::ShallowWaterEquations2D) @@ -28,66 +26,68 @@ The initial conditions is taken from Section 6.3 of the paper: """ function initial_condition_three_mounds(x, t, equations::ShallowWaterEquations2D) - # Set the background values - v1 = 0.0 - v2 = 0.0 + # Set the background values + v1 = 0.0 + v2 = 0.0 - x1, x2 = x - M_1 = 1 - 0.1 * sqrt( (x1 - 30.0)^2 + (x2 - 22.5)^2 ) - M_2 = 1 - 0.1 * sqrt( (x1 - 30.0)^2 + (x2 - 7.5)^2 ) - M_3 = 2.8 - 0.28 * sqrt( (x1 - 47.5)^2 + (x2 - 15.0)^2 ) + x1, x2 = x + M_1 = 1 - 0.1 * sqrt((x1 - 30.0)^2 + (x2 - 22.5)^2) + M_2 = 1 - 0.1 * sqrt((x1 - 30.0)^2 + (x2 - 7.5)^2) + M_3 = 2.8 - 0.28 * sqrt((x1 - 47.5)^2 + (x2 - 15.0)^2) - b = max(0.0, M_1, M_2, M_3) + b = max(0.0, M_1, M_2, M_3) - # use a logistic function to transfer water height value smoothly - L = equations.H0 # maximum of function - x0 = 8 # center point of function - k = -75.0 # sharpness of transfer + # use a logistic function to transfer water height value smoothly + L = equations.H0 # maximum of function + x0 = 8 # center point of function + k = -75.0 # sharpness of transfer - H = max(b, L / (1.0 + exp(-k * (x1 - x0)))) + H = max(b, L / (1.0 + exp(-k * (x1 - x0)))) - # Avoid division by zero by adjusting the initial condition with a small dry state threshold - # that defaults to 500*eps() ≈ 1e-13 in double precision and is set in the constructor above - # for the ShallowWaterEquations struct. - H = max(H, b + equations.threshold_limiter) - return prim2cons(SVector(H, v1, v2, b), equations) + # Avoid division by zero by adjusting the initial condition with a small dry state threshold + # that defaults to 500*eps() ≈ 1e-13 in double precision and is set in the constructor above + # for the ShallowWaterEquations struct. + H = max(H, b + equations.threshold_limiter) + return prim2cons(SVector(H, v1, v2, b), equations) end initial_condition = initial_condition_three_mounds function boundary_condition_outflow(u_inner, normal_direction::AbstractVector, x, t, - surface_flux_function, equations::ShallowWaterEquations2D) - # Impulse and bottom from inside, height from external state - u_outer = SVector(equations.threshold_wet, u_inner[2], u_inner[3], u_inner[4]) + surface_flux_function, + equations::ShallowWaterEquations2D) + # Impulse and bottom from inside, height from external state + u_outer = SVector(equations.threshold_wet, u_inner[2], u_inner[3], u_inner[4]) - # calculate the boundary flux - flux = surface_flux_function(u_inner, u_outer, normal_direction, equations) + # calculate the boundary flux + flux = surface_flux_function(u_inner, u_outer, normal_direction, equations) - return flux + return flux end -boundary_conditions = Dict( :Bottom => boundary_condition_slip_wall, - :Top => boundary_condition_slip_wall, - :Right => boundary_condition_outflow, - :Left => boundary_condition_slip_wall ) +boundary_conditions = Dict(:Bottom => boundary_condition_slip_wall, + :Top => boundary_condition_slip_wall, + :Right => boundary_condition_outflow, + :Left => boundary_condition_slip_wall) ############################################################################### # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, hydrostatic_reconstruction_chen_noelle), +surface_flux = (FluxHydrostaticReconstruction(flux_hll_chen_noelle, + hydrostatic_reconstruction_chen_noelle), flux_nonconservative_chen_noelle) basis = LobattoLegendreBasis(4) indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=waterheight_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = waterheight_pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) @@ -96,8 +96,9 @@ solver = DGSEM(basis, surface_flux, volume_integral) default_meshfile = joinpath(@__DIR__, "mesh_three_mound.mesh") -isfile(default_meshfile) || download("https://gist.githubusercontent.com/svengoldberg/c3c87fecb3fc6e46be7f0d1c7cb35f83/raw/e817ecd9e6c4686581d63c46128f9b6468d396d3/mesh_three_mound.mesh", - default_meshfile) +isfile(default_meshfile) || + download("https://gist.githubusercontent.com/svengoldberg/c3c87fecb3fc6e46be7f0d1c7cb35f83/raw/e817ecd9e6c4686581d63c46128f9b6468d396d3/mesh_three_mound.mesh", + default_meshfile) meshfile = default_meshfile @@ -105,7 +106,7 @@ mesh = UnstructuredMesh2D(meshfile) # Create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver; - boundary_conditions=boundary_conditions) + boundary_conditions = boundary_conditions) ############################################################################### # ODE solver @@ -119,21 +120,21 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) ############################################################################### # run the simulation -stage_limiter! = PositivityPreservingLimiterShallowWater(variables=(Trixi.waterheight,)) +stage_limiter! = PositivityPreservingLimiterShallowWater(variables = (Trixi.waterheight,)) sol = solve(ode, SSPRK43(stage_limiter!); - ode_default_options()..., callback=callbacks); + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl index d9e71e4aa44..2cab68b1cb5 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl @@ -7,7 +7,8 @@ using Trixi # Semidiscretization of the two-layer shallow water equations with a periodic # bottom topography function (set in the initial conditions) -equations = ShallowWaterTwoLayerEquations2D(gravity_constant=10.0, rho_upper=0.9, rho_lower=1.0) +equations = ShallowWaterTwoLayerEquations2D(gravity_constant = 10.0, rho_upper = 0.9, + rho_lower = 1.0) initial_condition = initial_condition_convergence_test @@ -16,23 +17,24 @@ initial_condition = initial_condition_convergence_test volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal) -solver = DGSEM(polydeg=6, surface_flux=surface_flux, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 6, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # This setup is for the curved, split form convergence test on a periodic domain # Get the unstructured quad mesh from a file (downloads the file if not available locally) default_mesh_file = joinpath(@__DIR__, "mesh_alfven_wave_with_twist_and_flip.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", + default_mesh_file) mesh_file = default_mesh_file -mesh = UnstructuredMesh2D(mesh_file, periodicity=true) +mesh = UnstructuredMesh2D(mesh_file, periodicity = true) # Create the semidiscretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_convergence_test) + source_terms = source_terms_convergence_test) ############################################################################### # ODE solvers, callbacks etc. @@ -43,15 +45,15 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 500 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=500, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 500, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) @@ -59,7 +61,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav ############################################################################### # 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); +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/unstructured_2d_dgsem/elixir_shallowwater_twolayer_dam_break.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_dam_break.jl index 4295f93b342..9d70e9287cf 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_dam_break.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_dam_break.jl @@ -7,62 +7,64 @@ using Trixi # Semidiscretization of the two-layer shallow water equations for a dam break test with a # discontinuous bottom topography function to test energy conservation -equations = ShallowWaterTwoLayerEquations2D(gravity_constant=1.0, rho_upper=0.9, rho_lower=1.0) +equations = ShallowWaterTwoLayerEquations2D(gravity_constant = 1.0, rho_upper = 0.9, + rho_lower = 1.0) # This test case uses a special work around to setup a truly discontinuous bottom topography # function and initial condition for this academic testcase of entropy conservation. First, a # dummy initial_condition_dam_break is introduced to create the semidiscretization. Then the initial # condition is reset with the true discontinuous values from initial_condition_discontinuous_dam_break. -function initial_condition_dam_break(x, t,equations::ShallowWaterTwoLayerEquations2D) - if x[1] < sqrt(2)/2 - H_upper = 1.0 - H_lower = 0.6 - b = 0.1 - else - H_upper = 0.9 - H_lower = 0.5 - b = 0.0 - end - - v1_upper = 0.0 - v2_upper = 0.0 - v1_lower = 0.0 - v2_lower = 0.0 - return prim2cons(SVector(H_upper, v1_upper, v2_upper, H_lower, v1_lower, v2_lower, b), equations) +function initial_condition_dam_break(x, t, equations::ShallowWaterTwoLayerEquations2D) + if x[1] < sqrt(2) / 2 + H_upper = 1.0 + H_lower = 0.6 + b = 0.1 + else + H_upper = 0.9 + H_lower = 0.5 + b = 0.0 + end + + v1_upper = 0.0 + v2_upper = 0.0 + v1_lower = 0.0 + v2_lower = 0.0 + return prim2cons(SVector(H_upper, v1_upper, v2_upper, H_lower, v1_lower, v2_lower, b), + equations) end initial_condition = initial_condition_dam_break boundary_condition_constant = BoundaryConditionDirichlet(initial_condition_dam_break) - ############################################################################### # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -surface_flux= (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal) -solver = DGSEM(polydeg=6, surface_flux=surface_flux, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal) +solver = DGSEM(polydeg = 6, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # Get the unstructured quad mesh from a file (downloads the file if not available locally) default_mesh_file = joinpath(@__DIR__, "mesh_alfven_wave_with_twist_and_flip.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", + default_mesh_file) mesh_file = default_mesh_file -mesh = UnstructuredMesh2D(mesh_file, periodicity=false) +mesh = UnstructuredMesh2D(mesh_file, periodicity = false) # Boundary conditions -boundary_condition = Dict(:Top => boundary_condition_slip_wall, - :Left => boundary_condition_slip_wall, - :Right => boundary_condition_slip_wall, +boundary_condition = Dict(:Top => boundary_condition_slip_wall, + :Left => boundary_condition_slip_wall, + :Right => boundary_condition_slip_wall, :Bottom => boundary_condition_slip_wall) # Create the semi discretization object -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, - solver, boundary_conditions=boundary_condition) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, + solver, boundary_conditions = boundary_condition) ############################################################################### # ODE solver @@ -79,58 +81,63 @@ ode = semidiscretize(semi, tspan) # `element_id` explicitly. In particular, this initial conditions works as intended # only for the specific mesh loaded above! -function initial_condition_discontinuous_dam_break(x, t, element_id, +function initial_condition_discontinuous_dam_break(x, t, element_id, equations::ShallowWaterTwoLayerEquations2D) - # Constant values - v1_upper = 0.0 - v2_upper = 0.0 - v1_lower = 0.0 - v2_lower = 0.0 - - # Left side of discontinuity - IDs = [1, 2, 5, 6, 9, 10, 13, 14] - if element_id in IDs - H_upper = 1.0 - H_lower = 0.6 - b = 0.0 - # Right side of discontinuity - else - H_upper = 0.9 - H_lower = 0.5 - b = 0.1 - end - - return prim2cons(SVector(H_upper, v1_upper, v2_upper, H_lower, v1_lower, v2_lower, b), equations) + # Constant values + v1_upper = 0.0 + v2_upper = 0.0 + v1_lower = 0.0 + v2_lower = 0.0 + + # Left side of discontinuity + IDs = [1, 2, 5, 6, 9, 10, 13, 14] + if element_id in IDs + H_upper = 1.0 + H_lower = 0.6 + b = 0.0 + # Right side of discontinuity + else + H_upper = 0.9 + H_lower = 0.5 + b = 0.1 + end + + return prim2cons(SVector(H_upper, v1_upper, v2_upper, H_lower, v1_lower, v2_lower, 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_discontinuous_dam_break(x_node, first(tspan), element, equations) - Trixi.set_node_vars!(u, u_node, equations, semi.solver, i, j, element) - end + 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_discontinuous_dam_break(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 = 500 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval,save_analysis=false, - extra_analysis_integrals=(energy_total, energy_kinetic, energy_internal,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = false, + extra_analysis_integrals = (energy_total, + energy_kinetic, + energy_internal)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=500, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 500, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) @@ -138,7 +145,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav ############################################################################### # 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); +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/unstructured_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl index 40bc9f2ab42..35b027c3a81 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl @@ -7,22 +7,25 @@ using Trixi # Semidiscretization of the two-layer shallow water equations with a discontinuous bottom # topography to test well-balancedness -equations = ShallowWaterTwoLayerEquations2D(gravity_constant=1.0, H0=0.6, rho_upper=0.9, rho_lower=1.0) +equations = ShallowWaterTwoLayerEquations2D(gravity_constant = 1.0, H0 = 0.6, + rho_upper = 0.9, rho_lower = 1.0) # An initial condition with constant total water height, zero velocities and a bottom topography to # test well-balancedness function initial_condition_well_balanced(x, t, equations::ShallowWaterTwoLayerEquations2D) - H_lower = 0.5 - H_upper = 0.6 - v1_upper = 0.0 - v2_upper = 0.0 - v1_lower = 0.0 - v2_lower = 0.0 - - # Bottom Topography - b = (((x[1] - 0.5)^2 + (x[2] - 0.5)^2) < 0.04 ? 0.2 * (cos(4 * pi * sqrt((x[1] - 0.5)^2 + (x[2] + - -0.5)^2)) + 1) : 0.0) - return prim2cons(SVector(H_upper, v1_upper, v2_upper, H_lower, v1_lower, v2_lower, b), equations) + H_lower = 0.5 + H_upper = 0.6 + v1_upper = 0.0 + v2_upper = 0.0 + v1_lower = 0.0 + v2_lower = 0.0 + + # Bottom Topography + b = (((x[1] - 0.5)^2 + (x[2] - 0.5)^2) < 0.04 ? + 0.2 * (cos(4 * pi * sqrt((x[1] - 0.5)^2 + (x[2] + + -0.5)^2)) + 1) : 0.0) + return prim2cons(SVector(H_upper, v1_upper, v2_upper, H_lower, v1_lower, v2_lower, b), + equations) end initial_condition = initial_condition_well_balanced @@ -32,19 +35,20 @@ initial_condition = initial_condition_well_balanced volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) surface_flux = (flux_es_fjordholm_etal, flux_nonconservative_fjordholm_etal) -solver = DGSEM(polydeg=6, surface_flux=surface_flux, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 6, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # This setup is for the curved, split form well-balancedness testing # Get the unstructured quad mesh from a file (downloads the file if not available locally) default_mesh_file = joinpath(@__DIR__, "mesh_alfven_wave_with_twist_and_flip.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", + default_mesh_file) mesh_file = default_mesh_file -mesh = UnstructuredMesh2D(mesh_file, periodicity=true) +mesh = UnstructuredMesh2D(mesh_file, periodicity = true) # Create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -58,16 +62,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(lake_at_rest_error,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (lake_at_rest_error,)) -stepsize_callback = StepsizeCallback(cfl=1.0) +stepsize_callback = StepsizeCallback(cfl = 1.0) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) @@ -75,7 +79,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav ############################################################################### # 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); +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/unstructured_2d_dgsem/elixir_shallowwater_wall_bc_shockcapturing.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_wall_bc_shockcapturing.jl index 4700724c520..76b9642d595 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_wall_bc_shockcapturing.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_wall_bc_shockcapturing.jl @@ -7,63 +7,66 @@ using Trixi # semidiscretization of the shallow water equations with a continuous # bottom topography function -equations = ShallowWaterEquations2D(gravity_constant=9.812, H0=2.0) +equations = ShallowWaterEquations2D(gravity_constant = 9.812, H0 = 2.0) function initial_condition_stone_throw(x, t, equations::ShallowWaterEquations2D) - # Set up polar coordinates - inicenter = SVector(0.15, 0.15) - x_norm = x[1] - inicenter[1] - y_norm = x[2] - inicenter[2] - r = sqrt(x_norm^2 + y_norm^2) - - # Calculate primitive variables - H = equations.H0 - v1 = r < 0.6 ? 2.0 : 0.0 - v2 = r < 0.6 ? -2.0 : 0.0 - # bottom topography taken from Pond.control in [HOHQMesh](https://github.com/trixi-framework/HOHQMesh) - x1, x2 = x - b = ( 1.5 / exp( 0.5 * ((x1 - 1.0)^2 + (x2 - 1.0)^2) ) - + 0.75 / exp( 0.5 * ((x1 + 1.0)^2 + (x2 + 1.0)^2) ) ) - - return prim2cons(SVector(H, v1, v2, b), equations) + # Set up polar coordinates + inicenter = SVector(0.15, 0.15) + x_norm = x[1] - inicenter[1] + y_norm = x[2] - inicenter[2] + r = sqrt(x_norm^2 + y_norm^2) + + # Calculate primitive variables + H = equations.H0 + v1 = r < 0.6 ? 2.0 : 0.0 + v2 = r < 0.6 ? -2.0 : 0.0 + # bottom topography taken from Pond.control in [HOHQMesh](https://github.com/trixi-framework/HOHQMesh) + x1, x2 = x + b = (1.5 / exp(0.5 * ((x1 - 1.0)^2 + (x2 - 1.0)^2)) + + 0.75 / exp(0.5 * ((x1 + 1.0)^2 + (x2 + 1.0)^2))) + + return prim2cons(SVector(H, v1, v2, b), equations) end initial_condition = initial_condition_stone_throw -boundary_condition = Dict( :OuterCircle => boundary_condition_slip_wall ) +boundary_condition = Dict(:OuterCircle => boundary_condition_slip_wall) ############################################################################### # Get the DG approximation space -surface_flux=(FluxHydrostaticReconstruction(flux_hll, hydrostatic_reconstruction_audusse_etal), - flux_nonconservative_audusse_etal) +surface_flux = (FluxHydrostaticReconstruction(flux_hll, + hydrostatic_reconstruction_audusse_etal), + flux_nonconservative_audusse_etal) volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) polydeg = 6 basis = LobattoLegendreBasis(polydeg) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=Trixi.waterheight) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = Trixi.waterheight) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) -solver = DGSEM(polydeg=polydeg, surface_flux=surface_flux, volume_integral=volume_integral) +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral) ############################################################################### # Get the unstructured quad mesh from a file (downloads the file if not available locally) default_mesh_file = joinpath(@__DIR__, "mesh_outer_circle.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/9beddd9cd00e2a0a15865129eeb24928/raw/be71e67fa48bc4e1e97f5f6cd77c3ed34c6ba9be/mesh_outer_circle.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/9beddd9cd00e2a0a15865129eeb24928/raw/be71e67fa48bc4e1e97f5f6cd77c3ed34c6ba9be/mesh_outer_circle.mesh", + default_mesh_file) mesh_file = default_mesh_file mesh = UnstructuredMesh2D(mesh_file) # Create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions=boundary_condition) + boundary_conditions = boundary_condition) ############################################################################### # ODE solvers, callbacks, etc. @@ -74,15 +77,16 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, save_analysis=false, - extra_analysis_integrals=(energy_kinetic, - energy_internal)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = false, + extra_analysis_integrals = (energy_kinetic, + energy_internal)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) @@ -90,6 +94,6 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav # run the simulation # use a Runge-Kutta method with automatic (error based) time step size control -sol = solve(ode, RDPK3SpFSAL49(); abstol=1.0e-8, reltol=1.0e-8, - ode_default_options()..., callback=callbacks); +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-8, reltol = 1.0e-8, + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/unstructured_2d_dgsem/elixir_shallowwater_well_balanced.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_well_balanced.jl index 645f985d10d..bf4d0be682a 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_well_balanced.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_well_balanced.jl @@ -7,21 +7,21 @@ using Trixi # semidiscretization of the shallow water equations with a discontinuous # bottom topography function (set in the initial conditions) -equations = ShallowWaterEquations2D(gravity_constant=9.81, H0=3.0) +equations = ShallowWaterEquations2D(gravity_constant = 9.81, H0 = 3.0) # An initial condition with constant total water height and zero velocities to test well-balancedness. # Note, this routine is used to compute errors in the analysis callback but the initialization is # overwritten by `initial_condition_discontinuous_well_balancedness` below. function initial_condition_well_balancedness(x, t, equations::ShallowWaterEquations2D) - # Set the background values - H = equations.H0 - v1 = 0.0 - v2 = 0.0 - # bottom topography taken from Pond.control in [HOHQMesh](https://github.com/trixi-framework/HOHQMesh) - x1, x2 = x - b = ( 1.5 / exp( 0.5 * ((x1 - 1.0)^2 + (x2 - 1.0)^2) ) - + 0.75 / exp( 0.5 * ((x1 + 1.0)^2 + (x2 + 1.0)^2) ) ) - return prim2cons(SVector(H, v1, v2, b), equations) + # Set the background values + H = equations.H0 + v1 = 0.0 + v2 = 0.0 + # bottom topography taken from Pond.control in [HOHQMesh](https://github.com/trixi-framework/HOHQMesh) + x1, x2 = x + b = (1.5 / exp(0.5 * ((x1 - 1.0)^2 + (x2 - 1.0)^2)) + + 0.75 / exp(0.5 * ((x1 + 1.0)^2 + (x2 + 1.0)^2))) + return prim2cons(SVector(H, v1, v2, b), equations) end initial_condition = initial_condition_well_balancedness @@ -30,20 +30,21 @@ initial_condition = initial_condition_well_balancedness # Get the DG approximation space volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -surface_flux=(flux_fjordholm_etal, flux_nonconservative_fjordholm_etal) -solver = DGSEM(polydeg=6, surface_flux=surface_flux, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal) +solver = DGSEM(polydeg = 6, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### # This setup is for the curved, split form well-balancedness testing # Get the unstructured quad mesh from a file (downloads the file if not available locally) default_mesh_file = joinpath(@__DIR__, "mesh_alfven_wave_with_twist_and_flip.mesh") -isfile(default_mesh_file) || download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", - default_mesh_file) +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", + default_mesh_file) mesh_file = default_mesh_file -mesh = UnstructuredMesh2D(mesh_file, periodicity=true) +mesh = UnstructuredMesh2D(mesh_file, periodicity = true) # Create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -64,30 +65,33 @@ ode = semidiscretize(semi, tspan) # 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_discontinuous_well_balancedness(x, t, element_id, equations::ShallowWaterEquations2D) - # Set the background values - H = equations.H0 - v1 = 0.0 - v2 = 0.0 - b = 0.0 - - # Setup a discontinuous bottom topography using the element id number - if element_id == 7 - b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) + 0.5 * cos(2.0 * pi * x[2]) - end - - return prim2cons(SVector(H, v1, v2, b), equations) +function initial_condition_discontinuous_well_balancedness(x, t, element_id, + equations::ShallowWaterEquations2D) + # Set the background values + H = equations.H0 + v1 = 0.0 + v2 = 0.0 + b = 0.0 + + # Setup a discontinuous bottom topography using the element id number + if element_id == 7 + b = 2.0 + 0.5 * sin(2.0 * pi * x[1]) + 0.5 * cos(2.0 * pi * 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_discontinuous_well_balancedness(x_node, first(tspan), element, equations) - Trixi.set_node_vars!(u, u_node, equations, semi.solver, i, j, element) - end + 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_discontinuous_well_balancedness(x_node, first(tspan), + element, equations) + Trixi.set_node_vars!(u, u_node, equations, semi.solver, i, j, element) + end end ############################################################################### @@ -96,16 +100,16 @@ end summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval, - extra_analysis_integrals=(lake_at_rest_error,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (lake_at_rest_error,)) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=1000, - save_initial_solution=true, - save_final_solution=true) +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true) -stepsize_callback = StepsizeCallback(cfl=3.0) +stepsize_callback = StepsizeCallback(cfl = 3.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) @@ -113,7 +117,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, sav ############################################################################### # 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); +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 From 158e53372cd168e3c2b243f70e3b9faa62c700c3 Mon Sep 17 00:00:00 2001 From: ArseniyKholod <119304909+ArseniyKholod@users.noreply.github.com> Date: Sun, 5 Nov 2023 15:44:01 +0100 Subject: [PATCH 153/263] Update differentiable_programming.jl (#1704) --- docs/literate/src/files/differentiable_programming.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/literate/src/files/differentiable_programming.jl b/docs/literate/src/files/differentiable_programming.jl index 33427803afc..0960ba25d9f 100644 --- a/docs/literate/src/files/differentiable_programming.jl +++ b/docs/literate/src/files/differentiable_programming.jl @@ -43,7 +43,7 @@ scatter(real.(λ), imag.(λ), label="central flux") # As you can see here, the maximal real part is close to zero. relative_maximum = maximum(real, λ) / maximum(abs, λ) -@test 3.0e-10 < relative_maximum < 8.0e-10 #src +@test 3.0e-10 < relative_maximum < 9.0e-10 #src # Interestingly, if we add dissipation by switching to the `flux_lax_friedrichs` # at the interfaces, the maximal real part of the eigenvalues increases. @@ -87,7 +87,7 @@ scatter(real.(λ), imag.(λ), label="central flux") # Here, the maximal real part is basically zero to machine accuracy. relative_maximum = maximum(real, λ) / maximum(abs, λ) -@test 1.0e-17 < relative_maximum < 1.0e-15 #src +@test 1.0e-17 < relative_maximum < 2.0e-15 #src # Moreover, the eigenvectors are not as ill-conditioned as in 2D. From 08a4c45c9c12a18e9ee9e4531ea61242c24f501b Mon Sep 17 00:00:00 2001 From: Jesse Chan <1156048+jlchan@users.noreply.github.com> Date: Mon, 6 Nov 2023 23:00:11 -0600 Subject: [PATCH 154/263] Update NEWS.md with quasi-1D SWE (#1710) --- NEWS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS.md b/NEWS.md index bc213fcea55..6baa7f77d23 100644 --- a/NEWS.md +++ b/NEWS.md @@ -13,6 +13,7 @@ for human readability. - Capability to set truly discontinuous initial conditions in 1D. - Wetting and drying feature and examples for 1D and 2D shallow water equations - Implementation of the polytropic Euler equations in 2D +- Implementation of the quasi-1D shallow water equations - Subcell positivity limiting support for conservative variables in 2D for `TreeMesh` - AMR for hyperbolic-parabolic equations on 2D/3D `TreeMesh` From 3186df5be024f1253d282339058d7df3e1a02307 Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Tue, 7 Nov 2023 06:02:03 +0100 Subject: [PATCH 155/263] Add downstream tests for TrixiShallowWater.jl (#1707) * Add downstream tests for TrixiShallowWater.jl * Fix workflow name * Explain rationale for using `main` branch of downstream package --------- Co-authored-by: Hendrik Ranocha --- .github/workflows/downstream.yml | 93 ++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 .github/workflows/downstream.yml diff --git a/.github/workflows/downstream.yml b/.github/workflows/downstream.yml new file mode 100644 index 00000000000..d9e3a2d8a7e --- /dev/null +++ b/.github/workflows/downstream.yml @@ -0,0 +1,93 @@ +# Note: this file is inspired by the downstream testing facilities in the SciML ecosystem +# x-ref: https://github.com/SciML/SciMLBase.jl/blob/ffe68aebedee5915190623cb08160d7ef1fbcce0/.github/workflows/Downstream.yml + +name: Downstream +on: + push: + branches: + - main + paths-ignore: + - 'AUTHORS.md' + - 'CITATION.bib' + - 'CONTRIBUTING.md' + - 'LICENSE.md' + - 'NEWS.md' + - 'README.md' + - '.zenodo.json' + - '.github/workflows/benchmark.yml' + - '.github/workflows/CompatHelper.yml' + - '.github/workflows/TagBot.yml' + - 'benchmark/**' + # - 'docs/**' + - 'utils/**' + pull_request: + paths-ignore: + - 'AUTHORS.md' + - 'CITATION.bib' + - 'CONTRIBUTING.md' + - 'LICENSE.md' + - 'NEWS.md' + - 'README.md' + - '.zenodo.json' + - '.github/workflows/benchmark.yml' + - '.github/workflows/CompatHelper.yml' + - '.github/workflows/TagBot.yml' + - 'benchmark/**' + # - 'docs/**' + - 'utils/**' + workflow_dispatch: + +# Cancel redundant CI tests automatically +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + if: "!contains(github.event.head_commit.message, 'skip ci')" + # We could also include the Julia version as in + # name: ${{ matrix.trixi_test }} - ${{ matrix.os }} - Julia ${{ matrix.version }} - ${{ matrix.arch }} - ${{ github.event_name }} + # to be more specific. However, that requires us updating the required CI tests whenever we update Julia. + name: ${{ matrix.package }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + version: + - '1.9' + os: + - ubuntu-latest + arch: + - x64 + package: + - TrixiShallowWater.jl + steps: + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v1 + with: + version: ${{ matrix.version }} + arch: ${{ matrix.arch }} + - run: julia -e 'using InteractiveUtils; versioninfo(verbose=true)' + - uses: julia-actions/cache@v1 + - uses: julia-actions/julia-buildpkg@v1 + - name: Retrieve downstream package + # Note: we retrieve the current `main` branch of the downstream package to ensure + # that compatibility errors we make in Trixi.jl are detected already here + # See also https://github.com/trixi-framework/Trixi.jl/pull/1707#discussion_r1382938895 + uses: actions/checkout@v4 + with: + repository: trixi-framework/${{ matrix.package }} + path: downstream + - name: Load upstream package into downstream environment + shell: julia --color=yes --project=downstream {0} + run: | + using Pkg + Pkg.develop(PackageSpec(path=".")) + Pkg.update() + - name: Run downstream tests (without coverage) + shell: julia --color=yes --project=downstream {0} + run: | + using Pkg + Pkg.test(coverage=false) + env: + TRIXI_TEST: upstream From 276dc3ca22a4c72b81aa6659e57ff1382dd1ae0c Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 7 Nov 2023 10:33:05 +0100 Subject: [PATCH 156/263] add compat bounds for stdlibs (#1711) * add comapt bounds for stdlibs * set compat bounds of stdlibs to v1 * set compat bounds for stdlibs to v1 --- Project.toml | 3 +++ docs/Project.toml | 1 + test/Project.toml | 5 +++++ 3 files changed, 9 insertions(+) diff --git a/Project.toml b/Project.toml index f19f7fdecc3..497f4a1add7 100644 --- a/Project.toml +++ b/Project.toml @@ -58,6 +58,7 @@ FillArrays = "0.13.2, 1" ForwardDiff = "0.10.18" HDF5 = "0.14, 0.15, 0.16, 0.17" IfElse = "0.1" +LinearAlgebra = "1" LinearMaps = "2.7, 3.0" LoopVectorization = "0.12.118" MPI = "0.20" @@ -68,12 +69,14 @@ OffsetArrays = "1.3" P4est = "0.4" Polyester = "0.7.5" PrecompileTools = "1.1" +Printf = "1" RecipesBase = "1.1" Reexport = "1.0" Requires = "1.1" SciMLBase = "1.90, 2" Setfield = "0.8, 1" SimpleUnPack = "1.1" +SparseArrays = "1" StartUpDG = "0.17" Static = "0.3, 0.4, 0.5, 0.6, 0.7, 0.8" StaticArrayInterface = "1.4" diff --git a/docs/Project.toml b/docs/Project.toml index ffa86e0b9f7..3a091f5b4f1 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -21,4 +21,5 @@ Literate = "2.9" Measurements = "2.5" OrdinaryDiffEq = "6.49.1" Plots = "1.9" +Test = "1" Trixi2Vtk = "0.3" diff --git a/test/Project.toml b/test/Project.toml index c45be49a5d0..83b431e269b 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -17,11 +17,16 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Aqua = "0.7" BSON = "0.3.3" CairoMakie = "0.6, 0.7, 0.8, 0.9, 0.10" +Downloads = "1" Flux = "0.13.15, 0.14" ForwardDiff = "0.10" +LinearAlgebra = "1" MPI = "0.20" OrdinaryDiffEq = "6.49.1" Plots = "1.16" +Printf = "1" +Random = "1" +Test = "1" [preferences.OrdinaryDiffEq] PrecompileAutoSpecialize = false From 9acaa9033fc2d062ab0a7e6d219414cb9aa30eeb Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Thu, 9 Nov 2023 08:07:17 +0100 Subject: [PATCH 157/263] Add Trixi2Vtk.jl to downstream tests (#1722) --- .github/workflows/downstream.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/downstream.yml b/.github/workflows/downstream.yml index d9e3a2d8a7e..b40d5d365c0 100644 --- a/.github/workflows/downstream.yml +++ b/.github/workflows/downstream.yml @@ -60,6 +60,7 @@ jobs: arch: - x64 package: + - Trixi2Vtk.jl - TrixiShallowWater.jl steps: - uses: actions/checkout@v4 From 63c625824c3d510611dcebba12a0319d7e9cad9a Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Fri, 10 Nov 2023 07:28:45 +0100 Subject: [PATCH 158/263] Fix bug (#1719) --- src/equations/compressible_euler_2d.jl | 2 +- test/test_p4est_2d.jl | 16 ++++++++-------- test/test_unit.jl | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/equations/compressible_euler_2d.jl b/src/equations/compressible_euler_2d.jl index 6c8f2e1e848..a992f99eaf4 100644 --- a/src/equations/compressible_euler_2d.jl +++ b/src/equations/compressible_euler_2d.jl @@ -1351,7 +1351,7 @@ of the numerical flux. v1_roe = (sqrt_rho_ll * v1_ll + sqrt_rho_rr * v1_rr) * inv_sum_sqrt_rho v2_roe = (sqrt_rho_ll * v2_ll + sqrt_rho_rr * v2_rr) * inv_sum_sqrt_rho v_roe = v1_roe * normal_direction[1] + v2_roe * normal_direction[2] - v_roe_mag = (v1_roe * normal_direction[1])^2 + (v2_roe * normal_direction[2])^2 + v_roe_mag = v1_roe^2 + v2_roe^2 H_roe = (sqrt_rho_ll * H_ll + sqrt_rho_rr * H_rr) * inv_sum_sqrt_rho c_roe = sqrt((equations.gamma - 1) * (H_roe - 0.5 * v_roe_mag)) * norm_ diff --git a/test/test_p4est_2d.jl b/test/test_p4est_2d.jl index 546e5bff8a6..07c6d02bbcd 100644 --- a/test/test_p4est_2d.jl +++ b/test/test_p4est_2d.jl @@ -203,16 +203,16 @@ end @trixi_testset "elixir_euler_sedov.jl (HLLE)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov.jl"), l2=[ - 0.411541263324004, - 0.2558929632770186, - 0.2558929632770193, - 1.298715766843915, + 0.40853279043747015, + 0.25356771650524296, + 0.2535677165052422, + 1.2984601729572691, ], linf=[ - 1.3457201726152221, - 1.3138961427140758, - 1.313896142714079, - 6.293305112638921, + 1.3840909333784284, + 1.3077772519086124, + 1.3077772519086157, + 6.298798630968632, ], surface_flux=flux_hlle, tspan=(0.0, 0.3)) diff --git a/test/test_unit.jl b/test/test_unit.jl index a73dfab5504..29390161ebe 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1191,7 +1191,7 @@ end u_values = [SVector(1.0, 0.5, -0.7, 1.0), SVector(1.5, -0.2, 0.1, 5.0)] fluxes = [flux_central, flux_ranocha, flux_shima_etal, flux_kennedy_gruber, - flux_hll, FluxHLL(min_max_speed_davis)] + flux_hll, FluxHLL(min_max_speed_davis), flux_hlle] for f_std in fluxes f_rot = FluxRotated(f_std) @@ -1215,7 +1215,7 @@ end SVector(1.5, -0.2, 0.1, 0.2, 5.0)] fluxes = [flux_central, flux_ranocha, flux_shima_etal, flux_kennedy_gruber, FluxLMARS(340), - flux_hll, FluxHLL(min_max_speed_davis)] + flux_hll, FluxHLL(min_max_speed_davis), flux_hlle] for f_std in fluxes f_rot = FluxRotated(f_std) From 910df76691685040cd46ed661253f7348cb35344 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 10 Nov 2023 07:44:38 +0100 Subject: [PATCH 159/263] fix IndicatorMax with multi-threading on ARM (#1723) --- src/solvers/dgsem_tree/indicators_1d.jl | 3 ++- src/solvers/dgsem_tree/indicators_2d.jl | 3 ++- src/solvers/dgsem_tree/indicators_3d.jl | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/solvers/dgsem_tree/indicators_1d.jl b/src/solvers/dgsem_tree/indicators_1d.jl index 8b57348861c..40bfd1e98c7 100644 --- a/src/solvers/dgsem_tree/indicators_1d.jl +++ b/src/solvers/dgsem_tree/indicators_1d.jl @@ -289,6 +289,7 @@ function (indicator_max::IndicatorMax)(u::AbstractArray{<:Any, 3}, kwargs...) @unpack alpha, indicator_threaded = indicator_max.cache resize!(alpha, nelements(dg, cache)) + indicator_variable = indicator_max.variable @threaded for element in eachelement(dg, cache) indicator = indicator_threaded[Threads.threadid()] @@ -296,7 +297,7 @@ function (indicator_max::IndicatorMax)(u::AbstractArray{<:Any, 3}, # Calculate indicator variables at Gauss-Lobatto nodes for i in eachnode(dg) u_local = get_node_vars(u, equations, dg, i, element) - indicator[i] = indicator_max.variable(u_local, equations) + indicator[i] = indicator_variable(u_local, equations) end alpha[element] = maximum(indicator) diff --git a/src/solvers/dgsem_tree/indicators_2d.jl b/src/solvers/dgsem_tree/indicators_2d.jl index 2f34e0eb661..da81b2a1d36 100644 --- a/src/solvers/dgsem_tree/indicators_2d.jl +++ b/src/solvers/dgsem_tree/indicators_2d.jl @@ -323,6 +323,7 @@ function (indicator_max::IndicatorMax)(u::AbstractArray{<:Any, 4}, kwargs...) @unpack alpha, indicator_threaded = indicator_max.cache resize!(alpha, nelements(dg, cache)) + indicator_variable = indicator_max.variable @threaded for element in eachelement(dg, cache) indicator = indicator_threaded[Threads.threadid()] @@ -330,7 +331,7 @@ function (indicator_max::IndicatorMax)(u::AbstractArray{<:Any, 4}, # Calculate indicator variables at Gauss-Lobatto nodes for j in eachnode(dg), i in eachnode(dg) u_local = get_node_vars(u, equations, dg, i, j, element) - indicator[i, j] = indicator_max.variable(u_local, equations) + indicator[i, j] = indicator_variable(u_local, equations) end alpha[element] = maximum(indicator) diff --git a/src/solvers/dgsem_tree/indicators_3d.jl b/src/solvers/dgsem_tree/indicators_3d.jl index 69041ed1298..40362889397 100644 --- a/src/solvers/dgsem_tree/indicators_3d.jl +++ b/src/solvers/dgsem_tree/indicators_3d.jl @@ -234,6 +234,7 @@ function (indicator_max::IndicatorMax)(u::AbstractArray{<:Any, 5}, kwargs...) @unpack alpha, indicator_threaded = indicator_max.cache resize!(alpha, nelements(dg, cache)) + indicator_variable = indicator_max.variable @threaded for element in eachelement(dg, cache) indicator = indicator_threaded[Threads.threadid()] @@ -241,7 +242,7 @@ function (indicator_max::IndicatorMax)(u::AbstractArray{<:Any, 5}, # Calculate indicator variables at Gauss-Lobatto nodes for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg) u_local = get_node_vars(u, equations, dg, i, j, k, element) - indicator[i, j, k] = indicator_max.variable(u_local, equations) + indicator[i, j, k] = indicator_variable(u_local, equations) end alpha[element] = maximum(indicator) From 9a00184c6ca656ce2fab4c8600bc837883a02b06 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Fri, 10 Nov 2023 07:46:35 +0100 Subject: [PATCH 160/263] Remove AMR CB from HLLE 2D Tree test (#1720) * remove amr cb * fmt --- test/test_tree_2d_euler.jl | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/test/test_tree_2d_euler.jl b/test/test_tree_2d_euler.jl index db36cb7d79f..93490f8ae09 100644 --- a/test/test_tree_2d_euler.jl +++ b/test/test_tree_2d_euler.jl @@ -425,19 +425,22 @@ end @trixi_testset "elixir_euler_sedov_blast_wave.jl (HLLE)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov_blast_wave.jl"), l2=[ - 0.35267161504176747, - 0.17218309138797958, - 0.17218307467125854, - 0.6236143054619037, + 0.352405949321075, + 0.17207721487429464, + 0.17207721487433883, + 0.6263024434020885, ], linf=[ - 2.77484045816607, - 1.8281111268370718, - 1.8281110470490887, - 6.24263735888126, + 2.760997358628186, + 1.8279186132509326, + 1.8279186132502805, + 6.251573757093399, ], tspan=(0.0, 0.5), - surface_flux=flux_hlle) + callbacks=CallbackSet(summary_callback, + analysis_callback, alive_callback, + stepsize_callback), + surface_flux=flux_hlle), # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let From cb8181f6e5ae2fa74054ab227b2e19a393edcee0 Mon Sep 17 00:00:00 2001 From: Patrick Ersing <114223904+patrickersing@users.noreply.github.com> Date: Fri, 10 Nov 2023 15:59:07 +0100 Subject: [PATCH 161/263] Fix the wet/dry test for SWE (#1727) * Adjust tolerance to fix wet_dry test * apply formatter --- test/test_tree_1d_shallowwater.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/test_tree_1d_shallowwater.jl b/test/test_tree_1d_shallowwater.jl index 658f178c941..7ec3089d33a 100644 --- a/test/test_tree_1d_shallowwater.jl +++ b/test/test_tree_1d_shallowwater.jl @@ -109,7 +109,9 @@ end 2.2447689894899726e-13, 1.9999999999999714, ], - tspan=(0.0, 0.25)) + tspan=(0.0, 0.25), + # Soften the tolerance as test results vary between different CPUs + atol=1000 * eps()) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let From 6158ba4cc319d7715d1b9419043c7ba55f15c473 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Sat, 11 Nov 2023 19:15:16 +0100 Subject: [PATCH 162/263] fix failing `DGMultiMesh` and Compressible Navier-Stokes convergence tests (#1728) (#1732) * fix failing test * more fixes * formatting * fix dropped part of source terms * fix p4est parabolic Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> --- .../p4est_2d_dgsem/elixir_navierstokes_convergence.jl | 1 + .../tree_2d_dgsem/elixir_navierstokes_convergence.jl | 11 ++++++----- test/test_parabolic_2d.jl | 3 ++- test/test_special_elixirs.jl | 6 ++++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/examples/p4est_2d_dgsem/elixir_navierstokes_convergence.jl b/examples/p4est_2d_dgsem/elixir_navierstokes_convergence.jl index 7aa14e25750..54ec09d2be8 100644 --- a/examples/p4est_2d_dgsem/elixir_navierstokes_convergence.jl +++ b/examples/p4est_2d_dgsem/elixir_navierstokes_convergence.jl @@ -161,6 +161,7 @@ end v1_yy * v1 * mu_ - v2_xy * v1 * mu_ - v1_y * v1_y * mu_ - + v2_x * v1_y * mu_ - 4.0 / 3.0 * v2_yy * v2 * mu_ + 2.0 / 3.0 * v1_xy * v2 * mu_ - 4.0 / 3.0 * v2_y * v2_y * mu_ + diff --git a/examples/tree_2d_dgsem/elixir_navierstokes_convergence.jl b/examples/tree_2d_dgsem/elixir_navierstokes_convergence.jl index 57558224854..b0c8678baad 100644 --- a/examples/tree_2d_dgsem/elixir_navierstokes_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_navierstokes_convergence.jl @@ -160,15 +160,16 @@ end # stress tensor and temperature gradient terms from y-direction v1_yy * v1 * mu_ - v2_xy * v1 * mu_ - + v1_y * v1_y * mu_ - v2_x * v1_y * mu_ - 4.0 / 3.0 * v2_yy * v2 * mu_ + - 2.0 / 3.0 * v1_xy - + 2.0 / 3.0 * v1_xy * v2 * mu_ - 4.0 / 3.0 * v2_y * v2_y * mu_ + - 2.0 / 3.0 * v1_x * v2_y * mu_ - - - - + 2.0 / 3.0 * v1_x * v2_y * mu_ - + T_const * inv_rho_cubed * (p_yy * rho * rho - - 2.0 * p_y * rho * rho_y + - - + 2.0 * p_y * rho * rho_y + + 2.0 * p * rho_y * rho_y - p * rho * rho_yy) * mu_) return SVector(du1, du2, du3, du4) diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 22a5a8b4e31..152ca52a6ca 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -16,7 +16,8 @@ isdir(outdir) && rm(outdir, recursive = true) dg = DGMulti(polydeg = 2, element_type = Quad(), approximation_type = Polynomial(), surface_integral = SurfaceIntegralWeakForm(flux_central), volume_integral = VolumeIntegralWeakForm()) - mesh = DGMultiMesh(dg, cells_per_dimension = (2, 2)) + cells_per_dimension = (2, 2) + mesh = DGMultiMesh(dg, cells_per_dimension) # test with polynomial initial condition x^2 * y # test if we recover the exact second derivative diff --git a/test/test_special_elixirs.jl b/test/test_special_elixirs.jl index 4f42414ccbf..85671002ba6 100644 --- a/test/test_special_elixirs.jl +++ b/test/test_special_elixirs.jl @@ -203,7 +203,8 @@ end volume_integral = VolumeIntegralWeakForm()) # DGMultiMesh is on [-1, 1]^ndims by default - mesh = DGMultiMesh(solver, cells_per_dimension = (2, 2), + cells_per_dimension = (2, 2) + mesh = DGMultiMesh(solver, cells_per_dimension, periodicity = (true, true)) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, @@ -225,7 +226,8 @@ end volume_integral = VolumeIntegralFluxDifferencing(flux_central)) # DGMultiMesh is on [-1, 1]^ndims by default - mesh = DGMultiMesh(solver, cells_per_dimension = (2, 2), + cells_per_dimension = (2, 2) + mesh = DGMultiMesh(solver, cells_per_dimension, periodicity = (true, true)) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, From 53456098659a9b85fdd5c0a22184d10b88a3ba83 Mon Sep 17 00:00:00 2001 From: Jesse Chan <1156048+jlchan@users.noreply.github.com> Date: Sat, 11 Nov 2023 14:10:55 -0600 Subject: [PATCH 163/263] Fix `flux` for quasi-1D SWE (#1731) * fix flux (remove non-conservative part) * add test * formatting --------- Co-authored-by: Hendrik Ranocha --- ...xir_shallowwater_quasi_1d_discontinuous.jl | 73 +++++++++++++++++++ src/equations/shallow_water_quasi_1d.jl | 9 +-- test/test_tree_1d_shallowwater.jl | 25 +++++++ 3 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 examples/tree_1d_dgsem/elixir_shallowwater_quasi_1d_discontinuous.jl diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_quasi_1d_discontinuous.jl b/examples/tree_1d_dgsem/elixir_shallowwater_quasi_1d_discontinuous.jl new file mode 100644 index 00000000000..76c04759389 --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_shallowwater_quasi_1d_discontinuous.jl @@ -0,0 +1,73 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# Semidiscretization of the quasi 1d shallow water equations +# See Chan et al. https://doi.org/10.48550/arXiv.2307.12089 for details + +equations = ShallowWaterEquationsQuasi1D(gravity_constant = 9.81) + +function initial_condition_discontinuity(x, t, equations::ShallowWaterEquationsQuasi1D) + H = 2 + 0.1 * exp(-25 * x[1]^2) + v = 0.0 + + if x[1] > 0 + b = 0.1 + a = 1.0 + else + b = 0.0 + a = 1.1 + end + + return prim2cons(SVector(H, v, b, a), equations) +end + +initial_condition = initial_condition_discontinuity + +############################################################################### +# Get the DG approximation space + +volume_flux = (flux_chan_etal, flux_nonconservative_chan_etal) +surface_flux = (flux_lax_friedrichs, flux_nonconservative_chan_etal) +solver = DGSEM(polydeg = 3, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +############################################################################### +# Get the TreeMesh and setup a periodic mesh + +coordinates_min = -0.5 +coordinates_max = 0.5 +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 3, + n_cells_max = 10_000, + periodicity = true) + +# create the semi discretization object +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.25) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 500 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 200, + save_initial_solution = true, + save_final_solution = true) + +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution) + +############################################################################### +# run the simulation + +# use a Runge-Kutta method with automatic (error based) time step size control +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-8, reltol = 1.0e-8, + ode_default_options()..., callback = callbacks); +summary_callback() # print the timer summary diff --git a/src/equations/shallow_water_quasi_1d.jl b/src/equations/shallow_water_quasi_1d.jl index 217a764e173..d3935f0e75f 100644 --- a/src/equations/shallow_water_quasi_1d.jl +++ b/src/equations/shallow_water_quasi_1d.jl @@ -137,17 +137,14 @@ as defined in [`initial_condition_convergence_test`](@ref). return SVector(du1, du2, 0.0, 0.0) end -# Calculate 1D flux for a single point +# Calculate 1D conservative flux for a single point # Note, the bottom topography and channel width have no flux @inline function flux(u, orientation::Integer, equations::ShallowWaterEquationsQuasi1D) - a_h, a_h_v, _, a = u - h = waterheight(u, equations) + _, a_h_v, _, _ = u v = velocity(u, equations) - p = 0.5 * a * equations.gravity * h^2 - f1 = a_h_v - f2 = a_h_v * v + p + f2 = a_h_v * v return SVector(f1, f2, zero(eltype(u)), zero(eltype(u))) end diff --git a/test/test_tree_1d_shallowwater.jl b/test/test_tree_1d_shallowwater.jl index 7ec3089d33a..fd69a0c1d0e 100644 --- a/test/test_tree_1d_shallowwater.jl +++ b/test/test_tree_1d_shallowwater.jl @@ -387,6 +387,31 @@ end @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 end end + +@trixi_testset "elixir_shallowwater_quasi_1d_discontinuous.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_quasi_1d_discontinuous.jl"), + l2=[ + 0.02843233740533314, + 0.14083324483705398, + 0.0054554472558998, + 0.005455447255899814, + ], + linf=[ + 0.26095842440037487, + 0.45919004549253795, + 0.09999999999999983, + 0.10000000000000009, + ],) + # 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 end # module From 6c70d18bd3c428662a2f80c7762099414d2ac4e3 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Sat, 11 Nov 2023 21:11:48 +0100 Subject: [PATCH 164/263] set version to v0.5.48 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 497f4a1add7..311891e3b85 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.5.48-pre" +version = "0.5.48" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From fbf7d54c1975a031dded027cb92645f44ecbf67d Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Sat, 11 Nov 2023 21:12:07 +0100 Subject: [PATCH 165/263] set development version to v0.5.49-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 311891e3b85..03973a8c8b4 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.5.48" +version = "0.5.49-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 6d95941e919472e56d2fbace741fb63510f4b2a4 Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Sat, 4 Nov 2023 13:05:10 +0100 Subject: [PATCH 166/263] Set version to v0.6.0 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 03973a8c8b4..e95e5347ee3 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.5.49-pre" +version = "0.6.0" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 726f1a2fa96ef877624887a4bf10afcf75ff08e2 Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Tue, 7 Nov 2023 07:22:09 +0100 Subject: [PATCH 167/263] Migrate neural network-based indicators to new repository (#1701) * Remove all neural network indicator stuff from `src/` * Migrate neural network tests * Migrate neural network examples * Migrate test dependencies * Update NEWS.md * Fix typo * Remove Requires.jl-based use of Flux.jl * Fix formatting * Add migration of indicators to section with breaking changes --------- Co-authored-by: Hendrik Ranocha --- NEWS.md | 19 + ...blast_wave_neuralnetwork_perssonperaire.jl | 109 ------ ...r_blast_wave_neuralnetwork_rayhesthaven.jl | 109 ------ ...ixir_euler_blast_wave_neuralnetwork_cnn.jl | 107 ------ ...blast_wave_neuralnetwork_perssonperaire.jl | 107 ------ ...r_blast_wave_neuralnetwork_rayhesthaven.jl | 110 ------ ...bility_amr_neuralnetwork_perssonperaire.jl | 134 ------- ...blast_wave_neuralnetwork_perssonperaire.jl | 126 ------- src/Trixi.jl | 8 +- src/solvers/dgsem_tree/indicators.jl | 195 ---------- src/solvers/dgsem_tree/indicators_1d.jl | 218 ----------- src/solvers/dgsem_tree/indicators_2d.jl | 351 ------------------ test/Project.toml | 4 - test/test_tree_1d_euler.jl | 20 - test/test_tree_2d_euler.jl | 114 ------ test/test_unit.jl | 8 - 16 files changed, 20 insertions(+), 1719 deletions(-) delete mode 100644 examples/tree_1d_dgsem/elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl delete mode 100644 examples/tree_1d_dgsem/elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl delete mode 100644 examples/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_cnn.jl delete mode 100644 examples/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl delete mode 100644 examples/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl delete mode 100644 examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_amr_neuralnetwork_perssonperaire.jl delete mode 100644 examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl diff --git a/NEWS.md b/NEWS.md index 6baa7f77d23..fc23e74d1db 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,22 @@ 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 when updating to v0.6 from v0.5.x + +#### Added + +#### Changed + +#### Deprecated + +#### Removed + +- The neural network-based shock indicators have been migrated to a new repository + [TrixiSmartShockFinder.jl](https://github.com/trixi-framework/TrixiSmartShockFinder.jl). + To continue using the indicators, you will need to use both Trixi.jl and + TrixiSmartShockFinder.jl, as explained in the latter packages' `README.md`. + + ## Changes in the v0.5 lifecycle #### Added @@ -32,6 +48,9 @@ for human readability. #### Removed +- Migrate neural network-based shock indicators to a new repository + [TrixiSmartShockFinder.jl](https://github.com/trixi-framework/TrixiSmartShockFinder.jl). + ## Changes when updating to v0.5 from v0.4.x diff --git a/examples/tree_1d_dgsem/elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl b/examples/tree_1d_dgsem/elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl deleted file mode 100644 index 05f392624fd..00000000000 --- a/examples/tree_1d_dgsem/elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl +++ /dev/null @@ -1,109 +0,0 @@ -using Downloads: download -using Flux -using BSON: load -network = joinpath(@__DIR__, "modelnnpp-0.97-0.0001.bson") -download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelnnpp-0.97-0.0001.bson", - network) -model1d = load(network, @__MODULE__)[:model1d] - -using OrdinaryDiffEq -using Trixi - -# This elixir was one of the setups used in the following master thesis: -# - Julia Odenthal (2021) -# Shock capturing with artificial neural networks -# University of Cologne, advisors: Gregor Gassner, Michael Schlottke-Lakemper -# This motivates the particular choice of fluxes, mesh resolution etc. - -############################################################################### -# semidiscretization of the compressible Euler equations - -equations = CompressibleEulerEquations1D(1.4) - -""" - initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations1D) - -A medium blast wave taken from -- Sebastian Hennemann, Gregor J. Gassner (2020) - A provably entropy stable subcell shock capturing approach for high order split form DG - [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) -""" -function initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations1D) - # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" - # Set up polar coordinates - inicenter = SVector(0.0) - x_norm = x[1] - inicenter[1] - r = abs(x_norm) - # The following code is equivalent to - # phi = atan(0.0, x_norm) - # cos_phi = cos(phi) - # in 1D but faster - cos_phi = x_norm > 0 ? one(x_norm) : -one(x_norm) - - # Calculate primitive variables - rho = r > 0.5 ? 1.0 : 1.1691 - v1 = r > 0.5 ? 0.0 : 0.1882 * cos_phi - p = r > 0.5 ? 1.0E-3 : 1.245 - - return prim2cons(SVector(rho, v1, p), equations) -end -initial_condition = initial_condition_blast_wave - -surface_flux = flux_lax_friedrichs -volume_flux = flux_chandrashekar -basis = LobattoLegendreBasis(3) -indicator_sc = IndicatorNeuralNetwork(equations, basis, - indicator_type = NeuralNetworkPerssonPeraire(), - alpha_max = 0.5, - alpha_min = 0.001, - alpha_smooth = true, - alpha_continuous = false, - alpha_amr = false, - variable = density_pressure, - network = model1d) -volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg = volume_flux, - volume_flux_fv = surface_flux) -solver = DGSEM(basis, surface_flux, volume_integral) - -coordinates_min = (-2.0,) -coordinates_max = (2.0,) -mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level = 6, - n_cells_max = 10_000) - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - -############################################################################### -# ODE solvers, callbacks etc. - -tspan = (0.0, 12.5) -ode = semidiscretize(semi, tspan) - -summary_callback = SummaryCallback() - -analysis_interval = 100 - -analysis_callback = AnalysisCallback(semi, interval = analysis_interval) - -alive_callback = AliveCallback(analysis_interval = analysis_interval) - -save_solution = SaveSolutionCallback(interval = 100, - save_initial_solution = true, - save_final_solution = true, - solution_variables = cons2prim) - -stepsize_callback = StepsizeCallback(cfl = 0.5) - -callbacks = CallbackSet(summary_callback, - analysis_callback, alive_callback, - save_solution, - 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/tree_1d_dgsem/elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl b/examples/tree_1d_dgsem/elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl deleted file mode 100644 index de2f5134a49..00000000000 --- a/examples/tree_1d_dgsem/elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl +++ /dev/null @@ -1,109 +0,0 @@ -using Downloads: download -using Flux -using BSON: load -network = joinpath(@__DIR__, "modelnnrh-0.95-0.009.bson") -download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelnnrh-0.95-0.009.bson", - network) -model1d = load(network, @__MODULE__)[:model1d] - -using OrdinaryDiffEq -using Trixi - -# This elixir was one of the setups used in the following master thesis: -# - Julia Odenthal (2021) -# Shock capturing with artificial neural networks -# University of Cologne, advisors: Gregor Gassner, Michael Schlottke-Lakemper -# This motivates the particular choice of fluxes, mesh resolution etc. - -############################################################################### -# semidiscretization of the compressible Euler equations - -equations = CompressibleEulerEquations1D(1.4) - -""" - initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations1D) - -A medium blast wave taken from -- Sebastian Hennemann, Gregor J. Gassner (2020) - A provably entropy stable subcell shock capturing approach for high order split form DG - [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) -""" -function initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations1D) - # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" - # Set up polar coordinates - inicenter = SVector(0.0) - x_norm = x[1] - inicenter[1] - r = abs(x_norm) - # The following code is equivalent to - # phi = atan(0.0, x_norm) - # cos_phi = cos(phi) - # in 1D but faster - cos_phi = x_norm > 0 ? one(x_norm) : -one(x_norm) - - # Calculate primitive variables - rho = r > 0.5 ? 1.0 : 1.1691 - v1 = r > 0.5 ? 0.0 : 0.1882 * cos_phi - p = r > 0.5 ? 1.0E-3 : 1.245 - - return prim2cons(SVector(rho, v1, p), equations) -end -initial_condition = initial_condition_blast_wave - -surface_flux = flux_lax_friedrichs -volume_flux = flux_chandrashekar -basis = LobattoLegendreBasis(3) -indicator_sc = IndicatorNeuralNetwork(equations, basis, - indicator_type = NeuralNetworkRayHesthaven(), - alpha_max = 0.5, - alpha_min = 0.001, - alpha_smooth = true, - alpha_continuous = false, - alpha_amr = false, - variable = density_pressure, - network = model1d) -volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg = volume_flux, - volume_flux_fv = surface_flux) -solver = DGSEM(basis, surface_flux, volume_integral) - -coordinates_min = (-2.0,) -coordinates_max = (2.0,) -mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level = 6, - n_cells_max = 10_000) - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - -############################################################################### -# ODE solvers, callbacks etc. - -tspan = (0.0, 12.5) -ode = semidiscretize(semi, tspan) - -summary_callback = SummaryCallback() - -analysis_interval = 100 - -analysis_callback = AnalysisCallback(semi, interval = analysis_interval) - -alive_callback = AliveCallback(analysis_interval = analysis_interval) - -save_solution = SaveSolutionCallback(interval = 100, - save_initial_solution = true, - save_final_solution = true, - solution_variables = cons2prim) - -stepsize_callback = StepsizeCallback(cfl = 0.5) - -callbacks = CallbackSet(summary_callback, - analysis_callback, alive_callback, - save_solution, - 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/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_cnn.jl b/examples/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_cnn.jl deleted file mode 100644 index 79d7474dc66..00000000000 --- a/examples/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_cnn.jl +++ /dev/null @@ -1,107 +0,0 @@ -using Downloads: download -using Flux -using BSON: load -network = joinpath(@__DIR__, "modelcnn-0.964-0.001.bson") -download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelcnn-0.964-0.001.bson", - network) -model2dcnn = load(network, @__MODULE__)[:model2dcnn] - -using OrdinaryDiffEq -using Trixi - -# This elixir was one of the setups used in the following master thesis: -# - Julia Odenthal (2021) -# Shock capturing with artificial neural networks -# University of Cologne, advisors: Gregor Gassner, Michael Schlottke-Lakemper -# This motivates the particular choice of fluxes, mesh resolution etc. - -############################################################################### -# semidiscretization of the compressible Euler equations - -equations = CompressibleEulerEquations2D(1.4) - -""" - initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations2D) - -A medium blast wave taken from -- Sebastian Hennemann, Gregor J. Gassner (2020) - A provably entropy stable subcell shock capturing approach for high order split form DG - [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) -""" -function initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations2D) - # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" - # 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) - phi = atan(y_norm, x_norm) - sin_phi, cos_phi = sincos(phi) - - # 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 - p = r > 0.5 ? 1.0E-3 : 1.245 - - return prim2cons(SVector(rho, v1, v2, p), equations) -end -initial_condition = initial_condition_blast_wave - -surface_flux = flux_lax_friedrichs -volume_flux = flux_chandrashekar -basis = LobattoLegendreBasis(3) -indicator_sc = IndicatorNeuralNetwork(equations, basis, - indicator_type = NeuralNetworkCNN(), - alpha_max = 0.5, - alpha_min = 0.001, - alpha_smooth = true, - alpha_continuous = true, - alpha_amr = false, - variable = density_pressure, - network = model2dcnn) -volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg = volume_flux, - volume_flux_fv = surface_flux) -solver = DGSEM(basis, surface_flux, volume_integral) - -coordinates_min = (-2.0, -2.0) -coordinates_max = (2.0, 2.0) -mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level = 6, - n_cells_max = 10_000) - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - -############################################################################### -# ODE solvers, callbacks etc. - -tspan = (0.0, 12.5) -ode = semidiscretize(semi, tspan) - -summary_callback = SummaryCallback() - -analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval = analysis_interval) - -alive_callback = AliveCallback(analysis_interval = analysis_interval) - -save_solution = SaveSolutionCallback(interval = 100, - save_initial_solution = true, - save_final_solution = true, - solution_variables = cons2prim) - -stepsize_callback = StepsizeCallback(cfl = 0.9) - -callbacks = CallbackSet(summary_callback, - analysis_callback, alive_callback, - save_solution, - 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/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl b/examples/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl deleted file mode 100644 index 27398593efd..00000000000 --- a/examples/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl +++ /dev/null @@ -1,107 +0,0 @@ -using Downloads: download -using Flux -using BSON: load -network = joinpath(@__DIR__, "modelnnpp-0.904-0.0005.bson") -download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelnnpp-0.904-0.0005.bson", - network) -model2d = load(network, @__MODULE__)[:model2d] - -using OrdinaryDiffEq -using Trixi - -# This elixir was one of the setups used in the following master thesis: -# - Julia Odenthal (2021) -# Shock capturing with artificial neural networks -# University of Cologne, advisors: Gregor Gassner, Michael Schlottke-Lakemper -# This motivates the particular choice of fluxes, mesh resolution etc. - -############################################################################### -# semidiscretization of the compressible Euler equations - -equations = CompressibleEulerEquations2D(1.4) - -""" - initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations2D) - -A medium blast wave taken from -- Sebastian Hennemann, Gregor J. Gassner (2020) - A provably entropy stable subcell shock capturing approach for high order split form DG - [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) -""" -function initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations2D) - # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" - # 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) - phi = atan(y_norm, x_norm) - sin_phi, cos_phi = sincos(phi) - - # 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 - p = r > 0.5 ? 1.0E-3 : 1.245 - - return prim2cons(SVector(rho, v1, v2, p), equations) -end -initial_condition = initial_condition_blast_wave - -surface_flux = flux_lax_friedrichs -volume_flux = flux_chandrashekar -basis = LobattoLegendreBasis(3) -indicator_sc = IndicatorNeuralNetwork(equations, basis, - indicator_type = NeuralNetworkPerssonPeraire(), - alpha_max = 0.5, - alpha_min = 0.001, - alpha_smooth = true, - alpha_continuous = true, - alpha_amr = false, - variable = density_pressure, - network = model2d) -volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg = volume_flux, - volume_flux_fv = surface_flux) -solver = DGSEM(basis, surface_flux, volume_integral) - -coordinates_min = (-2.0, -2.0) -coordinates_max = (2.0, 2.0) -mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level = 6, - n_cells_max = 10_000) - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - -############################################################################### -# ODE solvers, callbacks etc. - -tspan = (0.0, 12.5) -ode = semidiscretize(semi, tspan) - -summary_callback = SummaryCallback() - -analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval = analysis_interval) - -alive_callback = AliveCallback(analysis_interval = analysis_interval) - -save_solution = SaveSolutionCallback(interval = 100, - save_initial_solution = true, - save_final_solution = true, - solution_variables = cons2prim) - -stepsize_callback = StepsizeCallback(cfl = 0.9) - -callbacks = CallbackSet(summary_callback, - analysis_callback, alive_callback, - save_solution, - 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/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl b/examples/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl deleted file mode 100644 index 6c67f948636..00000000000 --- a/examples/tree_2d_dgsem/elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl +++ /dev/null @@ -1,110 +0,0 @@ -using Downloads: download -using Flux -using Random -using BSON: load -network = joinpath(@__DIR__, "modelnnrhs-0.973-0.001.bson") -download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelnnrhs-0.973-0.001.bson", - network) -model2d = load(network, @__MODULE__)[:model2d] - -using OrdinaryDiffEq -using Trixi - -# This elixir was one of the setups used in the following master thesis: -# - Julia Odenthal (2021) -# Shock capturing with artificial neural networks -# University of Cologne, advisors: Gregor Gassner, Michael Schlottke-Lakemper -# This motivates the particular choice of fluxes, mesh resolution etc. - -############################################################################### -# semidiscretization of the compressible Euler equations - -equations = CompressibleEulerEquations2D(1.4) - -""" - initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations2D) - -A medium blast wave taken from -- Sebastian Hennemann, Gregor J. Gassner (2020) - A provably entropy stable subcell shock capturing approach for high order split form DG - [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) -""" -function initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations2D) - # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" - # 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) - phi = atan(y_norm, x_norm) - sin_phi, cos_phi = sincos(phi) - - # 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 - p = r > 0.5 ? 1.0E-3 : 1.245 - - return prim2cons(SVector(rho, v1, v2, p), equations) -end -initial_condition = initial_condition_blast_wave - -surface_flux = flux_lax_friedrichs -volume_flux = flux_chandrashekar -basis = LobattoLegendreBasis(3) -indicator_sc = IndicatorNeuralNetwork(equations, basis, - indicator_type = NeuralNetworkRayHesthaven(), - alpha_max = 0.5, - alpha_min = 0.001, - alpha_smooth = true, - alpha_continuous = true, - alpha_amr = false, - variable = density_pressure, - network = model2d) -volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg = volume_flux, - volume_flux_fv = surface_flux) -solver = DGSEM(basis, surface_flux, volume_integral) - -coordinates_min = (-2.0, -2.0) -coordinates_max = (2.0, 2.0) -refinement_patches = () # To allow for specifying them via `trixi_include` -mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level = 6, - refinement_patches = refinement_patches, - n_cells_max = 10_000) - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - -############################################################################### -# ODE solvers, callbacks etc. - -tspan = (0.0, 12.5) -ode = semidiscretize(semi, tspan) - -summary_callback = SummaryCallback() - -analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval = analysis_interval) - -alive_callback = AliveCallback(analysis_interval = analysis_interval) - -save_solution = SaveSolutionCallback(interval = 100, - save_initial_solution = true, - save_final_solution = true, - solution_variables = cons2prim) - -stepsize_callback = StepsizeCallback(cfl = 0.9) - -callbacks = CallbackSet(summary_callback, - analysis_callback, alive_callback, - save_solution, - 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/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_amr_neuralnetwork_perssonperaire.jl b/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_amr_neuralnetwork_perssonperaire.jl deleted file mode 100644 index d2cab04223e..00000000000 --- a/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_amr_neuralnetwork_perssonperaire.jl +++ /dev/null @@ -1,134 +0,0 @@ -using Downloads: download -using Flux -using BSON: load -network = joinpath(@__DIR__, "modelnnpp-0.904-0.0005.bson") -download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelnnpp-0.904-0.0005.bson", - network) -model2d = load(network, @__MODULE__)[:model2d] - -using Random: seed! -seed!(0) - -using OrdinaryDiffEq -using Trixi - -# This elixir was one of the setups used in the following master thesis: -# - Julia Odenthal (2021) -# Shock capturing with artificial neural networks -# University of Cologne, advisors: Gregor Gassner, Michael Schlottke-Lakemper -# This motivates the particular choice of fluxes, mesh resolution etc. - -############################################################################### -# semidiscretization of the compressible Euler equations -gamma = 1.4 -equations = CompressibleEulerEquations2D(gamma) - -""" - initial_condition_kelvin_helmholtz_instability(x, t, equations::CompressibleEulerEquations2D) - -A version of the classical Kelvin-Helmholtz instability based on -https://rsaa.anu.edu.au/research/established-projects/fyris/2-d-kelvin-helmholtz-test. -""" -function initial_condition_kelvin_helmholtz_instability(x, t, - equations::CompressibleEulerEquations2D) - # change discontinuity to tanh - # typical resolution 128^2, 256^2 - # domain size is [-0.5,0.5]^2 - dens0 = 1.0 # outside density - dens1 = 2.0 # inside density - velx0 = -0.5 # outside velocity - velx1 = 0.5 # inside velocity - slope = 50 # used for tanh instead of discontinuous initial condition - # pressure equilibrium - p = 2.5 - # y velocity v2 is only white noise - v2 = 0.01 * (rand(Float64, 1)[1] - 0.5) - # density - rho = dens0 + - (dens1 - dens0) * 0.5 * - (1 + (tanh(slope * (x[2] + 0.25)) - (tanh(slope * (x[2] - 0.25)) + 1))) - # x velocity is also augmented with noise - v1 = velx0 + - (velx1 - velx0) * 0.5 * - (1 + (tanh(slope * (x[2] + 0.25)) - (tanh(slope * (x[2] - 0.25)) + 1))) + - 0.01 * (rand(Float64, 1)[1] - 0.5) - return prim2cons(SVector(rho, v1, v2, p), equations) -end -initial_condition = initial_condition_kelvin_helmholtz_instability - -surface_flux = flux_lax_friedrichs -volume_flux = flux_chandrashekar -polydeg = 3 -basis = LobattoLegendreBasis(polydeg) -indicator_sc = IndicatorNeuralNetwork(equations, basis, - indicator_type = NeuralNetworkPerssonPeraire(), - alpha_max = 0.002, - alpha_min = 0.0001, - alpha_smooth = true, - alpha_continuous = true, - alpha_amr = false, - variable = density_pressure, - network = model2d) -volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg = volume_flux, - volume_flux_fv = surface_flux) -solver = DGSEM(basis, surface_flux, volume_integral) - -coordinates_min = (-0.5, -0.5) -coordinates_max = (0.5, 0.5) -mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level = 5, - n_cells_max = 100_000) - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - -############################################################################### -# ODE solvers, callbacks etc. - -tspan = (0.0, 5.0) -ode = semidiscretize(semi, tspan) - -summary_callback = SummaryCallback() - -analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval = analysis_interval) - -alive_callback = AliveCallback(analysis_interval = analysis_interval) - -save_solution = SaveSolutionCallback(interval = 100, - save_initial_solution = true, - save_final_solution = true, - solution_variables = cons2prim) - -amr_indicator = IndicatorNeuralNetwork(semi, - indicator_type = NeuralNetworkPerssonPeraire(), - alpha_max = 1.0, - alpha_min = 0.0001, - alpha_smooth = false, - alpha_continuous = true, - alpha_amr = true, - variable = density_pressure, - network = model2d) -amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level = 4, - med_level = 6, med_threshold = 0.3, # med_level = current level - max_level = 7, max_threshold = 0.5) -amr_callback = AMRCallback(semi, amr_controller, - interval = 1, - adapt_initial_condition = true, - adapt_initial_condition_only_refine = true) - -stepsize_callback = StepsizeCallback(cfl = 1.3) - -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); -summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl b/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl deleted file mode 100644 index 39ea947f872..00000000000 --- a/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl +++ /dev/null @@ -1,126 +0,0 @@ -using Downloads: download -using Flux -using BSON: load -network = joinpath(@__DIR__, "modelnnpp-0.904-0.0005.bson") -download("https://github.com/trixi-framework/Trixi_IndicatorNeuralNetwork_networks/raw/main/networks/modelnnpp-0.904-0.0005.bson", - network) -model2d = load(network, @__MODULE__)[:model2d] - -using OrdinaryDiffEq -using Trixi - -# This elixir was one of the setups used in the following master thesis: -# - Julia Odenthal (2021) -# Shock capturing with artificial neural networks -# University of Cologne, advisors: Gregor Gassner, Michael Schlottke-Lakemper -# This motivates the particular choice of fluxes, mesh resolution etc. - -############################################################################### -# semidiscretization of the compressible Euler equations -gamma = 1.4 -equations = CompressibleEulerEquations2D(gamma) - -""" - initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations2D) - -The Sedov blast wave setup based on Flash -- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 -""" -function initial_condition_sedov_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) - - # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 - r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) - # r0 = 0.5 # = more reasonable setup - E = 1.0 - p0_inner = 3 * (equations.gamma - 1) * E / (3 * pi * r0^2) - p0_outer = 1.0e-5 # = true Sedov setup - # p0_outer = 1.0e-3 # = more reasonable setup - - # Calculate primitive variables - rho = 1.0 - 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_sedov_blast_wave - -surface_flux = flux_lax_friedrichs -volume_flux = flux_chandrashekar -basis = LobattoLegendreBasis(3) -indicator_sc = IndicatorNeuralNetwork(equations, basis, - indicator_type = NeuralNetworkPerssonPeraire(), - alpha_max = 0.5, - alpha_min = 0.001, - alpha_smooth = true, - alpha_continuous = true, - alpha_amr = false, - variable = density_pressure, - network = model2d) -volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg = volume_flux, - volume_flux_fv = surface_flux) -solver = DGSEM(basis, surface_flux, volume_integral) - -coordinates_min = (-2.0, -2.0) -coordinates_max = (2.0, 2.0) -mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level = 6, - n_cells_max = 100_000) - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) - -############################################################################### -# ODE solvers, callbacks etc. - -tspan = (0.0, 12.5) -ode = semidiscretize(semi, tspan) - -summary_callback = SummaryCallback() - -analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval = analysis_interval) - -alive_callback = AliveCallback(analysis_interval = analysis_interval) - -save_solution = SaveSolutionCallback(interval = 100, - save_initial_solution = true, - save_final_solution = true, - solution_variables = cons2prim) - -amr_indicator = IndicatorNeuralNetwork(semi, - indicator_type = NeuralNetworkPerssonPeraire(), - alpha_max = 0.5, - alpha_min = 0.001, - alpha_smooth = true, - alpha_continuous = true, - alpha_amr = true, - variable = density_pressure, - network = model2d) -amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level = 4, - max_level = 6, max_threshold = 0.22) -amr_callback = AMRCallback(semi, amr_controller, - interval = 5, - adapt_initial_condition = true, - adapt_initial_condition_only_refine = true) - -stepsize_callback = StepsizeCallback(cfl = 0.9) - -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); -summary_callback() # print the timer summary diff --git a/src/Trixi.jl b/src/Trixi.jl index 97d518d5b78..79810186d4d 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -260,9 +260,7 @@ export load_mesh, load_time, load_timestep, load_timestep!, load_dt, load_adaptive_time_integrator! export ControllerThreeLevel, ControllerThreeLevelCombined, - IndicatorLöhner, IndicatorLoehner, IndicatorMax, - IndicatorNeuralNetwork, NeuralNetworkPerssonPeraire, NeuralNetworkRayHesthaven, - NeuralNetworkCNN + IndicatorLöhner, IndicatorLoehner, IndicatorMax # TODO: TrixiShallowWater: move new limiter export PositivityPreservingLimiterZhangShu, PositivityPreservingLimiterShallowWater @@ -303,10 +301,6 @@ function __init__() end end - @require Flux="587475ba-b771-5e3f-ad9e-33799f191a9c" begin - using .Flux: params - end - # FIXME upstream. This is a hacky workaround for # https://github.com/trixi-framework/Trixi.jl/issues/628 # https://github.com/trixi-framework/Trixi.jl/issues/1185 diff --git a/src/solvers/dgsem_tree/indicators.jl b/src/solvers/dgsem_tree/indicators.jl index 4b83e9c1a9e..bb9109f2762 100644 --- a/src/solvers/dgsem_tree/indicators.jl +++ b/src/solvers/dgsem_tree/indicators.jl @@ -332,199 +332,4 @@ function Base.show(io::IO, ::MIME"text/plain", indicator::IndicatorMax) summary_box(io, "IndicatorMax", setup) end end - -""" - IndicatorNeuralNetwork - -Artificial neural network based indicator used for shock-capturing or AMR. -Depending on the indicator_type, different input values and corresponding trained networks are used. - -`indicator_type = NeuralNetworkPerssonPeraire()` -- Input: The energies in lower modes as well as nnodes(dg). - -`indicator_type = NeuralNetworkRayHesthaven()` -- 1d Input: Cell average of the cell and its neighboring cells as well as the interface values. -- 2d Input: Linear modal values of the cell and its neighboring cells. - -- Ray, Hesthaven (2018) - "An artificial neural network as a troubled-cell indicator" - [doi:10.1016/j.jcp.2018.04.029](https://doi.org/10.1016/j.jcp.2018.04.029) -- Ray, Hesthaven (2019) - "Detecting troubled-cells on two-dimensional unstructured grids using a neural network" - [doi:10.1016/j.jcp.2019.07.043](https://doi.org/10.1016/j.jcp.2019.07.043) - -`indicator_type = CNN (Only in 2d)` -- Based on convolutional neural network. -- 2d Input: Interpolation of the nodal values of the `indicator.variable` to the 4x4 LGL nodes. - -If `alpha_continuous == true` the continuous network output for troubled cells (`alpha > 0.5`) is considered. -If the cells are good (`alpha < 0.5`), `alpha` is set to `0`. -If `alpha_continuous == false`, the blending factor is set to `alpha = 0` for good cells and -`alpha = 1` for troubled cells. - -!!! warning "Experimental implementation" - This is an experimental feature and may change in future releases. - -""" -struct IndicatorNeuralNetwork{IndicatorType, RealT <: Real, Variable, Chain, Cache} <: - AbstractIndicator - indicator_type::IndicatorType - alpha_max::RealT - alpha_min::RealT - alpha_smooth::Bool - alpha_continuous::Bool - alpha_amr::Bool - variable::Variable - network::Chain - cache::Cache -end - -# this method is used when the indicator is constructed as for shock-capturing volume integrals -function IndicatorNeuralNetwork(equations::AbstractEquations, basis; - indicator_type, - alpha_max = 0.5, - alpha_min = 0.001, - alpha_smooth = true, - alpha_continuous = true, - alpha_amr = false, - variable, - network) - alpha_max, alpha_min = promote(alpha_max, alpha_min) - IndicatorType = typeof(indicator_type) - cache = create_cache(IndicatorNeuralNetwork{IndicatorType}, equations, basis) - IndicatorNeuralNetwork{IndicatorType, typeof(alpha_max), typeof(variable), - typeof(network), typeof(cache)}(indicator_type, alpha_max, - alpha_min, alpha_smooth, - alpha_continuous, alpha_amr, - variable, - network, cache) -end - -# this method is used when the indicator is constructed as for AMR -function IndicatorNeuralNetwork(semi::AbstractSemidiscretization; - indicator_type, - alpha_max = 0.5, - alpha_min = 0.001, - alpha_smooth = true, - alpha_continuous = true, - alpha_amr = true, - variable, - network) - alpha_max, alpha_min = promote(alpha_max, alpha_min) - IndicatorType = typeof(indicator_type) - cache = create_cache(IndicatorNeuralNetwork{IndicatorType}, semi) - IndicatorNeuralNetwork{IndicatorType, typeof(alpha_max), typeof(variable), - typeof(network), typeof(cache)}(indicator_type, alpha_max, - alpha_min, alpha_smooth, - alpha_continuous, alpha_amr, - variable, - network, cache) -end - -function Base.show(io::IO, indicator::IndicatorNeuralNetwork) - @nospecialize indicator # reduce precompilation time - - print(io, "IndicatorNeuralNetwork(") - print(io, indicator.indicator_type) - print(io, ", alpha_max=", indicator.alpha_max) - print(io, ", alpha_min=", indicator.alpha_min) - print(io, ", alpha_smooth=", indicator.alpha_smooth) - print(io, ", alpha_continuous=", indicator.alpha_continuous) - print(io, indicator.variable) - print(io, ")") -end - -function Base.show(io::IO, ::MIME"text/plain", indicator::IndicatorNeuralNetwork) - @nospecialize indicator # reduce precompilation time - - if get(io, :compact, false) - show(io, indicator) - else - setup = [ - "indicator type" => indicator.indicator_type, - "max. α" => indicator.alpha_max, - "min. α" => indicator.alpha_min, - "smooth α" => (indicator.alpha_smooth ? "yes" : "no"), - "continuous α" => (indicator.alpha_continuous ? "yes" : "no"), - "indicator variable" => indicator.variable, - ] - summary_box(io, "IndicatorNeuralNetwork", setup) - end -end - -# Convert probability for troubled cell to indicator value for shockcapturing/AMR -@inline function probability_to_indicator(probability_troubled_cell, alpha_continuous, - alpha_amr, - alpha_min, alpha_max) - # Initialize indicator to zero - alpha_element = zero(probability_troubled_cell) - - if alpha_continuous && !alpha_amr - # Set good cells to 0 and troubled cells to continuous value of the network prediction - if probability_troubled_cell > 0.5 - alpha_element = probability_troubled_cell - else - alpha_element = zero(probability_troubled_cell) - end - - # Take care of the case close to pure FV - if alpha_element > 1 - alpha_min - alpha_element = one(alpha_element) - end - - # Scale the probability for a troubled cell (in [0,1]) to the maximum allowed alpha - alpha_element *= alpha_max - elseif !alpha_continuous && !alpha_amr - # Set good cells to 0 and troubled cells to 1 - if probability_troubled_cell > 0.5 - alpha_element = alpha_max - else - alpha_element = zero(alpha_max) - end - elseif alpha_amr - # The entire continuous output of the neural network is used for AMR - alpha_element = probability_troubled_cell - - # Scale the probability for a troubled cell (in [0,1]) to the maximum allowed alpha - alpha_element *= alpha_max - end - - return alpha_element -end - -""" - NeuralNetworkPerssonPeraire - -Indicator type for creating an `IndicatorNeuralNetwork` indicator. - -!!! warning "Experimental implementation" - This is an experimental feature and may change in future releases. - -See also: [`IndicatorNeuralNetwork`](@ref) -""" -struct NeuralNetworkPerssonPeraire end - -""" - NeuralNetworkRayHesthaven - -Indicator type for creating an `IndicatorNeuralNetwork` indicator. - -!!! warning "Experimental implementation" - This is an experimental feature and may change in future releases. - -See also: [`IndicatorNeuralNetwork`](@ref) -""" -struct NeuralNetworkRayHesthaven end - -""" - NeuralNetworkCNN - -Indicator type for creating an `IndicatorNeuralNetwork` indicator. - -!!! warning "Experimental implementation" - This is an experimental feature and may change in future releases. - -See also: [`IndicatorNeuralNetwork`](@ref) -""" -struct NeuralNetworkCNN end end # @muladd diff --git a/src/solvers/dgsem_tree/indicators_1d.jl b/src/solvers/dgsem_tree/indicators_1d.jl index 40bfd1e98c7..4006932352e 100644 --- a/src/solvers/dgsem_tree/indicators_1d.jl +++ b/src/solvers/dgsem_tree/indicators_1d.jl @@ -305,222 +305,4 @@ function (indicator_max::IndicatorMax)(u::AbstractArray{<:Any, 3}, return alpha end - -# this method is used when the indicator is constructed as for shock-capturing volume integrals -# empty cache is default -function create_cache(::Type{<:IndicatorNeuralNetwork}, - equations::AbstractEquations{1}, basis::LobattoLegendreBasis) - return NamedTuple() -end - -# cache for NeuralNetworkPerssonPeraire-type indicator -function create_cache(::Type{IndicatorNeuralNetwork{NeuralNetworkPerssonPeraire}}, - equations::AbstractEquations{1}, basis::LobattoLegendreBasis) - alpha = Vector{real(basis)}() - alpha_tmp = similar(alpha) - A = Array{real(basis), ndims(equations)} - - prototype = A(undef, nnodes(basis)) - indicator_threaded = [similar(prototype) for _ in 1:Threads.nthreads()] - modal_threaded = [similar(prototype) for _ in 1:Threads.nthreads()] - - return (; alpha, alpha_tmp, indicator_threaded, modal_threaded) -end - -# cache for NeuralNetworkRayHesthaven-type indicator -function create_cache(::Type{IndicatorNeuralNetwork{NeuralNetworkRayHesthaven}}, - equations::AbstractEquations{1}, basis::LobattoLegendreBasis) - alpha = Vector{real(basis)}() - alpha_tmp = similar(alpha) - A = Array{real(basis), ndims(equations)} - - prototype = A(undef, nnodes(basis)) - indicator_threaded = [similar(prototype) for _ in 1:Threads.nthreads()] - neighbor_ids = Vector{Int}(undef, 2) - - return (; alpha, alpha_tmp, indicator_threaded, neighbor_ids) -end - -# this method is used when the indicator is constructed as for AMR -function create_cache(typ::Type{<:IndicatorNeuralNetwork}, - mesh, equations::AbstractEquations{1}, dg::DGSEM, cache) - create_cache(typ, equations, dg.basis) -end - -function (indicator_ann::IndicatorNeuralNetwork{NeuralNetworkPerssonPeraire})(u::AbstractArray{ - <:Any, - 3 - }, - mesh, - equations, - dg::DGSEM, - cache; - kwargs...) - @unpack indicator_type, alpha_max, alpha_min, alpha_smooth, alpha_continuous, alpha_amr, variable, network = indicator_ann - - @unpack alpha, alpha_tmp, indicator_threaded, modal_threaded = indicator_ann.cache - # TODO: Taal refactor, when to `resize!` stuff changed possibly by AMR? - # Shall we implement `resize!(semi::AbstractSemidiscretization, new_size)` - # or just `resize!` whenever we call the relevant methods as we do now? - resize!(alpha, nelements(dg, cache)) - if alpha_smooth - resize!(alpha_tmp, nelements(dg, cache)) - end - - @threaded for element in eachelement(dg, cache) - indicator = indicator_threaded[Threads.threadid()] - modal = modal_threaded[Threads.threadid()] - - # Calculate indicator variables at Gauss-Lobatto nodes - for i in eachnode(dg) - u_local = get_node_vars(u, equations, dg, i, element) - indicator[i] = indicator_ann.variable(u_local, equations) - end - - # Convert to modal representation - multiply_scalar_dimensionwise!(modal, dg.basis.inverse_vandermonde_legendre, - indicator) - - # Calculate total energies for all modes, without highest, without two highest - total_energy = zero(eltype(modal)) - for i in 1:nnodes(dg) - total_energy += modal[i]^2 - end - total_energy_clip1 = zero(eltype(modal)) - for i in 1:(nnodes(dg) - 1) - total_energy_clip1 += modal[i]^2 - end - total_energy_clip2 = zero(eltype(modal)) - for i in 1:(nnodes(dg) - 2) - total_energy_clip2 += modal[i]^2 - end - - # Calculate energy in highest modes - X1 = (total_energy - total_energy_clip1) / total_energy - X2 = (total_energy_clip1 - total_energy_clip2) / total_energy_clip1 - - # There are two versions of the network: - # The first one only takes the highest energy modes as input, the second one also the number of - # nodes. Automatically use the correct input by checking the number of inputs of the network. - if size(params(network)[1], 2) == 2 - network_input = SVector(X1, X2) - elseif size(params(network)[1], 2) == 3 - network_input = SVector(X1, X2, nnodes(dg)) - end - - # Scale input data - network_input = network_input / - max(maximum(abs, network_input), one(eltype(network_input))) - probability_troubled_cell = network(network_input)[1] - - # Compute indicator value - alpha[element] = probability_to_indicator(probability_troubled_cell, - alpha_continuous, - alpha_amr, alpha_min, alpha_max) - end - - if alpha_smooth - apply_smoothing!(mesh, alpha, alpha_tmp, dg, cache) - end - - return alpha -end - -function (indicator_ann::IndicatorNeuralNetwork{NeuralNetworkRayHesthaven})(u::AbstractArray{ - <:Any, - 3 - }, - mesh, - equations, - dg::DGSEM, - cache; - kwargs...) - @unpack indicator_type, alpha_max, alpha_min, alpha_smooth, alpha_continuous, alpha_amr, variable, network = indicator_ann - - @unpack alpha, alpha_tmp, indicator_threaded, neighbor_ids = indicator_ann.cache - # TODO: Taal refactor, when to `resize!` stuff changed possibly by AMR? - # Shall we implement `resize!(semi::AbstractSemidiscretization, new_size)` - # or just `resize!` whenever we call the relevant methods as we do now? - resize!(alpha, nelements(dg, cache)) - if alpha_smooth - resize!(alpha_tmp, nelements(dg, cache)) - end - - c2e = zeros(Int, length(mesh.tree)) - for element in eachelement(dg, cache) - c2e[cache.elements.cell_ids[element]] = element - end - - @threaded for element in eachelement(dg, cache) - indicator = indicator_threaded[Threads.threadid()] - cell_id = cache.elements.cell_ids[element] - - for direction in eachdirection(mesh.tree) - if !has_any_neighbor(mesh.tree, cell_id, direction) - neighbor_ids[direction] = element - continue - end - if has_neighbor(mesh.tree, cell_id, direction) - neighbor_cell_id = mesh.tree.neighbor_ids[direction, cell_id] - if has_children(mesh.tree, neighbor_cell_id) # Cell has small neighbor - if direction == 1 - neighbor_ids[direction] = c2e[mesh.tree.child_ids[2, - neighbor_cell_id]] - else - neighbor_ids[direction] = c2e[mesh.tree.child_ids[1, - neighbor_cell_id]] - end - else # Cell has same refinement level neighbor - neighbor_ids[direction] = c2e[neighbor_cell_id] - end - else # Cell is small and has large neighbor - parent_id = mesh.tree.parent_ids[cell_id] - neighbor_cell_id = mesh.tree.neighbor_ids[direction, parent_id] - neighbor_ids[direction] = c2e[neighbor_cell_id] - end - end - - # Calculate indicator variables at Gauss-Lobatto nodes - for i in eachnode(dg) - u_local = get_node_vars(u, equations, dg, i, element) - indicator[i] = indicator_ann.variable(u_local, equations) - end - - # Cell average and interface values of the cell - X2 = sum(indicator) / nnodes(dg) - X4 = indicator[1] - X5 = indicator[end] - - # Calculate indicator variables from left neighboring cell at Gauss-Lobatto nodes - for i in eachnode(dg) - u_local = get_node_vars(u, equations, dg, i, neighbor_ids[1]) - indicator[i] = indicator_ann.variable(u_local, equations) - end - X1 = sum(indicator) / nnodes(dg) - - # Calculate indicator variables from right neighboring cell at Gauss-Lobatto nodes - for i in eachnode(dg) - u_local = get_node_vars(u, equations, dg, i, neighbor_ids[2]) - indicator[i] = indicator_ann.variable(u_local, equations) - end - X3 = sum(indicator) / nnodes(dg) - network_input = SVector(X1, X2, X3, X4, X5) - - # Scale input data - network_input = network_input / - max(maximum(abs, network_input), one(eltype(network_input))) - probability_troubled_cell = network(network_input)[1] - - # Compute indicator value - alpha[element] = probability_to_indicator(probability_troubled_cell, - alpha_continuous, - alpha_amr, alpha_min, alpha_max) - end - - if alpha_smooth - apply_smoothing!(mesh, alpha, alpha_tmp, dg, cache) - end - - return alpha -end end # @muladd diff --git a/src/solvers/dgsem_tree/indicators_2d.jl b/src/solvers/dgsem_tree/indicators_2d.jl index da81b2a1d36..8333bb515d3 100644 --- a/src/solvers/dgsem_tree/indicators_2d.jl +++ b/src/solvers/dgsem_tree/indicators_2d.jl @@ -339,355 +339,4 @@ function (indicator_max::IndicatorMax)(u::AbstractArray{<:Any, 4}, return alpha end - -# this method is used when the indicator is constructed as for shock-capturing volume integrals -# empty cache is default -function create_cache(::Type{IndicatorNeuralNetwork}, - equations::AbstractEquations{2}, basis::LobattoLegendreBasis) - return NamedTuple() -end - -# cache for NeuralNetworkPerssonPeraire-type indicator -function create_cache(::Type{IndicatorNeuralNetwork{NeuralNetworkPerssonPeraire}}, - equations::AbstractEquations{2}, basis::LobattoLegendreBasis) - alpha = Vector{real(basis)}() - alpha_tmp = similar(alpha) - A = Array{real(basis), ndims(equations)} - - @assert nnodes(basis)>=4 "Indicator only works for nnodes >= 4 (polydeg > 2)" - - prototype = A(undef, nnodes(basis), nnodes(basis)) - indicator_threaded = [similar(prototype) for _ in 1:Threads.nthreads()] - modal_threaded = [similar(prototype) for _ in 1:Threads.nthreads()] - modal_tmp1_threaded = [similar(prototype) for _ in 1:Threads.nthreads()] - - return (; alpha, alpha_tmp, indicator_threaded, modal_threaded, modal_tmp1_threaded) -end - -# cache for NeuralNetworkRayHesthaven-type indicator -function create_cache(::Type{IndicatorNeuralNetwork{NeuralNetworkRayHesthaven}}, - equations::AbstractEquations{2}, basis::LobattoLegendreBasis) - alpha = Vector{real(basis)}() - alpha_tmp = similar(alpha) - A = Array{real(basis), ndims(equations)} - - prototype = A(undef, nnodes(basis), nnodes(basis)) - indicator_threaded = [similar(prototype) for _ in 1:Threads.nthreads()] - modal_threaded = [similar(prototype) for _ in 1:Threads.nthreads()] - modal_tmp1_threaded = [similar(prototype) for _ in 1:Threads.nthreads()] - - network_input = Vector{Float64}(undef, 15) - neighbor_ids = Array{Int64}(undef, 8) - neighbor_mean = Array{Float64}(undef, 4, 3) - - return (; alpha, alpha_tmp, indicator_threaded, modal_threaded, modal_tmp1_threaded, - network_input, neighbor_ids, neighbor_mean) -end - -# cache for NeuralNetworkCNN-type indicator -function create_cache(::Type{IndicatorNeuralNetwork{NeuralNetworkCNN}}, - equations::AbstractEquations{2}, basis::LobattoLegendreBasis) - alpha = Vector{real(basis)}() - alpha_tmp = similar(alpha) - A = Array{real(basis), ndims(equations)} - - prototype = A(undef, nnodes(basis), nnodes(basis)) - indicator_threaded = [similar(prototype) for _ in 1:Threads.nthreads()] - n_cnn = 4 - nodes, _ = gauss_lobatto_nodes_weights(nnodes(basis)) - cnn_nodes, _ = gauss_lobatto_nodes_weights(n_cnn) - vandermonde = polynomial_interpolation_matrix(nodes, cnn_nodes) - network_input = Array{Float32}(undef, n_cnn, n_cnn, 1, 1) - - return (; alpha, alpha_tmp, indicator_threaded, nodes, cnn_nodes, vandermonde, - network_input) -end - -# this method is used when the indicator is constructed as for AMR -function create_cache(typ::Type{<:IndicatorNeuralNetwork}, - mesh, equations::AbstractEquations{2}, dg::DGSEM, cache) - create_cache(typ, equations, dg.basis) -end - -function (indicator_ann::IndicatorNeuralNetwork{NeuralNetworkPerssonPeraire})(u, - mesh::TreeMesh{ - 2 - }, - equations, - dg::DGSEM, - cache; - kwargs...) - @unpack indicator_type, alpha_max, alpha_min, alpha_smooth, alpha_continuous, alpha_amr, variable, network = indicator_ann - - @unpack alpha, alpha_tmp, indicator_threaded, modal_threaded, modal_tmp1_threaded = indicator_ann.cache - # TODO: Taal refactor, when to `resize!` stuff changed possibly by AMR? - # Shall we implement `resize!(semi::AbstractSemidiscretization, new_size)` - # or just `resize!` whenever we call the relevant methods as we do now? - resize!(alpha, nelements(dg, cache)) - if alpha_smooth - resize!(alpha_tmp, nelements(dg, cache)) - end - - @threaded for element in eachelement(dg, cache) - indicator = indicator_threaded[Threads.threadid()] - modal = modal_threaded[Threads.threadid()] - modal_tmp1 = modal_tmp1_threaded[Threads.threadid()] - - # Calculate indicator variables at Gauss-Lobatto nodes - for j in eachnode(dg), i in eachnode(dg) - u_local = get_node_vars(u, equations, dg, i, j, element) - indicator[i, j] = indicator_ann.variable(u_local, equations) - end - - # Convert to modal representation - multiply_scalar_dimensionwise!(modal, dg.basis.inverse_vandermonde_legendre, - indicator, modal_tmp1) - - # Calculate total energies for all modes, without highest, without two highest - total_energy = zero(eltype(modal)) - for j in 1:nnodes(dg), i in 1:nnodes(dg) - total_energy += modal[i, j]^2 - end - total_energy_clip1 = zero(eltype(modal)) - for j in 1:(nnodes(dg) - 1), i in 1:(nnodes(dg) - 1) - total_energy_clip1 += modal[i, j]^2 - end - total_energy_clip2 = zero(eltype(modal)) - for j in 1:(nnodes(dg) - 2), i in 1:(nnodes(dg) - 2) - total_energy_clip2 += modal[i, j]^2 - end - total_energy_clip3 = zero(eltype(modal)) - for j in 1:(nnodes(dg) - 3), i in 1:(nnodes(dg) - 3) - total_energy_clip3 += modal[i, j]^2 - end - - # Calculate energy in higher modes and polynomial degree for the network input - X1 = (total_energy - total_energy_clip1) / total_energy - X2 = (total_energy_clip1 - total_energy_clip2) / total_energy_clip1 - X3 = (total_energy_clip2 - total_energy_clip3) / total_energy_clip2 - X4 = nnodes(dg) - network_input = SVector(X1, X2, X3, X4) - - # Scale input data - network_input = network_input / - max(maximum(abs, network_input), one(eltype(network_input))) - probability_troubled_cell = network(network_input)[1] - - # Compute indicator value - alpha[element] = probability_to_indicator(probability_troubled_cell, - alpha_continuous, - alpha_amr, alpha_min, alpha_max) - end - - if alpha_smooth - apply_smoothing!(mesh, alpha, alpha_tmp, dg, cache) - end - - return alpha -end - -function (indicator_ann::IndicatorNeuralNetwork{NeuralNetworkRayHesthaven})(u, - mesh::TreeMesh{ - 2 - }, - equations, - dg::DGSEM, - cache; - kwargs...) - @unpack indicator_type, alpha_max, alpha_min, alpha_smooth, alpha_continuous, alpha_amr, variable, network = indicator_ann - - @unpack alpha, alpha_tmp, indicator_threaded, modal_threaded, modal_tmp1_threaded, network_input, neighbor_ids, neighbor_mean = indicator_ann.cache #X, network_input - # TODO: Taal refactor, when to `resize!` stuff changed possibly by AMR? - # Shall we implement `resize!(semi::AbstractSemidiscretization, new_size)` - # or just `resize!` whenever we call the relevant methods as we do now? - resize!(alpha, nelements(dg, cache)) - if alpha_smooth - resize!(alpha_tmp, nelements(dg, cache)) - end - - c2e = zeros(Int, length(mesh.tree)) - for element in eachelement(dg, cache) - c2e[cache.elements.cell_ids[element]] = element - end - - X = Array{Float64}(undef, 3, nelements(dg, cache)) - - @threaded for element in eachelement(dg, cache) - indicator = indicator_threaded[Threads.threadid()] - modal = modal_threaded[Threads.threadid()] - modal_tmp1 = modal_tmp1_threaded[Threads.threadid()] - - # Calculate indicator variables at Gauss-Lobatto nodes - for j in eachnode(dg), i in eachnode(dg) - u_local = get_node_vars(u, equations, dg, i, j, element) - indicator[i, j] = indicator_ann.variable(u_local, equations) - end - - # Convert to modal representation - multiply_scalar_dimensionwise!(modal, dg.basis.inverse_vandermonde_legendre, - indicator, modal_tmp1) - # Save linear modal coefficients for the network input - X[1, element] = modal[1, 1] - X[2, element] = modal[1, 2] - X[3, element] = modal[2, 1] - end - - @threaded for element in eachelement(dg, cache) - cell_id = cache.elements.cell_ids[element] - - network_input[1] = X[1, element] - network_input[2] = X[2, element] - network_input[3] = X[3, element] - - for direction in eachdirection(mesh.tree) - if direction == 1 # -x - dir = 4 - elseif direction == 2 # +x - dir = 1 - elseif direction == 3 # -y - dir = 3 - elseif direction == 4 # +y - dir = 2 - end - - # Of no neighbor exists and current cell is not small - if !has_any_neighbor(mesh.tree, cell_id, direction) - network_input[3 * dir + 1] = X[1, element] - network_input[3 * dir + 2] = X[2, element] - network_input[3 * dir + 3] = X[3, element] - continue - end - - # Get Input data from neighbors - if has_neighbor(mesh.tree, cell_id, direction) - neighbor_cell_id = mesh.tree.neighbor_ids[direction, cell_id] - if has_children(mesh.tree, neighbor_cell_id) # Cell has small neighbor - # Mean over 4 neighbor cells - neighbor_ids[1] = mesh.tree.child_ids[1, neighbor_cell_id] - neighbor_ids[2] = mesh.tree.child_ids[2, neighbor_cell_id] - neighbor_ids[3] = mesh.tree.child_ids[3, neighbor_cell_id] - neighbor_ids[4] = mesh.tree.child_ids[4, neighbor_cell_id] - - for i in 1:4 - if has_children(mesh.tree, neighbor_ids[i]) - neighbor_ids5 = c2e[mesh.tree.child_ids[1, neighbor_ids[i]]] - neighbor_ids6 = c2e[mesh.tree.child_ids[2, neighbor_ids[i]]] - neighbor_ids7 = c2e[mesh.tree.child_ids[3, neighbor_ids[i]]] - neighbor_ids8 = c2e[mesh.tree.child_ids[4, neighbor_ids[i]]] - - neighbor_mean[i, 1] = (X[1, neighbor_ids5] + - X[1, neighbor_ids6] + - X[1, neighbor_ids7] + - X[1, neighbor_ids8]) / 4 - neighbor_mean[i, 2] = (X[2, neighbor_ids5] + - X[2, neighbor_ids6] + - X[2, neighbor_ids7] + - X[2, neighbor_ids8]) / 4 - neighbor_mean[i, 3] = (X[3, neighbor_ids5] + - X[3, neighbor_ids6] + - X[3, neighbor_ids7] + - X[3, neighbor_ids8]) / 4 - else - neighbor_id = c2e[neighbor_ids[i]] - neighbor_mean[i, 1] = X[1, neighbor_id] - neighbor_mean[i, 2] = X[2, neighbor_id] - neighbor_mean[i, 3] = X[3, neighbor_id] - end - end - network_input[3 * dir + 1] = (neighbor_mean[1, 1] + - neighbor_mean[2, 1] + - neighbor_mean[3, 1] + - neighbor_mean[4, 1]) / 4 - network_input[3 * dir + 2] = (neighbor_mean[1, 2] + - neighbor_mean[2, 2] + - neighbor_mean[3, 2] + - neighbor_mean[4, 2]) / 4 - network_input[3 * dir + 3] = (neighbor_mean[1, 3] + - neighbor_mean[2, 3] + - neighbor_mean[3, 3] + - neighbor_mean[4, 3]) / 4 - - else # Cell has same refinement level neighbor - neighbor_id = c2e[neighbor_cell_id] - network_input[3 * dir + 1] = X[1, neighbor_id] - network_input[3 * dir + 2] = X[2, neighbor_id] - network_input[3 * dir + 3] = X[3, neighbor_id] - end - else # Cell is small and has large neighbor - parent_id = mesh.tree.parent_ids[cell_id] - neighbor_id = c2e[mesh.tree.neighbor_ids[direction, parent_id]] - - network_input[3 * dir + 1] = X[1, neighbor_id] - network_input[3 * dir + 2] = X[2, neighbor_id] - network_input[3 * dir + 3] = X[3, neighbor_id] - end - end - - # Scale input data - network_input = network_input / - max(maximum(abs, network_input), one(eltype(network_input))) - probability_troubled_cell = network(network_input)[1] - - # Compute indicator value - alpha[element] = probability_to_indicator(probability_troubled_cell, - alpha_continuous, - alpha_amr, alpha_min, alpha_max) - end - - if alpha_smooth - apply_smoothing!(mesh, alpha, alpha_tmp, dg, cache) - end - - return alpha -end - -function (indicator_ann::IndicatorNeuralNetwork{NeuralNetworkCNN})(u, mesh::TreeMesh{2}, - equations, dg::DGSEM, - cache; kwargs...) - @unpack indicator_type, alpha_max, alpha_min, alpha_smooth, alpha_continuous, alpha_amr, variable, network = indicator_ann - - @unpack alpha, alpha_tmp, indicator_threaded, nodes, cnn_nodes, vandermonde, network_input = indicator_ann.cache - # TODO: Taal refactor, when to `resize!` stuff changed possibly by AMR? - # Shall we implement `resize!(semi::AbstractSemidiscretization, new_size)` - # or just `resize!` whenever we call the relevant methods as we do now? - resize!(alpha, nelements(dg, cache)) - if alpha_smooth - resize!(alpha_tmp, nelements(dg, cache)) - end - - @threaded for element in eachelement(dg, cache) - indicator = indicator_threaded[Threads.threadid()] - - # Calculate indicator variables at Gauss-Lobatto nodes - for j in eachnode(dg), i in eachnode(dg) - u_local = get_node_vars(u, equations, dg, i, j, element) - indicator[i, j] = indicator_ann.variable(u_local, equations) - end - - # Interpolate nodal data to 4x4 LGL nodes - for j in 1:4, i in 1:4 - acc = zero(eltype(indicator)) - for jj in eachnode(dg), ii in eachnode(dg) - acc += vandermonde[i, ii] * indicator[ii, jj] * vandermonde[j, jj] - end - network_input[i, j, 1, 1] = acc - end - - # Scale input data - network_input = network_input / - max(maximum(abs, network_input), one(eltype(network_input))) - probability_troubled_cell = network(network_input)[1] - - # Compute indicator value - alpha[element] = probability_to_indicator(probability_troubled_cell, - alpha_continuous, - alpha_amr, alpha_min, alpha_max) - end - - if alpha_smooth - apply_smoothing!(mesh, alpha, alpha_tmp, dg, cache) - end - - return alpha -end end # @muladd diff --git a/test/Project.toml b/test/Project.toml index 83b431e269b..fcb96b9e48f 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,9 +1,7 @@ [deps] Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" -BSON = "fbb218c0-5317-5bc6-957e-2ee96dd4b1f0" CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" -Flux = "587475ba-b771-5e3f-ad9e-33799f191a9c" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195" @@ -15,10 +13,8 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] Aqua = "0.7" -BSON = "0.3.3" CairoMakie = "0.6, 0.7, 0.8, 0.9, 0.10" Downloads = "1" -Flux = "0.13.15, 0.14" ForwardDiff = "0.10" LinearAlgebra = "1" MPI = "0.20" diff --git a/test/test_tree_1d_euler.jl b/test/test_tree_1d_euler.jl index 62afc5baee3..6cd7998ab02 100644 --- a/test/test_tree_1d_euler.jl +++ b/test/test_tree_1d_euler.jl @@ -393,26 +393,6 @@ end @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 end end - -@trixi_testset "elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl"), - l2=[0.21814833203212694, 0.2818328665444332, 0.5528379124720818], - linf=[1.5548653877320868, 1.4474018998129738, 2.071919577393772], - maxiters=30) -end - -@trixi_testset "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl"), - l2=[0.22054468879127423, 0.2828269190680846, 0.5542369885642424], - linf=[ - 1.5623359741479623, - 1.4290121654488288, - 2.1040405133123072, - ], - maxiters=30) -end end end # module diff --git a/test/test_tree_2d_euler.jl b/test/test_tree_2d_euler.jl index 93490f8ae09..4a1dc42772d 100644 --- a/test/test_tree_2d_euler.jl +++ b/test/test_tree_2d_euler.jl @@ -260,89 +260,6 @@ end end end -@trixi_testset "elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_euler_blast_wave_neuralnetwork_perssonperaire.jl"), - l2=[ - 0.4758794741390833, - 0.21045415565179362, - 0.21045325630191866, - 0.7022517958549878, - ], - linf=[ - 1.710832148442441, - 0.9711663578827681, - 0.9703787873632452, - 2.9619758810532653, - ], - initial_refinement_level=4, - maxiters=50) -end - -@trixi_testset "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl"), - l2=[ - 0.472445774440313, - 0.2090782039442978, - 0.20885558673697927, - 0.700569533591275, - ], - linf=[ - 1.7066492792835155, - 0.9856122336679919, - 0.9784316656930644, - 2.9372978989672873, - ], - initial_refinement_level=4, - maxiters=50) -end - -@trixi_testset "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl with mortars" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_euler_blast_wave_neuralnetwork_rayhesthaven.jl"), - l2=[ - 0.016486406327766923, - 0.03097329879894433, - 0.03101012918167401, - 0.15157175775429868, - ], - linf=[ - 0.27688647744873407, - 0.5653724536715139, - 0.565695523611447, - 2.513047611639946, - ], - refinement_patches=((type = "box", - coordinates_min = (-0.25, -0.25), - coordinates_max = (0.25, 0.25)), - (type = "box", - coordinates_min = (-0.125, -0.125), - coordinates_max = (0.125, 0.125))), - initial_refinement_level=4, - maxiters=5) -end - -@trixi_testset "elixir_euler_blast_wave_neuralnetwork_cnn.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_euler_blast_wave_neuralnetwork_cnn.jl"), - l2=[ - 0.4795795496408325, - 0.2125148972465021, - 0.21311260934645868, - 0.7033388737692883, - ], - linf=[ - 1.8295385992182336, - 0.9687795218482794, - 0.9616033072376108, - 2.9513245978047133, - ], - initial_refinement_level=4, - maxiters=50, - rtol=1.0e-7) -end - @trixi_testset "elixir_euler_blast_wave_pure_fv.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_blast_wave_pure_fv.jl"), l2=[ @@ -451,25 +368,6 @@ end end end -@trixi_testset "elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_euler_sedov_blast_wave_neuralnetwork_perssonperaire.jl"), - l2=[ - 0.0845430093623868, - 0.09271459184623232, - 0.09271459184623232, - 0.4377291875101709, - ], - linf=[ - 1.3608553480069898, - 1.6822884847136004, - 1.6822884847135997, - 4.2201475428867035, - ], - maxiters=30, - coverage_override=(maxiters = 6,)) -end - @trixi_testset "elixir_euler_positivity.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_positivity.jl"), l2=[ @@ -627,18 +525,6 @@ end end end -@trixi_testset "elixir_euler_kelvin_helmholtz_instability_amr_neuralnetwork_perssonperaire.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_euler_kelvin_helmholtz_instability_amr_neuralnetwork_perssonperaire.jl"), - # This stuff is experimental and annoying to test. In the future, we plan - # to move it to another repository. Thus, we save developer time right now - # and do not run these tests anymore. - # l2 = [0.0009823702998067061, 0.004943231496200673, 0.0048604522073091815, 0.00496983530893294], - # linf = [0.00855717053383187, 0.02087422420794427, 0.017121993783086185, 0.02720703869972585], - maxiters=30, - coverage_override=(maxiters = 2,)) -end - @trixi_testset "elixir_euler_colliding_flow.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_colliding_flow.jl"), l2=[ diff --git a/test/test_unit.jl b/test/test_unit.jl index 29390161ebe..609100793ba 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -427,14 +427,6 @@ end indicator_max = IndicatorMax("variable", (; cache = nothing)) @test_nowarn show(stdout, indicator_max) - - equations = CompressibleEulerEquations2D(1.4) - basis = LobattoLegendreBasis(3) - indicator_neuralnetwork = IndicatorNeuralNetwork(equations, basis, - indicator_type = NeuralNetworkPerssonPeraire(), - variable = density, - network = nothing) - @test_nowarn show(stdout, indicator_neuralnetwork) end @timed_testset "LBM 2D constructor" begin From 6eb0b5b4c9e803722abe297cff899595ded72da3 Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Wed, 8 Nov 2023 12:23:07 +0100 Subject: [PATCH 168/263] Make parabolic terms nonexperimental (#1714) * Make parabolic terms non-experimental * Make NSE a separate item * Add MPI to supported features * Mention that parabolic terms are now officially supported in NEWS.md Co-authored-by: Hendrik Ranocha --- NEWS.md | 3 +++ README.md | 4 +++- docs/src/index.md | 4 +++- docs/src/overview.md | 3 +-- src/equations/compressible_navier_stokes.jl | 6 ------ src/equations/compressible_navier_stokes_1d.jl | 3 --- src/equations/compressible_navier_stokes_2d.jl | 3 --- src/equations/compressible_navier_stokes_3d.jl | 3 --- 8 files changed, 10 insertions(+), 19 deletions(-) diff --git a/NEWS.md b/NEWS.md index fc23e74d1db..c037d47db81 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,6 +10,9 @@ for human readability. #### Changed +- Parabolic diffusion terms are now officially supported and not marked as experimental + anymore. + #### Deprecated #### Removed diff --git a/README.md b/README.md index 1d52089ae3e..c531ab4d1a4 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@

-**Trixi.jl** is a numerical simulation framework for hyperbolic conservation +**Trixi.jl** is a numerical simulation framework for conservation laws written in [Julia](https://julialang.org). A key objective for the framework is to be useful to both scientists and students. Therefore, next to having an extensible design with a fast implementation, Trixi.jl is @@ -46,6 +46,7 @@ installation and postprocessing procedures. Its features include: * Periodic and weakly-enforced boundary conditions * Multiple governing equations: * Compressible Euler equations + * Compressible Navier-Stokes equations * Magnetohydrodynamics (MHD) equations * Multi-component compressible Euler and MHD equations * Linearized Euler and acoustic perturbation equations @@ -56,6 +57,7 @@ installation and postprocessing procedures. Its features include: * Multi-physics simulations * [Self-gravitating gas dynamics](https://github.com/trixi-framework/paper-self-gravitating-gas-dynamics) * Shared-memory parallelization via multithreading +* Multi-node parallelization via MPI * Visualization and postprocessing of the results * In-situ and a posteriori visualization with [Plots.jl](https://github.com/JuliaPlots/Plots.jl) * Interactive visualization with [Makie.jl](https://makie.juliaplots.org/) diff --git a/docs/src/index.md b/docs/src/index.md index fd923348928..fbb4b36b224 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -12,7 +12,7 @@ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.3996439.svg)](https://doi.org/10.5281/zenodo.3996439) [**Trixi.jl**](https://github.com/trixi-framework/Trixi.jl) -is a numerical simulation framework for hyperbolic conservation +is a numerical simulation framework for conservation laws written in [Julia](https://julialang.org). A key objective for the framework is to be useful to both scientists and students. Therefore, next to having an extensible design with a fast implementation, Trixi.jl is @@ -40,6 +40,7 @@ installation and postprocessing procedures. Its features include: * Periodic and weakly-enforced boundary conditions * Multiple governing equations: * Compressible Euler equations + * Compressible Navier-Stokes equations * Magnetohydrodynamics (MHD) equations * Multi-component compressible Euler and MHD equations * Linearized Euler and acoustic perturbation equations @@ -50,6 +51,7 @@ installation and postprocessing procedures. Its features include: * Multi-physics simulations * [Self-gravitating gas dynamics](https://github.com/trixi-framework/paper-self-gravitating-gas-dynamics) * Shared-memory parallelization via multithreading +* Multi-node parallelization via MPI * Visualization and postprocessing of the results * In-situ and a posteriori visualization with [Plots.jl](https://github.com/JuliaPlots/Plots.jl) * Interactive visualization with [Makie.jl](https://makie.juliaplots.org/) diff --git a/docs/src/overview.md b/docs/src/overview.md index 9cd11a5df93..9bc523ca297 100644 --- a/docs/src/overview.md +++ b/docs/src/overview.md @@ -60,10 +60,9 @@ different features on different mesh types. | Flux differencing | ✅ | ✅ | ✅ | ✅ | ✅ | [`VolumeIntegralFluxDifferencing`](@ref) | Shock capturing | ✅ | ✅ | ✅ | ✅ | ❌ | [`VolumeIntegralShockCapturingHG`](@ref) | Nonconservative equations | ✅ | ✅ | ✅ | ✅ | ✅ | e.g., GLM MHD or shallow water equations -| Parabolic termsᵇ | ✅ | ✅ | ❌ | ✅ | ✅ | e.g., [`CompressibleNavierStokesDiffusion2D`](@ref) +| Parabolic terms | ✅ | ✅ | ❌ | ✅ | ✅ | e.g., [`CompressibleNavierStokesDiffusion2D`](@ref) ᵃ: quad = quadrilateral, hex = hexahedron -ᵇ: Parabolic terms do not currently support adaptivity. ## Time integration methods diff --git a/src/equations/compressible_navier_stokes.jl b/src/equations/compressible_navier_stokes.jl index af7897d4586..3059771197c 100644 --- a/src/equations/compressible_navier_stokes.jl +++ b/src/equations/compressible_navier_stokes.jl @@ -6,9 +6,6 @@ Creates a wall-type boundary conditions for the compressible Navier-Stokes equat The fields `boundary_condition_velocity` and `boundary_condition_heat_flux` are intended to be boundary condition types such as the `NoSlip` velocity boundary condition and the `Adiabatic` or `Isothermal` heat boundary condition. - -!!! warning "Experimental feature" - This is an experimental feature and may change in future releases. """ struct BoundaryConditionNavierStokesWall{V, H} boundary_condition_velocity::V @@ -52,9 +49,6 @@ struct Adiabatic{F} end """ -!!! warning "Experimental code" - This code is experimental and may be changed or removed in any future release. - `GradientVariablesPrimitive` and `GradientVariablesEntropy` are gradient variable type parameters for `CompressibleNavierStokesDiffusion1D`. By default, the gradient variables are set to be `GradientVariablesPrimitive`. Specifying `GradientVariablesEntropy` instead uses the entropy variable diff --git a/src/equations/compressible_navier_stokes_1d.jl b/src/equations/compressible_navier_stokes_1d.jl index 74d672ce7ae..f5ae598f389 100644 --- a/src/equations/compressible_navier_stokes_1d.jl +++ b/src/equations/compressible_navier_stokes_1d.jl @@ -79,9 +79,6 @@ where ```math w_2 = \frac{\rho v1}{p},\, w_3 = -\frac{\rho}{p} ``` - -!!! warning "Experimental code" - This code is experimental and may be changed or removed in any future release. """ struct CompressibleNavierStokesDiffusion1D{GradientVariables, RealT <: Real, E <: AbstractCompressibleEulerEquations{1} diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 80857999017..cc0c580bf10 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -79,9 +79,6 @@ where ```math w_2 = \frac{\rho v_1}{p},\, w_3 = \frac{\rho v_2}{p},\, w_4 = -\frac{\rho}{p} ``` - -!!! warning "Experimental code" - This code is experimental and may be changed or removed in any future release. """ struct CompressibleNavierStokesDiffusion2D{GradientVariables, RealT <: Real, E <: AbstractCompressibleEulerEquations{2} diff --git a/src/equations/compressible_navier_stokes_3d.jl b/src/equations/compressible_navier_stokes_3d.jl index de2cad99ea8..e9ad3eb6aad 100644 --- a/src/equations/compressible_navier_stokes_3d.jl +++ b/src/equations/compressible_navier_stokes_3d.jl @@ -79,9 +79,6 @@ where ```math w_2 = \frac{\rho v_1}{p},\, w_3 = \frac{\rho v_2}{p},\, w_4 = \frac{\rho v_3}{p},\, w_5 = -\frac{\rho}{p} ``` - -!!! warning "Experimental code" - This code is experimental and may be changed or removed in any future release. """ struct CompressibleNavierStokesDiffusion3D{GradientVariables, RealT <: Real, E <: AbstractCompressibleEulerEquations{3} From b860e651895276c261fbe5d19f44531c1e498fc3 Mon Sep 17 00:00:00 2001 From: Jesse Chan <1156048+jlchan@users.noreply.github.com> Date: Wed, 8 Nov 2023 09:16:58 -0600 Subject: [PATCH 169/263] Deprecate some `DGMultiMesh` constructors (#1709) * remove previously deprecated functions * fix typo in NEWS.md about deprecation vs removal * fix literate tutorial * removing other deprecation * format * Revert "fix typo in NEWS.md about deprecation vs removal" This reverts commit 6b03020a8c881a86550484891a0f53bca018e447. --- docs/literate/src/files/DGMulti_1.jl | 2 +- src/solvers/dgmulti/types.jl | 12 ------------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/docs/literate/src/files/DGMulti_1.jl b/docs/literate/src/files/DGMulti_1.jl index 5ef577e8eeb..6c9a5aea936 100644 --- a/docs/literate/src/files/DGMulti_1.jl +++ b/docs/literate/src/files/DGMulti_1.jl @@ -168,7 +168,7 @@ meshIO = StartUpDG.triangulate_domain(StartUpDG.RectangularDomainWithHole()); # The pre-defined Triangulate geometry in StartUpDG has integer boundary tags. With [`DGMultiMesh`](@ref) # we assign boundary faces based on these integer boundary tags and create a mesh compatible with Trixi.jl. -mesh = DGMultiMesh(meshIO, dg, Dict(:outer_boundary=>1, :inner_boundary=>2)) +mesh = DGMultiMesh(dg, meshIO, Dict(:outer_boundary=>1, :inner_boundary=>2)) #- boundary_condition_convergence_test = BoundaryConditionDirichlet(initial_condition) boundary_conditions = (; :outer_boundary => boundary_condition_convergence_test, diff --git a/src/solvers/dgmulti/types.jl b/src/solvers/dgmulti/types.jl index fe6510856b0..ae1eed7fd52 100644 --- a/src/solvers/dgmulti/types.jl +++ b/src/solvers/dgmulti/types.jl @@ -433,15 +433,3 @@ function LinearAlgebra.mul!(b_in, A_kronecker::SimpleKronecker{3}, x_in) return nothing end end # @muladd - -# TODO: deprecations introduced in Trixi.jl v0.6 -@deprecate DGMultiMesh(dg::DGMulti{NDIMS}; cells_per_dimension, kwargs...) where {NDIMS} DGMultiMesh(dg, - cells_per_dimension; - kwargs...) - -# TODO: deprecations introduced in Trixi.jl v0.5 -@deprecate DGMultiMesh(vertex_coordinates, EToV, dg::DGMulti{NDIMS}; - kwargs...) where {NDIMS} DGMultiMesh(dg, vertex_coordinates, EToV; - kwargs...) -@deprecate DGMultiMesh(triangulateIO, dg::DGMulti{2, Tri}, boundary_dict::Dict{Symbol, Int}; - kwargs...) DGMultiMesh(dg, triangulateIO, boundary_dict; kwargs...) From 07ef07c4c6a7c930b9e6b29e09fe1d1e79d37ffc Mon Sep 17 00:00:00 2001 From: Jesse Chan <1156048+jlchan@users.noreply.github.com> Date: Wed, 8 Nov 2023 09:17:35 -0600 Subject: [PATCH 170/263] add gradient variable type parameter to `AbstractEquationsParabolic` (#1409) * add gradient variable type parameter * fix parabolic literate test * remove trailing comment * remove unnecessary abstract type * move gradient variable structs * formatting * fix dropped changes * try to fix doc tests * fixing navier stokes 1D * formatting * remove duplicate GradientVariablesPrimitive/Entropy definition * update news --- NEWS.md | 1 + docs/literate/src/files/adding_new_parabolic_terms.jl | 11 +++++++++-- src/Trixi.jl | 2 +- src/equations/compressible_navier_stokes_1d.jl | 2 +- src/equations/compressible_navier_stokes_2d.jl | 2 +- src/equations/compressible_navier_stokes_3d.jl | 2 +- src/equations/equations.jl | 2 +- src/equations/equations_parabolic.jl | 11 ++++++++--- 8 files changed, 23 insertions(+), 10 deletions(-) diff --git a/NEWS.md b/NEWS.md index c037d47db81..5d258fa65bb 100644 --- a/NEWS.md +++ b/NEWS.md @@ -35,6 +35,7 @@ for human readability. - Implementation of the quasi-1D shallow water equations - Subcell positivity limiting support for conservative variables in 2D for `TreeMesh` - AMR for hyperbolic-parabolic equations on 2D/3D `TreeMesh` +- Added `GradientVariables` type parameter to `AbstractEquationsParabolic` #### Changed diff --git a/docs/literate/src/files/adding_new_parabolic_terms.jl b/docs/literate/src/files/adding_new_parabolic_terms.jl index f5c2b815f33..209ef62c988 100644 --- a/docs/literate/src/files/adding_new_parabolic_terms.jl +++ b/docs/literate/src/files/adding_new_parabolic_terms.jl @@ -18,8 +18,15 @@ equations_hyperbolic = LinearScalarAdvectionEquation2D(advection_velocity); # `ConstantAnisotropicDiffusion2D` has a field for `equations_hyperbolic`. It is useful to have # information about the hyperbolic system available to the parabolic part so that we can reuse # functions defined for hyperbolic equations (such as `varnames`). - -struct ConstantAnisotropicDiffusion2D{E, T} <: Trixi.AbstractEquationsParabolic{2, 1} +# +# The abstract type `Trixi.AbstractEquationsParabolic` has three parameters: `NDIMS` (the spatial dimension, +# e.g., 1D, 2D, or 3D), `NVARS` (the number of variables), and `GradientVariable`, which we set as +# `GradientVariablesConservative`. This indicates that the gradient should be taken with respect to the +# conservative variables (e.g., the same variables used in `equations_hyperbolic`). Users can also take +# the gradient with respect to a different set of variables; see, for example, the implementation of +# [`CompressibleNavierStokesDiffusion2D`](@ref), which can utilize either "primitive" or "entropy" variables. + +struct ConstantAnisotropicDiffusion2D{E, T} <: Trixi.AbstractEquationsParabolic{2, 1, GradientVariablesConservative} diffusivity::T equations_hyperbolic::E end diff --git a/src/Trixi.jl b/src/Trixi.jl index 79810186d4d..2d58a6b72a4 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -157,7 +157,7 @@ export LaplaceDiffusion1D, LaplaceDiffusion2D, LaplaceDiffusion3D, CompressibleNavierStokesDiffusion1D, CompressibleNavierStokesDiffusion2D, CompressibleNavierStokesDiffusion3D -export GradientVariablesPrimitive, GradientVariablesEntropy +export GradientVariablesConservative, GradientVariablesPrimitive, GradientVariablesEntropy export flux, flux_central, flux_lax_friedrichs, flux_hll, flux_hllc, flux_hlle, flux_godunov, diff --git a/src/equations/compressible_navier_stokes_1d.jl b/src/equations/compressible_navier_stokes_1d.jl index f5ae598f389..73436c99b7c 100644 --- a/src/equations/compressible_navier_stokes_1d.jl +++ b/src/equations/compressible_navier_stokes_1d.jl @@ -83,7 +83,7 @@ w_2 = \frac{\rho v1}{p},\, w_3 = -\frac{\rho}{p} struct CompressibleNavierStokesDiffusion1D{GradientVariables, RealT <: Real, E <: AbstractCompressibleEulerEquations{1} } <: - AbstractCompressibleNavierStokesDiffusion{1, 3} + AbstractCompressibleNavierStokesDiffusion{1, 3, GradientVariables} # TODO: parabolic # 1) For now save gamma and inv(gamma-1) again, but could potentially reuse them from the Euler equations # 2) Add NGRADS as a type parameter here and in AbstractEquationsParabolic, add `ngradients(...)` accessor function diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index cc0c580bf10..ad0db001872 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -83,7 +83,7 @@ w_2 = \frac{\rho v_1}{p},\, w_3 = \frac{\rho v_2}{p},\, w_4 = -\frac{\rho}{p} struct CompressibleNavierStokesDiffusion2D{GradientVariables, RealT <: Real, E <: AbstractCompressibleEulerEquations{2} } <: - AbstractCompressibleNavierStokesDiffusion{2, 4} + AbstractCompressibleNavierStokesDiffusion{2, 4, GradientVariables} # TODO: parabolic # 1) For now save gamma and inv(gamma-1) again, but could potentially reuse them from the Euler equations # 2) Add NGRADS as a type parameter here and in AbstractEquationsParabolic, add `ngradients(...)` accessor function diff --git a/src/equations/compressible_navier_stokes_3d.jl b/src/equations/compressible_navier_stokes_3d.jl index e9ad3eb6aad..c6a55983b53 100644 --- a/src/equations/compressible_navier_stokes_3d.jl +++ b/src/equations/compressible_navier_stokes_3d.jl @@ -83,7 +83,7 @@ w_2 = \frac{\rho v_1}{p},\, w_3 = \frac{\rho v_2}{p},\, w_4 = \frac{\rho v_3}{p} struct CompressibleNavierStokesDiffusion3D{GradientVariables, RealT <: Real, E <: AbstractCompressibleEulerEquations{3} } <: - AbstractCompressibleNavierStokesDiffusion{3, 5} + AbstractCompressibleNavierStokesDiffusion{3, 5, GradientVariables} # TODO: parabolic # 1) For now save gamma and inv(gamma-1) again, but could potentially reuse them from the Euler equations # 2) Add NGRADS as a type parameter here and in AbstractEquationsParabolic, add `ngradients(...)` accessor function diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 0e77b92e045..78b1b829b06 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -479,6 +479,6 @@ abstract type AbstractLinearizedEulerEquations{NDIMS, NVARS} <: AbstractEquations{NDIMS, NVARS} end include("linearized_euler_2d.jl") -abstract type AbstractEquationsParabolic{NDIMS, NVARS} <: +abstract type AbstractEquationsParabolic{NDIMS, NVARS, GradientVariables} <: AbstractEquations{NDIMS, NVARS} end end # @muladd diff --git a/src/equations/equations_parabolic.jl b/src/equations/equations_parabolic.jl index 47a76174cb1..a063e9f2758 100644 --- a/src/equations/equations_parabolic.jl +++ b/src/equations/equations_parabolic.jl @@ -2,16 +2,21 @@ # specialize this function to compute gradients e.g., of primitive variables instead of conservative gradient_variable_transformation(::AbstractEquationsParabolic) = cons2cons +# By default, the gradients are taken with respect to the conservative variables. +# this is reflected by the type parameter `GradientVariablesConservative` in the abstract +# type `AbstractEquationsParabolic{NDIMS, NVARS, GradientVariablesConservative}`. +struct GradientVariablesConservative end + # Linear scalar diffusion for use in linear scalar advection-diffusion problems abstract type AbstractLaplaceDiffusion{NDIMS, NVARS} <: - AbstractEquationsParabolic{NDIMS, NVARS} end + AbstractEquationsParabolic{NDIMS, NVARS, GradientVariablesConservative} end include("laplace_diffusion_1d.jl") include("laplace_diffusion_2d.jl") include("laplace_diffusion_3d.jl") # Compressible Navier-Stokes equations -abstract type AbstractCompressibleNavierStokesDiffusion{NDIMS, NVARS} <: - AbstractEquationsParabolic{NDIMS, NVARS} end +abstract type AbstractCompressibleNavierStokesDiffusion{NDIMS, NVARS, GradientVariables} <: + AbstractEquationsParabolic{NDIMS, NVARS, GradientVariables} end include("compressible_navier_stokes.jl") include("compressible_navier_stokes_1d.jl") include("compressible_navier_stokes_2d.jl") From b75cab9859e592f1d1d1514e7e8628e7621b3e3c Mon Sep 17 00:00:00 2001 From: Patrick Ersing <114223904+patrickersing@users.noreply.github.com> Date: Fri, 10 Nov 2023 07:54:56 +0100 Subject: [PATCH 171/263] Add new non-conservative flux for standard and two-layer shallow water equations (#1508) * Add flux_nonconservative_ersing_etal * Change formulation of flux_nonconservative_ersing * remove old fluxes (fjordholm, wintermeyer) * Update tests for new flux_ersing_etal * Add flux_nonconservative_ersing for standard SWE * Edit comments, change flux in elixir * fix well-balanced test * Update src/Trixi.jl Change order of exporting statements Co-authored-by: Andrew Winters * fix indentation * fix indentation II * Update src/equations/shallow_water_2d.jl Co-authored-by: Andrew Winters * fix energy total function * Apply formatter * add docstring references * remove flux_nonconservative_fjordholm_etal * apply formatter * Format examples --------- Co-authored-by: Andrew Winters Co-authored-by: Hendrik Ranocha --- ...lixir_shallowwater_twolayer_convergence.jl | 4 +- .../elixir_shallowwater_twolayer_dam_break.jl | 4 +- ...xir_shallowwater_twolayer_well_balanced.jl | 4 +- ...lixir_shallowwater_twolayer_convergence.jl | 4 +- ...xir_shallowwater_twolayer_well_balanced.jl | 4 +- ...lixir_shallowwater_twolayer_convergence.jl | 4 +- .../elixir_shallowwater_twolayer_dam_break.jl | 4 +- ...xir_shallowwater_twolayer_well_balanced.jl | 4 +- src/Trixi.jl | 3 +- src/equations/shallow_water_1d.jl | 38 ++ src/equations/shallow_water_2d.jl | 68 +++ src/equations/shallow_water_two_layer_1d.jl | 293 +++++-------- src/equations/shallow_water_two_layer_2d.jl | 391 +++++------------- test/test_tree_1d_shallowwater.jl | 50 +++ test/test_tree_1d_shallowwater_twolayer.jl | 138 +++---- test/test_tree_2d_shallowwater.jl | 58 +++ test/test_tree_2d_shallowwater_twolayer.jl | 162 +++----- test/test_unstructured_2d.jl | 94 ++++- 18 files changed, 630 insertions(+), 697 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_convergence.jl b/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_convergence.jl index fc76b4f034b..e6a01849852 100644 --- a/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_convergence.jl +++ b/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_convergence.jl @@ -13,9 +13,9 @@ initial_condition = initial_condition_convergence_test ############################################################################### # Get the DG approximation space -volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_ersing_etal) solver = DGSEM(polydeg = 3, - surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal), + surface_flux = (flux_wintermeyer_etal, flux_nonconservative_ersing_etal), volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_dam_break.jl b/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_dam_break.jl index b2e6a81401b..03b93754d0f 100644 --- a/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_dam_break.jl +++ b/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_dam_break.jl @@ -36,9 +36,9 @@ initial_condition = initial_condition_dam_break ############################################################################### # Get the DG approximation space -volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_ersing_etal) solver = DGSEM(polydeg = 3, - surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal), + surface_flux = (flux_wintermeyer_etal, flux_nonconservative_ersing_etal), volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### diff --git a/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl b/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl index 7236f1697d0..098e3aaf601 100644 --- a/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl +++ b/examples/tree_1d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl @@ -35,9 +35,9 @@ initial_condition = initial_condition_fjordholm_well_balanced ############################################################################### # Get the DG approximation space -volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_ersing_etal) solver = DGSEM(polydeg = 3, - surface_flux = (flux_es_fjordholm_etal, flux_nonconservative_fjordholm_etal), + surface_flux = (flux_es_ersing_etal, flux_nonconservative_ersing_etal), volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### diff --git a/examples/tree_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl b/examples/tree_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl index f7c8ab3a249..790916e4467 100644 --- a/examples/tree_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl @@ -13,9 +13,9 @@ initial_condition = initial_condition_convergence_test ############################################################################### # Get the DG approximation space -volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_ersing_etal) solver = DGSEM(polydeg = 3, - surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal), + surface_flux = (flux_wintermeyer_etal, flux_nonconservative_ersing_etal), volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) ############################################################################### diff --git a/examples/tree_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl b/examples/tree_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl index 1495e6d8568..264c26390fe 100644 --- a/examples/tree_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl +++ b/examples/tree_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl @@ -31,8 +31,8 @@ initial_condition = initial_condition_well_balanced ############################################################################### # Get the DG approximation space -volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -surface_flux = (flux_es_fjordholm_etal, flux_nonconservative_fjordholm_etal) +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_ersing_etal) +surface_flux = (flux_es_ersing_etal, flux_nonconservative_ersing_etal) solver = DGSEM(polydeg = 3, surface_flux = surface_flux, volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) diff --git a/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl index 2cab68b1cb5..0b86095663a 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl @@ -15,8 +15,8 @@ initial_condition = initial_condition_convergence_test ############################################################################### # Get the DG approximation space -volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal) +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_ersing_etal) +surface_flux = (flux_wintermeyer_etal, flux_nonconservative_ersing_etal) solver = DGSEM(polydeg = 6, surface_flux = surface_flux, volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) diff --git a/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_dam_break.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_dam_break.jl index 9d70e9287cf..4ad5f7e3201 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_dam_break.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_dam_break.jl @@ -41,8 +41,8 @@ boundary_condition_constant = BoundaryConditionDirichlet(initial_condition_dam_b ############################################################################### # Get the DG approximation space -volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -surface_flux = (flux_fjordholm_etal, flux_nonconservative_fjordholm_etal) +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_ersing_etal) +surface_flux = (flux_wintermeyer_etal, flux_nonconservative_ersing_etal) solver = DGSEM(polydeg = 6, surface_flux = surface_flux, volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) diff --git a/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl index 35b027c3a81..6a727df2502 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl @@ -33,8 +33,8 @@ initial_condition = initial_condition_well_balanced ############################################################################### # Get the DG approximation space -volume_flux = (flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal) -surface_flux = (flux_es_fjordholm_etal, flux_nonconservative_fjordholm_etal) +volume_flux = (flux_wintermeyer_etal, flux_nonconservative_ersing_etal) +surface_flux = (flux_es_ersing_etal, flux_nonconservative_ersing_etal) solver = DGSEM(polydeg = 6, surface_flux = surface_flux, volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) diff --git a/src/Trixi.jl b/src/Trixi.jl index 2d58a6b72a4..b8110cf5bdd 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -164,8 +164,9 @@ export flux, flux_central, flux_lax_friedrichs, flux_hll, flux_hllc, flux_hlle, flux_chandrashekar, flux_ranocha, flux_derigs_etal, flux_hindenlang_gassner, flux_nonconservative_powell, flux_nonconservative_powell_local_symmetric, flux_kennedy_gruber, flux_shima_etal, flux_ec, - flux_fjordholm_etal, flux_nonconservative_fjordholm_etal, flux_es_fjordholm_etal, + flux_fjordholm_etal, flux_nonconservative_fjordholm_etal, flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal, + flux_es_ersing_etal, flux_nonconservative_ersing_etal, flux_chan_etal, flux_nonconservative_chan_etal, flux_winters_etal, hydrostatic_reconstruction_audusse_etal, flux_nonconservative_audusse_etal, # TODO: TrixiShallowWater: move anything with "chen_noelle" to new file diff --git a/src/equations/shallow_water_1d.jl b/src/equations/shallow_water_1d.jl index 32782d5478c..25ce0fa79fe 100644 --- a/src/equations/shallow_water_1d.jl +++ b/src/equations/shallow_water_1d.jl @@ -380,6 +380,44 @@ Further details on the hydrostatic reconstruction and its motivation can be foun z) 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 + + z = zero(eltype(u_ll)) + + # Bottom gradient nonconservative term: (0, g h b_x, 0) + f = SVector(z, equations.gravity * h_ll * b_jump, z) + + return f +end + """ flux_fjordholm_etal(u_ll, u_rr, orientation, equations::ShallowWaterEquations1D) diff --git a/src/equations/shallow_water_2d.jl b/src/equations/shallow_water_2d.jl index a81fddeed49..e75c92a27d0 100644 --- a/src/equations/shallow_water_2d.jl +++ b/src/equations/shallow_water_2d.jl @@ -702,6 +702,74 @@ 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 + + z = zero(eltype(u_ll)) + # Bottom gradient nonconservative term: (0, g h b_x, g h b_y, 0) + if orientation == 1 + f = SVector(z, equations.gravity * h_ll * b_jump, z, z) + else # orientation == 2 + f = SVector(z, z, equations.gravity * h_ll * b_jump, z) + 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(zero(eltype(u_ll)), + normal_direction_average[1] * equations.gravity * h_ll * b_jump, + normal_direction_average[2] * equations.gravity * h_ll * b_jump, + zero(eltype(u_ll))) +end + """ flux_fjordholm_etal(u_ll, u_rr, orientation_or_normal_direction, equations::ShallowWaterEquations2D) diff --git a/src/equations/shallow_water_two_layer_1d.jl b/src/equations/shallow_water_two_layer_1d.jl index 4b64481cca3..42ff393593e 100644 --- a/src/equations/shallow_water_two_layer_1d.jl +++ b/src/equations/shallow_water_two_layer_1d.jl @@ -87,15 +87,15 @@ end have_nonconservative_terms(::ShallowWaterTwoLayerEquations1D) = True() function varnames(::typeof(cons2cons), ::ShallowWaterTwoLayerEquations1D) - ("h_upper", "h_v1_upper", - "h_lower", "h_v1_lower", "b") + ("h_upper", "h_v_upper", + "h_lower", "h_v_lower", "b") end # Note, we use the total water height, H_lower = h_upper + h_lower + b, and first layer total height # H_upper = h_upper + b as the first primitive variable for easier visualization and setting initial # conditions function varnames(::typeof(cons2prim), ::ShallowWaterTwoLayerEquations1D) - ("H_upper", "v1_upper", - "H_lower", "v1_lower", "b") + ("H_upper", "v_upper", + "H_lower", "v_lower", "b") end # Set initial conditions at physical location `x` for time `t` @@ -113,11 +113,11 @@ function initial_condition_convergence_test(x, t, H_lower = 2.0 + 0.1 * sin(ω * x[1] + t) H_upper = 4.0 + 0.1 * cos(ω * x[1] + t) - v1_lower = 1.0 - v1_upper = 0.9 + v_lower = 1.0 + v_upper = 0.9 b = 1.0 + 0.1 * cos(2.0 * ω * x[1]) - return prim2cons(SVector(H_upper, v1_upper, H_lower, v1_lower, b), equations) + return prim2cons(SVector(H_upper, v_upper, H_lower, v_lower, b), equations) end """ @@ -196,165 +196,77 @@ end # Note, the bottom topography has no flux @inline function flux(u, orientation::Integer, equations::ShallowWaterTwoLayerEquations1D) - h_upper, h_v1_upper, h_lower, h_v2_lower, _ = u + h_upper, h_v_upper, h_lower, h_v_lower, _ = u # Calculate velocities - v1_upper, v1_lower = velocity(u, equations) + v_upper, v_lower = velocity(u, equations) # Calculate pressure - p1 = 0.5 * equations.gravity * h_upper^2 - p2 = 0.5 * equations.gravity * h_lower^2 + p_upper = 0.5 * equations.gravity * h_upper^2 + p_lower = 0.5 * equations.gravity * h_lower^2 - f1 = h_v1_upper - f2 = h_v1_upper * v1_upper + p1 - f3 = h_v2_lower - f4 = h_v2_lower * v1_lower + p2 + f1 = h_v_upper + f2 = h_v_upper * v_upper + p_upper + f3 = h_v_lower + f4 = h_v_lower * v_lower + p_lower return SVector(f1, f2, f3, f4, zero(eltype(u))) end """ - flux_nonconservative_wintermeyer_etal(u_ll, u_rr, orientation::Integer, - equations::ShallowWaterTwoLayerEquations1D) + flux_nonconservative_ersing_etal(u_ll, u_rr, orientation::Integer, + equations::ShallowWaterTwoLayerEquations1D) !!! warning "Experimental code" This numerical flux is experimental and may change in any future release. -Non-symmetric two-point volume flux discretizing the nonconservative (source) term -that contains the gradient of the bottom topography [`ShallowWaterTwoLayerEquations2D`](@ref) and an -additional term that couples the momentum of both layers. This is a slightly modified version -to account for the additional source term compared to the standard SWE described in the paper. +Non-symmetric path-conservative two-point volume flux discretizing the nonconservative (source) term +that contains the gradient of the bottom topography [`ShallowWaterTwoLayerEquations1D`](@ref) and an +additional term that couples the momentum of both layers. -Further details are available in the paper: -- 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) +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_wintermeyer_etal(u_ll, u_rr, - orientation::Integer, - equations::ShallowWaterTwoLayerEquations1D) +@inline function flux_nonconservative_ersing_etal(u_ll, u_rr, + orientation::Integer, + equations::ShallowWaterTwoLayerEquations1D) # Pull the necessary left and right state information h_upper_ll, h_lower_ll = waterheight(u_ll, equations) h_upper_rr, h_lower_rr = waterheight(u_rr, equations) b_rr = u_rr[5] + b_ll = u_ll[5] - z = zero(eltype(u_ll)) - - # Bottom gradient nonconservative term: (0, g*h_upper*(b+h_lower)_x, - # 0, g*h_lower*(b+r*h_upper)_x, 0) - f = SVector(z, - equations.gravity * h_upper_ll * (b_rr + h_lower_rr), - z, - equations.gravity * h_lower_ll * (b_rr + equations.r * h_upper_rr), - z) - return f -end - -""" - flux_nonconservative_fjordholm_etal(u_ll, u_rr, orientation::Integer, - equations::ShallowWaterTwoLayerEquations1D) - -!!! warning "Experimental code" - This numerical flux is experimental and may change in any future release. - -Non-symmetric two-point surface flux discretizing the nonconservative (source) term that contains -the gradients of the bottom topography and an additional term that couples the momentum of both -layers [`ShallowWaterTwoLayerEquations2D`](@ref). - -Further details are available in the paper: -- Ulrik Skre Fjordholm (2012) - Energy conservative and stable schemes for the two-layer shallow water equations. - [DOI: 10.1142/9789814417099_0039](https://doi.org/10.1142/9789814417099_0039) -It should be noted that the equations are ordered differently and the -designation of the upper and lower layer has been changed which leads to a slightly different -formulation. -""" -@inline function flux_nonconservative_fjordholm_etal(u_ll, u_rr, - orientation::Integer, - equations::ShallowWaterTwoLayerEquations1D) - # Pull the necessary left and right state information - h_upper_ll, _, h_lower_ll, _, b_ll = u_ll - h_upper_rr, _, h_lower_rr, _, b_rr = u_rr - - # Create average and jump values - h_upper_average = 0.5 * (h_upper_ll + h_upper_rr) - h_lower_average = 0.5 * (h_lower_ll + h_lower_rr) - h_upper_jump = h_upper_rr - h_upper_ll - h_lower_jump = h_lower_rr - h_lower_ll - b_jump = b_rr - b_ll - - # Assign variables for constants for better readability - g = equations.gravity + # Calculate jumps + h_upper_jump = (h_upper_rr - h_upper_ll) + h_lower_jump = (h_lower_rr - h_lower_ll) + b_jump = (b_rr - b_ll) z = zero(eltype(u_ll)) # Bottom gradient nonconservative term: (0, g*h_upper*(b+h_lower)_x, # 0, g*h_lower*(b+r*h_upper)_x, 0) f = SVector(z, - g * h_upper_ll * (b_ll + h_lower_ll) + - g * h_upper_average * (b_jump + h_lower_jump), + equations.gravity * h_upper_ll * (b_jump + h_lower_jump), z, - g * h_lower_ll * (b_ll + equations.r * h_upper_ll) + - g * h_lower_average * (b_jump + - equations.r * h_upper_jump), + equations.gravity * h_lower_ll * (b_jump + equations.r * h_upper_jump), z) return f end -""" - flux_fjordholm_etal(u_ll, u_rr, orientation, - equations::ShallowWaterTwoLayerEquations1D) - -Total energy conservative (mathematical entropy for shallow water equations). When the bottom -topography is nonzero this should only be used as a surface flux otherwise the scheme will not be -well-balanced. For well-balancedness in the volume flux use [`flux_wintermeyer_etal`](@ref). - -Details are available in Eq. (4.1) in the paper: -- Ulrik S. Fjordholm, Siddhartha Mishra and Eitan Tadmor (2011) - Well-balanced and energy stable schemes for the shallow water equations with discontinuous - topography [DOI: 10.1016/j.jcp.2011.03.042](https://doi.org/10.1016/j.jcp.2011.03.042) -and the application to two layers is shown in the paper: -- Ulrik Skre Fjordholm (2012) - Energy conservative and stable schemes for the two-layer shallow water equations. - [DOI: 10.1142/9789814417099_0039](https://doi.org/10.1142/9789814417099_0039) -It should be noted that the equations are ordered differently and the -designation of the upper and lower layer has been changed which leads to a slightly different -formulation. -""" -@inline function flux_fjordholm_etal(u_ll, u_rr, - orientation::Integer, - equations::ShallowWaterTwoLayerEquations1D) - # Unpack left and right state - h_upper_ll, h_lower_ll = waterheight(u_ll, equations) - v1_ll, v2_ll = velocity(u_ll, equations) - h_upper_rr, h_lower_rr = waterheight(u_rr, equations) - v1_rr, v2_rr = velocity(u_rr, equations) - - # Average each factor of products in flux - h_upper_avg = 0.5 * (h_upper_ll + h_upper_rr) - h_lower_avg = 0.5 * (h_lower_ll + h_lower_rr) - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - p1_avg = 0.25 * equations.gravity * (h_upper_ll^2 + h_upper_rr^2) - p2_avg = 0.25 * equations.gravity * (h_lower_ll^2 + h_lower_rr^2) - - # Calculate fluxes - f1 = h_upper_avg * v1_avg - f2 = f1 * v1_avg + p1_avg - f3 = h_lower_avg * v2_avg - f4 = f3 * v2_avg + p2_avg - - return SVector(f1, f2, f3, f4, zero(eltype(u_ll))) -end - """ flux_wintermeyer_etal(u_ll, u_rr, orientation, equations::ShallowWaterTwoLayerEquations1D) Total energy conservative (mathematical entropy for two-layer 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). To obtain the flux for the -two-layer shallow water equations the flux that is described in the paper for the normal shallow +When the bottom topography is nonzero this scheme will be well-balanced when used with the +nonconservative [`flux_nonconservative_ersing_etal`](@ref). To obtain the flux for the +two-layer shallow water equations the flux that is described in the paper for the normal shallow water equations is used within each layer. Further details are available in Theorem 1 of the paper: @@ -367,51 +279,48 @@ Further details are available in Theorem 1 of the paper: orientation::Integer, equations::ShallowWaterTwoLayerEquations1D) # Unpack left and right state - h_upper_ll, h_v1_upper_ll, h_lower_ll, h_v2_lower_ll, _ = u_ll - h_upper_rr, h_v1_upper_rr, h_lower_rr, h_v2_lower_rr, _ = u_rr + h_upper_ll, h_v_upper_ll, h_lower_ll, h_v_lower_ll, _ = u_ll + h_upper_rr, h_v_upper_rr, h_lower_rr, h_v_lower_rr, _ = u_rr # Get the velocities on either side - v1_ll, v2_ll = velocity(u_ll, equations) - v1_rr, v2_rr = velocity(u_rr, equations) + v_upper_ll, v_lower_ll = velocity(u_ll, equations) + v_upper_rr, v_lower_rr = velocity(u_rr, equations) # Average each factor of products in flux - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - p1_avg = 0.5 * equations.gravity * h_upper_ll * h_upper_rr - p2_avg = 0.5 * equations.gravity * h_lower_ll * h_lower_rr + v_upper_avg = 0.5 * (v_upper_ll + v_upper_rr) + v_lower_avg = 0.5 * (v_lower_ll + v_lower_rr) + p_upper_avg = 0.5 * equations.gravity * h_upper_ll * h_upper_rr + p_lower_avg = 0.5 * equations.gravity * h_lower_ll * h_lower_rr # Calculate fluxes - f1 = 0.5 * (h_v1_upper_ll + h_v1_upper_rr) - f2 = f1 * v1_avg + p1_avg - f3 = 0.5 * (h_v2_lower_ll + h_v2_lower_rr) - f4 = f3 * v2_avg + p2_avg + f1 = 0.5 * (h_v_upper_ll + h_v_upper_rr) + f2 = f1 * v_upper_avg + p_upper_avg + f3 = 0.5 * (h_v_lower_ll + h_v_lower_rr) + f4 = f3 * v_lower_avg + p_lower_avg return SVector(f1, f2, f3, f4, zero(eltype(u_ll))) end """ - flux_es_fjordholm_etal(u_ll, u_rr, orientation, - equations::ShallowWaterTwoLayerEquations1D) - -Entropy stable surface flux for the two-layer shallow water equations. Uses the entropy -conservative [`flux_fjordholm_etal`](@ref) and adds a Lax-Friedrichs type dissipation dependent on the jump -of entropy variables. - -Further details are available in the paper: -- Ulrik Skre Fjordholm (2012) - Energy conservative and stable schemes for the two-layer shallow water equations. - [DOI: 10.1142/9789814417099_0039](https://doi.org/10.1142/9789814417099_0039) -It should be noted that the equations are ordered differently and the -designation of the upper and lower layer has been changed which leads to a slightly different -formulation. + flux_es_ersing_etal(u_ll, u_rr, orientation_or_normal_direction, + equations::ShallowWaterTwoLayerEquations1D) +Entropy stable surface flux for the two-layer shallow water equations. Uses the entropy conservative +[`flux_wintermeyer_etal`](@ref) and adds a Lax-Friedrichs type dissipation dependent on the jump of +entropy variables. + +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_es_fjordholm_etal(u_ll, u_rr, - orientation::Integer, - equations::ShallowWaterTwoLayerEquations1D) +@inline function flux_es_ersing_etal(u_ll, u_rr, + orientation::Integer, + equations::ShallowWaterTwoLayerEquations1D) # Compute entropy conservative flux but without the bottom topography - f_ec = flux_fjordholm_etal(u_ll, u_rr, - orientation, - equations) + f_ec = flux_wintermeyer_etal(u_ll, u_rr, + orientation, + equations) # Get maximum signal velocity λ = max_abs_speed_naive(u_ll, u_rr, orientation, equations) @@ -474,12 +383,12 @@ end orientation::Integer, equations::ShallowWaterTwoLayerEquations1D) # Unpack left and right state - h_upper_ll, h_v1_upper_ll, h_lower_ll, h_v2_lower_ll, _ = u_ll - h_upper_rr, h_v1_upper_rr, h_lower_rr, h_v2_lower_rr, _ = u_rr + h_upper_ll, h_v_upper_ll, h_lower_ll, h_v_lower_ll, _ = u_ll + h_upper_rr, h_v_upper_rr, h_lower_rr, h_v_lower_rr, _ = u_rr # Get the averaged velocity - v_m_ll = (h_v1_upper_ll + h_v2_lower_ll) / (h_upper_ll + h_lower_ll) - v_m_rr = (h_v1_upper_rr + h_v2_lower_rr) / (h_upper_rr + h_lower_rr) + v_m_ll = (h_v_upper_ll + h_v_lower_ll) / (h_upper_ll + h_lower_ll) + v_m_rr = (h_v_upper_rr + h_v_lower_rr) / (h_upper_rr + h_lower_rr) # Calculate the wave celerity on the left and right h_upper_ll, h_lower_ll = waterheight(u_ll, equations) @@ -503,10 +412,10 @@ end # Absolute speed of the barotropic mode @inline function max_abs_speeds(u, equations::ShallowWaterTwoLayerEquations1D) - h_upper, h_v1_upper, h_lower, h_v2_lower, _ = u + h_upper, h_v_upper, h_lower, h_v_lower, _ = u # Calculate averaged velocity of both layers - v_m = (h_v1_upper + h_v2_lower) / (h_upper + h_lower) + v_m = (h_v_upper + h_v_lower) / (h_upper + h_lower) c = sqrt(equations.gravity * (h_upper + h_lower)) return (abs(v_m) + c) @@ -514,11 +423,11 @@ end # Helper function to extract the velocity vector from the conservative variables @inline function velocity(u, equations::ShallowWaterTwoLayerEquations1D) - h_upper, h_v1_upper, h_lower, h_v2_lower, _ = u + h_upper, h_v_upper, h_lower, h_v_lower, _ = u - v1_upper = h_v1_upper / h_upper - v1_lower = h_v2_lower / h_lower - return SVector(v1_upper, v1_lower) + v_upper = h_v_upper / h_upper + v_lower = h_v_lower / h_lower + return SVector(v_upper, v_lower) end # Convert conservative variables to primitive @@ -527,8 +436,8 @@ end H_lower = h_lower + b H_upper = h_lower + h_upper + b - v1_upper, v1_lower = velocity(u, equations) - return SVector(H_upper, v1_upper, H_lower, v1_lower, b) + v_upper, v_lower = velocity(u, equations) + return SVector(H_upper, v_upper, H_lower, v_lower, b) end # Convert conservative variables to entropy variables @@ -536,26 +445,26 @@ end # bottom topography values for convenience @inline function cons2entropy(u, equations::ShallowWaterTwoLayerEquations1D) h_upper, _, h_lower, _, b = u - v1_upper, v1_lower = velocity(u, equations) - - w1 = equations.rho_upper * - (equations.gravity * (h_upper + h_lower + b) - 0.5 * v1_upper^2) - w2 = equations.rho_upper * v1_upper - w3 = equations.rho_lower * - (equations.gravity * (equations.r * h_upper + h_lower + b) - 0.5 * v1_lower^2) - w4 = equations.rho_lower * v1_lower + v_upper, v_lower = velocity(u, equations) + + w1 = (equations.rho_upper * + (equations.gravity * (h_upper + h_lower + b) - 0.5 * v_upper^2)) + w2 = equations.rho_upper * v_upper + w3 = (equations.rho_lower * + (equations.gravity * (equations.r * h_upper + h_lower + b) - 0.5 * v_lower^2)) + w4 = equations.rho_lower * v_lower return SVector(w1, w2, w3, w4, b) end # Convert primitive to conservative variables @inline function prim2cons(prim, equations::ShallowWaterTwoLayerEquations1D) - H_upper, v1_upper, H_lower, v1_lower, b = prim + H_upper, v_upper, H_lower, v_lower, b = prim h_lower = H_lower - b h_upper = H_upper - h_lower - b - h_v1_upper = h_upper * v1_upper - h_v2_lower = h_lower * v1_lower - return SVector(h_upper, h_v1_upper, h_lower, h_v2_lower, b) + h_v_upper = h_upper * v_upper + h_v_lower = h_lower * v_lower + return SVector(h_upper, h_v_upper, h_lower, h_v_lower, b) end @inline function waterheight(u, equations::ShallowWaterTwoLayerEquations1D) @@ -569,23 +478,23 @@ end # Calculate total energy for a conservative state `cons` @inline function energy_total(cons, equations::ShallowWaterTwoLayerEquations1D) - h_upper, h_v1_upper, h_lower, h_v2_lower, b = cons + h_upper, h_v_upper, h_lower, h_v_lower, b = cons # Set new variables for better readability g = equations.gravity rho_upper = equations.rho_upper rho_lower = equations.rho_lower - e = (0.5 * rho_upper * (h_v1_upper^2 / h_upper + g * h_upper^2) + - 0.5 * rho_lower * (h_v2_lower^2 / h_lower + g * h_lower^2) + + e = (0.5 * rho_upper * (h_v_upper^2 / h_upper + g * h_upper^2) + + 0.5 * rho_lower * (h_v_lower^2 / h_lower + g * h_lower^2) + g * rho_lower * h_lower * b + g * rho_upper * h_upper * (h_lower + b)) return e end # Calculate kinetic energy for a conservative state `cons` @inline function energy_kinetic(u, equations::ShallowWaterTwoLayerEquations1D) - h_upper, h_v1_upper, h_lower, h_v2_lower, _ = u - return 0.5 * equations.rho_upper * h_v1_upper^2 / h_upper + - 0.5 * equations.rho_lower * h_v2_lower^2 / h_lower + h_upper, h_v_upper, h_lower, h_v_lower, _ = u + return (0.5 * equations.rho_upper * h_v_upper^2 / h_upper + + 0.5 * equations.rho_lower * h_v_lower^2 / h_lower) end # Calculate potential energy for a conservative state `cons` diff --git a/src/equations/shallow_water_two_layer_2d.jl b/src/equations/shallow_water_two_layer_2d.jl index 87249e91948..a31d881f2ef 100644 --- a/src/equations/shallow_water_two_layer_2d.jl +++ b/src/equations/shallow_water_two_layer_2d.jl @@ -271,24 +271,24 @@ end v1_upper, v2_upper, v1_lower, v2_lower = velocity(u, equations) # Calculate pressure - p1 = 0.5 * equations.gravity * h_upper^2 - p2 = 0.5 * equations.gravity * h_lower^2 + p_upper = 0.5 * equations.gravity * h_upper^2 + p_lower = 0.5 * equations.gravity * h_lower^2 # Calculate fluxes depending on orientation if orientation == 1 f1 = h_v1_upper - f2 = h_v1_upper * v1_upper + p1 + f2 = h_v1_upper * v1_upper + p_upper f3 = h_v1_upper * v2_upper f4 = h_v1_lower - f5 = h_v1_lower * v1_lower + p2 + f5 = h_v1_lower * v1_lower + p_lower f6 = h_v1_lower * v2_lower else f1 = h_v2_upper f2 = h_v2_upper * v1_upper - f3 = h_v2_upper * v2_upper + p1 + f3 = h_v2_upper * v2_upper + p_upper f4 = h_v2_lower f5 = h_v2_lower * v1_lower - f6 = h_v2_lower * v2_lower + p2 + f6 = h_v2_lower * v2_lower + p_lower end return SVector(f1, f2, f3, f4, f5, f6, zero(eltype(u))) end @@ -305,44 +305,57 @@ end h_v_upper_normal = h_upper * v_normal_upper h_v_lower_normal = h_lower * v_normal_lower - p1 = 0.5 * equations.gravity * h_upper^2 - p2 = 0.5 * equations.gravity * h_lower^2 + p_upper = 0.5 * equations.gravity * h_upper^2 + p_lower = 0.5 * equations.gravity * h_lower^2 f1 = h_v_upper_normal - f2 = h_v_upper_normal * v1_upper + p1 * normal_direction[1] - f3 = h_v_upper_normal * v2_upper + p1 * normal_direction[2] + f2 = h_v_upper_normal * v1_upper + p_upper * normal_direction[1] + f3 = h_v_upper_normal * v2_upper + p_upper * normal_direction[2] f4 = h_v_lower_normal - f5 = h_v_lower_normal * v1_lower + p2 * normal_direction[1] - f6 = h_v_lower_normal * v2_lower + p2 * normal_direction[2] + f5 = h_v_lower_normal * v1_lower + p_lower * normal_direction[1] + f6 = h_v_lower_normal * v2_lower + p_lower * normal_direction[2] return SVector(f1, f2, f3, f4, f5, f6, zero(eltype(u))) end """ - flux_nonconservative_wintermeyer_etal(u_ll, u_rr, orientation::Integer, - equations::ShallowWaterTwoLayerEquations2D) + flux_nonconservative_ersing_etal(u_ll, u_rr, orientation::Integer, + equations::ShallowWaterTwoLayerEquations2D) + flux_nonconservative_ersing_etal(u_ll, u_rr, + normal_direction_ll::AbstractVector, + normal_direction_average::AbstractVector, + equations::ShallowWaterTwoLayerEquations2D) !!! warning "Experimental code" - This numerical flux is experimental and may change in any future release. + This numerical flux is experimental and may change in any future release. -Non-symmetric two-point volume flux discretizing the nonconservative (source) term +Non-symmetric path-conservative two-point volume flux discretizing the nonconservative (source) term that contains the gradient of the bottom topography [`ShallowWaterTwoLayerEquations2D`](@ref) and an -additional term that couples the momentum of both layers. This is a slightly modified version -to account for the additional source term compared to the standard SWE described in the paper. +additional term that couples the momentum of both layers. -Further details are available in the paper: -- 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) +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_wintermeyer_etal(u_ll, u_rr, - orientation::Integer, - equations::ShallowWaterTwoLayerEquations2D) +@inline function flux_nonconservative_ersing_etal(u_ll, u_rr, + orientation::Integer, + equations::ShallowWaterTwoLayerEquations2D) # Pull the necessary left and right state information h_upper_ll, h_lower_ll = waterheight(u_ll, equations) h_upper_rr, h_lower_rr = waterheight(u_rr, equations) b_rr = u_rr[7] + b_ll = u_ll[7] + + # Calculate jumps + h_upper_jump = (h_upper_rr - h_upper_ll) + h_lower_jump = (h_lower_rr - h_lower_ll) + b_jump = (b_rr - b_ll) z = zero(eltype(u_ll)) @@ -351,268 +364,64 @@ Further details are available in the paper: # g*h_lower*(b + r*h_upper)_y, 0) if orientation == 1 f = SVector(z, - equations.gravity * h_upper_ll * (b_rr + h_lower_rr), + equations.gravity * h_upper_ll * (b_jump + h_lower_jump), z, z, - equations.gravity * h_lower_ll * (b_rr + equations.r * h_upper_rr), + equations.gravity * h_lower_ll * + (b_jump + equations.r * h_upper_jump), z, z) else # orientation == 2 f = SVector(z, z, - equations.gravity * h_upper_ll * (b_rr + h_lower_rr), + equations.gravity * h_upper_ll * (b_jump + h_lower_jump), z, z, - equations.gravity * h_lower_ll * (b_rr + equations.r * h_upper_rr), + equations.gravity * h_lower_ll * + (b_jump + equations.r * h_upper_jump), z) end return f end -@inline function flux_nonconservative_wintermeyer_etal(u_ll, u_rr, - normal_direction_ll::AbstractVector, - normal_direction_average::AbstractVector, - equations::ShallowWaterTwoLayerEquations2D) +@inline function flux_nonconservative_ersing_etal(u_ll, u_rr, + normal_direction_ll::AbstractVector, + normal_direction_average::AbstractVector, + equations::ShallowWaterTwoLayerEquations2D) # Pull the necessary left and right state information h_upper_ll, h_lower_ll = waterheight(u_ll, equations) h_upper_rr, h_lower_rr = waterheight(u_rr, equations) b_rr = u_rr[7] + b_ll = u_ll[7] + + # Calculate jumps + h_upper_jump = (h_upper_rr - h_upper_ll) + h_lower_jump = (h_lower_rr - h_lower_ll) + 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(zero(eltype(u_ll)), normal_direction_average[1] * equations.gravity * h_upper_ll * - (b_rr + h_lower_rr), + (b_jump + h_lower_jump), normal_direction_average[2] * equations.gravity * h_upper_ll * - (b_rr + h_lower_rr), + (b_jump + h_lower_jump), zero(eltype(u_ll)), normal_direction_average[1] * equations.gravity * h_lower_ll * - (b_rr + - equations.r * h_upper_rr), + (b_jump + equations.r * h_upper_jump), normal_direction_average[2] * equations.gravity * h_lower_ll * - (b_rr + - equations.r * h_upper_rr), + (b_jump + equations.r * h_upper_jump), zero(eltype(u_ll))) end -""" - flux_nonconservative_fjordholm_etal(u_ll, u_rr, orientation::Integer, - equations::ShallowWaterTwoLayerEquations2D) - -!!! warning "Experimental code" - This numerical flux is experimental and may change in any future release. - -Non-symmetric two-point surface flux discretizing the nonconservative (source) term that contains -the gradients of the bottom topography and an additional term that couples the momentum of both -layers [`ShallowWaterTwoLayerEquations2D`](@ref). - -Further details are available in the paper: -- Ulrik Skre Fjordholm (2012) - Energy conservative and stable schemes for the two-layer shallow water equations. - [DOI: 10.1142/9789814417099_0039](https://doi.org/10.1142/9789814417099_0039) -It should be noted that the equations are ordered differently and the -designation of the upper and lower layer has been changed which leads to a slightly different -formulation. -""" -@inline function flux_nonconservative_fjordholm_etal(u_ll, u_rr, - orientation::Integer, - equations::ShallowWaterTwoLayerEquations2D) - # Pull the necessary left and right state information - h_upper_ll, h_v1_upper_ll, h_v2_upper_ll, h_lower_ll, h_v1_lower_ll, h_v2_lower_ll, b_ll = u_ll - h_upper_rr, h_v1_upper_rr, h_v2_upper_rr, h_lower_rr, h_v1_lower_rr, h_v2_lower_rr, b_rr = u_rr - - # Create average and jump values - h_upper_average = 0.5 * (h_upper_ll + h_upper_rr) - h_lower_average = 0.5 * (h_lower_ll + h_lower_rr) - h_upper_jump = h_upper_rr - h_upper_ll - h_lower_jump = h_lower_rr - h_lower_ll - b_jump = b_rr - b_ll - - # Assign variables for constants for better readability - g = equations.gravity - - # Bottom gradient nonconservative term: (0, g*h_upper*(b+h_lower)_x, g*h_upper*(b+h_lower)_y, 0, - # g*h_lower*(b+r*h_upper)_x, g*h_lower*(b+r*h_upper)_x, 0) - - # 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 - z = zero(eltype(u_ll)) - if orientation == 1 - f = SVector(z, - g * h_upper_ll * (b_ll + h_lower_ll) + - g * h_upper_average * (b_jump + h_lower_jump), - z, z, - g * h_lower_ll * (b_ll + equations.r * h_upper_ll) + - g * h_lower_average * (b_jump + - equations.r * h_upper_jump), - z, z) - else # orientation == 2 - f = SVector(z, z, - g * h_upper_ll * (b_ll + h_lower_ll) + - g * h_upper_average * (b_jump + h_lower_jump), - z, z, - g * h_lower_ll * (b_ll + equations.r * h_upper_ll) + - g * h_lower_average * (b_jump + - equations.r * h_upper_jump), - z) - end - - return f -end - -@inline function flux_nonconservative_fjordholm_etal(u_ll, u_rr, - normal_direction_ll::AbstractVector, - normal_direction_average::AbstractVector, - equations::ShallowWaterTwoLayerEquations2D) - # Pull the necessary left and right state information - h_upper_ll, h_v1_upper_ll, h_v2_upper_ll, h_lower_ll, h_v1_lower_ll, h_v2_lower_ll, b_ll = u_ll - h_upper_rr, h_v1_upper_rr, h_v2_upper_rr, h_lower_rr, h_v1_lower_rr, h_v2_lower_rr, b_rr = u_rr - - # Create average and jump values - h_upper_average = 0.5 * (h_upper_ll + h_upper_rr) - h_lower_average = 0.5 * (h_lower_ll + h_lower_rr) - h_upper_jump = h_upper_rr - h_upper_ll - h_lower_jump = h_lower_rr - h_lower_ll - b_jump = b_rr - b_ll - - # 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_upper_ll * - (b_ll + h_lower_ll) - f3 = normal_direction_average[2] * equations.gravity * h_upper_ll * - (b_ll + h_lower_ll) - f5 = normal_direction_average[1] * equations.gravity * h_lower_ll * - (b_ll + equations.r * h_upper_ll) - f6 = normal_direction_average[2] * equations.gravity * h_lower_ll * - (b_ll + equations.r * h_upper_ll) - # (ii) True surface part that uses `normal_direction_ll`, `h_average` and `b_jump` - # to handle discontinuous bathymetry - f2 += normal_direction_ll[1] * equations.gravity * h_upper_average * - (b_jump + h_lower_jump) - f3 += normal_direction_ll[2] * equations.gravity * h_upper_average * - (b_jump + h_lower_jump) - f5 += normal_direction_ll[1] * equations.gravity * h_lower_average * - (b_jump + - equations.r * h_upper_jump) - f6 += normal_direction_ll[2] * equations.gravity * h_lower_average * - (b_jump + - equations.r * h_upper_jump) - - # Continuity equations do not have a nonconservative flux - f1 = f4 = zero(eltype(u_ll)) - - return SVector(f1, f2, f3, f4, f5, f6, zero(eltype(u_ll))) -end - -""" - flux_fjordholm_etal(u_ll, u_rr, orientation, - equations::ShallowWaterTwoLayerEquations2D) - -Total energy conservative (mathematical entropy for two-layer shallow water equations). When the -bottom topography is nonzero this should only be used as a surface flux otherwise the scheme will -not be well-balanced. For well-balancedness in the volume flux use [`flux_wintermeyer_etal`](@ref). - -Details are available in Eq. (4.1) in the paper: -- Ulrik S. Fjordholm, Siddhartha Mishra and Eitan Tadmor (2011) - Well-balanced and energy stable schemes for the shallow water equations with discontinuous - topography [DOI: 10.1016/j.jcp.2011.03.042](https://doi.org/10.1016/j.jcp.2011.03.042) -and the application to two layers is shown in the paper: -- Ulrik Skre Fjordholm (2012) - Energy conservative and stable schemes for the two-layer shallow water equations. - [DOI: 10.1142/9789814417099_0039](https://doi.org/10.1142/9789814417099_0039) -It should be noted that the equations are ordered differently and the -designation of the upper and lower layer has been changed which leads to a slightly different -formulation. -""" -@inline function flux_fjordholm_etal(u_ll, u_rr, - orientation::Integer, - equations::ShallowWaterTwoLayerEquations2D) - # Unpack left and right state - h_upper_ll, h_lower_ll = waterheight(u_ll, equations) - v1_upper_ll, v2_upper_ll, v1_lower_ll, v2_lower_ll = velocity(u_ll, equations) - h_upper_rr, h_lower_rr = waterheight(u_rr, equations) - v1_upper_rr, v2_upper_rr, v1_lower_rr, v2_lower_rr = velocity(u_rr, equations) - - # Average each factor of products in flux - h_upper_avg = 0.5 * (h_upper_ll + h_upper_rr) - h_lower_avg = 0.5 * (h_lower_ll + h_lower_rr) - v1_upper_avg = 0.5 * (v1_upper_ll + v1_upper_rr) - v1_lower_avg = 0.5 * (v1_lower_ll + v1_lower_rr) - v2_upper_avg = 0.5 * (v2_upper_ll + v2_upper_rr) - v2_lower_avg = 0.5 * (v2_lower_ll + v2_lower_rr) - p1_avg = 0.25 * equations.gravity * (h_upper_ll^2 + h_upper_rr^2) - p2_avg = 0.25 * equations.gravity * (h_lower_ll^2 + h_lower_rr^2) - - # Calculate fluxes depending on orientation - if orientation == 1 - f1 = h_upper_avg * v1_upper_avg - f2 = f1 * v1_upper_avg + p1_avg - f3 = f1 * v2_upper_avg - f4 = h_lower_avg * v1_lower_avg - f5 = f4 * v1_lower_avg + p2_avg - f6 = f4 * v2_lower_avg - else - f1 = h_upper_avg * v2_upper_avg - f2 = f1 * v1_upper_avg - f3 = f1 * v2_upper_avg + p1_avg - f4 = h_lower_avg * v2_lower_avg - f5 = f4 * v1_lower_avg - f6 = f4 * v2_lower_avg + p2_avg - end - - return SVector(f1, f2, f3, f4, f5, f6, zero(eltype(u_ll))) -end - -@inline function flux_fjordholm_etal(u_ll, u_rr, - normal_direction::AbstractVector, - equations::ShallowWaterTwoLayerEquations2D) - # Unpack left and right state - h_upper_ll, h_lower_ll = waterheight(u_ll, equations) - v1_upper_ll, v2_upper_ll, v1_lower_ll, v2_lower_ll = velocity(u_ll, equations) - h_upper_rr, h_lower_rr = waterheight(u_rr, equations) - v1_upper_rr, v2_upper_rr, v1_lower_rr, v2_lower_rr = velocity(u_rr, equations) - - # Compute velocity in normal direction - v_upper_dot_n_ll = v1_upper_ll * normal_direction[1] + - v2_upper_ll * normal_direction[2] - v_upper_dot_n_rr = v1_upper_rr * normal_direction[1] + - v2_upper_rr * normal_direction[2] - v_lower_dot_n_ll = v1_lower_ll * normal_direction[1] + - v2_lower_ll * normal_direction[2] - v_lower_dot_n_rr = v1_lower_rr * normal_direction[1] + - v2_lower_rr * normal_direction[2] - - # Average each factor of products in flux - h_upper_avg = 0.5 * (h_upper_ll + h_upper_rr) - h_lower_avg = 0.5 * (h_lower_ll + h_lower_rr) - v1_upper_avg = 0.5 * (v1_upper_ll + v1_upper_rr) - v1_lower_avg = 0.5 * (v1_lower_ll + v1_lower_rr) - v2_upper_avg = 0.5 * (v2_upper_ll + v2_upper_rr) - v2_lower_avg = 0.5 * (v2_lower_ll + v2_lower_rr) - p1_avg = 0.25 * equations.gravity * (h_upper_ll^2 + h_upper_rr^2) - p2_avg = 0.25 * equations.gravity * (h_lower_ll^2 + h_lower_rr^2) - v_upper_dot_n_avg = 0.5 * (v_upper_dot_n_ll + v_upper_dot_n_rr) - v_lower_dot_n_avg = 0.5 * (v_lower_dot_n_ll + v_lower_dot_n_rr) - - # Calculate fluxes depending on normal_direction - f1 = h_upper_avg * v_upper_dot_n_avg - f2 = f1 * v1_upper_avg + p1_avg * normal_direction[1] - f3 = f1 * v2_upper_avg + p1_avg * normal_direction[2] - f4 = h_lower_avg * v_lower_dot_n_avg - f5 = f4 * v1_lower_avg + p2_avg * normal_direction[1] - f6 = f4 * v2_lower_avg + p2_avg * normal_direction[2] - - return SVector(f1, f2, f3, f4, f5, f6, zero(eltype(u_ll))) -end - """ flux_wintermeyer_etal(u_ll, u_rr, orientation, equations::ShallowWaterTwoLayerEquations2D) + flux_wintermeyer_etal(u_ll, u_rr, + normal_direction::AbstractVector, + equations::ShallowWaterTwoLayerEquations2D) Total energy conservative (mathematical entropy for two-layer 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). To obtain the flux for the -two-layer shallow water equations the flux that is described in the paper for the normal shallow +When the bottom topography is nonzero this scheme will be well-balanced when used with the +nonconservative [`flux_nonconservative_ersing_etal`](@ref). To obtain the flux for the +two-layer shallow water equations the flux that is described in the paper for the normal shallow water equations is used within each layer. Further details are available in Theorem 1 of the paper: @@ -637,24 +446,24 @@ Further details are available in Theorem 1 of the paper: v1_lower_avg = 0.5 * (v1_lower_ll + v1_lower_rr) v2_upper_avg = 0.5 * (v2_upper_ll + v2_upper_rr) v2_lower_avg = 0.5 * (v2_lower_ll + v2_lower_rr) - p1_avg = 0.5 * equations.gravity * h_upper_ll * h_upper_rr - p2_avg = 0.5 * equations.gravity * h_lower_ll * h_lower_rr + p_upper_avg = 0.5 * equations.gravity * h_upper_ll * h_upper_rr + p_lower_avg = 0.5 * equations.gravity * h_lower_ll * h_lower_rr # Calculate fluxes depending on orientation if orientation == 1 f1 = 0.5 * (h_v1_upper_ll + h_v1_upper_rr) - f2 = f1 * v1_upper_avg + p1_avg + f2 = f1 * v1_upper_avg + p_upper_avg f3 = f1 * v2_upper_avg f4 = 0.5 * (h_v1_lower_ll + h_v1_lower_rr) - f5 = f4 * v1_lower_avg + p2_avg + f5 = f4 * v1_lower_avg + p_lower_avg f6 = f4 * v2_lower_avg else f1 = 0.5 * (h_v2_upper_ll + h_v2_upper_rr) f2 = f1 * v1_upper_avg - f3 = f1 * v2_upper_avg + p1_avg + f3 = f1 * v2_upper_avg + p_upper_avg f4 = 0.5 * (h_v2_lower_ll + h_v2_lower_rr) f5 = f4 * v1_lower_avg - f6 = f4 * v2_lower_avg + p2_avg + f6 = f4 * v2_lower_avg + p_lower_avg end return SVector(f1, f2, f3, f4, f5, f6, zero(eltype(u_ll))) @@ -676,8 +485,8 @@ end v1_lower_avg = 0.5 * (v1_lower_ll + v1_lower_rr) v2_upper_avg = 0.5 * (v2_upper_ll + v2_upper_rr) v2_lower_avg = 0.5 * (v2_lower_ll + v2_lower_rr) - p1_avg = 0.5 * equations.gravity * h_upper_ll * h_upper_rr - p2_avg = 0.5 * equations.gravity * h_lower_ll * h_lower_rr + p_upper_avg = 0.5 * equations.gravity * h_upper_ll * h_upper_rr + p_lower_avg = 0.5 * equations.gravity * h_lower_ll * h_lower_rr h_v1_upper_avg = 0.5 * (h_v1_upper_ll + h_v1_upper_rr) h_v2_upper_avg = 0.5 * (h_v2_upper_ll + h_v2_upper_rr) h_v1_lower_avg = 0.5 * (h_v1_lower_ll + h_v1_lower_rr) @@ -685,38 +494,36 @@ end # Calculate fluxes depending on normal_direction f1 = h_v1_upper_avg * normal_direction[1] + h_v2_upper_avg * normal_direction[2] - f2 = f1 * v1_upper_avg + p1_avg * normal_direction[1] - f3 = f1 * v2_upper_avg + p1_avg * normal_direction[2] + f2 = f1 * v1_upper_avg + p_upper_avg * normal_direction[1] + f3 = f1 * v2_upper_avg + p_upper_avg * normal_direction[2] f4 = h_v1_lower_avg * normal_direction[1] + h_v2_lower_avg * normal_direction[2] - f5 = f4 * v1_lower_avg + p2_avg * normal_direction[1] - f6 = f4 * v2_lower_avg + p2_avg * normal_direction[2] + f5 = f4 * v1_lower_avg + p_lower_avg * normal_direction[1] + f6 = f4 * v2_lower_avg + p_lower_avg * normal_direction[2] return SVector(f1, f2, f3, f4, f5, f6, zero(eltype(u_ll))) end """ - flux_es_fjordholm_etal(u_ll, u_rr, orientation_or_normal_direction, - equations::ShallowWaterTwoLayerEquations1D) - -Entropy stable surface flux for the two-layer shallow water equations. Uses the entropy conservative -[`flux_fjordholm_etal`](@ref) and adds a Lax-Friedrichs type dissipation dependent on the jump of entropy -variables. - -Further details are available in the paper: -- Ulrik Skre Fjordholm (2012) -Energy conservative and stable schemes for the two-layer shallow water equations. -[DOI: 10.1142/9789814417099_0039](https://doi.org/10.1142/9789814417099_0039) -It should be noted that the equations are ordered differently and the -designation of the upper and lower layer has been changed which leads to a slightly different -formulation. + flux_es_ersing_etal(u_ll, u_rr, orientation_or_normal_direction, + equations::ShallowWaterTwoLayerEquations2D) + +Entropy stable surface flux for the two-layer shallow water equations. Uses the entropy conservative +[`flux_wintermeyer_etal`](@ref) and adds a Lax-Friedrichs type dissipation dependent on the jump of +entropy variables. + +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_es_fjordholm_etal(u_ll, u_rr, - orientation_or_normal_direction, - equations::ShallowWaterTwoLayerEquations2D) +@inline function flux_es_ersing_etal(u_ll, u_rr, + orientation_or_normal_direction, + equations::ShallowWaterTwoLayerEquations2D) # Compute entropy conservative flux but without the bottom topography - f_ec = flux_fjordholm_etal(u_ll, u_rr, - orientation_or_normal_direction, - equations) + f_ec = flux_wintermeyer_etal(u_ll, u_rr, + orientation_or_normal_direction, + equations) # Get maximum signal velocity λ = max_abs_speed_naive(u_ll, u_rr, orientation_or_normal_direction, equations) @@ -926,12 +733,12 @@ end rho_lower = equations.rho_lower v1_upper, v2_upper, v1_lower, v2_lower = velocity(u, equations) - w1 = rho_upper * (equations.gravity * (h_upper + h_lower + b) + - -0.5 * (v1_upper^2 + v2_upper^2)) + w1 = (rho_upper * (equations.gravity * (h_upper + h_lower + b) + + -0.5 * (v1_upper^2 + v2_upper^2))) w2 = rho_upper * v1_upper w3 = rho_upper * v2_upper - w4 = rho_lower * (equations.gravity * (equations.r * h_upper + h_lower + b) + - -0.5 * (v1_lower^2 + v2_lower^2)) + w4 = (rho_lower * (equations.gravity * (equations.r * h_upper + h_lower + b) + + -0.5 * (v1_lower^2 + v2_lower^2))) w5 = rho_lower * v1_lower w6 = rho_lower * v2_lower return SVector(w1, w2, w3, w4, w5, w6, b) diff --git a/test/test_tree_1d_shallowwater.jl b/test/test_tree_1d_shallowwater.jl index fd69a0c1d0e..2269e858928 100644 --- a/test/test_tree_1d_shallowwater.jl +++ b/test/test_tree_1d_shallowwater.jl @@ -96,6 +96,29 @@ end end end +@trixi_testset "elixir_shallowwater_well_balanced.jl with flux_nonconservative_ersing_etal" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced.jl"), + l2=[ + 0.10416666834254838, + 1.6657566141935285e-14, + 0.10416666834254838, + ], + 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), + tspan=(0.0, 0.25)) + # 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_wet_dry.jl with FluxHydrostaticReconstruction" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced_wet_dry.jl"), @@ -169,6 +192,33 @@ end end end +@trixi_testset "elixir_shallowwater_source_terms.jl with flux_nonconservative_ersing_etal" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), + l2=[ + 0.005774284062933275, + 0.017408601639513584, + 4.43649172561843e-5, + ], + linf=[ + 0.01639116193303547, + 0.05102877460799604, + 9.098379777450205e-5, + ], + surface_flux=(flux_wintermeyer_etal, + flux_nonconservative_ersing_etal), + volume_flux=(flux_wintermeyer_etal, + flux_nonconservative_ersing_etal), + tspan=(0.0, 0.025)) + # 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_source_terms_dirichlet.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms_dirichlet.jl"), diff --git a/test/test_tree_1d_shallowwater_twolayer.jl b/test/test_tree_1d_shallowwater_twolayer.jl index a504f4f93a6..180fb3ec3b3 100644 --- a/test/test_tree_1d_shallowwater_twolayer.jl +++ b/test/test_tree_1d_shallowwater_twolayer.jl @@ -10,95 +10,65 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @testset "Shallow Water Two layer" begin -#! format: noindent - -@trixi_testset "elixir_shallowwater_twolayer_convergence.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_shallowwater_twolayer_convergence.jl"), - l2=[0.0050681532925156945, 0.002089013899370176, - 0.005105544300292713, 0.002526442122643306, - 0.0004744186597732706], - linf=[0.022256679217306008, 0.005421833004652266, - 0.02233993939574197, 0.008765261497422516, - 0.0008992474511784199], - tspan=(0.0, 0.25)) - # 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 + @trixi_testset "elixir_shallowwater_twolayer_convergence.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_twolayer_convergence.jl"), + l2=[0.005012009872109003, 0.002091035326731071, + 0.005049271397924551, + 0.0024633066562966574, 0.0004744186597732739], + linf=[0.0213772149343594, 0.005385752427290447, + 0.02175023787351349, + 0.008212004668840978, 0.0008992474511784199], + tspan=(0.0, 0.25)) + # 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 -@trixi_testset "elixir_shallowwater_twolayer_convergence.jl with flux_es_fjordholm_etal" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_shallowwater_twolayer_convergence.jl"), - l2=[0.0027681377074701345, 0.0018007543202559165, - 0.0028036917433720576, - 0.0013980358596935737, 0.0004744186597732706], - linf=[0.005699303919826093, 0.006432952918256296, - 0.0058507082844360125, 0.002717615543961216, - 0.0008992474511784199], - surface_flux=(flux_es_fjordholm_etal, - flux_nonconservative_fjordholm_etal), - tspan=(0.0, 0.25)) - # 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 + @trixi_testset "elixir_shallowwater_twolayer_well_balanced.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_twolayer_well_balanced.jl"), + l2=[8.949288784402005e-16, 4.0636427176237915e-17, + 0.001002881985401548, + 2.133351105037203e-16, 0.0010028819854016578], + linf=[2.6229018956769323e-15, 1.878451903240623e-16, + 0.005119880996670156, + 8.003199803957679e-16, 0.005119880996670666], + tspan=(0.0, 0.25)) + # 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 -@trixi_testset "elixir_shallowwater_twolayer_well_balanced.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_shallowwater_twolayer_well_balanced.jl"), - l2=[8.949288784402005e-16, 4.0636427176237915e-17, - 0.001002881985401548, - 2.133351105037203e-16, 0.0010028819854016578], - linf=[2.6229018956769323e-15, 1.878451903240623e-16, - 0.005119880996670156, - 8.003199803957679e-16, 0.005119880996670666], - tspan=(0.0, 0.25)) - # 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 + @trixi_testset "elixir_shallowwater_twolayer_dam_break.jl with flux_lax_friedrichs" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_twolayer_dam_break.jl"), + l2=[0.1000774903431289, 0.5670692949571057, 0.08764242501014498, + 0.45412307886094555, 0.013638618139749523], + linf=[0.586718937495144, 2.1215606128311584, 0.5185911311186155, + 1.820382495072612, 0.5], + surface_flux=(flux_lax_friedrichs, + flux_nonconservative_ersing_etal), + tspan=(0.0, 0.25)) + # 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 -@trixi_testset "elixir_shallowwater_twolayer_dam_break.jl with flux_lax_friedrichs" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_shallowwater_twolayer_dam_break.jl"), - l2=[0.10010269243463918, 0.5668733957648654, - 0.08759617327649398, - 0.4538443183566172, 0.013638618139749523], - linf=[ - 0.5854202777756559, - 2.1278930820498934, - 0.5193686074348809, - 1.8071213168086229, - 0.5, - ], - surface_flux=(flux_lax_friedrichs, - flux_nonconservative_fjordholm_etal), - tspan=(0.0, 0.25)) - # 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 - end # module diff --git a/test/test_tree_2d_shallowwater.jl b/test/test_tree_2d_shallowwater.jl index d280e380192..58db7c5f35f 100644 --- a/test/test_tree_2d_shallowwater.jl +++ b/test/test_tree_2d_shallowwater.jl @@ -116,6 +116,35 @@ end end end +@trixi_testset "elixir_shallowwater_well_balanced.jl with flux_nonconservative_ersing_etal" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced.jl"), + l2=[ + 0.9130579602987146, + 1.0323158914614244e-14, + 1.0276096319430528e-14, + 0.9130579602987147, + ], + linf=[ + 2.11306203761566, + 4.063916419044386e-14, + 3.694484044448245e-14, + 2.1130620376156584, + ], + surface_flux=(flux_wintermeyer_etal, + flux_nonconservative_ersing_etal), + volume_flux=(flux_wintermeyer_etal, + flux_nonconservative_ersing_etal), + tspan=(0.0, 0.25)) + # 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_wet_dry.jl with FluxHydrostaticReconstruction" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced_wet_dry.jl"), @@ -219,6 +248,35 @@ end end end +@trixi_testset "elixir_shallowwater_source_terms.jl with flux_nonconservative_ersing_etal" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), + l2=[ + 0.002471853426064005, + 0.05619168608950033, + 0.11844727575152562, + 6.274146767730281e-5, + ], + linf=[ + 0.014332922987500218, + 0.2141204806174546, + 0.5392313755637872, + 0.0001819675955490041, + ], + surface_flux=(flux_wintermeyer_etal, + flux_nonconservative_ersing_etal), + volume_flux=(flux_wintermeyer_etal, + flux_nonconservative_ersing_etal), + tspan=(0.0, 0.25)) + # 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_conical_island.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_conical_island.jl"), l2=[ diff --git a/test/test_tree_2d_shallowwater_twolayer.jl b/test/test_tree_2d_shallowwater_twolayer.jl index 5959e7ed882..802bf4e021c 100644 --- a/test/test_tree_2d_shallowwater_twolayer.jl +++ b/test/test_tree_2d_shallowwater_twolayer.jl @@ -10,105 +10,79 @@ include("test_trixi.jl") EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem") @testset "Two-Layer Shallow Water" begin -#! format: noindent - -@trixi_testset "elixir_shallowwater_twolayer_convergence.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_shallowwater_twolayer_convergence.jl"), - l2=[0.0004040147445601598, 0.005466848793475609, - 0.006149138398472166, 0.0002908599437447256, - 0.003011817461911792, 0.0026806180089700674, - 8.873630921431545e-6], - linf=[0.002822006686981293, 0.014859895905040332, - 0.017590546190827894, 0.0016323702636176218, - 0.009361402900653015, 0.008411036357379165, - 3.361991620143279e-5], - tspan=(0.0, 0.25)) - # 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 + @trixi_testset "elixir_shallowwater_twolayer_convergence.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_twolayer_convergence.jl"), + l2=[0.0004016779699408397, 0.005466339651545468, + 0.006148841330156112, + 0.0002882339012602492, 0.0030120142442780313, + 0.002680752838455618, + 8.873630921431545e-6], + linf=[0.002788654460984752, 0.01484602033450666, + 0.017572229756493973, + 0.0016010835493927011, 0.009369847995372549, + 0.008407961775489636, + 3.361991620143279e-5], + tspan=(0.0, 0.25)) + # 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 -@trixi_testset "elixir_shallowwater_twolayer_convergence.jl with flux_es_fjordholm_etal" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_shallowwater_twolayer_convergence.jl"), - l2=[0.00024709443131137236, 0.0019215286339769443, - 0.0023833298173254447, - 0.00021258247976270914, 0.0011299428031136195, - 0.0009191313765262401, - 8.873630921431545e-6], - linf=[0.0016099763244645793, 0.007659242165565017, - 0.009123320235427057, - 0.0013496983982568267, 0.0035573687287770994, - 0.00296823235874899, - 3.361991620143279e-5], - surface_flux=(flux_es_fjordholm_etal, - flux_nonconservative_fjordholm_etal), - tspan=(0.0, 0.25)) - # 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 + @trixi_testset "elixir_shallowwater_twolayer_well_balanced.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_twolayer_well_balanced.jl"), + l2=[3.2935164267930016e-16, 4.6800825611195103e-17, + 4.843057532147818e-17, + 0.0030769233188015013, 1.4809161150389857e-16, + 1.509071695038043e-16, + 0.0030769233188014935], + linf=[2.248201624865942e-15, 2.346382070278936e-16, + 2.208565017494899e-16, + 0.026474051138910493, 9.237568031609006e-16, + 7.520758026187046e-16, + 0.026474051138910267], + tspan=(0.0, 0.25)) + # 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 -@trixi_testset "elixir_shallowwater_twolayer_well_balanced.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_shallowwater_twolayer_well_balanced.jl"), - l2=[3.2935164267930016e-16, 4.6800825611195103e-17, - 4.843057532147818e-17, - 0.0030769233188015013, 1.4809161150389857e-16, - 1.509071695038043e-16, - 0.0030769233188014935], - linf=[2.248201624865942e-15, 2.346382070278936e-16, - 2.208565017494899e-16, - 0.026474051138910493, 9.237568031609006e-16, - 7.520758026187046e-16, - 0.026474051138910267], - tspan=(0.0, 0.25)) - # 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 + @trixi_testset "elixir_shallowwater_twolayer_well_balanced with flux_lax_friedrichs.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_shallowwater_twolayer_well_balanced.jl"), + l2=[2.0525741072929735e-16, 6.000589392730905e-17, + 6.102759428478984e-17, + 0.0030769233188014905, 1.8421386173122792e-16, + 1.8473184927121752e-16, + 0.0030769233188014935], + linf=[7.355227538141662e-16, 2.960836949170518e-16, + 4.2726562436938764e-16, + 0.02647405113891016, 1.038795478061861e-15, + 1.0401789378532516e-15, + 0.026474051138910267], + surface_flux=(flux_lax_friedrichs, + flux_nonconservative_ersing_etal), + tspan=(0.0, 0.25)) + # 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 -@trixi_testset "elixir_shallowwater_twolayer_well_balanced with flux_lax_friedrichs.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_shallowwater_twolayer_well_balanced.jl"), - l2=[2.0525741072929735e-16, 6.000589392730905e-17, - 6.102759428478984e-17, - 0.0030769233188014905, 1.8421386173122792e-16, - 1.8473184927121752e-16, - 0.0030769233188014935], - linf=[7.355227538141662e-16, 2.960836949170518e-16, - 4.2726562436938764e-16, - 0.02647405113891016, 1.038795478061861e-15, - 1.0401789378532516e-15, - 0.026474051138910267], - surface_flux=(flux_lax_friedrichs, - flux_nonconservative_fjordholm_etal), - tspan=(0.0, 0.25)) - # 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 - end # module diff --git a/test/test_unstructured_2d.jl b/test/test_unstructured_2d.jl index 26483931cf3..d4416ac5b6a 100644 --- a/test/test_unstructured_2d.jl +++ b/test/test_unstructured_2d.jl @@ -349,6 +349,35 @@ end end end +@trixi_testset "elixir_shallowwater_well_balanced.jl with flux_nonconservative_ersing_etal" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_well_balanced.jl"), + l2=[ + 1.2164292510839083, + 2.590643638636187e-12, + 1.0945471514840143e-12, + 1.2164292510839079, + ], + linf=[ + 1.5138512282315792, + 5.0276441977281156e-11, + 1.9816934589292803e-11, + 1.513851228231574, + ], + surface_flux=(flux_wintermeyer_etal, + flux_nonconservative_ersing_etal), + volume_flux=(flux_wintermeyer_etal, + flux_nonconservative_ersing_etal), + tspan=(0.0, 0.25)) + # 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_source_terms.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), l2=[ @@ -402,6 +431,35 @@ end end end +@trixi_testset "elixir_shallowwater_source_terms.jl with flux_nonconservative_ersing_etal" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), + l2=[ + 0.0011196687776346434, + 0.044562672453443995, + 0.014306265289763618, + 5.089218476759981e-6, + ], + linf=[ + 0.007825021762002393, + 0.348550815397918, + 0.1115517935018282, + 2.6407324614341476e-5, + ], + surface_flux=(flux_wintermeyer_etal, + flux_nonconservative_ersing_etal), + volume_flux=(flux_wintermeyer_etal, + flux_nonconservative_ersing_etal), + tspan=(0.0, 0.025)) + # 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_source_terms.jl with flux_hll" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), l2=[ @@ -535,15 +593,15 @@ end @trixi_testset "elixir_shallowwater_twolayer_convergence.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_twolayer_convergence.jl"), - l2=[0.0007953969898161991, 0.00882074628714633, - 0.0024322572528892934, - 0.0007597425017400447, 0.004501238950166439, - 0.0015784803573661104, + l2=[0.0007935561625451243, 0.008825315509943844, + 0.002429969315645897, + 0.0007580145888686304, 0.004495741879625235, + 0.0015758146898767814, 6.849532064729749e-6], - linf=[0.00592559068081977, 0.08072451118697077, - 0.0344854497419107, 0.005892196680485795, - 0.04262651217675306, 0.014006223513881366, - 2.5829318284764646e-5], + linf=[0.0059205195991136605, 0.08072126590166251, + 0.03463806075399023, + 0.005884818649227186, 0.042658506561995546, + 0.014125956138838602, 2.5829318284764646e-5], tspan=(0.0, 0.25)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) @@ -582,17 +640,17 @@ end @trixi_testset "elixir_shallowwater_twolayer_dam_break.jl with flux_lax_friedrichs" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_twolayer_dam_break.jl"), - l2=[0.012471300561905669, 0.012363413819726868, - 0.0009541478004413331, - 0.09120260327331643, 0.015269590815749993, - 0.0012064657396853422, - 0.09991983966647647], - linf=[0.04497814714937959, 0.03286959000796511, - 0.010746094385294369, - 0.11138723974511211, 0.03640850605444494, - 0.014368386516056392, 0.10000000000000003], + l2=[0.012447632879122346, 0.012361250464676683, + 0.0009551519536340908, + 0.09119400061322577, 0.015276216721920347, + 0.0012126995108983853, 0.09991983966647647], + linf=[0.044305765721807444, 0.03279620980615845, + 0.010754320388190101, + 0.111309922939555, 0.03663360204931427, + 0.014332822306649284, + 0.10000000000000003], surface_flux=(flux_lax_friedrichs, - flux_nonconservative_fjordholm_etal), + flux_nonconservative_ersing_etal), tspan=(0.0, 0.25)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) From 5fd3d73630fd973f9216fab3c40c1c52509cca68 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Fri, 10 Nov 2023 16:02:11 +0100 Subject: [PATCH 172/263] HLL MHD Breaking changes for Consistency (#1708) * Breaking changes HLL MHD * format * format examples * hlle * fix * news, tests, example changes * fmt * remove left-right-biased flux from test * Set version to v0.6.0 * Migrate neural network-based indicators to new repository (#1701) * Remove all neural network indicator stuff from `src/` * Migrate neural network tests * Migrate neural network examples * Migrate test dependencies * Update NEWS.md * Fix typo * Remove Requires.jl-based use of Flux.jl * Fix formatting * Add migration of indicators to section with breaking changes --------- Co-authored-by: Hendrik Ranocha * fix hlle noncartesian 2d * remove parantheses * correct test vals * Make parabolic terms nonexperimental (#1714) * Make parabolic terms non-experimental * Make NSE a separate item * Add MPI to supported features * Mention that parabolic terms are now officially supported in NEWS.md Co-authored-by: Hendrik Ranocha * Deprecate some `DGMultiMesh` constructors (#1709) * remove previously deprecated functions * fix typo in NEWS.md about deprecation vs removal * fix literate tutorial * removing other deprecation * format * Revert "fix typo in NEWS.md about deprecation vs removal" This reverts commit 6b03020a8c881a86550484891a0f53bca018e447. * add gradient variable type parameter to `AbstractEquationsParabolic` (#1409) * add gradient variable type parameter * fix parabolic literate test * remove trailing comment * remove unnecessary abstract type * move gradient variable structs * formatting * fix dropped changes * try to fix doc tests * fixing navier stokes 1D * formatting * remove duplicate GradientVariablesPrimitive/Entropy definition * update news * bring downloads back * fix failing test * fmt --------- Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Hendrik Ranocha --- NEWS.md | 5 ++ .../p4est_2d_dgsem/elixir_mhd_alfven_wave.jl | 4 +- .../elixir_mhd_alfven_wave_nonconforming.jl | 4 +- .../elixir_mhd_alfven_wave.jl | 4 +- .../t8code_2d_dgsem/elixir_mhd_alfven_wave.jl | 2 +- .../elixir_mhd_briowu_shock_tube.jl | 2 +- .../elixir_mhd_ryujones_shock_tube.jl | 2 +- .../elixir_mhd_shu_osher_shock_tube.jl | 2 +- .../elixir_mhd_alfven_wave_mortar.jl | 4 +- .../elixir_mhd_alfven_wave_mortar.jl | 4 +- .../elixir_mhd_alfven_wave.jl | 4 +- src/equations/ideal_glm_mhd_1d.jl | 22 +++++- src/equations/ideal_glm_mhd_2d.jl | 60 ++++++++++++++-- src/equations/ideal_glm_mhd_3d.jl | 68 +++++++++++++++++-- test/test_tree_2d_mhd.jl | 3 +- test/test_tree_3d_mhd.jl | 3 +- test/test_unit.jl | 19 +++--- 17 files changed, 177 insertions(+), 35 deletions(-) diff --git a/NEWS.md b/NEWS.md index 5d258fa65bb..54fbb90b8fc 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,6 +10,11 @@ for human readability. #### Changed +- The wave speed estimates for `flux_hll`, `FluxHLL()` are now consistent across equations. + In particular, the functions `min_max_speed_naive`, `min_max_speed_einfeldt` are now + conceptually identical across equations. + Users, who have been using `flux_hll` for MHD have now to use `flux_hlle` in order to use the + Einfeldt wave speed estimate. - Parabolic diffusion terms are now officially supported and not marked as experimental anymore. diff --git a/examples/p4est_2d_dgsem/elixir_mhd_alfven_wave.jl b/examples/p4est_2d_dgsem/elixir_mhd_alfven_wave.jl index 93db7bfdbaf..b2b402a25f6 100644 --- a/examples/p4est_2d_dgsem/elixir_mhd_alfven_wave.jl +++ b/examples/p4est_2d_dgsem/elixir_mhd_alfven_wave.jl @@ -12,7 +12,9 @@ initial_condition = initial_condition_convergence_test # Get the DG approximation space volume_flux = (flux_central, flux_nonconservative_powell) -solver = DGSEM(polydeg = 4, surface_flux = (flux_hll, flux_nonconservative_powell), +solver = DGSEM(polydeg = 4, + surface_flux = (flux_hlle, + flux_nonconservative_powell), volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (0.0, 0.0) diff --git a/examples/p4est_3d_dgsem/elixir_mhd_alfven_wave_nonconforming.jl b/examples/p4est_3d_dgsem/elixir_mhd_alfven_wave_nonconforming.jl index 6a62368ef99..12ddf9e4a5f 100644 --- a/examples/p4est_3d_dgsem/elixir_mhd_alfven_wave_nonconforming.jl +++ b/examples/p4est_3d_dgsem/elixir_mhd_alfven_wave_nonconforming.jl @@ -10,7 +10,9 @@ equations = IdealGlmMhdEquations3D(5 / 3) initial_condition = initial_condition_convergence_test volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -solver = DGSEM(polydeg = 3, surface_flux = (flux_hll, flux_nonconservative_powell), +solver = DGSEM(polydeg = 3, + surface_flux = (flux_hlle, + flux_nonconservative_powell), volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-1.0, -1.0, -1.0) diff --git a/examples/structured_3d_dgsem/elixir_mhd_alfven_wave.jl b/examples/structured_3d_dgsem/elixir_mhd_alfven_wave.jl index 6eb35078ef4..03f50ff3e55 100644 --- a/examples/structured_3d_dgsem/elixir_mhd_alfven_wave.jl +++ b/examples/structured_3d_dgsem/elixir_mhd_alfven_wave.jl @@ -10,7 +10,9 @@ equations = IdealGlmMhdEquations3D(5 / 3) initial_condition = initial_condition_convergence_test volume_flux = (flux_central, flux_nonconservative_powell) -solver = DGSEM(polydeg = 5, surface_flux = (flux_hll, flux_nonconservative_powell), +solver = DGSEM(polydeg = 5, + surface_flux = (flux_hlle, + flux_nonconservative_powell), volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) # Create the mesh diff --git a/examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl b/examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl index 8040f79cafd..1e2362a123c 100644 --- a/examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl +++ b/examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl @@ -11,7 +11,7 @@ initial_condition = initial_condition_convergence_test # Get the DG approximation space volume_flux = (flux_central, flux_nonconservative_powell) -solver = DGSEM(polydeg = 4, surface_flux = (flux_hll, flux_nonconservative_powell), +solver = DGSEM(polydeg = 4, surface_flux = (flux_hlle, flux_nonconservative_powell), volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (0.0, 0.0) diff --git a/examples/tree_1d_dgsem/elixir_mhd_briowu_shock_tube.jl b/examples/tree_1d_dgsem/elixir_mhd_briowu_shock_tube.jl index bb294af68cb..4d537508b47 100644 --- a/examples/tree_1d_dgsem/elixir_mhd_briowu_shock_tube.jl +++ b/examples/tree_1d_dgsem/elixir_mhd_briowu_shock_tube.jl @@ -32,7 +32,7 @@ initial_condition = initial_condition_briowu_shock_tube boundary_conditions = BoundaryConditionDirichlet(initial_condition) -surface_flux = flux_hll +surface_flux = flux_hlle volume_flux = flux_derigs_etal basis = LobattoLegendreBasis(4) diff --git a/examples/tree_1d_dgsem/elixir_mhd_ryujones_shock_tube.jl b/examples/tree_1d_dgsem/elixir_mhd_ryujones_shock_tube.jl index b6f856fbc64..a7d7689a806 100644 --- a/examples/tree_1d_dgsem/elixir_mhd_ryujones_shock_tube.jl +++ b/examples/tree_1d_dgsem/elixir_mhd_ryujones_shock_tube.jl @@ -39,7 +39,7 @@ initial_condition = initial_condition_ryujones_shock_tube boundary_conditions = BoundaryConditionDirichlet(initial_condition) -surface_flux = flux_hll +surface_flux = flux_hlle volume_flux = flux_hindenlang_gassner basis = LobattoLegendreBasis(3) diff --git a/examples/tree_1d_dgsem/elixir_mhd_shu_osher_shock_tube.jl b/examples/tree_1d_dgsem/elixir_mhd_shu_osher_shock_tube.jl index 8c0317277b0..689537ebdd4 100644 --- a/examples/tree_1d_dgsem/elixir_mhd_shu_osher_shock_tube.jl +++ b/examples/tree_1d_dgsem/elixir_mhd_shu_osher_shock_tube.jl @@ -61,7 +61,7 @@ initial_condition = initial_condition_shu_osher_shock_tube boundary_conditions = BoundaryConditionDirichlet(initial_condition) -surface_flux = flux_hll +surface_flux = flux_hlle volume_flux = flux_hindenlang_gassner basis = LobattoLegendreBasis(4) diff --git a/examples/tree_2d_dgsem/elixir_mhd_alfven_wave_mortar.jl b/examples/tree_2d_dgsem/elixir_mhd_alfven_wave_mortar.jl index 229360f266e..0200b591844 100644 --- a/examples/tree_2d_dgsem/elixir_mhd_alfven_wave_mortar.jl +++ b/examples/tree_2d_dgsem/elixir_mhd_alfven_wave_mortar.jl @@ -10,7 +10,9 @@ equations = IdealGlmMhdEquations2D(gamma) initial_condition = initial_condition_convergence_test volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -solver = DGSEM(polydeg = 3, surface_flux = (flux_hll, flux_nonconservative_powell), +solver = DGSEM(polydeg = 3, + surface_flux = (flux_hlle, + flux_nonconservative_powell), volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (0.0, 0.0) diff --git a/examples/tree_3d_dgsem/elixir_mhd_alfven_wave_mortar.jl b/examples/tree_3d_dgsem/elixir_mhd_alfven_wave_mortar.jl index 3ce166a7fa7..2fa22d535d7 100644 --- a/examples/tree_3d_dgsem/elixir_mhd_alfven_wave_mortar.jl +++ b/examples/tree_3d_dgsem/elixir_mhd_alfven_wave_mortar.jl @@ -10,7 +10,9 @@ equations = IdealGlmMhdEquations3D(5 / 3) initial_condition = initial_condition_convergence_test volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell) -solver = DGSEM(polydeg = 3, surface_flux = (flux_hll, flux_nonconservative_powell), +solver = DGSEM(polydeg = 3, + surface_flux = (flux_hlle, + flux_nonconservative_powell), volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-1.0, -1.0, -1.0) diff --git a/examples/unstructured_2d_dgsem/elixir_mhd_alfven_wave.jl b/examples/unstructured_2d_dgsem/elixir_mhd_alfven_wave.jl index fdafed98c8d..3ed3e828ca8 100644 --- a/examples/unstructured_2d_dgsem/elixir_mhd_alfven_wave.jl +++ b/examples/unstructured_2d_dgsem/elixir_mhd_alfven_wave.jl @@ -11,7 +11,9 @@ equations = IdealGlmMhdEquations2D(gamma) initial_condition = initial_condition_convergence_test volume_flux = (flux_central, flux_nonconservative_powell) -solver = DGSEM(polydeg = 7, surface_flux = (flux_hll, flux_nonconservative_powell), +solver = DGSEM(polydeg = 7, + surface_flux = (flux_hlle, + flux_nonconservative_powell), volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) # Get the unstructured quad mesh from a file (downloads the file if not available locally) diff --git a/src/equations/ideal_glm_mhd_1d.jl b/src/equations/ideal_glm_mhd_1d.jl index 7e5c94c7bc3..85030e8a5ad 100644 --- a/src/equations/ideal_glm_mhd_1d.jl +++ b/src/equations/ideal_glm_mhd_1d.jl @@ -277,6 +277,22 @@ end λ_max = max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) end +# Calculate estimates for minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdEquations1D) + rho_ll, rho_v1_ll, _ = u_ll + rho_rr, rho_v1_rr, _ = u_rr + + # Calculate primitive variables + v1_ll = rho_v1_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + + λ_min = v1_ll - calc_fast_wavespeed(u_ll, orientation, equations) + λ_max = v1_rr + calc_fast_wavespeed(u_rr, orientation, equations) + + return λ_min, λ_max +end + # More refined estimates for minimum and maximum wave speeds for HLL-type fluxes @inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdEquations1D) @@ -298,15 +314,15 @@ end end """ - min_max_speed_naive(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdEquations1D) + min_max_speed_einfeldt(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdEquations1D) Calculate minimum and maximum wave speeds for HLL-type fluxes as in - Li (2005) An HLLC Riemann solver for magneto-hydrodynamics [DOI: 10.1016/j.jcp.2004.08.020](https://doi.org/10.1016/j.jcp.2004.08.020). """ -@inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer, - equations::IdealGlmMhdEquations1D) +@inline function min_max_speed_einfeldt(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdEquations1D) rho_ll, rho_v1_ll, _ = u_ll rho_rr, rho_v1_rr, _ = u_rr diff --git a/src/equations/ideal_glm_mhd_2d.jl b/src/equations/ideal_glm_mhd_2d.jl index e8de0cedde1..43d1991e34b 100644 --- a/src/equations/ideal_glm_mhd_2d.jl +++ b/src/equations/ideal_glm_mhd_2d.jl @@ -775,6 +775,56 @@ end return max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) end +# Calculate estimate for minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdEquations2D) + rho_ll, rho_v1_ll, rho_v2_ll, _ = u_ll + rho_rr, rho_v1_rr, rho_v2_rr, _ = u_rr + + # Calculate primitive velocity variables + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + + # Approximate the left-most and right-most eigenvalues in the Riemann fan + if orientation == 1 # x-direction + λ_min = v1_ll - calc_fast_wavespeed(u_ll, orientation, equations) + λ_max = v1_rr + calc_fast_wavespeed(u_rr, orientation, equations) + else # y-direction + λ_min = v2_ll - calc_fast_wavespeed(u_ll, orientation, equations) + λ_max = v2_rr + calc_fast_wavespeed(u_rr, orientation, equations) + end + + return λ_min, λ_max +end + +@inline function min_max_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, + equations::IdealGlmMhdEquations2D) + rho_ll, rho_v1_ll, rho_v2_ll, _ = u_ll + rho_rr, rho_v1_rr, rho_v2_rr, _ = u_rr + + # Calculate primitive velocity variables + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + + v_normal_ll = (v1_ll * normal_direction[1] + v2_ll * normal_direction[2]) + v_normal_rr = (v1_rr * normal_direction[1] + v2_rr * normal_direction[2]) + + c_f_ll = calc_fast_wavespeed(u_ll, normal_direction, equations) + c_f_rr = calc_fast_wavespeed(u_rr, normal_direction, equations) + + # Estimate the min/max eigenvalues in the normal direction + λ_min = min(v_normal_ll - c_f_ll, v_normal_rr - c_f_rr) + λ_max = max(v_normal_rr + c_f_rr, v_normal_rr + c_f_rr) + + return λ_min, λ_max +end + # More refined estimates for minimum and maximum wave speeds for HLL-type fluxes @inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdEquations2D) @@ -833,15 +883,15 @@ end end """ - min_max_speed_naive(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdEquations2D) + min_max_speed_einfeldt(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdEquations2D) Calculate minimum and maximum wave speeds for HLL-type fluxes as in - Li (2005) An HLLC Riemann solver for magneto-hydrodynamics [DOI: 10.1016/j.jcp.2004.08.020](https://doi.org/10.1016/j.jcp.2004.08.020). """ -@inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer, - equations::IdealGlmMhdEquations2D) +@inline function min_max_speed_einfeldt(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdEquations2D) rho_ll, rho_v1_ll, rho_v2_ll, _ = u_ll rho_rr, rho_v1_rr, rho_v2_rr, _ = u_rr @@ -870,8 +920,8 @@ Calculate minimum and maximum wave speeds for HLL-type fluxes as in return λ_min, λ_max end -@inline function min_max_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, - equations::IdealGlmMhdEquations2D) +@inline function min_max_speed_einfeldt(u_ll, u_rr, normal_direction::AbstractVector, + equations::IdealGlmMhdEquations2D) rho_ll, rho_v1_ll, rho_v2_ll, _ = u_ll rho_rr, rho_v1_rr, rho_v2_rr, _ = u_rr diff --git a/src/equations/ideal_glm_mhd_3d.jl b/src/equations/ideal_glm_mhd_3d.jl index 09990837706..321e501b051 100644 --- a/src/equations/ideal_glm_mhd_3d.jl +++ b/src/equations/ideal_glm_mhd_3d.jl @@ -670,6 +670,64 @@ end return max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) end +# Calculate estimate for minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdEquations3D) + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr + + # Calculate primitive variables and speed of sound + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + v3_rr = rho_v3_rr / rho_rr + + # Approximate the left-most and right-most eigenvalues in the Riemann fan + if orientation == 1 # x-direction + λ_min = v1_ll - calc_fast_wavespeed(u_ll, orientation, equations) + λ_max = v1_rr + calc_fast_wavespeed(u_rr, orientation, equations) + elseif orientation == 2 # y-direction + λ_min = v2_ll - calc_fast_wavespeed(u_ll, orientation, equations) + λ_max = v2_rr + calc_fast_wavespeed(u_rr, orientation, equations) + else # z-direction + λ_min = v3_ll - calc_fast_wavespeed(u_ll, orientation, equations) + λ_max = v3_rr + calc_fast_wavespeed(u_rr, orientation, equations) + end + + return λ_min, λ_max +end + +@inline function min_max_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, + equations::IdealGlmMhdEquations3D) + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr + + # Calculate primitive velocity variables + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + v3_rr = rho_v3_rr / rho_rr + + v_normal_ll = (v1_ll * normal_direction[1] + + v2_ll * normal_direction[2] + + v3_ll * normal_direction[3]) + v_normal_rr = (v1_rr * normal_direction[1] + + v2_rr * normal_direction[2] + + v3_rr * normal_direction[3]) + + # Estimate the min/max eigenvalues in the normal direction + λ_min = v_normal_ll - calc_fast_wavespeed(u_ll, normal_direction, equations) + λ_max = v_normal_rr + calc_fast_wavespeed(u_rr, normal_direction, equations) + + return λ_min, λ_max +end + # More refined estimates for minimum and maximum wave speeds for HLL-type fluxes @inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdEquations3D) @@ -742,15 +800,15 @@ end end """ - min_max_speed_naive(u_ll, u_rr, orientation_or_normal_direction, equations::IdealGlmMhdEquations3D) + min_max_speed_einfeldt(u_ll, u_rr, orientation_or_normal_direction, equations::IdealGlmMhdEquations3D) Calculate minimum and maximum wave speeds for HLL-type fluxes as in - Li (2005) An HLLC Riemann solver for magneto-hydrodynamics [DOI: 10.1016/j.jcp.2004.08.020](https://doi.org/10.1016/j.jcp.2004.08.020) """ -@inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer, - equations::IdealGlmMhdEquations3D) +@inline function min_max_speed_einfeldt(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdEquations3D) rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr @@ -787,8 +845,8 @@ Calculate minimum and maximum wave speeds for HLL-type fluxes as in return λ_min, λ_max end -@inline function min_max_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, - equations::IdealGlmMhdEquations3D) +@inline function min_max_speed_einfeldt(u_ll, u_rr, normal_direction::AbstractVector, + equations::IdealGlmMhdEquations3D) rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr diff --git a/test/test_tree_2d_mhd.jl b/test/test_tree_2d_mhd.jl index bd6a95bba50..953c077c0a3 100644 --- a/test/test_tree_2d_mhd.jl +++ b/test/test_tree_2d_mhd.jl @@ -208,7 +208,8 @@ end 0.04879208429337193, ], tspan=(0.0, 0.06), - surface_flux=(flux_hll, flux_nonconservative_powell)) + surface_flux=(flux_hlle, + flux_nonconservative_powell)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let diff --git a/test/test_tree_3d_mhd.jl b/test/test_tree_3d_mhd.jl index 7ce5ef1d18f..e75685f0b43 100644 --- a/test/test_tree_3d_mhd.jl +++ b/test/test_tree_3d_mhd.jl @@ -240,7 +240,8 @@ end 1000 end end, - surface_flux=(flux_hll, flux_nonconservative_powell), + surface_flux=(flux_hlle, + flux_nonconservative_powell), volume_flux=(flux_central, flux_nonconservative_powell), coordinates_min=(0.0, 0.0, 0.0), coordinates_max=(1.0, 1.0, 1.0), diff --git a/test/test_unit.jl b/test/test_unit.jl index 609100793ba..1d768c0df69 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -952,14 +952,12 @@ end end @timed_testset "Consistency check for HLLE flux: MHD" begin - # Note: min_max_speed_naive for MHD is essentially min_max_speed_einfeldt - equations = IdealGlmMhdEquations1D(1.4) u_values = [SVector(1.0, 0.4, -0.5, 0.1, 1.0, 0.1, -0.2, 0.1), SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2)] for u in u_values - @test flux_hll(u, u, 1, equations) ≈ flux(u, 1, equations) + @test flux_hlle(u, u, 1, equations) ≈ flux(u, 1, equations) end equations = IdealGlmMhdEquations2D(1.4, 5.0) #= c_h =# @@ -973,11 +971,11 @@ end SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2)] for u in u_values, orientation in orientations - @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hlle(u, u, orientation, equations) ≈ flux(u, orientation, equations) end for u in u_values, normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ + @test flux_hlle(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) end @@ -993,11 +991,11 @@ end SVector(1.5, -0.2, 0.1, 0.2, 5.0, -0.1, 0.1, 0.2, 0.2)] for u in u_values, orientation in orientations - @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + @test flux_hlle(u, u, orientation, equations) ≈ flux(u, orientation, equations) end for u in u_values, normal_direction in normal_directions - @test flux_hll(u, u, normal_direction, equations) ≈ + @test flux_hlle(u, u, normal_direction, equations) ≈ flux(u, normal_direction, equations) end end @@ -1244,8 +1242,8 @@ end fluxes = [ flux_central, flux_hindenlang_gassner, - flux_hll, FluxHLL(min_max_speed_davis), + flux_hlle, ] for f_std in fluxes @@ -1271,8 +1269,8 @@ end fluxes = [ flux_central, flux_hindenlang_gassner, - flux_hll, FluxHLL(min_max_speed_davis), + flux_hlle, ] for f_std in fluxes @@ -1322,7 +1320,8 @@ end dg = DGMulti(polydeg = 1, element_type = Line(), approximation_type = Polynomial(), surface_integral = SurfaceIntegralWeakForm(flux_central), volume_integral = VolumeIntegralFluxDifferencing(flux_central)) - mesh = DGMultiMesh(dg, cells_per_dimension = (1,), periodicity = false) + cells_per_dimension = (1,) + mesh = DGMultiMesh(dg, cells_per_dimension, periodicity = false) @test mesh.boundary_faces[:entire_boundary] == [1, 2] end From 1b75f5ecbd0b21d5cdce25f3e4f1884a06727fbb Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Sun, 12 Nov 2023 07:16:33 +0100 Subject: [PATCH 173/263] set development version to v0.6.1-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index e95e5347ee3..da618dc78c1 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.6.0" +version = "0.6.1-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From d772bf88d3c3693c3228e68b65eb1df31ea30a98 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 06:08:09 +0100 Subject: [PATCH 174/263] CompatHelper: bump compat for Trixi to 0.6 for package benchmark, (keep existing compat) (#1735) Co-authored-by: CompatHelper Julia --- benchmark/Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/Project.toml b/benchmark/Project.toml index fb985572532..e94144cfd15 100644 --- a/benchmark/Project.toml +++ b/benchmark/Project.toml @@ -8,4 +8,4 @@ Trixi = "a7f1ee26-1774-49b1-8366-f1abc58fbfcb" BenchmarkTools = "0.5, 0.7, 1.0" OrdinaryDiffEq = "5.65, 6" PkgBenchmark = "0.2.10" -Trixi = "0.4, 0.5" +Trixi = "0.4, 0.5, 0.6" From 7bb3b463a660edb5754fcf917ff8812f6791716a Mon Sep 17 00:00:00 2001 From: Benjamin Bolm <74359358+bennibolm@users.noreply.github.com> Date: Mon, 13 Nov 2023 14:57:06 +0100 Subject: [PATCH 175/263] Add two-sided Zalesak-type IDP subcell limiting (#1648) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add two-sided limiting for conservative variables * Fix visualization routines * Add bounds calculation for BoundaryConditionDirichlet * Reduce cfl in elixir * Fix test * Add comment about subcell limiting with non-conforming meshes * Remove subcell visualization * Fix last commit * Remove @unpack * Add comment to `News.md` * Fix source for sedov blast setup; Formatting * Reduce allocations * Replace construction of Symbols * Add bounds check for local limiting * Implement suggestions * Fix format * Add subcell allocation tests; Add changes to minmax limiter * Undo changes in elixirs * Implement suggestions * Skip positivity limiting if local limiting is more restrictive * Reduce allocations * Pass variables as strings instead of ints * Add `_nonperiodic` to elixir name * Fix unit test * Implement suggestions * Add missing comma in export of bounds check deviation * Implement suggestions --------- Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Andrés Rueda-Ramírez --- NEWS.md | 3 +- ...euler_blast_wave_sc_subcell_nonperiodic.jl | 93 +++++++++ ...lixir_euler_sedov_blast_wave_sc_subcell.jl | 91 +++++++++ .../elixir_euler_shockcapturing_subcell.jl | 2 +- ...ck_bubble_shockcapturing_subcell_minmax.jl | 142 ++++++++++++++ ...ubble_shockcapturing_subcell_positivity.jl | 5 +- .../elixir_mhd_shockcapturing_subcell.jl | 2 +- src/callbacks_stage/subcell_bounds_check.jl | 24 ++- .../subcell_bounds_check_2d.jl | 38 +++- src/equations/equations.jl | 20 +- src/solvers/dg.jl | 6 + .../dgsem_tree/dg_2d_subcell_limiters.jl | 17 ++ src/solvers/dgsem_tree/subcell_limiters.jl | 66 +++++-- src/solvers/dgsem_tree/subcell_limiters_2d.jl | 178 ++++++++++++++++++ test/test_tree_2d_euler.jl | 56 ++++++ test/test_tree_2d_eulermulti.jl | 29 +++ test/test_unit.jl | 2 +- 17 files changed, 744 insertions(+), 30 deletions(-) create mode 100644 examples/tree_2d_dgsem/elixir_euler_blast_wave_sc_subcell_nonperiodic.jl create mode 100644 examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave_sc_subcell.jl create mode 100644 examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_minmax.jl diff --git a/NEWS.md b/NEWS.md index 54fbb90b8fc..5dd911391a6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -38,7 +38,8 @@ for human readability. - Wetting and drying feature and examples for 1D and 2D shallow water equations - Implementation of the polytropic Euler equations in 2D - Implementation of the quasi-1D shallow water equations -- Subcell positivity limiting support for conservative variables in 2D for `TreeMesh` +- Subcell (positivity and local min/max) limiting support for conservative variables + in 2D for `TreeMesh` - AMR for hyperbolic-parabolic equations on 2D/3D `TreeMesh` - Added `GradientVariables` type parameter to `AbstractEquationsParabolic` diff --git a/examples/tree_2d_dgsem/elixir_euler_blast_wave_sc_subcell_nonperiodic.jl b/examples/tree_2d_dgsem/elixir_euler_blast_wave_sc_subcell_nonperiodic.jl new file mode 100644 index 00000000000..209aa2ae352 --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_euler_blast_wave_sc_subcell_nonperiodic.jl @@ -0,0 +1,93 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations2D(1.4) + +""" + initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations2D) + +A medium blast wave taken from +- Sebastian Hennemann, Gregor J. Gassner (2020) + A provably entropy stable subcell shock capturing approach for high order split form DG + [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) +""" +function initial_condition_blast_wave(x, t, equations::CompressibleEulerEquations2D) + # Modified From Hennemann & Gassner JCP paper 2020 (Sec. 6.3) -> "medium blast wave" + # 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) + phi = atan(y_norm, x_norm) + sin_phi, cos_phi = sincos(phi) + + # 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 + p = r > 0.5 ? 1.0E-3 : 1.245 + + return prim2cons(SVector(rho, v1, v2, p), equations) +end +initial_condition = initial_condition_blast_wave + +boundary_condition = BoundaryConditionDirichlet(initial_condition) + +surface_flux = flux_lax_friedrichs +volume_flux = flux_ranocha +basis = LobattoLegendreBasis(3) +limiter_idp = SubcellLimiterIDP(equations, basis; + local_minmax_variables_cons = ["rho"]) +volume_integral = VolumeIntegralSubcellLimiting(limiter_idp; + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) +solver = DGSEM(basis, surface_flux, volume_integral) + +coordinates_min = (-2.0, -2.0) +coordinates_max = (2.0, 2.0) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 6, + n_cells_max = 10_000, + periodicity = false) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_condition) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 2.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 0.3) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback) + +############################################################################### +# run the simulation + +stage_callbacks = (SubcellLimiterIDPCorrection(), BoundsCheckCallback(save_errors = false)) + +sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks = stage_callbacks); + 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/tree_2d_dgsem/elixir_euler_sedov_blast_wave_sc_subcell.jl b/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave_sc_subcell.jl new file mode 100644 index 00000000000..c1ba3d96962 --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave_sc_subcell.jl @@ -0,0 +1,91 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations +gamma = 1.4 +equations = CompressibleEulerEquations2D(gamma) + +""" + initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations2D) + +The Sedov blast wave setup based on Flash +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 +""" +function initial_condition_sedov_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) + + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 + r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) + # r0 = 0.5 # = more reasonable setup + E = 1.0 + p0_inner = 3 * (equations.gamma - 1) * E / (3 * pi * r0^2) + p0_outer = 1.0e-5 # = true Sedov setup + # p0_outer = 1.0e-3 # = more reasonable setup + + # Calculate primitive variables + rho = 1.0 + 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_sedov_blast_wave + +surface_flux = flux_lax_friedrichs +volume_flux = flux_chandrashekar +basis = LobattoLegendreBasis(3) +limiter_idp = SubcellLimiterIDP(equations, basis; + local_minmax_variables_cons = ["rho"]) +volume_integral = VolumeIntegralSubcellLimiting(limiter_idp; + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) +solver = DGSEM(basis, surface_flux, volume_integral) + +coordinates_min = (-2.0, -2.0) +coordinates_max = (2.0, 2.0) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 3, + n_cells_max = 100_000) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 3.0) +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, + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 0.6) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + stepsize_callback, + save_solution) +############################################################################### +# run the simulation + +stage_callbacks = (SubcellLimiterIDPCorrection(), BoundsCheckCallback(save_errors = false)) + +sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks = stage_callbacks); + 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/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl b/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl index 3fea48b30da..282805a0e03 100644 --- a/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl +++ b/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl @@ -39,7 +39,7 @@ surface_flux = flux_lax_friedrichs volume_flux = flux_ranocha basis = LobattoLegendreBasis(3) limiter_idp = SubcellLimiterIDP(equations, basis; - positivity_variables_cons = [1], + positivity_variables_cons = ["rho"], positivity_correction_factor = 0.5) volume_integral = VolumeIntegralSubcellLimiting(limiter_idp; volume_flux_dg = volume_flux, diff --git a/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_minmax.jl b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_minmax.jl new file mode 100644 index 00000000000..3159a2066ad --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_minmax.jl @@ -0,0 +1,142 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler multicomponent equations + +# 1) Dry Air 2) Helium + 28% Air +equations = CompressibleEulerMulticomponentEquations2D(gammas = (1.4, 1.648), + gas_constants = (0.287, 1.578)) + +""" + initial_condition_shock_bubble(x, t, equations::CompressibleEulerMulticomponentEquations2D{5, 2}) + +A shock-bubble testcase for multicomponent Euler equations +- Ayoub Gouasmi, Karthik Duraisamy, Scott Murman + Formulation of Entropy-Stable schemes for the multicomponent compressible Euler equations + [arXiv: 1904.00972](https://arxiv.org/abs/1904.00972) +""" +function initial_condition_shock_bubble(x, t, + equations::CompressibleEulerMulticomponentEquations2D{ + 5, + 2 + }) + # bubble test case, see Gouasmi et al. https://arxiv.org/pdf/1904.00972 + # other reference: https://www.researchgate.net/profile/Pep_Mulet/publication/222675930_A_flux-split_algorithm_applied_to_conservative_models_for_multicomponent_compressible_flows/links/568da54508aeaa1481ae7af0.pdf + # typical domain is rectangular, we change it to a square, as Trixi can only do squares + @unpack gas_constants = equations + + # Positivity Preserving Parameter, can be set to zero if scheme is positivity preserving + delta = 0.03 + + # Region I + rho1_1 = delta + rho2_1 = 1.225 * gas_constants[1] / gas_constants[2] - delta + v1_1 = zero(delta) + v2_1 = zero(delta) + p_1 = 101325 + + # Region II + rho1_2 = 1.225 - delta + rho2_2 = delta + v1_2 = zero(delta) + v2_2 = zero(delta) + p_2 = 101325 + + # Region III + rho1_3 = 1.6861 - delta + rho2_3 = delta + v1_3 = -113.5243 + v2_3 = zero(delta) + p_3 = 159060 + + # Set up Region I & II: + inicenter = SVector(zero(delta), zero(delta)) + x_norm = x[1] - inicenter[1] + y_norm = x[2] - inicenter[2] + r = sqrt(x_norm^2 + y_norm^2) + + if (x[1] > 0.50) + # Set up Region III + rho1 = rho1_3 + rho2 = rho2_3 + v1 = v1_3 + v2 = v2_3 + p = p_3 + elseif (r < 0.25) + # Set up Region I + rho1 = rho1_1 + rho2 = rho2_1 + v1 = v1_1 + v2 = v2_1 + p = p_1 + else + # Set up Region II + rho1 = rho1_2 + rho2 = rho2_2 + v1 = v1_2 + v2 = v2_2 + p = p_2 + end + + return prim2cons(SVector(v1, v2, p, rho1, rho2), equations) +end +initial_condition = initial_condition_shock_bubble + +surface_flux = flux_lax_friedrichs +volume_flux = flux_ranocha +basis = LobattoLegendreBasis(3) + +limiter_idp = SubcellLimiterIDP(equations, basis; + local_minmax_variables_cons = ["rho" * string(i) + for i in eachcomponent(equations)]) +volume_integral = VolumeIntegralSubcellLimiting(limiter_idp; + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + +coordinates_min = (-2.25, -2.225) +coordinates_max = (2.20, 2.225) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 3, + n_cells_max = 1_000_000) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.01) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 300 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (Trixi.density,)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 600, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 0.5) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) + +############################################################################### +# run the simulation + +stage_callbacks = (SubcellLimiterIDPCorrection(), BoundsCheckCallback(save_errors = false)) + +sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks = stage_callbacks); + 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/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl index 6241ca30938..7856c9bafbd 100644 --- a/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl +++ b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl @@ -88,9 +88,8 @@ volume_flux = flux_ranocha basis = LobattoLegendreBasis(3) limiter_idp = SubcellLimiterIDP(equations, basis; - positivity_variables_cons = [ - (i + 3 for i in eachcomponent(equations))..., - ]) + positivity_variables_cons = ["rho" * string(i) + for i in eachcomponent(equations)]) volume_integral = VolumeIntegralSubcellLimiting(limiter_idp; volume_flux_dg = volume_flux, diff --git a/examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl b/examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl index b2cdff2ab53..fe9ad92467f 100644 --- a/examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl +++ b/examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl @@ -51,7 +51,7 @@ volume_flux = (flux_derigs_etal, flux_nonconservative_powell_local_symmetric) basis = LobattoLegendreBasis(3) limiter_idp = SubcellLimiterIDP(equations, basis; - positivity_variables_cons = [1], + positivity_variables_cons = ["rho"], positivity_correction_factor = 0.5) volume_integral = VolumeIntegralSubcellLimiting(limiter_idp; volume_flux_dg = volume_flux, diff --git a/src/callbacks_stage/subcell_bounds_check.jl b/src/callbacks_stage/subcell_bounds_check.jl index c86f266147c..d7e30ab1621 100644 --- a/src/callbacks_stage/subcell_bounds_check.jl +++ b/src/callbacks_stage/subcell_bounds_check.jl @@ -77,15 +77,24 @@ function init_callback(callback::BoundsCheckCallback, semi, limiter::SubcellLimi return nothing end - (; positivity) = limiter + (; local_minmax, positivity) = limiter (; output_directory) = callback variables = varnames(cons2cons, semi.equations) mkpath(output_directory) open("$output_directory/deviations.txt", "a") do f print(f, "# iter, simu_time") + if local_minmax + for v in limiter.local_minmax_variables_cons + variable_string = string(variables[v]) + print(f, ", " * variable_string * "_min, " * variable_string * "_max") + end + end if positivity for v in limiter.positivity_variables_cons + if v in limiter.local_minmax_variables_cons + continue + end print(f, ", " * string(variables[v]) * "_min") end end @@ -108,15 +117,26 @@ end @inline function finalize_callback(callback::BoundsCheckCallback, semi, limiter::SubcellLimiterIDP) - (; positivity) = limiter + (; local_minmax, positivity) = limiter (; idp_bounds_delta) = limiter.cache variables = varnames(cons2cons, semi.equations) println("─"^100) println("Maximum deviation from bounds:") println("─"^100) + if local_minmax + for v in limiter.local_minmax_variables_cons + v_string = string(v) + println("$(variables[v]):") + println("-lower bound: ", idp_bounds_delta[Symbol(v_string, "_min")][2]) + println("-upper bound: ", idp_bounds_delta[Symbol(v_string, "_max")][2]) + end + end if positivity for v in limiter.positivity_variables_cons + if v in limiter.local_minmax_variables_cons + continue + end println(string(variables[v]) * ":\n- positivity: ", idp_bounds_delta[Symbol(string(v), "_min")][2]) end diff --git a/src/callbacks_stage/subcell_bounds_check_2d.jl b/src/callbacks_stage/subcell_bounds_check_2d.jl index 8159becb503..d52eb6edb9e 100644 --- a/src/callbacks_stage/subcell_bounds_check_2d.jl +++ b/src/callbacks_stage/subcell_bounds_check_2d.jl @@ -8,12 +8,35 @@ @inline function check_bounds(u, mesh::AbstractMesh{2}, equations, solver, cache, limiter::SubcellLimiterIDP, time, iter, output_directory, save_errors) - (; positivity) = solver.volume_integral.limiter + (; local_minmax, positivity) = solver.volume_integral.limiter (; variable_bounds) = limiter.cache.subcell_limiter_coefficients (; idp_bounds_delta) = limiter.cache + if local_minmax + for v in limiter.local_minmax_variables_cons + v_string = string(v) + key_min = Symbol(v_string, "_min") + key_max = Symbol(v_string, "_max") + deviation_min = idp_bounds_delta[key_min] + deviation_max = idp_bounds_delta[key_max] + for element in eachelement(solver, cache), j in eachnode(solver), + i in eachnode(solver) + + var = u[v, i, j, element] + deviation_min[1] = max(deviation_min[1], + variable_bounds[key_min][i, j, element] - var) + deviation_max[1] = max(deviation_max[1], + var - variable_bounds[key_max][i, j, element]) + end + deviation_min[2] = max(deviation_min[2], deviation_min[1]) + deviation_max[2] = max(deviation_max[2], deviation_max[1]) + end + end if positivity for v in limiter.positivity_variables_cons + if v in limiter.local_minmax_variables_cons + continue + end key = Symbol(string(v), "_min") deviation = idp_bounds_delta[key] for element in eachelement(solver, cache), j in eachnode(solver), @@ -30,10 +53,19 @@ # Print to output file open("$output_directory/deviations.txt", "a") do f print(f, iter, ", ", time) + if local_minmax + for v in limiter.local_minmax_variables_cons + v_string = string(v) + print(f, ", ", idp_bounds_delta[Symbol(v_string, "_min")][1], ", ", + idp_bounds_delta[Symbol(v_string, "_max")][1]) + end + end if positivity for v in limiter.positivity_variables_cons - key = Symbol(string(v), "_min") - print(f, ", ", idp_bounds_delta[key][1]) + if v in limiter.local_minmax_variables_cons + continue + end + print(f, ", ", idp_bounds_delta[Symbol(string(v), "_min")][1]) end end println(f) diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 78b1b829b06..ba2ad1cd1cd 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -42,6 +42,18 @@ Common choices of the `conversion_function` are [`cons2cons`](@ref) and """ function varnames end +# Return the index of `varname` in `varnames(solution_variables, equations)` if available. +# Otherwise, throw an error. +function get_variable_index(varname, equations; + solution_variables = cons2cons) + index = findfirst(==(varname), varnames(solution_variables, equations)) + if isnothing(index) + throw(ArgumentError("$varname is no valid variable.")) + end + + return index +end + # Add methods to show some information on systems of equations. function Base.show(io::IO, equations::AbstractEquations) # Since this is not performance-critical, we can use `@nospecialize` to reduce latency. @@ -211,8 +223,8 @@ end """ NonConservativeLocal() -Struct used for multiple dispatch on non-conservative flux functions in the format of "local * symmetric". -When the argument `nonconservative_type` is of type `NonConservativeLocal`, +Struct used for multiple dispatch on non-conservative flux functions in the format of "local * symmetric". +When the argument `nonconservative_type` is of type `NonConservativeLocal`, the function returns the local part of the non-conservative term. """ struct NonConservativeLocal end @@ -220,8 +232,8 @@ struct NonConservativeLocal end """ NonConservativeSymmetric() -Struct used for multiple dispatch on non-conservative flux functions in the format of "local * symmetric". -When the argument `nonconservative_type` is of type `NonConservativeSymmetric`, +Struct used for multiple dispatch on non-conservative flux functions in the format of "local * symmetric". +When the argument `nonconservative_type` is of type `NonConservativeSymmetric`, the function returns the symmetric part of the non-conservative term. """ struct NonConservativeSymmetric end diff --git a/src/solvers/dg.jl b/src/solvers/dg.jl index 91ad59b76b6..9e5ebc7f9b5 100644 --- a/src/solvers/dg.jl +++ b/src/solvers/dg.jl @@ -191,6 +191,12 @@ end A subcell limiting volume integral type for DG methods based on subcell blending approaches with a low-order FV method. Used with limiter [`SubcellLimiterIDP`](@ref). +!!! note + Subcell limiting methods are not fully functional on non-conforming meshes. This is + mainly because the implementation assumes that low- and high-order schemes have the same + surface terms, which is not guaranteed for non-conforming meshes. The low-order scheme + with a high-order mortar is not invariant domain preserving. + !!! warning "Experimental implementation" This is an experimental feature and may change in future releases. """ diff --git a/src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl b/src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl index 97843db7743..2fc62f548d2 100644 --- a/src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl +++ b/src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl @@ -463,4 +463,21 @@ end return nothing end + +""" + get_boundary_outer_state(boundary_condition::BoundaryConditionDirichlet, + cache, t, equations, dg, indices...) +For subcell limiting, the calculation of local bounds for non-periodic domains require the boundary +outer state. This function returns the boundary value at time `t` and for node with spatial +indices `indices`. +""" +@inline function get_boundary_outer_state(boundary_condition::BoundaryConditionDirichlet, + cache, t, equations, dg, indices...) + (; node_coordinates) = cache.elements + + x = get_node_coords(node_coordinates, equations, dg, indices...) + u_outer = boundary_condition.boundary_value_function(x, t, equations) + + return u_outer +end end # @muladd diff --git a/src/solvers/dgsem_tree/subcell_limiters.jl b/src/solvers/dgsem_tree/subcell_limiters.jl index 55d402954bf..055e7ce24a4 100644 --- a/src/solvers/dgsem_tree/subcell_limiters.jl +++ b/src/solvers/dgsem_tree/subcell_limiters.jl @@ -14,12 +14,17 @@ end """ SubcellLimiterIDP(equations::AbstractEquations, basis; - positivity_variables_cons = [], + local_minmax_variables_cons = String[], + positivity_variables_cons = String[], positivity_correction_factor = 0.1) Subcell invariant domain preserving (IDP) limiting used with [`VolumeIntegralSubcellLimiting`](@ref) including: -- positivity limiting for conservative variables (`positivity_variables_cons`) +- Local maximum/minimum Zalesak-type limiting for conservative variables (`local_minmax_variables_cons`) +- Positivity limiting for conservative variables (`positivity_variables_cons`) + +Conservative variables to be limited are passed as a vector of strings, e.g. `local_minmax_variables_cons = ["rho"]` +and `positivity_variables_cons = ["rho"]`. The bounds are calculated using the low-order FV solution. The positivity limiter uses `positivity_correction_factor` such that `u^new >= positivity_correction_factor * u^FV`. @@ -41,62 +46,95 @@ The bounds are calculated using the low-order FV solution. The positivity limite This is an experimental feature and may change in future releases. """ struct SubcellLimiterIDP{RealT <: Real, Cache} <: AbstractSubcellLimiter + local_minmax::Bool + local_minmax_variables_cons::Vector{Int} # Local mininum/maximum principles for conservative variables positivity::Bool positivity_variables_cons::Vector{Int} # Positivity for conservative variables positivity_correction_factor::RealT cache::Cache end -# this method is used when the indicator is constructed as for shock-capturing volume integrals +# this method is used when the limiter is constructed as for shock-capturing volume integrals function SubcellLimiterIDP(equations::AbstractEquations, basis; - positivity_variables_cons = [], + local_minmax_variables_cons = String[], + positivity_variables_cons = String[], positivity_correction_factor = 0.1) + local_minmax = (length(local_minmax_variables_cons) > 0) positivity = (length(positivity_variables_cons) > 0) - bound_keys = Tuple(Symbol(string(v), "_min") for v in positivity_variables_cons) + local_minmax_variables_cons_ = get_variable_index.(local_minmax_variables_cons, + equations) + positivity_variables_cons_ = get_variable_index.(positivity_variables_cons, + equations) + + bound_keys = () + if local_minmax + for v in local_minmax_variables_cons_ + v_string = string(v) + bound_keys = (bound_keys..., Symbol(v_string, "_min"), + Symbol(v_string, "_max")) + end + end + for v in positivity_variables_cons_ + if !(v in local_minmax_variables_cons_) + bound_keys = (bound_keys..., Symbol(string(v), "_min")) + end + end cache = create_cache(SubcellLimiterIDP, equations, basis, bound_keys) - SubcellLimiterIDP{typeof(positivity_correction_factor), typeof(cache)}(positivity, - positivity_variables_cons, - positivity_correction_factor, - cache) + SubcellLimiterIDP{typeof(positivity_correction_factor), + typeof(cache)}(local_minmax, local_minmax_variables_cons_, + positivity, positivity_variables_cons_, + positivity_correction_factor, cache) end function Base.show(io::IO, limiter::SubcellLimiterIDP) @nospecialize limiter # reduce precompilation time - @unpack positivity = limiter + (; local_minmax, positivity) = limiter print(io, "SubcellLimiterIDP(") - if !(positivity) + if !(local_minmax || positivity) print(io, "No limiter selected => pure DG method") else print(io, "limiter=(") + local_minmax && print(io, "min/max limiting, ") positivity && print(io, "positivity") print(io, "), ") end + print(io, "Local bounds with FV solution") print(io, ")") end function Base.show(io::IO, ::MIME"text/plain", limiter::SubcellLimiterIDP) @nospecialize limiter # reduce precompilation time - @unpack positivity = limiter + (; local_minmax, positivity) = limiter if get(io, :compact, false) show(io, limiter) else - if !(positivity) + if !(local_minmax || positivity) setup = ["limiter" => "No limiter selected => pure DG method"] else setup = ["limiter" => ""] + if local_minmax + setup = [ + setup..., + "" => "local maximum/minimum bounds for conservative variables $(limiter.local_minmax_variables_cons)", + ] + end if positivity - string = "positivity with conservative variables $(limiter.positivity_variables_cons)" + string = "positivity for conservative variables $(limiter.positivity_variables_cons)" setup = [setup..., "" => string] setup = [ setup..., "" => " positivity correction factor = $(limiter.positivity_correction_factor)", ] end + setup = [ + setup..., + "Local bounds" => "FV solution", + ] end summary_box(io, "SubcellLimiterIDP", setup) end diff --git a/src/solvers/dgsem_tree/subcell_limiters_2d.jl b/src/solvers/dgsem_tree/subcell_limiters_2d.jl index 0a72b79ea3f..bc69e55f264 100644 --- a/src/solvers/dgsem_tree/subcell_limiters_2d.jl +++ b/src/solvers/dgsem_tree/subcell_limiters_2d.jl @@ -30,6 +30,10 @@ function (limiter::SubcellLimiterIDP)(u::AbstractArray{<:Any, 4}, semi, dg::DGSE @unpack alpha = limiter.cache.subcell_limiter_coefficients alpha .= zero(eltype(alpha)) + if limiter.local_minmax + @trixi_timeit timer() "local min/max limiting" idp_local_minmax!(alpha, limiter, + u, t, dt, semi) + end if limiter.positivity @trixi_timeit timer() "positivity" idp_positivity!(alpha, limiter, u, dt, semi) end @@ -52,6 +56,173 @@ function (limiter::SubcellLimiterIDP)(u::AbstractArray{<:Any, 4}, semi, dg::DGSE return nothing end +@inline function calc_bounds_twosided!(var_min, var_max, variable, u, t, semi) + mesh, equations, dg, cache = mesh_equations_solver_cache(semi) + # Calc bounds inside elements + @threaded for element in eachelement(dg, cache) + var_min[:, :, element] .= typemax(eltype(var_min)) + var_max[:, :, element] .= typemin(eltype(var_max)) + # Calculate bounds at Gauss-Lobatto nodes using u + for j in eachnode(dg), i in eachnode(dg) + var = u[variable, i, j, element] + var_min[i, j, element] = min(var_min[i, j, element], var) + var_max[i, j, element] = max(var_max[i, j, element], var) + + if i > 1 + var_min[i - 1, j, element] = min(var_min[i - 1, j, element], var) + var_max[i - 1, j, element] = max(var_max[i - 1, j, element], var) + end + if i < nnodes(dg) + var_min[i + 1, j, element] = min(var_min[i + 1, j, element], var) + var_max[i + 1, j, element] = max(var_max[i + 1, j, element], var) + end + if j > 1 + var_min[i, j - 1, element] = min(var_min[i, j - 1, element], var) + var_max[i, j - 1, element] = max(var_max[i, j - 1, element], var) + end + if j < nnodes(dg) + var_min[i, j + 1, element] = min(var_min[i, j + 1, element], var) + var_max[i, j + 1, element] = max(var_max[i, j + 1, element], var) + end + end + end + + # Values at element boundary + calc_bounds_twosided_interface!(var_min, var_max, variable, u, t, semi, mesh) +end + +@inline function calc_bounds_twosided_interface!(var_min, var_max, variable, u, t, semi, + mesh::TreeMesh2D) + _, equations, dg, cache = mesh_equations_solver_cache(semi) + (; boundary_conditions) = semi + # Calc bounds at interfaces and periodic boundaries + for interface in eachinterface(dg, cache) + # Get neighboring element ids + left = cache.interfaces.neighbor_ids[1, interface] + right = cache.interfaces.neighbor_ids[2, interface] + + orientation = cache.interfaces.orientations[interface] + + for i in eachnode(dg) + index_left = (nnodes(dg), i) + index_right = (1, i) + if orientation == 2 + index_left = reverse(index_left) + index_right = reverse(index_right) + end + var_left = u[variable, index_left..., left] + var_right = u[variable, index_right..., right] + + var_min[index_right..., right] = min(var_min[index_right..., right], + var_left) + var_max[index_right..., right] = max(var_max[index_right..., right], + var_left) + + var_min[index_left..., left] = min(var_min[index_left..., left], var_right) + var_max[index_left..., left] = max(var_max[index_left..., left], var_right) + end + end + + # Calc bounds at physical boundaries + for boundary in eachboundary(dg, cache) + element = cache.boundaries.neighbor_ids[boundary] + orientation = cache.boundaries.orientations[boundary] + neighbor_side = cache.boundaries.neighbor_sides[boundary] + + for i in eachnode(dg) + if neighbor_side == 2 # Element is on the right, boundary on the left + index = (1, i) + boundary_index = 1 + else # Element is on the left, boundary on the right + index = (nnodes(dg), i) + boundary_index = 2 + end + if orientation == 2 + index = reverse(index) + boundary_index += 2 + end + u_outer = get_boundary_outer_state(boundary_conditions[boundary_index], + cache, t, equations, dg, + index..., element) + var_outer = u_outer[variable] + + var_min[index..., element] = min(var_min[index..., element], var_outer) + var_max[index..., element] = max(var_max[index..., element], var_outer) + end + end + + return nothing +end + +@inline function idp_local_minmax!(alpha, limiter, u, t, dt, semi) + for variable in limiter.local_minmax_variables_cons + idp_local_minmax!(alpha, limiter, u, t, dt, semi, variable) + end + + return nothing +end + +@inline function idp_local_minmax!(alpha, limiter, u, t, dt, semi, variable) + _, _, dg, cache = mesh_equations_solver_cache(semi) + (; antidiffusive_flux1_L, antidiffusive_flux2_L, antidiffusive_flux1_R, antidiffusive_flux2_R) = cache.antidiffusive_fluxes + (; inverse_weights) = dg.basis + + (; variable_bounds) = limiter.cache.subcell_limiter_coefficients + variable_string = string(variable) + var_min = variable_bounds[Symbol(variable_string, "_min")] + var_max = variable_bounds[Symbol(variable_string, "_max")] + calc_bounds_twosided!(var_min, var_max, variable, u, t, semi) + + @threaded for element in eachelement(dg, semi.cache) + inverse_jacobian = cache.elements.inverse_jacobian[element] + for j in eachnode(dg), i in eachnode(dg) + var = u[variable, i, j, element] + # Real Zalesak type limiter + # * Zalesak (1979). "Fully multidimensional flux-corrected transport algorithms for fluids" + # * Kuzmin et al. (2010). "Failsafe flux limiting and constrained data projections for equations of gas dynamics" + # Note: The Zalesak limiter has to be computed, even if the state is valid, because the correction is + # for each interface, not each node + + Qp = max(0, (var_max[i, j, element] - var) / dt) + Qm = min(0, (var_min[i, j, element] - var) / dt) + + # Calculate Pp and Pm + # Note: Boundaries of antidiffusive_flux1/2 are constant 0, so they make no difference here. + val_flux1_local = inverse_weights[i] * + antidiffusive_flux1_R[variable, i, j, element] + val_flux1_local_ip1 = -inverse_weights[i] * + antidiffusive_flux1_L[variable, i + 1, j, element] + val_flux2_local = inverse_weights[j] * + antidiffusive_flux2_R[variable, i, j, element] + val_flux2_local_jp1 = -inverse_weights[j] * + antidiffusive_flux2_L[variable, i, j + 1, element] + + Pp = max(0, val_flux1_local) + max(0, val_flux1_local_ip1) + + max(0, val_flux2_local) + max(0, val_flux2_local_jp1) + Pm = min(0, val_flux1_local) + min(0, val_flux1_local_ip1) + + min(0, val_flux2_local) + min(0, val_flux2_local_jp1) + + Qp = max(0, (var_max[i, j, element] - var) / dt) + Qm = min(0, (var_min[i, j, element] - var) / dt) + + Pp = inverse_jacobian * Pp + Pm = inverse_jacobian * Pm + + # Compute blending coefficient avoiding division by zero + # (as in paper of [Guermond, Nazarov, Popov, Thomas] (4.8)) + Qp = abs(Qp) / + (abs(Pp) + eps(typeof(Qp)) * 100 * abs(var_max[i, j, element])) + Qm = abs(Qm) / + (abs(Pm) + eps(typeof(Qm)) * 100 * abs(var_max[i, j, element])) + + # Calculate alpha at nodes + alpha[i, j, element] = max(alpha[i, j, element], 1 - min(1, Qp, Qm)) + end + end + + return nothing +end + @inline function idp_positivity!(alpha, limiter, u, dt, semi) # Conservative variables for variable in limiter.positivity_variables_cons @@ -79,6 +250,13 @@ end end # Compute bound + if limiter.local_minmax && + variable in limiter.local_minmax_variables_cons && + var_min[i, j, element] >= positivity_correction_factor * var + # Local limiting is more restrictive that positivity limiting + # => Skip positivity limiting for this node + continue + end var_min[i, j, element] = positivity_correction_factor * var # Real one-sided Zalesak-type limiter diff --git a/test/test_tree_2d_euler.jl b/test/test_tree_2d_euler.jl index 4a1dc42772d..04a295537a3 100644 --- a/test/test_tree_2d_euler.jl +++ b/test/test_tree_2d_euler.jl @@ -313,6 +313,34 @@ end end end +@trixi_testset "elixir_euler_blast_wave_sc_subcell_nonperiodic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_blast_wave_sc_subcell_nonperiodic.jl"), + l2=[ + 0.3517507570120483, + 0.19252291020146015, + 0.19249751956580294, + 0.618717827188004, + ], + linf=[ + 1.6699566795772216, + 1.3608007992899402, + 1.361864507190922, + 2.44022884092527, + ], + tspan=(0.0, 0.5), + initial_refinement_level=4, + 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)) < 15000 + end +end + @trixi_testset "elixir_euler_sedov_blast_wave.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov_blast_wave.jl"), l2=[ @@ -339,6 +367,34 @@ end end end +@trixi_testset "elixir_euler_sedov_blast_wave_sc_subcell.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_sedov_blast_wave_sc_subcell.jl"), + l2=[ + 0.4328635350273501, + 0.15011135840723572, + 0.15011135840723572, + 0.616129927549474, + ], + linf=[ + 1.6145297181778906, + 0.8614006163026988, + 0.8614006163026972, + 6.450225090647602, + ], + tspan=(0.0, 1.0), + initial_refinement_level=4, + 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)) < 15000 + end +end + @trixi_testset "elixir_euler_sedov_blast_wave.jl (HLLE)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov_blast_wave.jl"), l2=[ diff --git a/test/test_tree_2d_eulermulti.jl b/test/test_tree_2d_eulermulti.jl index 2e808af6473..30d52b37b96 100644 --- a/test/test_tree_2d_eulermulti.jl +++ b/test/test_tree_2d_eulermulti.jl @@ -75,6 +75,35 @@ end end end +@trixi_testset "elixir_eulermulti_shock_bubble_shockcapturing_subcell_minmax.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_eulermulti_shock_bubble_shockcapturing_subcell_minmax.jl"), + l2=[ + 73.10832638093902, + 1.4599215762968585, + 57176.014861335476, + 0.17812843581838675, + 0.010123079422717837, + ], + linf=[ + 214.50568817511956, + 25.40392579616452, + 152862.41011222568, + 0.564195553101797, + 0.0956331651771212, + ], + initial_refinement_level=3, + tspan=(0.0, 0.001)) + # 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)) < 15000 + end +end + @trixi_testset "elixir_eulermulti_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_ec.jl"), l2=[ diff --git a/test/test_unit.jl b/test/test_unit.jl index 1d768c0df69..0c5f2bf0a4c 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -414,7 +414,7 @@ end indicator_hg = IndicatorHennemannGassner(1.0, 0.0, true, "variable", "cache") @test_nowarn show(stdout, indicator_hg) - limiter_idp = SubcellLimiterIDP(true, [1], 0.1, "cache") + limiter_idp = SubcellLimiterIDP(true, [1], true, [1], 0.1, "cache") @test_nowarn show(stdout, limiter_idp) # TODO: TrixiShallowWater: move unit test From 3f3ac9a9903759519992108357194a61117be3df Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Wed, 15 Nov 2023 22:55:34 +0100 Subject: [PATCH 176/263] HLLC Flux for Ideal MHD 1D (#1702) * start HLLC MHD 1D Cartesian * Continue HLLC * tests and format * remove ode diff eq and plots * Update src/equations/ideal_glm_mhd_1d.jl Co-authored-by: Hendrik Ranocha * Update src/equations/ideal_glm_mhd_1d.jl Co-authored-by: Hendrik Ranocha * comments * further 1d simplifications * label variables in hll flux comp * update test vals for updated ode * fmt --------- Co-authored-by: Hendrik Ranocha --- src/equations/ideal_glm_mhd_1d.jl | 142 ++++++++++++++++++++++++++++++ test/test_tree_1d_mhd.jl | 24 +++++ test/test_unit.jl | 1 + 3 files changed, 167 insertions(+) diff --git a/src/equations/ideal_glm_mhd_1d.jl b/src/equations/ideal_glm_mhd_1d.jl index 85030e8a5ad..a465571989b 100644 --- a/src/equations/ideal_glm_mhd_1d.jl +++ b/src/equations/ideal_glm_mhd_1d.jl @@ -259,6 +259,148 @@ Hindenlang and Gassner (2019), extending [`flux_ranocha`](@ref) to the MHD equat return SVector(f1, f2, f3, f4, f5, f6, f7, f8) end +""" + flux_hllc(u_ll, u_rr, orientation, equations::IdealGlmMhdEquations1D) + +- Li (2005) +An HLLC Riemann solver for magneto-hydrodynamics +[DOI: 10.1016/j.jcp.2004.08.020](https://doi.org/10.1016/j.jcp.2004.08.020). +""" +function flux_hllc(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdEquations1D) + # Unpack left and right states + rho_ll, v1_ll, v2_ll, v3_ll, p_ll, B1_ll, B2_ll, B3_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr, v3_rr, p_rr, B1_rr, B2_rr, B3_rr = cons2prim(u_rr, equations) + + # Conserved variables + rho_v1_ll = u_ll[2] + rho_v2_ll = u_ll[3] + rho_v3_ll = u_ll[4] + + rho_v1_rr = u_rr[2] + rho_v2_rr = u_rr[3] + rho_v3_rr = u_rr[4] + + # Obtain left and right fluxes + f_ll = flux(u_ll, orientation, equations) + f_rr = flux(u_rr, orientation, equations) + + SsL, SsR = min_max_speed_naive(u_ll, u_rr, orientation, equations) + sMu_L = SsL - v1_ll + sMu_R = SsR - v1_rr + if SsL >= 0 + f1 = f_ll[1] + f2 = f_ll[2] + f3 = f_ll[3] + f4 = f_ll[4] + f5 = f_ll[5] + f6 = f_ll[6] + f7 = f_ll[7] + f8 = f_ll[8] + elseif SsR <= 0 + f1 = f_rr[1] + f2 = f_rr[2] + f3 = f_rr[3] + f4 = f_rr[4] + f5 = f_rr[5] + f6 = f_rr[6] + f7 = f_rr[7] + f8 = f_rr[8] + else + # Compute the "HLLC-speed", eq. (14) from paper mentioned above + #= + SStar = (rho_rr * v1_rr * sMu_R - rho_ll * v1_ll * sMu_L + p_ll - p_rr - B1_ll^2 + B1_rr^2 ) / + (rho_rr * sMu_R - rho_ll * sMu_L) + =# + # Simplification for 1D: B1 is constant + SStar = (rho_rr * v1_rr * sMu_R - rho_ll * v1_ll * sMu_L + p_ll - p_rr) / + (rho_rr * sMu_R - rho_ll * sMu_L) + + Sdiff = SsR - SsL + + # Compute HLL values for vStar, BStar + # These correspond to eq. (28) and (30) from the referenced paper + # and the classic HLL intermediate state given by (2) + rho_HLL = (SsR * rho_rr - SsL * rho_ll - (f_rr[1] - f_ll[1])) / Sdiff + + v1Star = (SsR * rho_v1_rr - SsL * rho_v1_ll - (f_rr[2] - f_ll[2])) / + (Sdiff * rho_HLL) + v2Star = (SsR * rho_v2_rr - SsL * rho_v2_ll - (f_rr[3] - f_ll[3])) / + (Sdiff * rho_HLL) + v3Star = (SsR * rho_v3_rr - SsL * rho_v3_ll - (f_rr[4] - f_ll[4])) / + (Sdiff * rho_HLL) + + #B1Star = (SsR * B1_rr - SsL * B1_ll - (f_rr[6] - f_ll[6])) / Sdiff + # 1D B1 = constant => B1_ll = B1_rr = B1Star + B1Star = B1_ll + + B2Star = (SsR * B2_rr - SsL * B2_ll - (f_rr[7] - f_ll[7])) / Sdiff + B3Star = (SsR * B3_rr - SsL * B3_ll - (f_rr[8] - f_ll[8])) / Sdiff + if SsL <= SStar + SdiffStar = SsL - SStar + + densStar = rho_ll * sMu_L / SdiffStar # (19) + + mom_1_Star = densStar * SStar # (20) + mom_2_Star = densStar * v2_ll - + (B1Star * B2Star - B1_ll * B2_ll) / SdiffStar # (21) + mom_3_Star = densStar * v3_ll - + (B1Star * B3Star - B1_ll * B3_ll) / SdiffStar # (22) + + #pstar = rho_ll * sMu_L * (SStar - v1_ll) + p_ll - B1_ll^2 + B1Star^2 # (17) + # 1D B1 = constant => B1_ll = B1_rr = B1Star + pstar = rho_ll * sMu_L * (SStar - v1_ll) + p_ll # (17) + + enerStar = u_ll[5] * sMu_L / SdiffStar + + (pstar * SStar - p_ll * v1_ll - (B1Star * + (B1Star * v1Star + B2Star * v2Star + B3Star * v3Star) - + B1_ll * (B1_ll * v1_ll + B2_ll * v2_ll + B3_ll * v3_ll))) / + SdiffStar # (23) + + # Classic HLLC update (32) + f1 = f_ll[1] + SsL * (densStar - u_ll[1]) + f2 = f_ll[2] + SsL * (mom_1_Star - u_ll[2]) + f3 = f_ll[3] + SsL * (mom_2_Star - u_ll[3]) + f4 = f_ll[4] + SsL * (mom_3_Star - u_ll[4]) + f5 = f_ll[5] + SsL * (enerStar - u_ll[5]) + f6 = f_ll[6] + SsL * (B1Star - u_ll[6]) + f7 = f_ll[7] + SsL * (B2Star - u_ll[7]) + f8 = f_ll[8] + SsL * (B3Star - u_ll[8]) + else # SStar <= Ssr + SdiffStar = SsR - SStar + + densStar = rho_rr * sMu_R / SdiffStar # (19) + + mom_1_Star = densStar * SStar # (20) + mom_2_Star = densStar * v2_rr - + (B1Star * B2Star - B1_rr * B2_rr) / SdiffStar # (21) + mom_3_Star = densStar * v3_rr - + (B1Star * B3Star - B1_rr * B3_rr) / SdiffStar # (22) + + #pstar = rho_rr * sMu_R * (SStar - v1_rr) + p_rr - B1_rr^2 + B1Star^2 # (17) + # 1D B1 = constant => B1_ll = B1_rr = B1Star + pstar = rho_rr * sMu_R * (SStar - v1_rr) + p_rr # (17) + + enerStar = u_rr[5] * sMu_R / SdiffStar + + (pstar * SStar - p_rr * v1_rr - (B1Star * + (B1Star * v1Star + B2Star * v2Star + B3Star * v3Star) - + B1_rr * (B1_rr * v1_rr + B2_rr * v2_rr + B3_rr * v3_rr))) / + SdiffStar # (23) + + # Classic HLLC update (32) + f1 = f_rr[1] + SsR * (densStar - u_rr[1]) + f2 = f_rr[2] + SsR * (mom_1_Star - u_rr[2]) + f3 = f_rr[3] + SsR * (mom_2_Star - u_rr[3]) + f4 = f_rr[4] + SsR * (mom_3_Star - u_rr[4]) + f5 = f_rr[5] + SsR * (enerStar - u_rr[5]) + f6 = f_rr[6] + SsR * (B1Star - u_rr[6]) + f7 = f_rr[7] + SsR * (B2Star - u_rr[7]) + f8 = f_rr[8] + SsR * (B3Star - u_rr[8]) + end + end + return SVector(f1, f2, f3, f4, f5, f6, f7, f8) +end + # Calculate maximum wave speed for local Lax-Friedrichs-type dissipation @inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdEquations1D) diff --git a/test/test_tree_1d_mhd.jl b/test/test_tree_1d_mhd.jl index b34bdf0660c..447572eee88 100644 --- a/test/test_tree_1d_mhd.jl +++ b/test/test_tree_1d_mhd.jl @@ -206,6 +206,30 @@ end end end +@trixi_testset "elixir_mhd_torrilhon_shock_tube.jl (HLLC)" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_torrilhon_shock_tube.jl"), + surface_flux=flux_hllc, + l2=[ + 0.4574266553239646, 0.4794143154876439, 0.3407079689595056, + 0.44797768430829343, 0.9206916204424165, + 1.3216517820475193e-16, 0.2889748702415378, + 0.25529778018020927, + ], + linf=[ + 1.217943947570543, 0.8868438459815245, 0.878215340656725, + 0.9710882819266371, 1.6742759645320984, + 2.220446049250313e-16, 0.704710220504591, 0.6562122176458641, + ]) + # 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_mhd_ryujones_shock_tube.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ryujones_shock_tube.jl"), l2=[ diff --git a/test/test_unit.jl b/test/test_unit.jl index 0c5f2bf0a4c..aa7840ec7aa 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -958,6 +958,7 @@ end for u in u_values @test flux_hlle(u, u, 1, equations) ≈ flux(u, 1, equations) + @test flux_hllc(u, u, 1, equations) ≈ flux(u, 1, equations) end equations = IdealGlmMhdEquations2D(1.4, 5.0) #= c_h =# From 8bdd0cded6f4252e090e4349a604a0fd23edb0d6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 16 Nov 2023 15:45:44 +0100 Subject: [PATCH 177/263] CompatHelper: bump compat for Aqua to 0.8 for package test, (keep existing compat) (#1740) * CompatHelper: bump compat for Aqua to 0.8 for package test, (keep existing compat) * only v0.8 of Aqua.jl * update Aqua.jl keyword * format --------- Co-authored-by: CompatHelper Julia Co-authored-by: Hendrik Ranocha Co-authored-by: Hendrik Ranocha --- test/Project.toml | 2 +- test/test_aqua.jl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Project.toml b/test/Project.toml index fcb96b9e48f..ecae0ac0900 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -12,7 +12,7 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] -Aqua = "0.7" +Aqua = "0.8" CairoMakie = "0.6, 0.7, 0.8, 0.9, 0.10" Downloads = "1" ForwardDiff = "0.10" diff --git a/test/test_aqua.jl b/test/test_aqua.jl index 9f57791406f..93457caba28 100644 --- a/test/test_aqua.jl +++ b/test/test_aqua.jl @@ -11,8 +11,8 @@ include("test_trixi.jl") ambiguities = false, # exceptions necessary for adding a new method `StartUpDG.estimate_h` # in src/solvers/dgmulti/sbp.jl - piracy = (treat_as_own = [Trixi.StartUpDG.RefElemData, - Trixi.StartUpDG.MeshData],)) + piracies = (treat_as_own = [Trixi.StartUpDG.RefElemData, + Trixi.StartUpDG.MeshData],)) end end #module From c8e1f99dc52666cee2d5d8000d881e7f3dac60e0 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Fri, 17 Nov 2023 08:36:37 +0100 Subject: [PATCH 178/263] HLL Davis wave speeds & Cartesian Flux Winters for polytropic Euler (#1733) * hll_davis for polytropic euler * flux winters for tree and tests * fmt * typo * remove copied comment * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Andrew Winters * orientation_or_normal_direction * typo --------- Co-authored-by: Andrew Winters --- .../elixir_eulerpolytropic_convergence.jl | 63 +++++++++++ src/equations/polytropic_euler_2d.jl | 102 +++++++++++++++++- test/test_structured_2d.jl | 23 ++++ test/test_tree_2d_eulerpolytropic.jl | 35 ++++++ test/test_tree_2d_part2.jl | 3 + test/test_unit.jl | 48 +++++++++ 6 files changed, 272 insertions(+), 2 deletions(-) create mode 100644 examples/tree_2d_dgsem/elixir_eulerpolytropic_convergence.jl create mode 100644 test/test_tree_2d_eulerpolytropic.jl diff --git a/examples/tree_2d_dgsem/elixir_eulerpolytropic_convergence.jl b/examples/tree_2d_dgsem/elixir_eulerpolytropic_convergence.jl new file mode 100644 index 00000000000..95ef38eb701 --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_eulerpolytropic_convergence.jl @@ -0,0 +1,63 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the polytropic Euler equations + +gamma = 1.4 +kappa = 0.5 # Scaling factor for the pressure. +equations = PolytropicEulerEquations2D(gamma, kappa) + +initial_condition = initial_condition_convergence_test + +volume_flux = flux_winters_etal +solver = DGSEM(polydeg = 3, surface_flux = FluxHLL(min_max_speed_davis), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = (0.0, 0.0) +coordinates_max = (1.0, 1.0) + +# Create a uniformly refined mesh with periodic boundaries +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 2, + periodicity = true, + n_cells_max = 30_000) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_convergence_test) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.1) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:l2_error_primitive, + :linf_error_primitive)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 0.1) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + 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/src/equations/polytropic_euler_2d.jl b/src/equations/polytropic_euler_2d.jl index d4902bbafb2..f5d2f7b0bad 100644 --- a/src/equations/polytropic_euler_2d.jl +++ b/src/equations/polytropic_euler_2d.jl @@ -120,7 +120,7 @@ function initial_condition_weak_blast_wave(x, t, equations::PolytropicEulerEquat return prim2cons(SVector(rho, v1, v2), equations) end -# Calculate 1D flux for a single point in the normal direction +# Calculate 2D flux for a single point in the normal direction # Note, this directional vector is not normalized @inline function flux(u, normal_direction::AbstractVector, equations::PolytropicEulerEquations2D) @@ -135,8 +135,28 @@ end return SVector(f1, f2, f3) end +# Calculate 2D flux for a single point +@inline function flux(u, orientation::Integer, equations::PolytropicEulerEquations2D) + _, v1, v2 = cons2prim(u, equations) + p = pressure(u, equations) + + rho_v1 = u[2] + rho_v2 = u[3] + + if orientation == 1 + f1 = rho_v1 + f2 = rho_v1 * v1 + p + f3 = rho_v1 * v2 + else + f1 = rho_v2 + f2 = rho_v2 * v1 + f3 = rho_v2 * v2 + p + end + return SVector(f1, f2, f3) +end + """ - flux_winters_etal(u_ll, u_rr, normal_direction, + flux_winters_etal(u_ll, u_rr, orientation_or_normal_direction, equations::PolytropicEulerEquations2D) Entropy conserving two-point flux for isothermal or polytropic gases. @@ -178,6 +198,37 @@ For details see Section 3.2 of the following reference return SVector(f1, f2, f3) end +@inline function flux_winters_etal(u_ll, u_rr, orientation::Integer, + equations::PolytropicEulerEquations2D) + # Unpack left and right state + rho_ll, v1_ll, v2_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr = cons2prim(u_rr, equations) + p_ll = equations.kappa * rho_ll^equations.gamma + p_rr = equations.kappa * rho_rr^equations.gamma + + # Compute the necessary mean values + if equations.gamma == 1.0 # 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) + + if orientation == 1 # x-direction + f1 = rho_mean * 0.5 * (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) + f2 = f1 * v1_avg + f3 = f1 * v2_avg + p_avg + end + + return SVector(f1, f2, f3) +end + @inline function min_max_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, equations::PolytropicEulerEquations2D) rho_ll, v1_ll, v2_ll = cons2prim(u_ll, equations) @@ -196,6 +247,53 @@ end return lambda_min, lambda_max end +# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer, + equations::PolytropicEulerEquations2D) + rho_ll, v1_ll, v2_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr = cons2prim(u_rr, equations) + # Pressure for polytropic Euler + p_ll = equations.kappa * rho_ll^equations.gamma + p_rr = equations.kappa * rho_rr^equations.gamma + + c_ll = sqrt(equations.gamma * p_ll / rho_ll) + c_rr = sqrt(equations.gamma * p_rr / rho_rr) + + if orientation == 1 # x-direction + λ_min = min(v1_ll - c_ll, v1_rr - c_rr) + λ_max = max(v1_ll + c_ll, v1_rr + c_rr) + else # y-direction + λ_min = min(v2_ll - c_ll, v2_rr - c_rr) + λ_max = max(v2_ll + c_ll, v2_rr + c_rr) + end + + return λ_min, λ_max +end + +# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_davis(u_ll, u_rr, normal_direction::AbstractVector, + equations::PolytropicEulerEquations2D) + rho_ll, v1_ll, v2_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr = cons2prim(u_rr, equations) + # Pressure for polytropic Euler + p_ll = equations.kappa * rho_ll^equations.gamma + p_rr = equations.kappa * rho_rr^equations.gamma + + norm_ = norm(normal_direction) + + c_ll = sqrt(equations.gamma * p_ll / rho_ll) * norm_ + c_rr = sqrt(equations.gamma * p_rr / rho_rr) * norm_ + + v_normal_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] + v_normal_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] + + # The v_normals are already scaled by the norm + λ_min = min(v_normal_ll - c_ll, v_normal_rr - c_rr) + λ_max = max(v_normal_ll + c_ll, v_normal_rr + c_rr) + + return λ_min, λ_max +end + @inline function max_abs_speeds(u, equations::PolytropicEulerEquations2D) rho, v1, v2 = cons2prim(u, equations) c = sqrt(equations.gamma * equations.kappa * rho^(equations.gamma - 1)) diff --git a/test/test_structured_2d.jl b/test/test_structured_2d.jl index dd2248e10b2..17ba001d5ec 100644 --- a/test/test_structured_2d.jl +++ b/test/test_structured_2d.jl @@ -598,6 +598,29 @@ end end end +@trixi_testset "elixir_eulerpolytropic_convergence.jl: HLL(Davis)" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulerpolytropic_convergence.jl"), + solver=DGSEM(polydeg = 3, + surface_flux = FluxHLL(min_max_speed_davis), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)), + l2=[ + 0.0016689832177644243, 0.0025920263793104445, + 0.003281074494629298, + ], + linf=[ + 0.01099488320190023, 0.013309526619350365, + 0.02008032661117909, + ]) + # 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_eulerpolytropic_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulerpolytropic_ec.jl"), l2=[ diff --git a/test/test_tree_2d_eulerpolytropic.jl b/test/test_tree_2d_eulerpolytropic.jl new file mode 100644 index 00000000000..545cf7274ff --- /dev/null +++ b/test/test_tree_2d_eulerpolytropic.jl @@ -0,0 +1,35 @@ +module TestExamples2DEulerMulticomponent + +using Test +using Trixi + +include("test_trixi.jl") + +EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") + +@testset "Polytropic Euler" begin +#! format: noindent + +@trixi_testset "elixir_eulerpolytropic_convergence.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_eulerpolytropic_convergence.jl"), + l2=[ + 0.0016689832177626373, 0.0025920263793094526, + 0.003281074494626679, + ], + linf=[ + 0.010994883201896677, 0.013309526619350365, + 0.02008032661117376, + ]) + # 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 + +end # module diff --git a/test/test_tree_2d_part2.jl b/test/test_tree_2d_part2.jl index d8e86d14f18..622f12109ff 100644 --- a/test/test_tree_2d_part2.jl +++ b/test/test_tree_2d_part2.jl @@ -26,6 +26,9 @@ isdir(outdir) && rm(outdir, recursive = true) # Compressible Euler Multicomponent include("test_tree_2d_eulermulti.jl") + # Compressible Polytropic Euler + include("test_tree_2d_eulerpolytropic.jl") + # Compressible Euler coupled with acoustic perturbation equations include("test_tree_2d_euleracoustics.jl") diff --git a/test/test_unit.jl b/test/test_unit.jl index aa7840ec7aa..20368481607 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -782,6 +782,54 @@ end end end +@timed_testset "Consistency check for HLL flux with Davis wave speed estimates: Polytropic CEE" begin + flux_hll = FluxHLL(min_max_speed_davis) + + gamma = 1.4 + kappa = 0.5 # Scaling factor for the pressure. + equations = PolytropicEulerEquations2D(gamma, kappa) + u = SVector(1.1, -0.5, 2.34) + + orientations = [1, 2] + for orientation in orientations + @test flux_hll(u, u, orientation, equations) ≈ flux(u, orientation, equations) + end + + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + + for normal_direction in normal_directions + @test flux_hll(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) + end +end + +@timed_testset "Consistency check for Winters flux: Polytropic CEE" begin + for gamma in [1.4, 1.0, 5 / 3] + kappa = 0.5 # Scaling factor for the pressure. + equations = PolytropicEulerEquations2D(gamma, kappa) + u = SVector(1.1, -0.5, 2.34) + + orientations = [1, 2] + for orientation in orientations + @test flux_winters_etal(u, u, orientation, equations) ≈ + flux(u, orientation, equations) + end + + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + + for normal_direction in normal_directions + @test flux_winters_etal(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) + end + end +end + @timed_testset "Consistency check for HLL flux with Davis wave speed estimates: LEE" begin flux_hll = FluxHLL(min_max_speed_davis) From 4fecc09b927bc516258513a673882e6f8b446353 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 17 Nov 2023 09:47:31 +0100 Subject: [PATCH 179/263] set version to v0.6.1 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index da618dc78c1..e324de5fc77 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.6.1-pre" +version = "0.6.1" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 09bdf97df69f55075f853842a97fb2cc2faf703d Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 17 Nov 2023 09:47:49 +0100 Subject: [PATCH 180/263] set development version to v0.6.2-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index e324de5fc77..17c02a2adac 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.6.1" +version = "0.6.2-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 1635d318b2bf68f9da2bd9392e8ef782c7e562c6 Mon Sep 17 00:00:00 2001 From: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> Date: Sat, 18 Nov 2023 16:20:32 +0100 Subject: [PATCH 181/263] Throw error in `trixi_include` when assignment is not found (#1737) * Throw error in `trixi_include` when assignment is not found * Add tests for `trixi_include` * Reformat * Update test/test_unit.jl Co-authored-by: Michael Schlottke-Lakemper * Add more comments * Fix convergence tests and `trixi_include` with `skip_coverage` * Fix tests trying to override non-existing assignments * Add `maxiters` to restart elixirs and exclude for coverage tests * Reformat * Reformat * Add comment and more specific error in `convergence_test` * Update src/auxiliary/special_elixirs.jl Co-authored-by: Michael Schlottke-Lakemper * Update src/auxiliary/special_elixirs.jl Co-authored-by: Michael Schlottke-Lakemper * Fix tests * Use `@test_nowarn_mod` * Fix tests * Fix tests (again) --------- Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Hendrik Ranocha --- .../elixir_advection_restart.jl | 2 +- .../elixir_advection_restart.jl | 2 +- .../elixir_advection_restart.jl | 2 +- .../elixir_advection_restart.jl | 2 +- .../tree_2d_dgsem/elixir_advection_restart.jl | 2 +- .../tree_3d_dgsem/elixir_advection_restart.jl | 2 +- .../elixir_euler_restart.jl | 2 +- src/auxiliary/special_elixirs.jl | 47 +++++++-- test/test_mpi_p4est_2d.jl | 5 +- test/test_mpi_p4est_3d.jl | 5 +- test/test_p4est_2d.jl | 9 +- test/test_p4est_3d.jl | 9 +- test/test_special_elixirs.jl | 13 +-- test/test_structured_2d.jl | 15 ++- test/test_structured_3d.jl | 5 +- test/test_threaded.jl | 5 +- test/test_tree_3d_advection.jl | 5 +- test/test_trixi.jl | 2 +- test/test_unit.jl | 97 +++++++++++++++++++ test/test_unstructured_2d.jl | 5 +- test/test_visualization.jl | 5 +- 21 files changed, 196 insertions(+), 45 deletions(-) diff --git a/examples/p4est_2d_dgsem/elixir_advection_restart.jl b/examples/p4est_2d_dgsem/elixir_advection_restart.jl index 4f43e122ab3..0f573714c1f 100644 --- a/examples/p4est_2d_dgsem/elixir_advection_restart.jl +++ b/examples/p4est_2d_dgsem/elixir_advection_restart.jl @@ -31,7 +31,7 @@ save_solution.condition.save_initial_solution = false integrator = init(ode, CarpenterKennedy2N54(williamson_condition = false), dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep = false, callback = callbacks); + save_everystep = false, callback = callbacks, maxiters = 100_000); # Get the last time index and work with that. load_timestep!(integrator, restart_filename) diff --git a/examples/p4est_3d_dgsem/elixir_advection_restart.jl b/examples/p4est_3d_dgsem/elixir_advection_restart.jl index cd97d69d692..b3dead42399 100644 --- a/examples/p4est_3d_dgsem/elixir_advection_restart.jl +++ b/examples/p4est_3d_dgsem/elixir_advection_restart.jl @@ -29,7 +29,7 @@ save_solution.condition.save_initial_solution = false integrator = init(ode, CarpenterKennedy2N54(williamson_condition = false), dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep = false, callback = callbacks); + save_everystep = false, callback = callbacks, maxiters = 100_000); # Get the last time index and work with that. load_timestep!(integrator, restart_filename) diff --git a/examples/structured_2d_dgsem/elixir_advection_restart.jl b/examples/structured_2d_dgsem/elixir_advection_restart.jl index 19863faae8d..0accbdba702 100644 --- a/examples/structured_2d_dgsem/elixir_advection_restart.jl +++ b/examples/structured_2d_dgsem/elixir_advection_restart.jl @@ -30,7 +30,7 @@ save_solution.condition.save_initial_solution = false integrator = init(ode, CarpenterKennedy2N54(williamson_condition = false), dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep = false, callback = callbacks); + save_everystep = false, callback = callbacks, maxiters = 100_000); # Get the last time index and work with that. load_timestep!(integrator, restart_filename) diff --git a/examples/structured_3d_dgsem/elixir_advection_restart.jl b/examples/structured_3d_dgsem/elixir_advection_restart.jl index e81ad5d6430..e516d794df8 100644 --- a/examples/structured_3d_dgsem/elixir_advection_restart.jl +++ b/examples/structured_3d_dgsem/elixir_advection_restart.jl @@ -29,7 +29,7 @@ save_solution.condition.save_initial_solution = false integrator = init(ode, CarpenterKennedy2N54(williamson_condition = false), dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep = false, callback = callbacks); + save_everystep = false, callback = callbacks, maxiters = 100_000); # Get the last time index and work with that. load_timestep!(integrator, restart_filename) diff --git a/examples/tree_2d_dgsem/elixir_advection_restart.jl b/examples/tree_2d_dgsem/elixir_advection_restart.jl index 770629bb15e..e0d1003f524 100644 --- a/examples/tree_2d_dgsem/elixir_advection_restart.jl +++ b/examples/tree_2d_dgsem/elixir_advection_restart.jl @@ -29,7 +29,7 @@ save_solution.condition.save_initial_solution = false integrator = init(ode, alg, dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep = false, callback = callbacks; ode_default_options()...) + callback = callbacks, maxiters = 100_000; ode_default_options()...) # Load saved context for adaptive time integrator if integrator.opts.adaptive diff --git a/examples/tree_3d_dgsem/elixir_advection_restart.jl b/examples/tree_3d_dgsem/elixir_advection_restart.jl index f81e013fc0a..a53f4ebf5b1 100644 --- a/examples/tree_3d_dgsem/elixir_advection_restart.jl +++ b/examples/tree_3d_dgsem/elixir_advection_restart.jl @@ -27,7 +27,7 @@ save_solution.condition.save_initial_solution = false integrator = init(ode, CarpenterKennedy2N54(williamson_condition = false), dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep = false, callback = callbacks); + save_everystep = false, callback = callbacks, maxiters = 100_000); # Get the last time index and work with that. load_timestep!(integrator, restart_filename) diff --git a/examples/unstructured_2d_dgsem/elixir_euler_restart.jl b/examples/unstructured_2d_dgsem/elixir_euler_restart.jl index 4d6af65b8a4..c1908691902 100644 --- a/examples/unstructured_2d_dgsem/elixir_euler_restart.jl +++ b/examples/unstructured_2d_dgsem/elixir_euler_restart.jl @@ -29,7 +29,7 @@ save_solution.condition.save_initial_solution = false integrator = init(ode, CarpenterKennedy2N54(williamson_condition = false), dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep = false, callback = callbacks); + save_everystep = false, callback = callbacks, maxiters = 100_000); # Get the last time index and work with that. load_timestep!(integrator, restart_filename) diff --git a/src/auxiliary/special_elixirs.jl b/src/auxiliary/special_elixirs.jl index 25bca8939ce..5fdd9aea0c5 100644 --- a/src/auxiliary/special_elixirs.jl +++ b/src/auxiliary/special_elixirs.jl @@ -20,7 +20,7 @@ providing examples with sensible default values for users. Before replacing assignments in `elixir`, the keyword argument `maxiters` is inserted into calls to `solve` and `Trixi.solve` with it's default value used in the SciML ecosystem -for ODEs, see the "Miscellaneous" section of the +for ODEs, see the "Miscellaneous" section of the [documentation](https://docs.sciml.ai/DiffEqDocs/stable/basics/common_solver_opts/). # Examples @@ -36,6 +36,16 @@ julia> redirect_stdout(devnull) do ``` """ function trixi_include(mod::Module, elixir::AbstractString; kwargs...) + # Check that all kwargs exist as assignments + code = read(elixir, String) + expr = Meta.parse("begin \n$code \nend") + expr = insert_maxiters(expr) + + for (key, val) in kwargs + # This will throw an error when `key` is not found + find_assignment(expr, key) + end + # Print information on potential wait time only in non-parallel case if !mpi_isparallel() @info "You just called `trixi_include`. Julia may now compile the code, please be patient." @@ -243,6 +253,7 @@ end function find_assignment(expr, destination) # declare result to be able to assign to it in the closure local result + found = false # find explicit and keyword assignments walkexpr(expr) do x @@ -250,12 +261,17 @@ function find_assignment(expr, destination) if (x.head === Symbol("=") || x.head === :kw) && x.args[1] === Symbol(destination) result = x.args[2] + found = true # dump(x) end end return x end + if !found + throw(ArgumentError("assignment `$destination` not found in expression")) + end + result end @@ -274,17 +290,28 @@ function extract_initial_resolution(elixir, kwargs) return initial_refinement_level end catch e - if isa(e, UndefVarError) - # get cells_per_dimension from the elixir - cells_per_dimension = eval(find_assignment(expr, :cells_per_dimension)) - - if haskey(kwargs, :cells_per_dimension) - return kwargs[:cells_per_dimension] - else - return cells_per_dimension + # If `initial_refinement_level` is not found, we will get an `ArgumentError` + if isa(e, ArgumentError) + try + # get cells_per_dimension from the elixir + cells_per_dimension = eval(find_assignment(expr, :cells_per_dimension)) + + if haskey(kwargs, :cells_per_dimension) + return kwargs[:cells_per_dimension] + else + return cells_per_dimension + end + catch e2 + # If `cells_per_dimension` is not found either + if isa(e2, ArgumentError) + throw(ArgumentError("`convergence_test` requires the elixir to define " * + "`initial_refinement_level` or `cells_per_dimension`")) + else + rethrow() + end end else - throw(e) + rethrow() end end end diff --git a/test/test_mpi_p4est_2d.jl b/test/test_mpi_p4est_2d.jl index 1edbce8f6c8..da90537fcfd 100644 --- a/test/test_mpi_p4est_2d.jl +++ b/test/test_mpi_p4est_2d.jl @@ -69,7 +69,10 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_2d_dgsem") @trixi_testset "elixir_advection_restart.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), l2=[4.507575525876275e-6], - linf=[6.21489667023134e-5]) + linf=[6.21489667023134e-5], + # With the default `maxiters = 1` in coverage tests, + # there would be no time steps after the restart. + coverage_override=(maxiters = 100_000,)) end @trixi_testset "elixir_euler_source_terms_nonconforming_unstructured_flag.jl" begin diff --git a/test/test_mpi_p4est_3d.jl b/test/test_mpi_p4est_3d.jl index 8082930b3b4..75f43650082 100644 --- a/test/test_mpi_p4est_3d.jl +++ b/test/test_mpi_p4est_3d.jl @@ -63,7 +63,10 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_3d_dgsem") @trixi_testset "elixir_advection_restart.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), l2=[0.002590388934758452], - linf=[0.01840757696885409]) + linf=[0.01840757696885409], + # With the default `maxiters = 1` in coverage tests, + # there would be no time steps after the restart. + coverage_override=(maxiters = 100_000,)) end @trixi_testset "elixir_advection_cubed_sphere.jl" begin diff --git a/test/test_p4est_2d.jl b/test/test_p4est_2d.jl index 07c6d02bbcd..db34aecc168 100644 --- a/test/test_p4est_2d.jl +++ b/test/test_p4est_2d.jl @@ -94,7 +94,10 @@ end @trixi_testset "elixir_advection_restart.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), l2=[4.507575525876275e-6], - linf=[6.21489667023134e-5]) + linf=[6.21489667023134e-5], + # With the default `maxiters = 1` in coverage tests, + # there would be no time steps after the restart. + coverage_override=(maxiters = 100_000,)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let @@ -216,8 +219,8 @@ end ], surface_flux=flux_hlle, tspan=(0.0, 0.3)) - # Ensure that we do not have excessive memory allocations - # (e.g., from type instabilities) + # Ensure that we do not have excessive memory allocations + # (e.g., from type instabilities) let t = sol.t[end] u_ode = sol.u[end] diff --git a/test/test_p4est_3d.jl b/test/test_p4est_3d.jl index 346c61c7448..f2467f30204 100644 --- a/test/test_p4est_3d.jl +++ b/test/test_p4est_3d.jl @@ -110,7 +110,10 @@ end @trixi_testset "elixir_advection_restart.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), l2=[0.002590388934758452], - linf=[0.01840757696885409]) + linf=[0.01840757696885409], + # With the default `maxiters = 1` in coverage tests, + # there would be no time steps after the restart. + coverage_override=(maxiters = 100_000,)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let @@ -305,8 +308,8 @@ end ], tspan=(0.0, 0.3), surface_flux=flux_hlle) - # Ensure that we do not have excessive memory allocations - # (e.g., from type instabilities) + # Ensure that we do not have excessive memory allocations + # (e.g., from type instabilities) let t = sol.t[end] u_ode = sol.u[end] diff --git a/test/test_special_elixirs.jl b/test/test_special_elixirs.jl index 85671002ba6..ba670a6025e 100644 --- a/test/test_special_elixirs.jl +++ b/test/test_special_elixirs.jl @@ -92,8 +92,7 @@ coverage = occursin("--code-coverage", cmd) && !occursin("--code-coverage=none", # the convergence test logic @test_nowarn_mod convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_2d_dgsem", - "elixir_advection_basic.jl"), 2, - tspan = (0.0, 0.01)) + "elixir_advection_basic.jl"), 2) @test_nowarn_mod convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "tree_2d_dgsem", "elixir_advection_extended.jl"), 2, @@ -101,12 +100,10 @@ coverage = occursin("--code-coverage", cmd) && !occursin("--code-coverage=none", tspan = (0.0, 0.1)) @test_nowarn_mod convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "structured_2d_dgsem", - "elixir_advection_basic.jl"), 2, - tspan = (0.0, 0.01)) + "elixir_advection_basic.jl"), 2) @test_nowarn_mod convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "structured_2d_dgsem", - "elixir_advection_coupled.jl"), 2, - tspan = (0.0, 0.01)) + "elixir_advection_coupled.jl"), 2) @test_nowarn_mod convergence_test(@__MODULE__, joinpath(EXAMPLES_DIR, "structured_2d_dgsem", "elixir_advection_extended.jl"), 2, @@ -345,8 +342,8 @@ end end @timed_testset "elixir_euler_ad.jl" begin - @test_trixi_include(joinpath(examples_dir(), "special_elixirs", - "elixir_euler_ad.jl")) + @test_nowarn_mod trixi_include(joinpath(examples_dir(), "special_elixirs", + "elixir_euler_ad.jl")) end end end diff --git a/test/test_structured_2d.jl b/test/test_structured_2d.jl index 17ba001d5ec..96202e00f58 100644 --- a/test/test_structured_2d.jl +++ b/test/test_structured_2d.jl @@ -194,7 +194,10 @@ end @trixi_testset "elixir_advection_restart.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), l2=[4.219208035582454e-6], - linf=[3.438434404412494e-5]) + linf=[3.438434404412494e-5], + # With the default `maxiters = 1` in coverage tests, + # there would be no time steps after the restart. + coverage_override=(maxiters = 100_000,)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let @@ -211,7 +214,10 @@ end linf=[0.0015194252169410394], rtol=5.0e-5, # Higher tolerance to make tests pass in CI (in particular with macOS) elixir_file="elixir_advection_waving_flag.jl", - restart_file="restart_000021.h5") + restart_file="restart_000021.h5", + # With the default `maxiters = 1` in coverage tests, + # there would be no time steps after the restart. + coverage_override=(maxiters = 100_000,)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let @@ -227,7 +233,10 @@ end l2=[7.841217436552029e-15], linf=[1.0857981180834031e-13], elixir_file="elixir_advection_free_stream.jl", - restart_file="restart_000036.h5") + restart_file="restart_000036.h5", + # With the default `maxiters = 1` in coverage tests, + # there would be no time steps after the restart. + coverage_override=(maxiters = 100_000,)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let diff --git a/test/test_structured_3d.jl b/test/test_structured_3d.jl index 0213e1a9813..a52c459d6be 100644 --- a/test/test_structured_3d.jl +++ b/test/test_structured_3d.jl @@ -62,7 +62,10 @@ end @trixi_testset "elixir_advection_restart.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), l2=[0.0025903889347585777], - linf=[0.018407576968841655]) + linf=[0.018407576968841655], + # With the default `maxiters = 1` in coverage tests, + # there would be no time steps after the restart. + coverage_override=(maxiters = 100_000,)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let diff --git a/test/test_threaded.jl b/test/test_threaded.jl index 478c90b476a..dbbcbf4c7ce 100644 --- a/test/test_threaded.jl +++ b/test/test_threaded.jl @@ -208,7 +208,10 @@ end linf=[0.0015194252169410394], rtol=5.0e-5, # Higher tolerance to make tests pass in CI (in particular with macOS) elixir_file="elixir_advection_waving_flag.jl", - restart_file="restart_000021.h5") + restart_file="restart_000021.h5", + # With the default `maxiters = 1` in coverage tests, + # there would be no time steps after the restart. + coverage_override=(maxiters = 100_000,)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) diff --git a/test/test_tree_3d_advection.jl b/test/test_tree_3d_advection.jl index 56278629417..ae53a2df52f 100644 --- a/test/test_tree_3d_advection.jl +++ b/test/test_tree_3d_advection.jl @@ -27,7 +27,10 @@ end @trixi_testset "elixir_advection_restart.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"), l2=[0.00016017848135651983], - linf=[0.0014175368788298393]) + linf=[0.0014175368788298393], + # With the default `maxiters = 1` in coverage tests, + # there would be no time steps after the restart. + coverage_override=(maxiters = 100_000,)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let diff --git a/test/test_trixi.jl b/test/test_trixi.jl index 245efbc0175..cebe2164ae6 100644 --- a/test/test_trixi.jl +++ b/test/test_trixi.jl @@ -33,7 +33,7 @@ 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)) + !(arg.args[1] in (:l2, :linf, :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_unit.jl b/test/test_unit.jl index 20368481607..7f774e11d3b 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1374,6 +1374,103 @@ end @test mesh.boundary_faces[:entire_boundary] == [1, 2] end + +@testset "trixi_include" begin + @trixi_testset "Basic" begin + example = """ + x = 4 + """ + + filename = tempname() + try + open(filename, "w") do file + write(file, example) + end + + # Use `@trixi_testset`, which wraps code in a temporary module, and call + # `trixi_include` with `@__MODULE__` in order to isolate this test. + @test_warn "You just called" trixi_include(@__MODULE__, filename) + @test @isdefined x + @test x == 4 + + @test_warn "You just called" trixi_include(@__MODULE__, filename, x = 7) + @test x == 7 + + @test_throws "assignment `y` not found in expression" trixi_include(@__MODULE__, + filename, + y = 3) + finally + rm(filename, force = true) + end + end + + @trixi_testset "With `solve` Without `maxiters`" begin + # `trixi_include` assumes this to be the `solve` function of OrdinaryDiffEq, + # and therefore tries to insert the kwarg `maxiters`, which will fail here. + example = """ + solve() = 0 + x = solve() + """ + + filename = tempname() + try + open(filename, "w") do file + write(file, example) + end + + # Use `@trixi_testset`, which wraps code in a temporary module, and call + # `trixi_include` with `@__MODULE__` in order to isolate this test. + @test_throws "no method matching solve(; maxiters::Int64)" trixi_include(@__MODULE__, + filename) + + @test_throws "no method matching solve(; maxiters::Int64)" trixi_include(@__MODULE__, + filename, + maxiters = 3) + finally + rm(filename, force = true) + end + end + + @trixi_testset "With `solve` with `maxiters`" begin + # We need another example file that we include with `Base.include` first, in order to + # define the `solve` method without `trixi_include` trying to insert `maxiters` kwargs. + # Then, we can test that `trixi_include` inserts the kwarg in the `solve()` call. + example1 = """ + solve(; maxiters=0) = maxiters + """ + + example2 = """ + x = solve() + """ + + filename1 = tempname() + filename2 = tempname() + try + open(filename1, "w") do file + write(file, example1) + end + open(filename2, "w") do file + write(file, example2) + end + + # Use `@trixi_testset`, which wraps code in a temporary module, and call + # `Base.include` and `trixi_include` with `@__MODULE__` in order to isolate this test. + Base.include(@__MODULE__, filename1) + @test_warn "You just called" trixi_include(@__MODULE__, filename2) + @test @isdefined x + # This is the default `maxiters` inserted by `trixi_include` + @test x == 10^5 + + @test_warn "You just called" trixi_include(@__MODULE__, filename2, + maxiters = 7) + # Test that `maxiters` got overwritten + @test x == 7 + finally + rm(filename1, force = true) + rm(filename2, force = true) + end + end +end end end #module diff --git a/test/test_unstructured_2d.jl b/test/test_unstructured_2d.jl index d4416ac5b6a..5341d86a7d1 100644 --- a/test/test_unstructured_2d.jl +++ b/test/test_unstructured_2d.jl @@ -129,7 +129,10 @@ end 0.005243995459478956, 0.004685630332338153, 0.01750217718347713, - ]) + ], + # With the default `maxiters = 1` in coverage tests, + # there would be no time steps after the restart. + coverage_override=(maxiters = 100_000,)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let diff --git a/test/test_visualization.jl b/test/test_visualization.jl index 48164a70fb3..6444dc91d5d 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -243,7 +243,6 @@ end @test_nowarn_mod trixi_include(@__MODULE__, joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_basic.jl"), - tspan = (0, 0.1), analysis_callback = Trixi.TrivialCallback()) @test adapt_to_mesh_level(sol, 5) isa Tuple @@ -259,7 +258,6 @@ end @test_nowarn_mod trixi_include(@__MODULE__, joinpath(examples_dir(), "tree_3d_dgsem", "elixir_advection_basic.jl"), - tspan = (0, 0.1), analysis_callback = Trixi.TrivialCallback(), initial_refinement_level = 1) @test PlotData2D(sol) isa Trixi.PlotData2DCartesian @@ -288,8 +286,7 @@ end @test_nowarn_mod trixi_include(@__MODULE__, joinpath(examples_dir(), "structured_3d_dgsem", - "elixir_advection_basic.jl"), - tspan = (0, 0.1)) + "elixir_advection_basic.jl")) @testset "1D plot from 3D solution and general mesh" begin @testset "Create 1D plot as slice" begin From eb0478b682e6dd3ca3eccea34af1322d1873a129 Mon Sep 17 00:00:00 2001 From: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Date: Tue, 21 Nov 2023 07:29:13 +0100 Subject: [PATCH 182/263] Initialize p4est and t8code only if possible (#1745) * initialize p4est and t8code only if possible * format * add warning if p4est/t8code are not usable --- Project.toml | 4 +-- src/auxiliary/p4est.jl | 18 ++++++++----- src/auxiliary/t8code.jl | 56 +++++++++++++++++++++++------------------ 3 files changed, 45 insertions(+), 33 deletions(-) diff --git a/Project.toml b/Project.toml index 17c02a2adac..4b7b69af93b 100644 --- a/Project.toml +++ b/Project.toml @@ -66,7 +66,7 @@ Makie = "0.19" MuladdMacro = "0.2.2" Octavian = "0.3.5" OffsetArrays = "1.3" -P4est = "0.4" +P4est = "0.4.9" Polyester = "0.7.5" PrecompileTools = "1.1" Printf = "1" @@ -84,7 +84,7 @@ StaticArrays = "1" StrideArrays = "0.1.18" StructArrays = "0.6" SummationByPartsOperators = "0.5.41" -T8code = "0.4.1" +T8code = "0.4.3" TimerOutputs = "0.5" Triangulate = "2.0" TriplotBase = "0.1" diff --git a/src/auxiliary/p4est.jl b/src/auxiliary/p4est.jl index 968af339cbd..0b826254129 100644 --- a/src/auxiliary/p4est.jl +++ b/src/auxiliary/p4est.jl @@ -13,14 +13,20 @@ This function will check if `p4est` is already initialized and if yes, do nothing, thus it is safe to call it multiple times. """ function init_p4est() - p4est_package_id = P4est.package_id() - if p4est_package_id >= 0 - return nothing + # Only initialize p4est if P4est.jl can be used + if P4est.preferences_set_correctly() + p4est_package_id = P4est.package_id() + if p4est_package_id >= 0 + return nothing + end + + # Initialize `p4est` with log level ERROR to prevent a lot of output in AMR simulations + p4est_init(C_NULL, SC_LP_ERROR) + else + @warn "Preferences for P4est.jl are not set correctly. Until fixed, using `P4estMesh` will result in a crash. " * + "See also https://trixi-framework.github.io/Trixi.jl/stable/parallelization/#parallel_system_MPI" end - # Initialize `p4est` with log level ERROR to prevent a lot of output in AMR simulations - p4est_init(C_NULL, SC_LP_ERROR) - return nothing end diff --git a/src/auxiliary/t8code.jl b/src/auxiliary/t8code.jl index 37cb782bb93..bd781b21c1e 100644 --- a/src/auxiliary/t8code.jl +++ b/src/auxiliary/t8code.jl @@ -7,34 +7,40 @@ is already initialized and if yes, do nothing, thus it is safe to call it multiple times. """ function init_t8code() - t8code_package_id = t8_get_package_id() - if t8code_package_id >= 0 - return nothing - end + # Only initialize t8code if T8code.jl can be used + if T8code.preferences_set_correctly() + t8code_package_id = t8_get_package_id() + if t8code_package_id >= 0 + return nothing + end - # Initialize the sc library, has to happen before we initialize t8code. - let catch_signals = 0, print_backtrace = 0, log_handler = C_NULL - T8code.Libt8.sc_init(mpi_comm(), catch_signals, print_backtrace, log_handler, - T8code.Libt8.SC_LP_ERROR) - end + # Initialize the sc library, has to happen before we initialize t8code. + let catch_signals = 0, print_backtrace = 0, log_handler = C_NULL + T8code.Libt8.sc_init(mpi_comm(), catch_signals, print_backtrace, log_handler, + T8code.Libt8.SC_LP_ERROR) + end - if T8code.Libt8.p4est_is_initialized() == 0 - # Initialize `p4est` with log level ERROR to prevent a lot of output in AMR simulations - T8code.Libt8.p4est_init(C_NULL, T8code.Libt8.SC_LP_ERROR) - end + if T8code.Libt8.p4est_is_initialized() == 0 + # Initialize `p4est` with log level ERROR to prevent a lot of output in AMR simulations + T8code.Libt8.p4est_init(C_NULL, T8code.Libt8.SC_LP_ERROR) + end - # Initialize t8code with log level ERROR to prevent a lot of output in AMR simulations. - t8_init(T8code.Libt8.SC_LP_ERROR) - - if haskey(ENV, "TRIXI_T8CODE_SC_FINALIZE") - # Normally, `sc_finalize` should always be called during shutdown of an - # application. It checks whether there is still un-freed memory by t8code - # and/or T8code.jl and throws an exception if this is the case. For - # production runs this is not mandatory, but is helpful during - # development. Hence, this option is only activated when environment - # variable TRIXI_T8CODE_SC_FINALIZE exists. - @warn "T8code.jl: sc_finalize will be called during shutdown of Trixi.jl." - MPI.add_finalize_hook!(T8code.Libt8.sc_finalize) + # Initialize t8code with log level ERROR to prevent a lot of output in AMR simulations. + t8_init(T8code.Libt8.SC_LP_ERROR) + + if haskey(ENV, "TRIXI_T8CODE_SC_FINALIZE") + # Normally, `sc_finalize` should always be called during shutdown of an + # application. It checks whether there is still un-freed memory by t8code + # and/or T8code.jl and throws an exception if this is the case. For + # production runs this is not mandatory, but is helpful during + # development. Hence, this option is only activated when environment + # variable TRIXI_T8CODE_SC_FINALIZE exists. + @warn "T8code.jl: sc_finalize will be called during shutdown of Trixi.jl." + MPI.add_finalize_hook!(T8code.Libt8.sc_finalize) + end + else + @warn "Preferences for T8code.jl are not set correctly. Until fixed, using `T8codeMesh` will result in a crash. " * + "See also https://trixi-framework.github.io/Trixi.jl/stable/parallelization/#parallel_system_MPI" end return nothing From 9317f7c5e0dacd0c704913239b2bc06ecb140343 Mon Sep 17 00:00:00 2001 From: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Date: Tue, 21 Nov 2023 07:29:43 +0100 Subject: [PATCH 183/263] Update docs on system-provided MPI including HDF5 (#1706) * update docs on system-provided MPI including HDF5 * fix typo * Apply suggestions from code review Co-authored-by: Michael Schlottke-Lakemper * put LocalPreferences.toml in code font * add notes when which preferences need to be set * T8codeMesh does not support MPI yet --------- Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Hendrik Ranocha --- docs/src/parallelization.md | 67 ++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/docs/src/parallelization.md b/docs/src/parallelization.md index fa6fc1a5d32..3cce7c381b2 100644 --- a/docs/src/parallelization.md +++ b/docs/src/parallelization.md @@ -53,30 +53,43 @@ a system-provided MPI installation with Trixi.jl can be found in the following s ### [Using a system-provided MPI installation](@id parallel_system_MPI) -When using Trixi.jl with a system-provided MPI backend the underlying -[`p4est`](https://github.com/cburstedde/p4est) and [`t8code`](https://github.com/DLR-AMR/t8code) -libraries need to be compiled with the same MPI installation. Therefore, you also need to -use system-provided `p4est` and `t8code` installations (for notes on how to install `p4est` -and `t8code` see e.g. [here](https://github.com/cburstedde/p4est/blob/master/README) and -[here](https://github.com/DLR-AMR/t8code/wiki/Installation), use the configure option -`--enable-mpi`). Note that `t8code` already comes with a `p4est` installation, so it suffices -to install `t8code`. In addition, [P4est.jl](https://github.com/trixi-framework/P4est.jl) and -[T8code.jl](https://github.com/DLR-AMR/T8code.jl) need to be configured to use the custom -installations. Follow the steps described -[here](https://github.com/DLR-AMR/T8code.jl/blob/main/README.md#installation) and -[here](https://github.com/trixi-framework/P4est.jl/blob/main/README.md#installation) for the -configuration. The paths that point to `libp4est.so` (and potentially to `libsc.so`) need to be -the same for P4est.jl and T8code.jl. This could e.g. be `libp4est.so` that usually can be found -in `lib/` or `local/lib/` in the installation directory of `t8code`. -In total, in your active Julia project you should have a LocalPreferences.toml file with sections -`[MPIPreferences]`, `[T8code]` and `[P4est]` as well as an entry `MPIPreferences` in your -Project.toml to use a custom MPI installation. A `LocalPreferences.toml` file +When using Trixi.jl with a system-provided MPI backend, the underlying +[`p4est`](https://github.com/cburstedde/p4est), [`t8code`](https://github.com/DLR-AMR/t8code) +and [`HDF5`](https://github.com/HDFGroup/hdf5) libraries need to be compiled with the same MPI +installation. If you want to use `p4est` (via the `P4estMesh`) or `t8code` (via the `T8codeMesh`) +from Trixi.jl, you also need to use system-provided `p4est` or `t8code` installations +(for notes on how to install `p4est` and `t8code` see, e.g., [here](https://github.com/cburstedde/p4est/blob/master/README) +and [here](https://github.com/DLR-AMR/t8code/wiki/Installation), use the configure option +`--enable-mpi`). Otherwise, there will be warnings that no preference is set for P4est.jl and +T8code.jl that can be ignored if you do not use these libraries from Trixi.jl. Note that +`t8code` already comes with a `p4est` installation, so it suffices to install `t8code`. +In order to use system-provided `p4est` and `t8code` installations, [P4est.jl](https://github.com/trixi-framework/P4est.jl) +and [T8code.jl](https://github.com/DLR-AMR/T8code.jl) need to be configured to use the custom +installations. Follow the steps described [here](https://github.com/DLR-AMR/T8code.jl/blob/main/README.md#installation) and +[here](https://github.com/trixi-framework/P4est.jl/blob/main/README.md#installation). +for the configuration. The paths that point to `libp4est.so` (and potentially to `libsc.so`) need to be +the same for P4est.jl and T8code.jl. This could, e.g., be `libp4est.so` that usually can be found +in `lib/` or `local/lib/` in the installation directory of `t8code`. Note that the `T8codeMesh`, however, +does not support MPI yet. +The preferences for [HDF5.jl](https://github.com/JuliaIO/HDF5.jl) always need to be set, even if you +do not want to use `HDF5` from Trixi.jl, see also https://github.com/JuliaIO/HDF5.jl/issues/1079. +To set the preferences for HDF5.jl, follow the instructions described +[here](https://trixi-framework.github.io/Trixi.jl/stable/parallelization/#Using-parallel-input-and-output). + +In total, in your active Julia project you should have a `LocalPreferences.toml` file with sections +`[MPIPreferences]`, `[T8code]` (only needed if `T8codeMesh` is used), `[P4est]` (only needed if +`P4estMesh` is used), and `[HDF5]` as well as an entry `MPIPreferences` in your +`Project.toml` to use a custom MPI installation. A `LocalPreferences.toml` file created as described above might look something like the following: ```toml [HDF5] libhdf5 = "/usr/lib/x86_64-linux-gnu/hdf5/openmpi/libhdf5.so" libhdf5_hl = "/usr/lib/x86_64-linux-gnu/hdf5/openmpi/libhdf5_hl.so" +[HDF5_jll] +libhdf5_hl_path = "/usr/lib/x86_64-linux-gnu/hdf5/openmpi/libhdf5_hl.so" +libhdf5_path = "/usr/lib/x86_64-linux-gnu/hdf5/openmpi/libhdf5.so" + [MPIPreferences] __clear__ = ["preloads_env_switch"] _format = "1.0" @@ -97,6 +110,22 @@ libsc = "/home/mschlott/hackathon/libtrixi/t8code/install/lib/libsc.so" libt8 = "/home/mschlott/hackathon/libtrixi/t8code/install/lib/libt8.so" ``` +This file is created with the following sequence of commands: +```julia +julia> using MPIPreferences +julia> MPIPreferences.use_system_binary() +``` +Restart the Julia REPL +```julia +julia> using P4est +julia> P4est.set_library_p4est!("/home/mschlott/hackathon/libtrixi/t8code/install/lib/libp4est.so") +julia> P4est.set_library_sc!("/home/mschlott/hackathon/libtrixi/t8code/install/lib/libsc.so") +julia> using T8code +julia> T8code.set_libraries_path!("/home/mschlott/hackathon/libtrixi/t8code/install/lib/") +julia> using HDF5 +julia> HDF5.API.set_libraries!("/usr/lib/x86_64-linux-gnu/hdf5/openmpi/libhdf5.so", "/usr/lib/x86_64-linux-gnu/hdf5/openmpi/libhdf5_hl.so") +``` +After the preferences are set, restart the Julia REPL again. ### [Usage](@id parallel_usage) @@ -218,7 +247,7 @@ julia> HDF5.API.set_libraries!("/path/to/your/libhdf5.so", "/path/to/your/libhdf ``` For more information see also the [documentation of HDF5.jl](https://juliaio.github.io/HDF5.jl/stable/mpi/). In total, you should -have a file called LocalPreferences.toml in the project directory that contains a section +have a file called `LocalPreferences.toml` in the project directory that contains a section `[MPIPreferences]`, a section `[HDF5]` with entries `libhdf5` and `libhdf5_hl`, a section `[P4est]` with the entry `libp4est` as well as a section `[T8code]` with the entries `libt8`, `libp4est` and `libsc`. From 3c1762b20189cba6b27abaa88e1575dc495c5c73 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Tue, 21 Nov 2023 09:48:43 +0100 Subject: [PATCH 184/263] AMR for 2D Parabolic P4est (#1691) * Clean branch * Un-Comment * un-comment * test coarsen * remove redundancy * Remove support for passive terms * expand resize * comments * format * Avoid code duplication * Update src/callbacks_step/amr_dg1d.jl Co-authored-by: Michael Schlottke-Lakemper * comment * comment & format * Try to increase coverage * Slightly more expressive names * Apply suggestions from code review * add specifier for 1d * Structs for resizing parabolic helpers * check if mortars are present * reuse `reinitialize_containers!` * resize calls for parabolic helpers * update analysis callbacks * Velocities for compr euler * Init container * correct copy-paste error * resize each dim * add dispatch * Add AMR for shear layer * USe only amr shear layer * first steps towards p4est parabolic amr * Add tests * remove plots * Format * remove redundant line * look into p4est amr parabolic * platform independent tests * Working on mortars for parabolic p4est * print analysis every step * No need for different flux_viscous comps after adding container_viscous to p4est * Laplace 3d * coarsen also for p4est mesh * Eliminate unused stuff * Longer times to allow converage to hit coarsen! * Increase testing of Laplace 3D * Add tests for velocities * Continue working on AMR p4est 2d * Note possible remedy for paraboic p4est mortars * remove comment * remove some comments * clean up attempts * add elixir for amr testing * adding commented out mortar routines in 2D * Adding Mortar to 2d dg parabolic term * remove testing snippet * fix comments * add more arguments for dispatch * add some temporary todo notes * some updates for AP and KS * specialize mortar_fluxes_to_elements * BUGFIX: apply_jacobian_parabolic! was incorrect for P4estMesh * fixed rhs_parabolic! for mortars * more changes to elixir * indexing bug * comments * Adding the example for nonperiodic BCs with amr * hopefully this fixes AMR boundaries for parabolic terms * add elixir * Example with non periodic bopundary conditions * remove cruft * clean up merge nonsense * restore examples * restore project * restore * more similar * more similar to standard case * correct amr file * delete doubled tests * remove unused * remove duplicate test * format * BCs are not periodic * straighten examples, provide tests * format * fmt * reduce test time intervals * shorten test * test vals updated ode * cache_parabolic does not require mortars * add couple comments * Update src/callbacks_step/amr.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Update src/callbacks_step/amr.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Update src/solvers/dgsem_p4est/dg_2d_parabolic.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Update src/solvers/dgsem_p4est/dg_2d_parabolic.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Update src/solvers/dgsem_p4est/dg_2d_parabolic.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Update src/solvers/dgsem_p4est/dg_2d_parabolic.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * fmt * add news entry * Update src/callbacks_step/amr.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * typo --------- Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> Co-authored-by: Jesse Chan Co-authored-by: Ahmad Peyvan Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> Co-authored-by: Hendrik Ranocha --- NEWS.md | 1 + ...xir_advection_diffusion_nonperiodic_amr.jl | 98 +++++++ ...elixir_advection_diffusion_periodic_amr.jl | 83 ++++++ .../elixir_navierstokes_lid_driven_cavity.jl | 1 - ...ixir_navierstokes_lid_driven_cavity_amr.jl | 94 +++++++ .../elixir_navierstokes_lid_driven_cavity.jl | 1 - src/callbacks_step/amr.jl | 97 +++++++ src/callbacks_step/amr_dg2d.jl | 8 +- src/solvers/dgsem_p4est/containers.jl | 18 +- src/solvers/dgsem_p4est/dg_2d_parabolic.jl | 256 +++++++++++++++++- test/test_parabolic_2d.jl | 54 ++++ 11 files changed, 690 insertions(+), 21 deletions(-) create mode 100644 examples/p4est_2d_dgsem/elixir_advection_diffusion_nonperiodic_amr.jl create mode 100644 examples/p4est_2d_dgsem/elixir_advection_diffusion_periodic_amr.jl create mode 100644 examples/p4est_2d_dgsem/elixir_navierstokes_lid_driven_cavity_amr.jl diff --git a/NEWS.md b/NEWS.md index 5dd911391a6..265979c3508 100644 --- a/NEWS.md +++ b/NEWS.md @@ -7,6 +7,7 @@ for human readability. ## Changes when updating to v0.6 from v0.5.x #### Added +- AMR for hyperbolic-parabolic equations on 2D `P4estMesh` #### Changed diff --git a/examples/p4est_2d_dgsem/elixir_advection_diffusion_nonperiodic_amr.jl b/examples/p4est_2d_dgsem/elixir_advection_diffusion_nonperiodic_amr.jl new file mode 100644 index 00000000000..f87c0e056ca --- /dev/null +++ b/examples/p4est_2d_dgsem/elixir_advection_diffusion_nonperiodic_amr.jl @@ -0,0 +1,98 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear advection-diffusion equation + +diffusivity() = 5.0e-2 +advection_velocity = (1.0, 0.0) +equations = LinearScalarAdvectionEquation2D(advection_velocity) +equations_parabolic = LaplaceDiffusion2D(diffusivity(), equations) + +# 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) + +coordinates_min = (-1.0, -0.5) # minimum coordinates (min(x), min(y)) +coordinates_max = (0.0, 0.5) # maximum coordinates (max(x), max(y)) + +trees_per_dimension = (4, 4) +mesh = P4estMesh(trees_per_dimension, + polydeg = 3, initial_refinement_level = 2, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + periodicity = false) + +# Example setup taken from +# - Truman Ellis, Jesse Chan, and Leszek Demkowicz (2016). +# Robust DPG methods for transient convection-diffusion. +# In: Building bridges: connections and challenges in modern approaches +# to numerical partial differential equations. +# [DOI](https://doi.org/10.1007/978-3-319-41640-3_6). +function initial_condition_eriksson_johnson(x, t, equations) + l = 4 + epsilon = diffusivity() # TODO: this requires epsilon < .6 due to sqrt + lambda_1 = (-1 + sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + lambda_2 = (-1 - sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + r1 = (1 + sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + s1 = (1 - sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + u = exp(-l * t) * (exp(lambda_1 * x[1]) - exp(lambda_2 * x[1])) + + cos(pi * x[2]) * (exp(s1 * x[1]) - exp(r1 * x[1])) / (exp(-s1) - exp(-r1)) + return SVector{1}(u) +end +initial_condition = initial_condition_eriksson_johnson + +boundary_conditions = Dict(:x_neg => BoundaryConditionDirichlet(initial_condition), + :y_neg => BoundaryConditionDirichlet(initial_condition), + :y_pos => BoundaryConditionDirichlet(initial_condition), + :x_pos => boundary_condition_do_nothing) + +boundary_conditions_parabolic = Dict(:x_neg => BoundaryConditionDirichlet(initial_condition), + :x_pos => BoundaryConditionDirichlet(initial_condition), + :y_neg => BoundaryConditionDirichlet(initial_condition), + :y_pos => BoundaryConditionDirichlet(initial_condition)) + +# A semidiscretization collects data structures and functions for the spatial discretization +semi = SemidiscretizationHyperbolicParabolic(mesh, + (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic)) + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span `tspan` +tspan = (0.0, 0.5) +ode = semidiscretize(semi, tspan) + +# 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_interval = 1000 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +# The AliveCallback prints short status information in regular intervals +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first), + base_level = 1, + med_level = 2, med_threshold = 0.9, + max_level = 3, max_threshold = 1.0) + +amr_callback = AMRCallback(semi, amr_controller, + interval = 50) + +# Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, amr_callback) + +############################################################################### +# run the simulation + +# OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks +time_int_tol = 1.0e-11 +sol = solve(ode, dt = 1e-7, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) + +# Print the timer summary +summary_callback() diff --git a/examples/p4est_2d_dgsem/elixir_advection_diffusion_periodic_amr.jl b/examples/p4est_2d_dgsem/elixir_advection_diffusion_periodic_amr.jl new file mode 100644 index 00000000000..fdecb05f7bd --- /dev/null +++ b/examples/p4est_2d_dgsem/elixir_advection_diffusion_periodic_amr.jl @@ -0,0 +1,83 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear advection-diffusion equation + +advection_velocity = (1.5, 1.0) +equations = LinearScalarAdvectionEquation2D(advection_velocity) +diffusivity() = 5.0e-2 +equations_parabolic = LaplaceDiffusion2D(diffusivity(), equations) + +# 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) + +coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) +coordinates_max = (1.0, 1.0) # maximum coordinates (max(x), max(y)) + +trees_per_dimension = (4, 4) +mesh = P4estMesh(trees_per_dimension, + polydeg = 3, initial_refinement_level = 1, + coordinates_min = coordinates_min, coordinates_max = coordinates_max) + +# Define initial condition +function initial_condition_diffusive_convergence_test(x, t, + equation::LinearScalarAdvectionEquation2D) + # Store translated coordinate for easy use of exact solution + x_trans = x - equation.advection_velocity * t + + nu = diffusivity() + c = 1.0 + A = 0.5 + L = 2 + f = 1 / L + omega = 2 * pi * f + scalar = c + A * sin(omega * sum(x_trans)) * exp(-2 * nu * omega^2 * t) + return SVector(scalar) +end +initial_condition = initial_condition_diffusive_convergence_test + +# A semidiscretization collects data structures and functions for the spatial discretization +semi = SemidiscretizationHyperbolicParabolic(mesh, + (equations, equations_parabolic), + initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span `tspan` +tspan = (0.0, 0.5) +ode = semidiscretize(semi, tspan); + +# 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_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +# The AliveCallback prints short status information in regular intervals +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first), + base_level = 1, + med_level = 2, med_threshold = 1.25, + max_level = 3, max_threshold = 1.45) + +amr_callback = AMRCallback(semi, amr_controller, + interval = 20) + +# Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, amr_callback) + +############################################################################### +# run the simulation + +# OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks +time_int_tol = 1.0e-11 +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) + +# Print the timer summary +summary_callback() diff --git a/examples/p4est_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl b/examples/p4est_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl index e6566edb18a..bc28ae6ffb3 100644 --- a/examples/p4est_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl +++ b/examples/p4est_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl @@ -41,7 +41,6 @@ heat_bc = Adiabatic((x, t, equations) -> 0.0) boundary_condition_lid = BoundaryConditionNavierStokesWall(velocity_bc_lid, heat_bc) boundary_condition_cavity = BoundaryConditionNavierStokesWall(velocity_bc_cavity, heat_bc) -# define periodic boundary conditions everywhere boundary_conditions = Dict(:x_neg => boundary_condition_slip_wall, :y_neg => boundary_condition_slip_wall, :y_pos => boundary_condition_slip_wall, diff --git a/examples/p4est_2d_dgsem/elixir_navierstokes_lid_driven_cavity_amr.jl b/examples/p4est_2d_dgsem/elixir_navierstokes_lid_driven_cavity_amr.jl new file mode 100644 index 00000000000..898366969a4 --- /dev/null +++ b/examples/p4est_2d_dgsem/elixir_navierstokes_lid_driven_cavity_amr.jl @@ -0,0 +1,94 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal compressible Navier-Stokes equations + +# TODO: parabolic; unify names of these accessor functions +prandtl_number() = 0.72 +mu() = 0.001 + +equations = CompressibleEulerEquations2D(1.4) +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu = mu(), + Prandtl = prandtl_number()) + +# 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) + +coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) +coordinates_max = (1.0, 1.0) # maximum coordinates (max(x), max(y)) + +# Create a uniformly refined mesh +trees_per_dimension = (6, 6) +mesh = P4estMesh(trees_per_dimension, + polydeg = 3, initial_refinement_level = 2, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + periodicity = (false, false)) + +function initial_condition_cavity(x, t, equations::CompressibleEulerEquations2D) + Ma = 0.1 + rho = 1.0 + u, v = 0.0, 0.0 + p = 1.0 / (Ma^2 * equations.gamma) + return prim2cons(SVector(rho, u, v, p), equations) +end +initial_condition = initial_condition_cavity + +# BC types +velocity_bc_lid = NoSlip((x, t, equations) -> SVector(1.0, 0.0)) +velocity_bc_cavity = NoSlip((x, t, equations) -> SVector(0.0, 0.0)) +heat_bc = Adiabatic((x, t, equations) -> 0.0) +boundary_condition_lid = BoundaryConditionNavierStokesWall(velocity_bc_lid, heat_bc) +boundary_condition_cavity = BoundaryConditionNavierStokesWall(velocity_bc_cavity, heat_bc) + +boundary_conditions = Dict(:x_neg => boundary_condition_slip_wall, + :y_neg => boundary_condition_slip_wall, + :y_pos => boundary_condition_slip_wall, + :x_pos => boundary_condition_slip_wall) + +boundary_conditions_parabolic = Dict(:x_neg => boundary_condition_cavity, + :y_neg => boundary_condition_cavity, + :y_pos => boundary_condition_lid, + :x_pos => boundary_condition_cavity) + +# A semidiscretization collects data structures and functions for the spatial discretization +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic)) + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span `tspan` +tspan = (0.0, 25.0) +ode = semidiscretize(semi, tspan); + +summary_callback = SummaryCallback() +alive_callback = AliveCallback(alive_interval = 2000) +analysis_interval = 2000 +analysis_callback = AnalysisCallback(semi, 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.005, + max_level = 2, max_threshold = 0.01) + +amr_callback = AMRCallback(semi, amr_controller, + interval = 50, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) + +callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback, amr_callback) +# callbacks = CallbackSet(summary_callback, alive_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) + +summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl b/examples/tree_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl index 7bd1ec0c647..70d76fc9075 100644 --- a/examples/tree_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl +++ b/examples/tree_2d_dgsem/elixir_navierstokes_lid_driven_cavity.jl @@ -40,7 +40,6 @@ heat_bc = Adiabatic((x, t, equations) -> 0.0) boundary_condition_lid = BoundaryConditionNavierStokesWall(velocity_bc_lid, heat_bc) boundary_condition_cavity = BoundaryConditionNavierStokesWall(velocity_bc_cavity, heat_bc) -# define periodic boundary conditions everywhere boundary_conditions = boundary_condition_slip_wall boundary_conditions_parabolic = (; x_neg = boundary_condition_cavity, diff --git a/src/callbacks_step/amr.jl b/src/callbacks_step/amr.jl index ba840ff9675..5854c8617c3 100644 --- a/src/callbacks_step/amr.jl +++ b/src/callbacks_step/amr.jl @@ -528,6 +528,103 @@ function copy_to_quad_iter_volume(info, user_data) return nothing end +# specialized callback which includes the `cache_parabolic` argument +function (amr_callback::AMRCallback)(u_ode::AbstractVector, mesh::P4estMesh, + equations, dg::DG, cache, cache_parabolic, + semi, + t, iter; + only_refine = false, only_coarsen = false, + passive_args = ()) + @unpack controller, adaptor = amr_callback + + u = wrap_array(u_ode, mesh, equations, dg, cache) + lambda = @trixi_timeit timer() "indicator" controller(u, mesh, equations, dg, cache, + t = t, iter = iter) + + @boundscheck begin + @assert axes(lambda)==(Base.OneTo(ncells(mesh)),) ("Indicator array (axes = $(axes(lambda))) and mesh cells (axes = $(Base.OneTo(ncells(mesh)))) have different axes") + end + + # Copy controller value of each quad to the quad's user data storage + iter_volume_c = cfunction(copy_to_quad_iter_volume, Val(ndims(mesh))) + + # The pointer to lambda will be interpreted as Ptr{Int} below + @assert lambda isa Vector{Int} + iterate_p4est(mesh.p4est, lambda; iter_volume_c = iter_volume_c) + + @trixi_timeit timer() "refine" if !only_coarsen + # Refine mesh + refined_original_cells = @trixi_timeit timer() "mesh" refine!(mesh) + + # Refine solver + @trixi_timeit timer() "solver" refine!(u_ode, adaptor, mesh, equations, dg, + cache, cache_parabolic, + refined_original_cells) + for (p_u_ode, p_mesh, p_equations, p_dg, p_cache) in passive_args + @trixi_timeit timer() "passive solver" refine!(p_u_ode, adaptor, p_mesh, + p_equations, + p_dg, p_cache, + refined_original_cells) + end + else + # If there is nothing to refine, create empty array for later use + refined_original_cells = Int[] + end + + @trixi_timeit timer() "coarsen" if !only_refine + # Coarsen mesh + coarsened_original_cells = @trixi_timeit timer() "mesh" coarsen!(mesh) + + # coarsen solver + @trixi_timeit timer() "solver" coarsen!(u_ode, adaptor, mesh, equations, dg, + cache, cache_parabolic, + coarsened_original_cells) + for (p_u_ode, p_mesh, p_equations, p_dg, p_cache) in passive_args + @trixi_timeit timer() "passive solver" coarsen!(p_u_ode, adaptor, p_mesh, + p_equations, + p_dg, p_cache, + coarsened_original_cells) + end + else + # If there is nothing to coarsen, create empty array for later use + coarsened_original_cells = Int[] + end + + # Store whether there were any cells coarsened or refined and perform load balancing + has_changed = !isempty(refined_original_cells) || !isempty(coarsened_original_cells) + # Check if mesh changed on other processes + if mpi_isparallel() + has_changed = MPI.Allreduce!(Ref(has_changed), |, mpi_comm())[] + end + + if has_changed # TODO: Taal decide, where shall we set this? + # don't set it to has_changed since there can be changes from earlier calls + mesh.unsaved_changes = true + + if mpi_isparallel() && amr_callback.dynamic_load_balancing + @trixi_timeit timer() "dynamic load balancing" begin + global_first_quadrant = unsafe_wrap(Array, + unsafe_load(mesh.p4est).global_first_quadrant, + mpi_nranks() + 1) + old_global_first_quadrant = copy(global_first_quadrant) + partition!(mesh) + rebalance_solver!(u_ode, mesh, equations, dg, cache, + old_global_first_quadrant) + end + end + + reinitialize_boundaries!(semi.boundary_conditions, cache) + # if the semidiscretization also stores parabolic boundary conditions, + # reinitialize them after each refinement step as well. + if hasproperty(semi, :boundary_conditions_parabolic) + reinitialize_boundaries!(semi.boundary_conditions_parabolic, cache) + end + end + + # Return true if there were any cells coarsened or refined, otherwise false + return has_changed +end + # 2D function cfunction(::typeof(copy_to_quad_iter_volume), ::Val{2}) @cfunction(copy_to_quad_iter_volume, Cvoid, diff --git a/src/callbacks_step/amr_dg2d.jl b/src/callbacks_step/amr_dg2d.jl index 6395a9f348f..969f9c564f3 100644 --- a/src/callbacks_step/amr_dg2d.jl +++ b/src/callbacks_step/amr_dg2d.jl @@ -136,8 +136,8 @@ function refine!(u_ode::AbstractVector, adaptor, mesh::Union{TreeMesh{2}, P4estM return nothing end -# AMR for hyperbolic-parabolic equations currently only supported on TreeMeshes -function refine!(u_ode::AbstractVector, adaptor, mesh::Union{TreeMesh{2}, TreeMesh{3}}, +function refine!(u_ode::AbstractVector, adaptor, + mesh::Union{TreeMesh{2}, P4estMesh{2}, TreeMesh{3}}, equations, dg::DGSEM, cache, cache_parabolic, elements_to_refine) # Call `refine!` for the hyperbolic part, which does the heavy lifting of @@ -298,8 +298,8 @@ function coarsen!(u_ode::AbstractVector, adaptor, return nothing end -# AMR for hyperbolic-parabolic equations currently only supported on TreeMeshes -function coarsen!(u_ode::AbstractVector, adaptor, mesh::Union{TreeMesh{2}, TreeMesh{3}}, +function coarsen!(u_ode::AbstractVector, adaptor, + mesh::Union{TreeMesh{2}, P4estMesh{2}, TreeMesh{3}}, equations, dg::DGSEM, cache, cache_parabolic, elements_to_remove) # Call `coarsen!` for the hyperbolic part, which does the heavy lifting of diff --git a/src/solvers/dgsem_p4est/containers.jl b/src/solvers/dgsem_p4est/containers.jl index 0176f5c6346..5fe68e06710 100644 --- a/src/solvers/dgsem_p4est/containers.jl +++ b/src/solvers/dgsem_p4est/containers.jl @@ -429,13 +429,17 @@ function reinitialize_containers!(mesh::P4estMesh, equations, dg::DGSEM, cache) @unpack boundaries = cache resize!(boundaries, required.boundaries) - # resize mortars container - @unpack mortars = cache - resize!(mortars, required.mortars) - - # re-initialize containers together to reduce - # the number of iterations over the mesh in `p4est` - init_surfaces!(interfaces, mortars, boundaries, mesh) + # re-initialize mortars container + if hasproperty(cache, :mortars) # cache_parabolic does not carry mortars + @unpack mortars = cache + resize!(mortars, required.mortars) + + # re-initialize containers together to reduce + # the number of iterations over the mesh in `p4est` + init_surfaces!(interfaces, mortars, boundaries, mesh) + else + init_surfaces!(interfaces, nothing, boundaries, mesh) + end end # A helper struct used in initialization methods below diff --git a/src/solvers/dgsem_p4est/dg_2d_parabolic.jl b/src/solvers/dgsem_p4est/dg_2d_parabolic.jl index cf07645b949..9dd10df16ae 100644 --- a/src/solvers/dgsem_p4est/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_p4est/dg_2d_parabolic.jl @@ -94,8 +94,19 @@ function rhs_parabolic!(du, u, t, mesh::P4estMesh{2}, dg.surface_integral, dg) end - # TODO: parabolic; extend to mortars - @assert nmortars(dg, cache) == 0 + # Prolong solution to mortars (specialized for AbstractEquationsParabolic) + # !!! NOTE: we reuse the hyperbolic cache here since it contains "mortars" and "u_threaded". See https://github.com/trixi-framework/Trixi.jl/issues/1674 for a discussion + @trixi_timeit timer() "prolong2mortars" begin + prolong2mortars_divergence!(cache, flux_viscous, mesh, equations_parabolic, + dg.mortar, dg.surface_integral, dg) + end + + # Calculate mortar fluxes (specialized for AbstractEquationsParabolic) + @trixi_timeit timer() "mortar flux" begin + calc_mortar_flux_divergence!(cache_parabolic.elements.surface_flux_values, + mesh, equations_parabolic, dg.mortar, + dg.surface_integral, dg, cache) + end # Calculate surface integrals @trixi_timeit timer() "surface integral" begin @@ -176,14 +187,15 @@ 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. This reuses P4est `calc_interface_flux!` along with a - # specialization for AbstractEquationsParabolic. + # 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, mesh, False(), # False() = no nonconservative terms @@ -202,8 +214,21 @@ function calc_gradient!(gradients, u_transformed, t, mesh, equations_parabolic, dg.surface_integral, dg) end - # TODO: parabolic; mortars - @assert nmortars(dg, cache) == 0 + # Prolong solution to mortars. This resues the hyperbolic version of `prolong2mortars` + @trixi_timeit timer() "prolong2mortars" begin + prolong2mortars!(cache, u_transformed, mesh, equations_parabolic, + dg.mortar, dg.surface_integral, dg) + 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. + @trixi_timeit timer() "mortar flux" begin + calc_mortar_flux!(cache_parabolic.elements.surface_flux_values, + mesh, False(), # False() = no nonconservative terms + equations_parabolic, + dg.mortar, dg.surface_integral, dg, cache) + end # Calculate surface integrals @trixi_timeit timer() "surface integral" begin @@ -303,6 +328,64 @@ 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 +# into `surface_flux_values`. +@inline function mortar_fluxes_to_elements!(surface_flux_values, + mesh::Union{P4estMesh{2}, T8codeMesh{2}}, + equations::AbstractEquationsParabolic, + mortar_l2::LobattoLegendreMortarL2, + dg::DGSEM, cache, mortar, fstar, u_buffer) + @unpack neighbor_ids, node_indices = cache.mortars + # Copy solution small to small + small_indices = node_indices[1, mortar] + small_direction = indices2direction(small_indices) + + for position in 1:2 + element = neighbor_ids[position, mortar] + for i in eachnode(dg) + for v in eachvariable(equations) + surface_flux_values[v, i, small_direction, element] = fstar[position][v, + i] + end + end + end + + # Project small fluxes to large element. + multiply_dimensionwise!(u_buffer, + mortar_l2.reverse_upper, fstar[2], + mortar_l2.reverse_lower, fstar[1]) + + # Copy interpolated flux values from buffer to large element face in the + # correct orientation. + # Note that the index of the small sides will always run forward but + # the index of the large side might need to run backwards for flipped sides. + large_element = neighbor_ids[3, mortar] + large_indices = node_indices[2, mortar] + large_direction = indices2direction(large_indices) + + if :i_backward in large_indices + for i in eachnode(dg) + for v in eachvariable(equations) + surface_flux_values[v, end + 1 - i, large_direction, large_element] = u_buffer[v, + i] + end + end + else + for i in eachnode(dg) + for v in eachvariable(equations) + surface_flux_values[v, i, large_direction, large_element] = u_buffer[v, + i] + end + end + end + + return nothing +end + # This version is used for parabolic gradient computations @inline function calc_interface_flux!(surface_flux_values, mesh::P4estMesh{2}, nonconservative_terms::False, @@ -321,7 +404,7 @@ end flux_ = 0.5 * (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, + # 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. for v in eachvariable(equations) surface_flux_values[v, primary_node_index, primary_direction_index, primary_element_index] = flux_[v] @@ -520,6 +603,163 @@ function calc_interface_flux!(surface_flux_values, return nothing end +function prolong2mortars_divergence!(cache, flux_viscous::Vector{Array{uEltype, 4}}, + mesh::Union{P4estMesh{2}, T8codeMesh{2}}, equations, + mortar_l2::LobattoLegendreMortarL2, + surface_integral, dg::DGSEM) where {uEltype <: Real} + @unpack neighbor_ids, node_indices = cache.mortars + @unpack contravariant_vectors = cache.elements + index_range = eachnode(dg) + + flux_viscous_x, flux_viscous_y = flux_viscous + + @threaded for mortar in eachmortar(dg, cache) + # Copy solution data from the small elements using "delayed indexing" with + # a start value and a step size to get the correct face and orientation. + small_indices = node_indices[1, mortar] + direction_index = indices2direction(small_indices) + + i_small_start, i_small_step = index_to_start_step_2d(small_indices[1], + index_range) + j_small_start, j_small_step = index_to_start_step_2d(small_indices[2], + index_range) + + for position in 1:2 + i_small = i_small_start + j_small = j_small_start + element = neighbor_ids[position, mortar] + for i in eachnode(dg) + normal_direction = get_normal_direction(direction_index, + contravariant_vectors, + i_small, j_small, element) + + for v in eachvariable(equations) + flux_viscous = SVector(flux_viscous_x[v, i_small, j_small, element], + flux_viscous_y[v, i_small, j_small, element]) + + cache.mortars.u[1, v, position, i, mortar] = dot(flux_viscous, + normal_direction) + end + i_small += i_small_step + j_small += j_small_step + end + end + + # Buffer to copy solution values of the large element in the correct orientation + # before interpolating + u_buffer = cache.u_threaded[Threads.threadid()] + + # Copy solution of large element face to buffer in the + # correct orientation + large_indices = node_indices[2, mortar] + direction_index = indices2direction(large_indices) + + i_large_start, i_large_step = index_to_start_step_2d(large_indices[1], + index_range) + j_large_start, j_large_step = index_to_start_step_2d(large_indices[2], + index_range) + + i_large = i_large_start + j_large = j_large_start + element = neighbor_ids[3, mortar] + for i in eachnode(dg) + normal_direction = get_normal_direction(direction_index, contravariant_vectors, + i_large, j_large, element) + + for v in eachvariable(equations) + 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 + # element (these normal directions are "scaled" by the surface Jacobian) + u_buffer[v, i] = -0.5 * dot(flux_viscous, normal_direction) + end + i_large += i_large_step + j_large += j_large_step + end + + # Interpolate large element face data from buffer to small face locations + multiply_dimensionwise!(view(cache.mortars.u, 2, :, 1, :, mortar), + mortar_l2.forward_lower, + u_buffer) + multiply_dimensionwise!(view(cache.mortars.u, 2, :, 2, :, mortar), + mortar_l2.forward_upper, + u_buffer) + end + + return nothing +end + +# 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, + mortar_l2::LobattoLegendreMortarL2, + surface_integral, dg::DG, cache) + @unpack neighbor_ids, node_indices = cache.mortars + @unpack contravariant_vectors = cache.elements + @unpack fstar_upper_threaded, fstar_lower_threaded = cache + index_range = eachnode(dg) + + @threaded for mortar in eachmortar(dg, cache) + # Choose thread-specific pre-allocated container + fstar = (fstar_lower_threaded[Threads.threadid()], + fstar_upper_threaded[Threads.threadid()]) + + for position in 1:2 + for node in eachnode(dg) + for v in eachvariable(equations) + viscous_flux_normal_ll = cache.mortars.u[1, v, position, node, mortar] + viscous_flux_normal_rr = cache.mortars.u[2, v, position, node, mortar] + + # TODO: parabolic; only BR1 at the moment + fstar[position][v, node] = 0.5 * (viscous_flux_normal_ll + + viscous_flux_normal_rr) + end + end + end + + # Buffer to interpolate flux values of the large element to before + # copying in the correct orientation + u_buffer = cache.u_threaded[Threads.threadid()] + + # this reuses the hyperbolic version of `mortar_fluxes_to_elements!` + mortar_fluxes_to_elements!(surface_flux_values, + mesh, equations, mortar_l2, dg, cache, + mortar, fstar, u_buffer) + end + + 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 +# terms (e.g., we compute a viscous conservative "flux") and thus no +# non-conservative terms are present. +@inline function calc_mortar_flux!(fstar, + mesh::Union{P4estMesh{2}, T8codeMesh{2}}, + nonconservative_terms::False, + equations::AbstractEquationsParabolic, + surface_integral, dg::DG, cache, + mortar_index, position_index, normal_direction, + node_index) + @unpack u = cache.mortars + @unpack surface_flux = surface_integral + + u_ll, u_rr = get_surface_node_vars(u, equations, dg, position_index, node_index, + mortar_index) + + # TODO: parabolic; only BR1 at the moment + flux_ = 0.5 * (u_ll + u_rr) + + # Copy flux to buffer + set_node_vars!(fstar[position_index], flux_, equations, dg, node_index) +end + # TODO: parabolic, finish implementing `calc_boundary_flux_gradients!` and `calc_boundary_flux_divergence!` function prolong2boundaries!(cache_parabolic, flux_viscous, mesh::P4estMesh{2}, diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 152ca52a6ca..6632cd0bb27 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -541,6 +541,38 @@ end end end +@trixi_testset "P4estMesh2D: elixir_advection_diffusion_periodic_amr.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", + "elixir_advection_diffusion_periodic_amr.jl"), + tspan=(0.0, 0.01), + l2=[0.014715887539773128], + linf=[0.2285802791900049]) + # 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 "P4estMesh2D: elixir_advection_diffusion_nonperiodic_amr.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", + "elixir_advection_diffusion_nonperiodic_amr.jl"), + tspan=(0.0, 0.01), + l2=[0.00793438523666649], + linf=[0.11030633127144573]) + # 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 "P4estMesh2D: elixir_advection_diffusion_nonperiodic_curved.jl" begin @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_advection_diffusion_nonperiodic_curved.jl"), @@ -635,6 +667,28 @@ end @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 end end + +@trixi_testset "P4estMesh2D: elixir_navierstokes_lid_driven_cavity_amr.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", + "elixir_navierstokes_lid_driven_cavity_amr.jl"), + tspan=(0.0, 1.0), + l2=[ + 0.0005323841980601085, 0.07892044543547208, + 0.02909671646389337, 0.11717468256112017, + ], + linf=[ + 0.006045292737899444, 0.9233292581786228, + 0.7982129977236198, 1.6864546235292153, + ]) + # 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 a3f3884619aedf0826e5fd694d62f5ab4eee768c Mon Sep 17 00:00:00 2001 From: Simon Candelaresi <10759273+SimonCan@users.noreply.github.com> Date: Tue, 21 Nov 2023 10:28:24 +0000 Subject: [PATCH 185/263] Sc/compressible euler multicomponent 2d fluxes (#1681) * Added coupling converters. * Added generic converter_function for structured 2d meshes. * Added fluxes to 2d compressible multicomponent Euler. * Removed backup file. * Removed redundant project toml file. * Removed redundant Project toml file. * Removed redundant project toml file. * Removed redundant project toml files. * Removed rdundant files. * Removed p4est coupling test elixir. This is too experimental to be in any branch yet. * Removed coupling converter functions. These should be part of a different PR. * Removed further coupling converter functions. * Removed redundant swap file. * Reverted coupling semidiscretization to the main branch's by hand. This should be part of a different PR. * Added example elixir for the multicomponent Euler equations on structured meshes. * Added test for structured 2d Euler multicomponent elixir. * Reduced resolution of Euler multicomponent elixir to reduce compute time. * Applied autoformatter on multicomponent Euler. * Autoformatter on test. * Update src/equations/compressible_euler_multicomponent_2d.jl Co-authored-by: Hendrik Ranocha * Added checks for type instability for the structured mesh multicomponent Euler equations. * Autoformatted structured 2d test. * Added consistency check for new multicomponent Euler fluxes. * Added rotational invariance test for CompressibleEulerMulticomponentEquations2D. * Added rotations. * Added rotated surface for fluxes with only one u-vector. * Corrected type instability in rotation. * Applied autoformatter on 2d multicomponent Euler equations. * Removed redundant speed functions from multicomponent Euler equations. * Applied autoformatter on unit test. --------- Co-authored-by: Hendrik Ranocha --- .../elixir_eulermulti_convergence_ec.jl | 55 +++++++ .../compressible_euler_multicomponent_2d.jl | 137 ++++++++++++++++++ src/equations/numerical_fluxes.jl | 17 +++ test/test_structured_2d.jl | 26 ++++ test/test_unit.jl | 43 +++++- 5 files changed, 275 insertions(+), 3 deletions(-) create mode 100644 examples/structured_2d_dgsem/elixir_eulermulti_convergence_ec.jl diff --git a/examples/structured_2d_dgsem/elixir_eulermulti_convergence_ec.jl b/examples/structured_2d_dgsem/elixir_eulermulti_convergence_ec.jl new file mode 100644 index 00000000000..95f71f38130 --- /dev/null +++ b/examples/structured_2d_dgsem/elixir_eulermulti_convergence_ec.jl @@ -0,0 +1,55 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler multicomponent equations +equations = CompressibleEulerMulticomponentEquations2D(gammas = (1.4, 1.4), + gas_constants = (0.4, 0.4)) + +initial_condition = initial_condition_convergence_test + +volume_flux = flux_ranocha +solver = DGSEM(polydeg = 3, surface_flux = flux_ranocha, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +cells_per_dimension = (16, 16) +coordinates_min = (-1.0, -1.0) +coordinates_max = (1.0, 1.0) +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_convergence_test) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.4) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 0.5) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + 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/src/equations/compressible_euler_multicomponent_2d.jl b/src/equations/compressible_euler_multicomponent_2d.jl index 7b437f4a1b4..ecd3bc80c0a 100644 --- a/src/equations/compressible_euler_multicomponent_2d.jl +++ b/src/equations/compressible_euler_multicomponent_2d.jl @@ -270,6 +270,29 @@ end return vcat(f_other, f_rho) end +# Calculate 1D flux for a single point +@inline function flux(u, normal_direction::AbstractVector, + equations::CompressibleEulerMulticomponentEquations2D) + rho_v1, rho_v2, rho_e = u + + rho = density(u, equations) + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v_normal = v1 * normal_direction[1] + v2 * normal_direction[2] + gamma = totalgamma(u, equations) + p = (gamma - 1) * (rho_e - 0.5 * rho * (v1^2 + v2^2)) + + f_rho = densities(u, v_normal, equations) + f1 = rho_v1 * v_normal + p * normal_direction[1] + f2 = rho_v2 * v_normal + p * normal_direction[2] + f3 = (rho_e + p) * v_normal + + f_other = SVector{3, real(equations)}(f1, f2, f3) + + return vcat(f_other, f_rho) +end + """ flux_chandrashekar(u_ll, u_rr, orientation, equations::CompressibleEulerMulticomponentEquations2D) @@ -446,6 +469,76 @@ See also return vcat(f_other, f_rho) end +@inline function flux_ranocha(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleEulerMulticomponentEquations2D) + # Unpack left and right state + @unpack gammas, gas_constants, cv = equations + rho_v1_ll, rho_v2_ll, rho_e_ll = u_ll + rho_v1_rr, rho_v2_rr, rho_e_rr = u_rr + rhok_mean = SVector{ncomponents(equations), real(equations)}(ln_mean(u_ll[i + 3], + u_rr[i + 3]) + for i in eachcomponent(equations)) + rhok_avg = SVector{ncomponents(equations), real(equations)}(0.5 * (u_ll[i + 3] + + u_rr[i + 3]) + for i in eachcomponent(equations)) + + # Iterating over all partial densities + rho_ll = density(u_ll, equations) + rho_rr = density(u_rr, equations) + + # Calculating gamma + gamma = totalgamma(0.5 * (u_ll + u_rr), equations) + inv_gamma_minus_one = 1 / (gamma - 1) + + # extract velocities + v1_ll = rho_v1_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_ll = rho_v2_ll / rho_ll + v2_rr = rho_v2_rr / rho_rr + v2_avg = 0.5 * (v2_ll + v2_rr) + velocity_square_avg = 0.5 * (v1_ll * v1_rr + v2_ll * v2_rr) + v_dot_n_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] + v_dot_n_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] + + # helpful variables + help1_ll = zero(v1_ll) + help1_rr = zero(v1_rr) + enth_ll = zero(v1_ll) + enth_rr = zero(v1_rr) + for i in eachcomponent(equations) + enth_ll += u_ll[i + 3] * gas_constants[i] + enth_rr += u_rr[i + 3] * gas_constants[i] + help1_ll += u_ll[i + 3] * cv[i] + help1_rr += u_rr[i + 3] * cv[i] + end + + # temperature and pressure + T_ll = (rho_e_ll - 0.5 * rho_ll * (v1_ll^2 + v2_ll^2)) / help1_ll + T_rr = (rho_e_rr - 0.5 * rho_rr * (v1_rr^2 + v2_rr^2)) / help1_rr + p_ll = T_ll * enth_ll + p_rr = T_rr * enth_rr + p_avg = 0.5 * (p_ll + p_rr) + inv_rho_p_mean = p_ll * p_rr * inv_ln_mean(rho_ll * p_rr, rho_rr * p_ll) + + f_rho_sum = zero(T_rr) + f_rho = SVector{ncomponents(equations), real(equations)}(rhok_mean[i] * 0.5 * + (v_dot_n_ll + v_dot_n_rr) + for i in eachcomponent(equations)) + for i in eachcomponent(equations) + f_rho_sum += f_rho[i] + end + f1 = f_rho_sum * v1_avg + p_avg * normal_direction[1] + f2 = f_rho_sum * v2_avg + p_avg * normal_direction[2] + f3 = f_rho_sum * (velocity_square_avg + inv_rho_p_mean * inv_gamma_minus_one) + + 0.5 * (p_ll * v_dot_n_rr + p_rr * v_dot_n_ll) + + # momentum and energy flux + f_other = SVector(f1, f2, f3) + + return vcat(f_other, f_rho) +end + # Calculate maximum wave speed for local Lax-Friedrichs-type dissipation @inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::CompressibleEulerMulticomponentEquations2D) @@ -491,6 +584,50 @@ end return (abs(v1) + c, abs(v2) + c) end +@inline function rotate_to_x(u, normal_vector, + equations::CompressibleEulerMulticomponentEquations2D) + # cos and sin of the angle between the x-axis and the normalized normal_vector are + # the normalized vector's x and y coordinates respectively (see unit circle). + c = normal_vector[1] + s = normal_vector[2] + + # Apply the 2D rotation matrix with normal and tangent directions of the form + # [ n_1 n_2 0 0; + # t_1 t_2 0 0; + # 0 0 1 0 + # 0 0 0 1] + # where t_1 = -n_2 and t_2 = n_1 + + densities = @view u[4:end] + return SVector(c * u[1] + s * u[2], + -s * u[1] + c * u[2], + u[3], + densities...) +end + +# Called inside `FluxRotated` in `numerical_fluxes.jl` so the direction +# has been normalized prior to this back-rotation of the state vector +@inline function rotate_from_x(u, normal_vector, + equations::CompressibleEulerMulticomponentEquations2D) + # cos and sin of the angle between the x-axis and the normalized normal_vector are + # the normalized vector's x and y coordinates respectively (see unit circle). + c = normal_vector[1] + s = normal_vector[2] + + # Apply the 2D back-rotation matrix with normal and tangent directions of the form + # [ n_1 t_1 0 0; + # n_2 t_2 0 0; + # 0 0 1 0; + # 0 0 0 1 ] + # where t_1 = -n_2 and t_2 = n_1 + + densities = @view u[4:end] + return SVector(c * u[1] - s * u[2], + s * u[1] + c * u[2], + u[3], + densities...) +end + # Convert conservative variables to primitive @inline function cons2prim(u, equations::CompressibleEulerMulticomponentEquations2D) rho_v1, rho_v2, rho_e = u diff --git a/src/equations/numerical_fluxes.jl b/src/equations/numerical_fluxes.jl index 71782644b17..43be04f745d 100644 --- a/src/equations/numerical_fluxes.jl +++ b/src/equations/numerical_fluxes.jl @@ -61,6 +61,23 @@ struct FluxRotated{NumericalFlux} numerical_flux::NumericalFlux end +# Rotated surface flux computation (2D version) +@inline function (flux_rotated::FluxRotated)(u, + normal_direction::AbstractVector, + equations::AbstractEquations{2}) + @unpack numerical_flux = flux_rotated + + norm_ = norm(normal_direction) + # Normalize the vector without using `normalize` since we need to multiply by the `norm_` later + normal_vector = normal_direction / norm_ + + u_rotated = rotate_to_x(u, normal_vector, equations) + + f = numerical_flux(u_rotated, 1, equations) + + return rotate_from_x(f, normal_vector, equations) * norm_ +end + # Rotated surface flux computation (2D version) @inline function (flux_rotated::FluxRotated)(u_ll, u_rr, normal_direction::AbstractVector, diff --git a/test/test_structured_2d.jl b/test/test_structured_2d.jl index 96202e00f58..1addc29e3e6 100644 --- a/test/test_structured_2d.jl +++ b/test/test_structured_2d.jl @@ -247,6 +247,32 @@ end end end +@trixi_testset "elixir_eulermulti_convergence_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_ec.jl"), + l2=[ + 1.5123651627525257e-5, + 1.51236516273878e-5, + 2.4544918394022538e-5, + 5.904791661362391e-6, + 1.1809583322724782e-5, + ], + linf=[ + 8.393471747591974e-5, + 8.393471748258108e-5, + 0.00015028562494778797, + 3.504466610437795e-5, + 7.00893322087559e-5, + ]) + # 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_source_terms.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms.jl"), # Expected errors are exactly the same as with TreeMesh! diff --git a/test/test_unit.jl b/test/test_unit.jl index 7f774e11d3b..d2e744da62f 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -296,9 +296,11 @@ end end Trixi.move_connectivity!(c::MyContainer, first, last, destination) = c Trixi.delete_connectivity!(c::MyContainer, first, last) = c - Trixi.reset_data_structures!(c::MyContainer) = (c.data = Vector{Int}(undef, - c.capacity + 1); - c) + function Trixi.reset_data_structures!(c::MyContainer) + (c.data = Vector{Int}(undef, + c.capacity + 1); + c) + end function Base.:(==)(c1::MyContainer, c2::MyContainer) return (c1.capacity == c2.capacity && c1.length == c2.length && @@ -611,6 +613,18 @@ end @test_throws ArgumentError TimeSeriesCallback(semi, [1.0 1.0 1.0; 2.0 2.0 2.0]) end +@timed_testset "Consistency check for single point flux: CEMCE" begin + equations = CompressibleEulerMulticomponentEquations2D(gammas = (1.4, 1.4), + gas_constants = (0.4, 0.4)) + u = SVector(0.1, -0.5, 1.0, 1.0, 2.0) + + orientations = [1, 2] + for orientation in orientations + @test flux(u, orientation, equations) ≈ + flux_ranocha(u, u, orientation, equations) + end +end + @timed_testset "Consistency check for HLL flux (naive): CEE" begin flux_hll = FluxHLL(min_max_speed_naive) @@ -1221,6 +1235,29 @@ end end @testset "FluxRotated vs. direct implementation" begin + @timed_testset "CompressibleEulerMulticomponentEquations2D" begin + equations = CompressibleEulerMulticomponentEquations2D(gammas = (1.4, 1.4), + gas_constants = (0.4, + 0.4)) + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + u_values = [SVector(0.1, -0.5, 1.0, 1.0, 2.0), + SVector(-0.1, -0.3, 1.2, 1.3, 1.4)] + + f_std = flux + f_rot = FluxRotated(f_std) + println(typeof(f_std)) + println(typeof(f_rot)) + for u in u_values, + normal_direction in normal_directions + + @test f_rot(u, normal_direction, equations) ≈ + f_std(u, normal_direction, equations) + end + end + @timed_testset "CompressibleEulerEquations2D" begin equations = CompressibleEulerEquations2D(1.4) normal_directions = [SVector(1.0, 0.0), From f522652c7810920f1ca6342502d3d699b4f8b2d7 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 21 Nov 2023 16:03:38 +0100 Subject: [PATCH 186/263] set version to v0.6.2 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 4b7b69af93b..e1f8febd2bb 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.6.2-pre" +version = "0.6.2" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 12b083948fa24744de17c6a33bb6e76d42f31427 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 21 Nov 2023 16:03:54 +0100 Subject: [PATCH 187/263] set development version to v0.6.3-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index e1f8febd2bb..4e2a89dc133 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.6.2" +version = "0.6.3-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 004bc84c1daa006a7e24ad9e5876ada8a7fb194f Mon Sep 17 00:00:00 2001 From: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Date: Wed, 22 Nov 2023 08:40:09 +0100 Subject: [PATCH 188/263] fix typo and adjust some references (#1750) --- docs/src/meshes/dgmulti_mesh.md | 2 +- docs/src/parallelization.md | 6 +++--- docs/src/performance.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/src/meshes/dgmulti_mesh.md b/docs/src/meshes/dgmulti_mesh.md index fc086bba146..efa71334bf8 100644 --- a/docs/src/meshes/dgmulti_mesh.md +++ b/docs/src/meshes/dgmulti_mesh.md @@ -21,7 +21,7 @@ around Jonathan Shewchuk's [Triangle](https://www.cs.cmu.edu/~quake/triangle.htm ## The `DGMulti` solver type -Trixi.jl solvers on simplicial meshes use the `[DGMulti](@ref)` solver type, which allows users to specify +Trixi.jl solvers on simplicial meshes use the [`DGMulti`](@ref) solver type, which allows users to specify `element_type` and `approximation_type` in addition to `polydeg`, `surface_flux`, `surface_integral`, and `volume_integral`. diff --git a/docs/src/parallelization.md b/docs/src/parallelization.md index 3cce7c381b2..f599eb5fafe 100644 --- a/docs/src/parallelization.md +++ b/docs/src/parallelization.md @@ -66,13 +66,13 @@ T8code.jl that can be ignored if you do not use these libraries from Trixi.jl. N In order to use system-provided `p4est` and `t8code` installations, [P4est.jl](https://github.com/trixi-framework/P4est.jl) and [T8code.jl](https://github.com/DLR-AMR/T8code.jl) need to be configured to use the custom installations. Follow the steps described [here](https://github.com/DLR-AMR/T8code.jl/blob/main/README.md#installation) and -[here](https://github.com/trixi-framework/P4est.jl/blob/main/README.md#installation). -for the configuration. The paths that point to `libp4est.so` (and potentially to `libsc.so`) need to be +[here](https://github.com/trixi-framework/P4est.jl/blob/main/README.md#installation) for the configuration. +The paths that point to `libp4est.so` (and potentially to `libsc.so`) need to be the same for P4est.jl and T8code.jl. This could, e.g., be `libp4est.so` that usually can be found in `lib/` or `local/lib/` in the installation directory of `t8code`. Note that the `T8codeMesh`, however, does not support MPI yet. The preferences for [HDF5.jl](https://github.com/JuliaIO/HDF5.jl) always need to be set, even if you -do not want to use `HDF5` from Trixi.jl, see also https://github.com/JuliaIO/HDF5.jl/issues/1079. +do not want to use `HDF5` from Trixi.jl, see also [issue #1079 in HDF5.jl](https://github.com/JuliaIO/HDF5.jl/issues/1079). To set the preferences for HDF5.jl, follow the instructions described [here](https://trixi-framework.github.io/Trixi.jl/stable/parallelization/#Using-parallel-input-and-output). diff --git a/docs/src/performance.md b/docs/src/performance.md index bbe3a3390b7..df66f451b79 100644 --- a/docs/src/performance.md +++ b/docs/src/performance.md @@ -34,7 +34,7 @@ Hence, you should at least investigate the performance roughly by comparing the timings of several elixirs. Deeper investigations and micro-benchmarks should usually use [BenchmarkTools.jl](https://github.com/JuliaCI/BenchmarkTools.jl). For example, the following steps were used to benchmark the changes introduced in -https://github.com/trixi-framework/Trixi.jl/pull/256. +[PR #256](https://github.com/trixi-framework/Trixi.jl/pull/256). 1. `git checkout e7ebf3846b3fd62ee1d0042e130afb50d7fe8e48` (new version) 2. Start `julia --threads=1 --check-bounds=no`. From 5c08cf4a4a7407d3ffa90182baafaf8c286b8c33 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Fri, 24 Nov 2023 10:45:07 +0100 Subject: [PATCH 189/263] Switch (back) to Einfeldt wave-speed estimate from paper (#1751) * Switch (back) to wave-speed estimate from paper * upadte test vals --- src/equations/ideal_glm_mhd_1d.jl | 2 +- test/test_tree_1d_mhd.jl | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/equations/ideal_glm_mhd_1d.jl b/src/equations/ideal_glm_mhd_1d.jl index a465571989b..eca06c8c203 100644 --- a/src/equations/ideal_glm_mhd_1d.jl +++ b/src/equations/ideal_glm_mhd_1d.jl @@ -285,7 +285,7 @@ function flux_hllc(u_ll, u_rr, orientation::Integer, f_ll = flux(u_ll, orientation, equations) f_rr = flux(u_rr, orientation, equations) - SsL, SsR = min_max_speed_naive(u_ll, u_rr, orientation, equations) + SsL, SsR = min_max_speed_einfeldt(u_ll, u_rr, orientation, equations) sMu_L = SsL - v1_ll sMu_R = SsR - v1_rr if SsL >= 0 diff --git a/test/test_tree_1d_mhd.jl b/test/test_tree_1d_mhd.jl index 447572eee88..8895fe30e8b 100644 --- a/test/test_tree_1d_mhd.jl +++ b/test/test_tree_1d_mhd.jl @@ -210,15 +210,16 @@ end @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_torrilhon_shock_tube.jl"), surface_flux=flux_hllc, l2=[ - 0.4574266553239646, 0.4794143154876439, 0.3407079689595056, - 0.44797768430829343, 0.9206916204424165, - 1.3216517820475193e-16, 0.2889748702415378, - 0.25529778018020927, + 0.45738965718253993, 0.479402222862685, 0.34069729746967664, + 0.44795514335568865, 0.9206813325913135, + 1.3216517820475193e-16, 0.2889672868491632, + 0.2552794220777942, ], linf=[ - 1.217943947570543, 0.8868438459815245, 0.878215340656725, - 0.9710882819266371, 1.6742759645320984, - 2.220446049250313e-16, 0.704710220504591, 0.6562122176458641, + 1.2181099854251536, 0.8869319941747589, 0.8763562906332134, + 0.9712221036087284, 1.6734231113527818, + 2.220446049250313e-16, 0.7035011427822779, + 0.6562884129650286, ]) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) From d7e1f746462e806a317f005d4745c9c7db739d95 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Tue, 28 Nov 2023 10:28:45 +0100 Subject: [PATCH 190/263] Store capacity serial tree mesh (#1748) * Store capacity serial tree mesh * relevant changes * fmt * shorten * move capacity * Update src/meshes/mesh_io.jl Co-authored-by: Michael Schlottke-Lakemper --------- Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Hendrik Ranocha --- src/meshes/mesh_io.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/meshes/mesh_io.jl b/src/meshes/mesh_io.jl index 92e38ce1bf3..337e33e6969 100644 --- a/src/meshes/mesh_io.jl +++ b/src/meshes/mesh_io.jl @@ -30,6 +30,7 @@ function save_mesh_file(mesh::TreeMesh, output_directory, timestep, attributes(file)["mesh_type"] = get_name(mesh) attributes(file)["ndims"] = ndims(mesh) attributes(file)["n_cells"] = n_cells + attributes(file)["capacity"] = mesh.tree.capacity attributes(file)["n_leaf_cells"] = count_leaf_cells(mesh.tree) attributes(file)["minimum_level"] = minimum_level(mesh.tree) attributes(file)["maximum_level"] = maximum_level(mesh.tree) @@ -249,10 +250,10 @@ function load_mesh_serial(mesh_file::AbstractString; n_cells_max, RealT) end if mesh_type == "TreeMesh" - n_cells = h5open(mesh_file, "r") do file - return read(attributes(file)["n_cells"]) + capacity = h5open(mesh_file, "r") do file + return read(attributes(file)["capacity"]) end - mesh = TreeMesh(SerialTree{ndims}, max(n_cells, n_cells_max)) + mesh = TreeMesh(SerialTree{ndims}, max(n_cells_max, capacity)) load_mesh!(mesh, mesh_file) elseif mesh_type == "StructuredMesh" size_, mapping_as_string = h5open(mesh_file, "r") do file From 17d507071622a121afeaee810618ed0dc02bb5dd Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Fri, 1 Dec 2023 13:38:44 +0100 Subject: [PATCH 191/263] Use total pressure for 1D HLLC MHD (#1756) * Use total pressure * Update src/equations/ideal_glm_mhd_1d.jl Co-authored-by: Andrew Winters --------- Co-authored-by: Andrew Winters --- src/equations/ideal_glm_mhd_1d.jl | 20 +++++++++------ test/test_tree_1d_mhd.jl | 41 +++++++++++++++++++++++++------ 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/equations/ideal_glm_mhd_1d.jl b/src/equations/ideal_glm_mhd_1d.jl index eca06c8c203..5a523daf3f6 100644 --- a/src/equations/ideal_glm_mhd_1d.jl +++ b/src/equations/ideal_glm_mhd_1d.jl @@ -272,6 +272,10 @@ function flux_hllc(u_ll, u_rr, orientation::Integer, rho_ll, v1_ll, v2_ll, v3_ll, p_ll, B1_ll, B2_ll, B3_ll = cons2prim(u_ll, equations) rho_rr, v1_rr, v2_rr, v3_rr, p_rr, B1_rr, B2_rr, B3_rr = cons2prim(u_rr, equations) + # Total pressure, i.e., thermal + magnetic pressures (eq. (12)) + p_tot_ll = p_ll + 0.5 * (B1_ll^2 + B2_ll^2 + B3_ll^2) + p_tot_rr = p_rr + 0.5 * (B1_rr^2 + B2_rr^2 + B3_rr^2) + # Conserved variables rho_v1_ll = u_ll[2] rho_v2_ll = u_ll[3] @@ -309,11 +313,11 @@ function flux_hllc(u_ll, u_rr, orientation::Integer, else # Compute the "HLLC-speed", eq. (14) from paper mentioned above #= - SStar = (rho_rr * v1_rr * sMu_R - rho_ll * v1_ll * sMu_L + p_ll - p_rr - B1_ll^2 + B1_rr^2 ) / + SStar = (rho_rr * v1_rr * sMu_R - rho_ll * v1_ll * sMu_L + p_tot_ll - p_tot_rr - B1_ll^2 + B1_rr^2 ) / (rho_rr * sMu_R - rho_ll * sMu_L) =# # Simplification for 1D: B1 is constant - SStar = (rho_rr * v1_rr * sMu_R - rho_ll * v1_ll * sMu_L + p_ll - p_rr) / + SStar = (rho_rr * v1_rr * sMu_R - rho_ll * v1_ll * sMu_L + p_tot_ll - p_tot_rr) / (rho_rr * sMu_R - rho_ll * sMu_L) Sdiff = SsR - SsL @@ -347,12 +351,12 @@ function flux_hllc(u_ll, u_rr, orientation::Integer, mom_3_Star = densStar * v3_ll - (B1Star * B3Star - B1_ll * B3_ll) / SdiffStar # (22) - #pstar = rho_ll * sMu_L * (SStar - v1_ll) + p_ll - B1_ll^2 + B1Star^2 # (17) + #p_tot_Star = rho_ll * sMu_L * (SStar - v1_ll) + p_tot_ll - B1_ll^2 + B1Star^2 # (17) # 1D B1 = constant => B1_ll = B1_rr = B1Star - pstar = rho_ll * sMu_L * (SStar - v1_ll) + p_ll # (17) + p_tot_Star = rho_ll * sMu_L * (SStar - v1_ll) + p_tot_ll # (17) enerStar = u_ll[5] * sMu_L / SdiffStar + - (pstar * SStar - p_ll * v1_ll - (B1Star * + (p_tot_Star * SStar - p_tot_ll * v1_ll - (B1Star * (B1Star * v1Star + B2Star * v2Star + B3Star * v3Star) - B1_ll * (B1_ll * v1_ll + B2_ll * v2_ll + B3_ll * v3_ll))) / SdiffStar # (23) @@ -377,12 +381,12 @@ function flux_hllc(u_ll, u_rr, orientation::Integer, mom_3_Star = densStar * v3_rr - (B1Star * B3Star - B1_rr * B3_rr) / SdiffStar # (22) - #pstar = rho_rr * sMu_R * (SStar - v1_rr) + p_rr - B1_rr^2 + B1Star^2 # (17) + #p_tot_Star = rho_rr * sMu_R * (SStar - v1_rr) + p_tot_rr - B1_rr^2 + B1Star^2 # (17) # 1D B1 = constant => B1_ll = B1_rr = B1Star - pstar = rho_rr * sMu_R * (SStar - v1_rr) + p_rr # (17) + p_tot_Star = rho_rr * sMu_R * (SStar - v1_rr) + p_tot_rr # (17) enerStar = u_rr[5] * sMu_R / SdiffStar + - (pstar * SStar - p_rr * v1_rr - (B1Star * + (p_tot_Star * SStar - p_tot_rr * v1_rr - (B1Star * (B1Star * v1Star + B2Star * v2Star + B3Star * v3Star) - B1_rr * (B1_rr * v1_rr + B2_rr * v2_rr + B3_rr * v3_rr))) / SdiffStar # (23) diff --git a/test/test_tree_1d_mhd.jl b/test/test_tree_1d_mhd.jl index 8895fe30e8b..2150ddfd074 100644 --- a/test/test_tree_1d_mhd.jl +++ b/test/test_tree_1d_mhd.jl @@ -109,6 +109,31 @@ end end end +@trixi_testset "elixir_mhd_alfven_wave.jl with flux_hllc" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), + l2=[ + 1.036850596986597e-5, 1.965192583650368e-6, + 3.5882124656715505e-5, 3.5882124656638764e-5, + 5.270975504780837e-6, 1.1963224165731992e-16, + 3.595811808912869e-5, 3.5958118089159453e-5, + ], + linf=[ + 2.887280521446378e-5, 7.310580790352001e-6, + 0.00012390046377899755, 0.00012390046377787345, + 1.5102711136583125e-5, 2.220446049250313e-16, + 0.0001261935452181312, 0.0001261935452182006, + ], + surface_flux=flux_hllc) + # 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_mhd_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_ec.jl"), l2=[ @@ -210,16 +235,16 @@ end @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_torrilhon_shock_tube.jl"), surface_flux=flux_hllc, l2=[ - 0.45738965718253993, 0.479402222862685, 0.34069729746967664, - 0.44795514335568865, 0.9206813325913135, - 1.3216517820475193e-16, 0.2889672868491632, - 0.2552794220777942, + 0.4573799618744708, 0.4792633358230866, 0.34064852506872795, + 0.4479668434955162, 0.9203891782415092, + 1.3216517820475193e-16, 0.28887826520860815, + 0.255281629265771, ], linf=[ - 1.2181099854251536, 0.8869319941747589, 0.8763562906332134, - 0.9712221036087284, 1.6734231113527818, - 2.220446049250313e-16, 0.7035011427822779, - 0.6562884129650286, + 1.2382842201671505, 0.8929169308132259, 0.871298623806198, + 0.9822415614542821, 1.6726170732132717, + 2.220446049250313e-16, 0.7016155888023747, + 0.6556091522071984, ]) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) From 74aafa08e41ce1ffdfeae4c42d46a28e381e0375 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Mon, 4 Dec 2023 07:40:08 +0100 Subject: [PATCH 192/263] Update test vals of failing tests for upstream packages (#1760) * Update test vals * fmt --------- Co-authored-by: Hendrik Ranocha --- .../elixir_eulermulti_shock_bubble.jl | 6 +- ...ck_bubble_shockcapturing_subcell_minmax.jl | 6 +- ...ubble_shockcapturing_subcell_positivity.jl | 6 +- ext/TrixiMakieExt.jl | 7 +- src/auxiliary/precompile.jl | 58 +++++++--------- src/callbacks_step/averaging.jl | 3 +- .../euler_acoustics_coupling.jl | 7 +- src/callbacks_step/glm_speed_dg.jl | 7 +- src/callbacks_step/save_solution.jl | 6 +- src/callbacks_step/save_solution_dg.jl | 6 +- .../compressible_euler_multicomponent_1d.jl | 22 +++--- .../compressible_euler_multicomponent_2d.jl | 22 +++--- .../compressible_navier_stokes_1d.jl | 59 +++++----------- .../compressible_navier_stokes_2d.jl | 67 +++++-------------- .../compressible_navier_stokes_3d.jl | 59 +++++----------- .../ideal_glm_mhd_multicomponent_1d.jl | 22 +++--- .../ideal_glm_mhd_multicomponent_2d.jl | 22 +++--- src/equations/numerical_fluxes.jl | 5 +- src/meshes/unstructured_mesh.jl | 5 +- .../semidiscretization_coupled.jl | 8 +-- .../semidiscretization_hyperbolic.jl | 29 ++++---- ...semidiscretization_hyperbolic_parabolic.jl | 47 +++++++------ src/solvers/dgmulti/flux_differencing.jl | 12 ++-- .../dgmulti/flux_differencing_gauss_sbp.jl | 5 +- src/solvers/dgmulti/sbp.jl | 34 +++++----- src/solvers/dgmulti/types.jl | 53 +++++++-------- src/solvers/dgsem/basis_lobatto_legendre.jl | 6 +- src/solvers/dgsem_p4est/containers.jl | 3 +- .../dgsem_p4est/containers_parallel.jl | 3 +- .../dgsem_p4est/containers_parallel_2d.jl | 4 +- .../dgsem_p4est/containers_parallel_3d.jl | 4 +- src/solvers/dgsem_p4est/dg_2d_parabolic.jl | 3 +- src/solvers/dgsem_p4est/dg_parallel.jl | 3 +- src/solvers/dgsem_structured/containers.jl | 4 +- src/solvers/dgsem_tree/dg_1d_parabolic.jl | 12 ++-- src/solvers/dgsem_tree/dg_2d.jl | 4 +- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 12 ++-- src/solvers/dgsem_tree/dg_3d.jl | 12 ++-- src/solvers/dgsem_tree/dg_3d_parabolic.jl | 12 ++-- src/solvers/dgsem_tree/indicators_1d.jl | 4 +- src/solvers/dgsem_tree/indicators_2d.jl | 4 +- src/solvers/dgsem_tree/subcell_limiters_2d.jl | 7 +- src/visualization/recipes_plots.jl | 7 +- test/test_tree_3d_fdsbp.jl | 4 +- 44 files changed, 263 insertions(+), 428 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble.jl b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble.jl index f5ef51c108a..c6ed07dcda1 100644 --- a/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble.jl +++ b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble.jl @@ -17,10 +17,8 @@ A shock-bubble testcase for multicomponent Euler equations [arXiv: 1904.00972](https://arxiv.org/abs/1904.00972) """ function initial_condition_shock_bubble(x, t, - equations::CompressibleEulerMulticomponentEquations2D{ - 5, - 2 - }) + equations::CompressibleEulerMulticomponentEquations2D{5, + 2}) # bubble test case, see Gouasmi et al. https://arxiv.org/pdf/1904.00972 # other reference: https://www.researchgate.net/profile/Pep_Mulet/publication/222675930_A_flux-split_algorithm_applied_to_conservative_models_for_multicomponent_compressible_flows/links/568da54508aeaa1481ae7af0.pdf # typical domain is rectangular, we change it to a square, as Trixi can only do squares diff --git a/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_minmax.jl b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_minmax.jl index 3159a2066ad..4b606502ebe 100644 --- a/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_minmax.jl +++ b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_minmax.jl @@ -17,10 +17,8 @@ A shock-bubble testcase for multicomponent Euler equations [arXiv: 1904.00972](https://arxiv.org/abs/1904.00972) """ function initial_condition_shock_bubble(x, t, - equations::CompressibleEulerMulticomponentEquations2D{ - 5, - 2 - }) + equations::CompressibleEulerMulticomponentEquations2D{5, + 2}) # bubble test case, see Gouasmi et al. https://arxiv.org/pdf/1904.00972 # other reference: https://www.researchgate.net/profile/Pep_Mulet/publication/222675930_A_flux-split_algorithm_applied_to_conservative_models_for_multicomponent_compressible_flows/links/568da54508aeaa1481ae7af0.pdf # typical domain is rectangular, we change it to a square, as Trixi can only do squares diff --git a/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl index 7856c9bafbd..78ff47e255f 100644 --- a/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl +++ b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl @@ -17,10 +17,8 @@ A shock-bubble testcase for multicomponent Euler equations [arXiv: 1904.00972](https://arxiv.org/abs/1904.00972) """ function initial_condition_shock_bubble(x, t, - equations::CompressibleEulerMulticomponentEquations2D{ - 5, - 2 - }) + equations::CompressibleEulerMulticomponentEquations2D{5, + 2}) # bubble test case, see Gouasmi et al. https://arxiv.org/pdf/1904.00972 # other reference: https://www.researchgate.net/profile/Pep_Mulet/publication/222675930_A_flux-split_algorithm_applied_to_conservative_models_for_multicomponent_compressible_flows/links/568da54508aeaa1481ae7af0.pdf # typical domain is rectangular, we change it to a square, as Trixi can only do squares diff --git a/ext/TrixiMakieExt.jl b/ext/TrixiMakieExt.jl index 8cd7576a6e5..301a7656da9 100644 --- a/ext/TrixiMakieExt.jl +++ b/ext/TrixiMakieExt.jl @@ -29,9 +29,7 @@ import Trixi: iplot, iplot! # First some utilities # Given a reference plotting triangulation, this function generates a plotting triangulation for # the entire global mesh. The output can be plotted using `Makie.mesh`. -function global_plotting_triangulation_makie(pds::PlotDataSeries{ - <:PlotData2DTriangulated - }; +function global_plotting_triangulation_makie(pds::PlotDataSeries{<:PlotData2DTriangulated}; set_z_coordinate_zero = false) @unpack variable_id = pds pd = pds.plot_data @@ -61,8 +59,7 @@ end # Returns a list of `Makie.Point`s which can be used to plot the mesh, or a solution "wireframe" # (e.g., a plot of the mesh lines but with the z-coordinate equal to the value of the solution). -function convert_PlotData2D_to_mesh_Points(pds::PlotDataSeries{<:PlotData2DTriangulated - }; +function convert_PlotData2D_to_mesh_Points(pds::PlotDataSeries{<:PlotData2DTriangulated}; set_z_coordinate_zero = false) @unpack variable_id = pds pd = pds.plot_data diff --git a/src/auxiliary/precompile.jl b/src/auxiliary/precompile.jl index 7ed0e26b5ef..9cec502f6cb 100644 --- a/src/auxiliary/precompile.jl +++ b/src/auxiliary/precompile.jl @@ -186,8 +186,7 @@ function _precompile_manual_() Matrix{RealT}, # DerivativeMatrix #StaticArrays.SArray{Tuple{nnodes_,nnodes_},RealT,2,nnodes_^2}, - Matrix{RealT} - } + Matrix{RealT}} end function mortar_type_dgsem(RealT, nnodes_) @@ -197,8 +196,7 @@ function _precompile_manual_() Matrix{RealT}, # ReverseMatrix # StaticArrays.SArray{Tuple{nnodes_,nnodes_},RealT,2,nnodes_^2}, - Matrix{RealT} - } + Matrix{RealT}} end function analyzer_type_dgsem(RealT, nnodes_) @@ -208,8 +206,7 @@ function _precompile_manual_() # VectorT StaticArrays.SVector{nnodes_analysis, RealT}, # Vandermonde - Array{RealT, 2} - } + Array{RealT, 2}} end function adaptor_type_dgsem(RealT, nnodes_) @@ -242,8 +239,8 @@ function _precompile_manual_() @assert Base.precompile(Tuple{Core.kwftype(typeof(Trixi.Type)), NamedTuple{(:initial_refinement_level, :n_cells_max), Tuple{Int, Int}}, Type{TreeMesh}, - Tuple{RealT, RealT, RealT}, Tuple{RealT, RealT, RealT - }}) + Tuple{RealT, RealT, RealT}, + Tuple{RealT, RealT, RealT}}) end for TreeType in (SerialTree, ParallelTree), NDIMS in 1:3 @assert Base.precompile(Tuple{typeof(Trixi.initialize!), @@ -308,8 +305,8 @@ function _precompile_manual_() Base.precompile(Tuple{Type{LobattoLegendreBasis}, Int}) for RealT in (Float64,) Base.precompile(Tuple{Type{LobattoLegendreBasis}, RealT, Int}) - @assert Base.precompile(Tuple{typeof(Trixi.calc_dhat), Vector{RealT}, Vector{RealT} - }) + @assert Base.precompile(Tuple{typeof(Trixi.calc_dhat), Vector{RealT}, + Vector{RealT}}) @assert Base.precompile(Tuple{typeof(Trixi.calc_dsplit), Vector{RealT}, Vector{RealT}}) @assert Base.precompile(Tuple{typeof(Trixi.polynomial_derivative_matrix), @@ -332,10 +329,10 @@ function _precompile_manual_() @assert Base.precompile(Tuple{typeof(Trixi.calc_forward_lower), Int}) @assert Base.precompile(Tuple{typeof(Trixi.calc_reverse_upper), Int, Val{:gauss}}) @assert Base.precompile(Tuple{typeof(Trixi.calc_reverse_lower), Int, Val{:gauss}}) - @assert Base.precompile(Tuple{typeof(Trixi.calc_reverse_upper), Int, Val{:gauss_lobatto - }}) - @assert Base.precompile(Tuple{typeof(Trixi.calc_reverse_lower), Int, Val{:gauss_lobatto - }}) + @assert Base.precompile(Tuple{typeof(Trixi.calc_reverse_upper), Int, + Val{:gauss_lobatto}}) + @assert Base.precompile(Tuple{typeof(Trixi.calc_reverse_lower), Int, + Val{:gauss_lobatto}}) # Constructors: mortars, analyzers, adaptors for RealT in (Float64,), polydeg in 1:7 @@ -362,14 +359,12 @@ function _precompile_manual_() NamedTuple{(:interval, :save_final_restart), Tuple{Int, Bool}}, Type{SaveRestartCallback}}) @assert Base.precompile(Tuple{Core.kwftype(typeof(Trixi.Type)), - NamedTuple{ - (:interval, :save_initial_solution, + NamedTuple{(:interval, :save_initial_solution, :save_final_solution, :solution_variables), Tuple{Int, Bool, Bool, typeof(cons2cons)}}, Type{SaveSolutionCallback}}) @assert Base.precompile(Tuple{Core.kwftype(typeof(Trixi.Type)), - NamedTuple{ - (:interval, :save_initial_solution, + NamedTuple{(:interval, :save_initial_solution, :save_final_solution, :solution_variables), Tuple{Int, Bool, Bool, typeof(cons2prim)}}, Type{SaveSolutionCallback}}) @@ -385,8 +380,7 @@ function _precompile_manual_() # end # end @assert Base.precompile(Tuple{typeof(SummaryCallback)}) - @assert Base.precompile(Tuple{ - DiscreteCallback{typeof(Trixi.summary_callback), + @assert Base.precompile(Tuple{DiscreteCallback{typeof(Trixi.summary_callback), typeof(Trixi.summary_callback), typeof(Trixi.initialize_summary_callback), typeof(SciMLBase.FINALIZE_DEFAULT)}}) @@ -419,8 +413,8 @@ function _precompile_manual_() Trixi.ElementContainer2D{RealT, uEltype}}) @assert Base.precompile(Tuple{typeof(Trixi.init_mortars), Array{Int, 1}, TreeMesh{2, Trixi.SerialTree{2}}, - Trixi.ElementContainer2D{RealT, uEltype}, mortar_type - }) + Trixi.ElementContainer2D{RealT, uEltype}, + mortar_type}) @assert Base.precompile(Tuple{typeof(Trixi.save_mesh_file), TreeMesh{2, Trixi.SerialTree{2}}, String}) @@ -433,8 +427,8 @@ function _precompile_manual_() Trixi.ElementContainer2D{RealT, uEltype}}) @assert Base.precompile(Tuple{typeof(Trixi.init_mortars), Array{Int, 1}, TreeMesh{2, Trixi.ParallelTree{2}}, - Trixi.ElementContainer2D{RealT, uEltype}, mortar_type - }) + Trixi.ElementContainer2D{RealT, uEltype}, + mortar_type}) @assert Base.precompile(Tuple{typeof(Trixi.init_mpi_interfaces), Array{Int, 1}, TreeMesh{2, Trixi.ParallelTree{2}}, Trixi.ElementContainer2D{RealT, uEltype}}) @@ -450,8 +444,8 @@ function _precompile_manual_() Trixi.ElementContainer3D{RealT, uEltype}}) @assert Base.precompile(Tuple{typeof(Trixi.init_mortars), Array{Int, 1}, TreeMesh{3, Trixi.SerialTree{3}}, - Trixi.ElementContainer3D{RealT, uEltype}, mortar_type - }) + Trixi.ElementContainer3D{RealT, uEltype}, + mortar_type}) @assert Base.precompile(Tuple{typeof(Trixi.save_mesh_file), TreeMesh{3, Trixi.SerialTree{3}}, String}) end @@ -548,16 +542,10 @@ function _precompile_manual_() restart_callback_type}) for solution_variables in (cons2cons, cons2prim) - save_solution_callback_type = DiscreteCallback{ - SaveSolutionCallback{ - typeof(solution_variables) - }, - SaveSolutionCallback{ - typeof(solution_variables) - }, + save_solution_callback_type = DiscreteCallback{SaveSolutionCallback{typeof(solution_variables)}, + SaveSolutionCallback{typeof(solution_variables)}, typeof(Trixi.initialize!), - typeof(SciMLBase.FINALIZE_DEFAULT) - } + typeof(SciMLBase.FINALIZE_DEFAULT)} @assert Base.precompile(Tuple{typeof(show), Base.TTY, save_solution_callback_type}) @assert Base.precompile(Tuple{typeof(show), IOContext{Base.TTY}, diff --git a/src/callbacks_step/averaging.jl b/src/callbacks_step/averaging.jl index 8d2dcfeaefe..efa71af9b91 100644 --- a/src/callbacks_step/averaging.jl +++ b/src/callbacks_step/averaging.jl @@ -52,8 +52,7 @@ function Base.show(io::IO, ::MIME"text/plain", end function AveragingCallback(semi::SemidiscretizationHyperbolic{<:Any, - <:CompressibleEulerEquations2D - }, + <:CompressibleEulerEquations2D}, tspan; output_directory = "out", filename = "averaging.h5") mesh, equations, solver, cache = mesh_equations_solver_cache(semi) mean_values = initialize_mean_values(mesh, equations, solver, cache) diff --git a/src/callbacks_step/euler_acoustics_coupling.jl b/src/callbacks_step/euler_acoustics_coupling.jl index ea33175d0c5..52dc55befdc 100644 --- a/src/callbacks_step/euler_acoustics_coupling.jl +++ b/src/callbacks_step/euler_acoustics_coupling.jl @@ -34,8 +34,8 @@ the [`AveragingCallback`](@ref). A direct-hybrid method for aeroacoustic analysis [DOI: 10.18154/RWTH-2017-04082](https://doi.org/10.18154/RWTH-2017-04082) """ -mutable struct EulerAcousticsCouplingCallback{RealT <: Real, MeanValues, IntegratorEuler - } +mutable struct EulerAcousticsCouplingCallback{RealT <: Real, MeanValues, + IntegratorEuler} stepsize_callback_acoustics::StepsizeCallback{RealT} stepsize_callback_euler::StepsizeCallback{RealT} mean_values::MeanValues @@ -85,8 +85,7 @@ The mean values for the acoustic perturbation equations are read from `averaging """ function EulerAcousticsCouplingCallback(ode_euler, averaging_callback::DiscreteCallback{<:Any, - <:AveragingCallback - }, + <:AveragingCallback}, alg, cfl_acoustics::Real, cfl_euler::Real; kwargs...) @unpack mean_values = averaging_callback.affect! diff --git a/src/callbacks_step/glm_speed_dg.jl b/src/callbacks_step/glm_speed_dg.jl index 0686c547a34..302aae356ab 100644 --- a/src/callbacks_step/glm_speed_dg.jl +++ b/src/callbacks_step/glm_speed_dg.jl @@ -7,8 +7,8 @@ function calc_dt_for_cleaning_speed(cfl::Real, mesh, equations::Union{AbstractIdealGlmMhdEquations, - AbstractIdealGlmMhdMulticomponentEquations - }, dg::DG, cache) + AbstractIdealGlmMhdMulticomponentEquations}, + dg::DG, cache) # compute time step for GLM linear advection equation with c_h=1 for the DG discretization on # Cartesian meshes max_scaled_speed_for_c_h = maximum(cache.elements.inverse_jacobian) * @@ -20,8 +20,7 @@ end function calc_dt_for_cleaning_speed(cfl::Real, mesh, equations::Union{AbstractIdealGlmMhdEquations, - AbstractIdealGlmMhdMulticomponentEquations - }, + AbstractIdealGlmMhdMulticomponentEquations}, dg::DGMulti, cache) rd = dg.basis md = mesh.md diff --git a/src/callbacks_step/save_solution.jl b/src/callbacks_step/save_solution.jl index 0092360cb20..c106fe69bcd 100644 --- a/src/callbacks_step/save_solution.jl +++ b/src/callbacks_step/save_solution.jl @@ -39,8 +39,7 @@ end function Base.show(io::IO, cb::DiscreteCallback{<:Any, - <:PeriodicCallbackAffect{<:SaveSolutionCallback - }}) + <:PeriodicCallbackAffect{<:SaveSolutionCallback}}) @nospecialize cb # reduce precompilation time save_solution_callback = cb.affect!.affect! @@ -71,8 +70,7 @@ end function Base.show(io::IO, ::MIME"text/plain", cb::DiscreteCallback{<:Any, - <:PeriodicCallbackAffect{<:SaveSolutionCallback - }}) + <:PeriodicCallbackAffect{<:SaveSolutionCallback}}) @nospecialize cb # reduce precompilation time if get(io, :compact, false) diff --git a/src/callbacks_step/save_solution_dg.jl b/src/callbacks_step/save_solution_dg.jl index 7c015999035..350aee7336a 100644 --- a/src/callbacks_step/save_solution_dg.jl +++ b/src/callbacks_step/save_solution_dg.jl @@ -33,8 +33,7 @@ function save_solution_file(u, time, dt, timestep, # compute the solution variables via broadcasting, and reinterpret the # result as a plain array of floating point numbers data = Array(reinterpret(eltype(u), - solution_variables.(reinterpret(SVector{ - nvariables(equations), + solution_variables.(reinterpret(SVector{nvariables(equations), eltype(u)}, u), Ref(equations)))) @@ -116,8 +115,7 @@ function save_solution_file(u, time, dt, timestep, # compute the solution variables via broadcasting, and reinterpret the # result as a plain array of floating point numbers data = Array(reinterpret(eltype(u), - solution_variables.(reinterpret(SVector{ - nvariables(equations), + solution_variables.(reinterpret(SVector{nvariables(equations), eltype(u)}, u), Ref(equations)))) diff --git a/src/equations/compressible_euler_multicomponent_1d.jl b/src/equations/compressible_euler_multicomponent_1d.jl index 23ac222b976..8ddb0dcd08f 100644 --- a/src/equations/compressible_euler_multicomponent_1d.jl +++ b/src/equations/compressible_euler_multicomponent_1d.jl @@ -54,19 +54,15 @@ struct CompressibleEulerMulticomponentEquations1D{NVARS, NCOMP, RealT <: Real} < cv::SVector{NCOMP, RealT} cp::SVector{NCOMP, RealT} - function CompressibleEulerMulticomponentEquations1D{NVARS, NCOMP, RealT}(gammas::SVector{ - NCOMP, - RealT - }, - gas_constants::SVector{ - NCOMP, - RealT - }) where { - NVARS, - NCOMP, - RealT <: - Real - } + function CompressibleEulerMulticomponentEquations1D{NVARS, NCOMP, RealT}(gammas::SVector{NCOMP, + RealT}, + gas_constants::SVector{NCOMP, + RealT}) where { + NVARS, + NCOMP, + RealT <: + Real + } NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `gas_constants` have to be filled with at least one value")) diff --git a/src/equations/compressible_euler_multicomponent_2d.jl b/src/equations/compressible_euler_multicomponent_2d.jl index ecd3bc80c0a..940d88b1aa5 100644 --- a/src/equations/compressible_euler_multicomponent_2d.jl +++ b/src/equations/compressible_euler_multicomponent_2d.jl @@ -58,19 +58,15 @@ struct CompressibleEulerMulticomponentEquations2D{NVARS, NCOMP, RealT <: Real} < cv::SVector{NCOMP, RealT} cp::SVector{NCOMP, RealT} - function CompressibleEulerMulticomponentEquations2D{NVARS, NCOMP, RealT}(gammas::SVector{ - NCOMP, - RealT - }, - gas_constants::SVector{ - NCOMP, - RealT - }) where { - NVARS, - NCOMP, - RealT <: - Real - } + function CompressibleEulerMulticomponentEquations2D{NVARS, NCOMP, RealT}(gammas::SVector{NCOMP, + RealT}, + gas_constants::SVector{NCOMP, + RealT}) where { + NVARS, + NCOMP, + RealT <: + Real + } NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `gas_constants` have to be filled with at least one value")) diff --git a/src/equations/compressible_navier_stokes_1d.jl b/src/equations/compressible_navier_stokes_1d.jl index 73436c99b7c..d2c46ecc7d8 100644 --- a/src/equations/compressible_navier_stokes_1d.jl +++ b/src/equations/compressible_navier_stokes_1d.jl @@ -81,8 +81,7 @@ w_2 = \frac{\rho v1}{p},\, w_3 = -\frac{\rho}{p} ``` """ struct CompressibleNavierStokesDiffusion1D{GradientVariables, RealT <: Real, - E <: AbstractCompressibleEulerEquations{1} - } <: + E <: AbstractCompressibleEulerEquations{1}} <: AbstractCompressibleNavierStokesDiffusion{1, 3, GradientVariables} # TODO: parabolic # 1) For now save gamma and inv(gamma-1) again, but could potentially reuse them from the Euler equations @@ -130,14 +129,10 @@ end # we specialize this function to compute gradients of primitive variables instead of # conservative variables. -function gradient_variable_transformation(::CompressibleNavierStokesDiffusion1D{ - GradientVariablesPrimitive - }) +function gradient_variable_transformation(::CompressibleNavierStokesDiffusion1D{GradientVariablesPrimitive}) cons2prim end -function gradient_variable_transformation(::CompressibleNavierStokesDiffusion1D{ - GradientVariablesEntropy - }) +function gradient_variable_transformation(::CompressibleNavierStokesDiffusion1D{GradientVariablesEntropy}) cons2entropy end @@ -202,17 +197,13 @@ end # For CNS, it is simplest to formulate the viscous terms in primitive variables, so we transform the transformed # variables into primitive variables. @inline function convert_transformed_to_primitive(u_transformed, - equations::CompressibleNavierStokesDiffusion1D{ - GradientVariablesPrimitive - }) + equations::CompressibleNavierStokesDiffusion1D{GradientVariablesPrimitive}) return u_transformed end # TODO: parabolic. Make this more efficient! @inline function convert_transformed_to_primitive(u_transformed, - equations::CompressibleNavierStokesDiffusion1D{ - GradientVariablesEntropy - }) + equations::CompressibleNavierStokesDiffusion1D{GradientVariablesEntropy}) # note: this uses CompressibleNavierStokesDiffusion1D versions of cons2prim and entropy2cons return cons2prim(entropy2cons(u_transformed, equations), equations) end @@ -223,17 +214,13 @@ end # Note, the first component of `gradient_entropy_vars` contains gradient(rho) which is unused. # TODO: parabolic; entropy stable viscous terms @inline function convert_derivative_to_primitive(u, gradient, - ::CompressibleNavierStokesDiffusion1D{ - GradientVariablesPrimitive - }) + ::CompressibleNavierStokesDiffusion1D{GradientVariablesPrimitive}) return gradient end # the first argument is always the "transformed" variables. @inline function convert_derivative_to_primitive(w, gradient_entropy_vars, - equations::CompressibleNavierStokesDiffusion1D{ - GradientVariablesEntropy - }) + equations::CompressibleNavierStokesDiffusion1D{GradientVariablesEntropy}) # TODO: parabolic. This is inefficient to pass in transformed variables but then transform them back. # We can fix this if we directly compute v1, v2, T from the entropy variables @@ -272,9 +259,7 @@ end x, t, operator_type::Gradient, - equations::CompressibleNavierStokesDiffusion1D{ - GradientVariablesPrimitive - }) + equations::CompressibleNavierStokesDiffusion1D{GradientVariablesPrimitive}) v1 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) return SVector(u_inner[1], v1, u_inner[3]) @@ -288,9 +273,7 @@ end x, t, operator_type::Divergence, - equations::CompressibleNavierStokesDiffusion1D{ - GradientVariablesPrimitive - }) + equations::CompressibleNavierStokesDiffusion1D{GradientVariablesPrimitive}) # rho, v1, v2, _ = u_inner normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x, t, @@ -310,9 +293,7 @@ end x, t, operator_type::Gradient, - equations::CompressibleNavierStokesDiffusion1D{ - GradientVariablesPrimitive - }) + equations::CompressibleNavierStokesDiffusion1D{GradientVariablesPrimitive}) v1 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) T = boundary_condition.boundary_condition_heat_flux.boundary_value_function(x, t, @@ -328,9 +309,7 @@ end x, t, operator_type::Divergence, - equations::CompressibleNavierStokesDiffusion1D{ - GradientVariablesPrimitive - }) + equations::CompressibleNavierStokesDiffusion1D{GradientVariablesPrimitive}) return flux_inner end @@ -350,9 +329,7 @@ end x, t, operator_type::Gradient, - equations::CompressibleNavierStokesDiffusion1D{ - GradientVariablesEntropy - }) + equations::CompressibleNavierStokesDiffusion1D{GradientVariablesEntropy}) v1 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) negative_rho_inv_p = w_inner[3] # w_3 = -rho / p @@ -368,9 +345,7 @@ end x, t, operator_type::Divergence, - equations::CompressibleNavierStokesDiffusion1D{ - GradientVariablesEntropy - }) + equations::CompressibleNavierStokesDiffusion1D{GradientVariablesEntropy}) normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x, t, equations) @@ -389,9 +364,7 @@ end x, t, operator_type::Gradient, - equations::CompressibleNavierStokesDiffusion1D{ - GradientVariablesEntropy - }) + equations::CompressibleNavierStokesDiffusion1D{GradientVariablesEntropy}) v1 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) T = boundary_condition.boundary_condition_heat_flux.boundary_value_function(x, t, @@ -410,9 +383,7 @@ end x, t, operator_type::Divergence, - equations::CompressibleNavierStokesDiffusion1D{ - GradientVariablesEntropy - }) + equations::CompressibleNavierStokesDiffusion1D{GradientVariablesEntropy}) return SVector(flux_inner[1], flux_inner[2], flux_inner[3]) end end # @muladd diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index ad0db001872..5df7c01ca5c 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -81,8 +81,7 @@ w_2 = \frac{\rho v_1}{p},\, w_3 = \frac{\rho v_2}{p},\, w_4 = -\frac{\rho}{p} ``` """ struct CompressibleNavierStokesDiffusion2D{GradientVariables, RealT <: Real, - E <: AbstractCompressibleEulerEquations{2} - } <: + E <: AbstractCompressibleEulerEquations{2}} <: AbstractCompressibleNavierStokesDiffusion{2, 4, GradientVariables} # TODO: parabolic # 1) For now save gamma and inv(gamma-1) again, but could potentially reuse them from the Euler equations @@ -130,14 +129,10 @@ end # we specialize this function to compute gradients of primitive variables instead of # conservative variables. -function gradient_variable_transformation(::CompressibleNavierStokesDiffusion2D{ - GradientVariablesPrimitive - }) +function gradient_variable_transformation(::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive}) cons2prim end -function gradient_variable_transformation(::CompressibleNavierStokesDiffusion2D{ - GradientVariablesEntropy - }) +function gradient_variable_transformation(::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy}) cons2entropy end @@ -224,17 +219,13 @@ end # For CNS, it is simplest to formulate the viscous terms in primitive variables, so we transform the transformed # variables into primitive variables. @inline function convert_transformed_to_primitive(u_transformed, - equations::CompressibleNavierStokesDiffusion2D{ - GradientVariablesPrimitive - }) + equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive}) return u_transformed end # TODO: parabolic. Make this more efficient! @inline function convert_transformed_to_primitive(u_transformed, - equations::CompressibleNavierStokesDiffusion2D{ - GradientVariablesEntropy - }) + equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy}) # note: this uses CompressibleNavierStokesDiffusion2D versions of cons2prim and entropy2cons return cons2prim(entropy2cons(u_transformed, equations), equations) end @@ -245,17 +236,13 @@ end # Note, the first component of `gradient_entropy_vars` contains gradient(rho) which is unused. # TODO: parabolic; entropy stable viscous terms @inline function convert_derivative_to_primitive(u, gradient, - ::CompressibleNavierStokesDiffusion2D{ - GradientVariablesPrimitive - }) + ::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive}) return gradient end # the first argument is always the "transformed" variables. @inline function convert_derivative_to_primitive(w, gradient_entropy_vars, - equations::CompressibleNavierStokesDiffusion2D{ - GradientVariablesEntropy - }) + equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy}) # TODO: parabolic. This is inefficient to pass in transformed variables but then transform them back. # We can fix this if we directly compute v1, v2, T from the entropy variables @@ -310,9 +297,7 @@ end x, t, operator_type::Gradient, - equations::CompressibleNavierStokesDiffusion2D{ - GradientVariablesPrimitive - }) + equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive}) v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) @@ -326,9 +311,7 @@ end x, t, operator_type::Divergence, - equations::CompressibleNavierStokesDiffusion2D{ - GradientVariablesPrimitive - }) + equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive}) # rho, v1, v2, _ = u_inner normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x, t, @@ -348,9 +331,7 @@ end x, t, operator_type::Gradient, - equations::CompressibleNavierStokesDiffusion2D{ - GradientVariablesPrimitive - }) + equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive}) v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) @@ -366,9 +347,7 @@ end x, t, operator_type::Divergence, - equations::CompressibleNavierStokesDiffusion2D{ - GradientVariablesPrimitive - }) + equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive}) return flux_inner end @@ -387,9 +366,7 @@ end x, t, operator_type::Gradient, - equations::CompressibleNavierStokesDiffusion2D{ - GradientVariablesEntropy - }) + equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy}) v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) @@ -406,9 +383,7 @@ end x, t, operator_type::Divergence, - equations::CompressibleNavierStokesDiffusion2D{ - GradientVariablesEntropy - }) + equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy}) normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x, t, equations) @@ -427,9 +402,7 @@ end x, t, operator_type::Gradient, - equations::CompressibleNavierStokesDiffusion2D{ - GradientVariablesEntropy - }) + equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy}) v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) @@ -448,9 +421,7 @@ end x, t, operator_type::Divergence, - equations::CompressibleNavierStokesDiffusion2D{ - GradientVariablesEntropy - }) + equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy}) return SVector(flux_inner[1], flux_inner[2], flux_inner[3], flux_inner[4]) end @@ -461,9 +432,7 @@ end normal::AbstractVector, x, t, operator_type::Gradient, - equations::CompressibleNavierStokesDiffusion2D{ - GradientVariablesPrimitive - }) + equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive}) # BCs are usually specified as conservative variables so we convert them to primitive variables # because the gradients are assumed to be with respect to the primitive variables u_boundary = boundary_condition.boundary_value_function(x, t, equations) @@ -476,9 +445,7 @@ end normal::AbstractVector, x, t, operator_type::Divergence, - equations::CompressibleNavierStokesDiffusion2D{ - GradientVariablesPrimitive - }) + equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive}) # for Dirichlet boundary conditions, we do not impose any conditions on the viscous fluxes return flux_inner end diff --git a/src/equations/compressible_navier_stokes_3d.jl b/src/equations/compressible_navier_stokes_3d.jl index c6a55983b53..e5567ae5789 100644 --- a/src/equations/compressible_navier_stokes_3d.jl +++ b/src/equations/compressible_navier_stokes_3d.jl @@ -81,8 +81,7 @@ w_2 = \frac{\rho v_1}{p},\, w_3 = \frac{\rho v_2}{p},\, w_4 = \frac{\rho v_3}{p} ``` """ struct CompressibleNavierStokesDiffusion3D{GradientVariables, RealT <: Real, - E <: AbstractCompressibleEulerEquations{3} - } <: + E <: AbstractCompressibleEulerEquations{3}} <: AbstractCompressibleNavierStokesDiffusion{3, 5, GradientVariables} # TODO: parabolic # 1) For now save gamma and inv(gamma-1) again, but could potentially reuse them from the Euler equations @@ -130,14 +129,10 @@ end # we specialize this function to compute gradients of primitive variables instead of # conservative variables. -function gradient_variable_transformation(::CompressibleNavierStokesDiffusion3D{ - GradientVariablesPrimitive - }) +function gradient_variable_transformation(::CompressibleNavierStokesDiffusion3D{GradientVariablesPrimitive}) cons2prim end -function gradient_variable_transformation(::CompressibleNavierStokesDiffusion3D{ - GradientVariablesEntropy - }) +function gradient_variable_transformation(::CompressibleNavierStokesDiffusion3D{GradientVariablesEntropy}) cons2entropy end @@ -250,17 +245,13 @@ end # For CNS, it is simplest to formulate the viscous terms in primitive variables, so we transform the transformed # variables into primitive variables. @inline function convert_transformed_to_primitive(u_transformed, - equations::CompressibleNavierStokesDiffusion3D{ - GradientVariablesPrimitive - }) + equations::CompressibleNavierStokesDiffusion3D{GradientVariablesPrimitive}) return u_transformed end # TODO: parabolic. Make this more efficient! @inline function convert_transformed_to_primitive(u_transformed, - equations::CompressibleNavierStokesDiffusion3D{ - GradientVariablesEntropy - }) + equations::CompressibleNavierStokesDiffusion3D{GradientVariablesEntropy}) # note: this uses CompressibleNavierStokesDiffusion3D versions of cons2prim and entropy2cons return cons2prim(entropy2cons(u_transformed, equations), equations) end @@ -271,17 +262,13 @@ end # Note, the first component of `gradient_entropy_vars` contains gradient(rho) which is unused. # TODO: parabolic; entropy stable viscous terms @inline function convert_derivative_to_primitive(u, gradient, - ::CompressibleNavierStokesDiffusion3D{ - GradientVariablesPrimitive - }) + ::CompressibleNavierStokesDiffusion3D{GradientVariablesPrimitive}) return gradient end # the first argument is always the "transformed" variables. @inline function convert_derivative_to_primitive(w, gradient_entropy_vars, - equations::CompressibleNavierStokesDiffusion3D{ - GradientVariablesEntropy - }) + equations::CompressibleNavierStokesDiffusion3D{GradientVariablesEntropy}) # TODO: parabolic. This is inefficient to pass in transformed variables but then transform them back. # We can fix this if we directly compute v1, v2, v3, T from the entropy variables @@ -342,9 +329,7 @@ end x, t, operator_type::Gradient, - equations::CompressibleNavierStokesDiffusion3D{ - GradientVariablesPrimitive - }) + equations::CompressibleNavierStokesDiffusion3D{GradientVariablesPrimitive}) v1, v2, v3 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) @@ -358,9 +343,7 @@ end x, t, operator_type::Divergence, - equations::CompressibleNavierStokesDiffusion3D{ - GradientVariablesPrimitive - }) + equations::CompressibleNavierStokesDiffusion3D{GradientVariablesPrimitive}) # rho, v1, v2, v3, _ = u_inner normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x, t, @@ -381,9 +364,7 @@ end x, t, operator_type::Gradient, - equations::CompressibleNavierStokesDiffusion3D{ - GradientVariablesPrimitive - }) + equations::CompressibleNavierStokesDiffusion3D{GradientVariablesPrimitive}) v1, v2, v3 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) @@ -399,9 +380,7 @@ end x, t, operator_type::Divergence, - equations::CompressibleNavierStokesDiffusion3D{ - GradientVariablesPrimitive - }) + equations::CompressibleNavierStokesDiffusion3D{GradientVariablesPrimitive}) return flux_inner end @@ -420,9 +399,7 @@ end x, t, operator_type::Gradient, - equations::CompressibleNavierStokesDiffusion3D{ - GradientVariablesEntropy - }) + equations::CompressibleNavierStokesDiffusion3D{GradientVariablesEntropy}) v1, v2, v3 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) @@ -439,9 +416,7 @@ end x, t, operator_type::Divergence, - equations::CompressibleNavierStokesDiffusion3D{ - GradientVariablesEntropy - }) + equations::CompressibleNavierStokesDiffusion3D{GradientVariablesEntropy}) normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x, t, equations) @@ -461,9 +436,7 @@ end x, t, operator_type::Gradient, - equations::CompressibleNavierStokesDiffusion3D{ - GradientVariablesEntropy - }) + equations::CompressibleNavierStokesDiffusion3D{GradientVariablesEntropy}) v1, v2, v3 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) @@ -482,9 +455,7 @@ end x, t, operator_type::Divergence, - equations::CompressibleNavierStokesDiffusion3D{ - GradientVariablesEntropy - }) + equations::CompressibleNavierStokesDiffusion3D{GradientVariablesEntropy}) return SVector(flux_inner[1], flux_inner[2], flux_inner[3], flux_inner[4], flux_inner[5]) end diff --git a/src/equations/ideal_glm_mhd_multicomponent_1d.jl b/src/equations/ideal_glm_mhd_multicomponent_1d.jl index 0efa6426448..dad7c27e86c 100644 --- a/src/equations/ideal_glm_mhd_multicomponent_1d.jl +++ b/src/equations/ideal_glm_mhd_multicomponent_1d.jl @@ -17,19 +17,15 @@ mutable struct IdealGlmMhdMulticomponentEquations1D{NVARS, NCOMP, RealT <: Real} cv::SVector{NCOMP, RealT} cp::SVector{NCOMP, RealT} - function IdealGlmMhdMulticomponentEquations1D{NVARS, NCOMP, RealT}(gammas::SVector{ - NCOMP, - RealT - }, - gas_constants::SVector{ - NCOMP, - RealT - }) where { - NVARS, - NCOMP, - RealT <: - Real - } + function IdealGlmMhdMulticomponentEquations1D{NVARS, NCOMP, RealT}(gammas::SVector{NCOMP, + RealT}, + gas_constants::SVector{NCOMP, + RealT}) where { + NVARS, + NCOMP, + RealT <: + Real + } NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `gas_constants` have to be filled with at least one value")) diff --git a/src/equations/ideal_glm_mhd_multicomponent_2d.jl b/src/equations/ideal_glm_mhd_multicomponent_2d.jl index 9b0eeb411e8..a3a50c0485f 100644 --- a/src/equations/ideal_glm_mhd_multicomponent_2d.jl +++ b/src/equations/ideal_glm_mhd_multicomponent_2d.jl @@ -18,19 +18,15 @@ mutable struct IdealGlmMhdMulticomponentEquations2D{NVARS, NCOMP, RealT <: Real} cp::SVector{NCOMP, RealT} c_h::RealT # GLM cleaning speed - function IdealGlmMhdMulticomponentEquations2D{NVARS, NCOMP, RealT}(gammas::SVector{ - NCOMP, - RealT - }, - gas_constants::SVector{ - NCOMP, - RealT - }) where { - NVARS, - NCOMP, - RealT <: - Real - } + function IdealGlmMhdMulticomponentEquations2D{NVARS, NCOMP, RealT}(gammas::SVector{NCOMP, + RealT}, + gas_constants::SVector{NCOMP, + RealT}) where { + NVARS, + NCOMP, + RealT <: + Real + } NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `gas_constants` have to be filled with at least one value")) diff --git a/src/equations/numerical_fluxes.jl b/src/equations/numerical_fluxes.jl index 43be04f745d..44d523b6e89 100644 --- a/src/equations/numerical_fluxes.jl +++ b/src/equations/numerical_fluxes.jl @@ -198,10 +198,7 @@ function max_abs_speed_naive end end const FluxLaxFriedrichs{MaxAbsSpeed} = FluxPlusDissipation{typeof(flux_central), - DissipationLocalLaxFriedrichs{ - MaxAbsSpeed - } - } + DissipationLocalLaxFriedrichs{MaxAbsSpeed}} """ FluxLaxFriedrichs(max_abs_speed=max_abs_speed_naive) diff --git a/src/meshes/unstructured_mesh.jl b/src/meshes/unstructured_mesh.jl index c370c0f25f8..fae52f834b3 100644 --- a/src/meshes/unstructured_mesh.jl +++ b/src/meshes/unstructured_mesh.jl @@ -15,8 +15,9 @@ An unstructured (possibly curved) quadrilateral mesh. All mesh information, neighbour coupling, and boundary curve information is read in from a mesh file `filename`. """ -mutable struct UnstructuredMesh2D{RealT <: Real, CurvedSurfaceT <: CurvedSurface{RealT} - } <: AbstractMesh{2} +mutable struct UnstructuredMesh2D{RealT <: Real, + CurvedSurfaceT <: CurvedSurface{RealT}} <: + AbstractMesh{2} filename :: String n_corners :: Int n_surfaces :: Int # total number of surfaces diff --git a/src/semidiscretization/semidiscretization_coupled.jl b/src/semidiscretization/semidiscretization_coupled.jl index 49763b12e5d..0941ae6a8ca 100644 --- a/src/semidiscretization/semidiscretization_coupled.jl +++ b/src/semidiscretization/semidiscretization_coupled.jl @@ -41,8 +41,9 @@ function SemidiscretizationCoupled(semis...) performance_counter = PerformanceCounter() - SemidiscretizationCoupled{typeof(semis), typeof(u_indices), typeof(performance_counter) - }(semis, u_indices, performance_counter) + SemidiscretizationCoupled{typeof(semis), typeof(u_indices), + typeof(performance_counter)}(semis, u_indices, + performance_counter) end function Base.show(io::IO, semi::SemidiscretizationCoupled) @@ -432,8 +433,7 @@ function allocate_coupled_boundary_condition(boundary_condition, direction, mesh end # In 2D -function allocate_coupled_boundary_condition(boundary_condition::BoundaryConditionCoupled{2 - }, +function allocate_coupled_boundary_condition(boundary_condition::BoundaryConditionCoupled{2}, direction, mesh, equations, dg::DGSEM) if direction in (1, 2) cell_size = size(mesh, 2) diff --git a/src/semidiscretization/semidiscretization_hyperbolic.jl b/src/semidiscretization/semidiscretization_hyperbolic.jl index 9d465bfcc5f..7ebd758de37 100644 --- a/src/semidiscretization/semidiscretization_hyperbolic.jl +++ b/src/semidiscretization/semidiscretization_hyperbolic.jl @@ -29,17 +29,18 @@ struct SemidiscretizationHyperbolic{Mesh, Equations, InitialCondition, performance_counter::PerformanceCounter function SemidiscretizationHyperbolic{Mesh, Equations, InitialCondition, - BoundaryConditions, SourceTerms, Solver, Cache - }(mesh::Mesh, equations::Equations, - initial_condition::InitialCondition, - boundary_conditions::BoundaryConditions, - source_terms::SourceTerms, - solver::Solver, - cache::Cache) where {Mesh, Equations, - InitialCondition, - BoundaryConditions, - SourceTerms, Solver, - Cache} + BoundaryConditions, SourceTerms, Solver, + Cache}(mesh::Mesh, equations::Equations, + initial_condition::InitialCondition, + boundary_conditions::BoundaryConditions, + source_terms::SourceTerms, + solver::Solver, + cache::Cache) where {Mesh, Equations, + InitialCondition, + BoundaryConditions, + SourceTerms, + Solver, + Cache} @assert ndims(mesh) == ndims(equations) performance_counter = PerformanceCounter() @@ -268,8 +269,7 @@ end function print_boundary_conditions(io, semi::SemiHypMeshBCSolver{<:Any, - <:UnstructuredSortedBoundaryTypes - }) + <:UnstructuredSortedBoundaryTypes}) @unpack boundary_conditions = semi @unpack boundary_dictionary = boundary_conditions summary_line(io, "boundary conditions", length(boundary_dictionary)) @@ -289,8 +289,7 @@ function print_boundary_conditions(io, semi::SemiHypMeshBCSolver{<:Any, <:NamedT end function print_boundary_conditions(io, - semi::SemiHypMeshBCSolver{ - <:Union{TreeMesh, + semi::SemiHypMeshBCSolver{<:Union{TreeMesh, StructuredMesh}, <:Union{Tuple, NamedTuple, AbstractArray}}) diff --git a/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl b/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl index 35340d65b1e..0f44941390a 100644 --- a/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl +++ b/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl @@ -45,30 +45,29 @@ struct SemidiscretizationHyperbolicParabolic{Mesh, Equations, EquationsParabolic BoundaryConditionsParabolic, SourceTerms, Solver, SolverParabolic, Cache, - CacheParabolic - }(mesh::Mesh, - equations::Equations, - equations_parabolic::EquationsParabolic, - initial_condition::InitialCondition, - boundary_conditions::BoundaryConditions, - boundary_conditions_parabolic::BoundaryConditionsParabolic, - source_terms::SourceTerms, - solver::Solver, - solver_parabolic::SolverParabolic, - cache::Cache, - cache_parabolic::CacheParabolic) where { - Mesh, - Equations, - EquationsParabolic, - InitialCondition, - BoundaryConditions, - BoundaryConditionsParabolic, - SourceTerms, - Solver, - SolverParabolic, - Cache, - CacheParabolic - } + CacheParabolic}(mesh::Mesh, + equations::Equations, + equations_parabolic::EquationsParabolic, + initial_condition::InitialCondition, + boundary_conditions::BoundaryConditions, + boundary_conditions_parabolic::BoundaryConditionsParabolic, + source_terms::SourceTerms, + solver::Solver, + solver_parabolic::SolverParabolic, + cache::Cache, + cache_parabolic::CacheParabolic) where { + Mesh, + Equations, + EquationsParabolic, + InitialCondition, + BoundaryConditions, + BoundaryConditionsParabolic, + SourceTerms, + Solver, + SolverParabolic, + Cache, + CacheParabolic + } @assert ndims(mesh) == ndims(equations) # Todo: assert nvariables(equations)==nvariables(equations_parabolic) diff --git a/src/solvers/dgmulti/flux_differencing.jl b/src/solvers/dgmulti/flux_differencing.jl index 884a8fac43b..36aa50dff4e 100644 --- a/src/solvers/dgmulti/flux_differencing.jl +++ b/src/solvers/dgmulti/flux_differencing.jl @@ -88,8 +88,8 @@ end # Version for sparse operators and symmetric fluxes @inline function hadamard_sum!(du, - A::LinearAlgebra.Adjoint{<:Any, <:AbstractSparseMatrixCSC - }, + A::LinearAlgebra.Adjoint{<:Any, + <:AbstractSparseMatrixCSC}, flux_is_symmetric::True, volume_flux, orientation_or_normal_direction, u, equations) A_base = parent(A) # the adjoint of a SparseMatrixCSC is basically a SparseMatrixCSR @@ -122,8 +122,8 @@ end # Version for sparse operators and symmetric fluxes with curved meshes @inline function hadamard_sum!(du, - A::LinearAlgebra.Adjoint{<:Any, <:AbstractSparseMatrixCSC - }, + A::LinearAlgebra.Adjoint{<:Any, + <:AbstractSparseMatrixCSC}, flux_is_symmetric::True, volume_flux, normal_directions::AbstractVector{<:AbstractVector}, u, equations) @@ -161,8 +161,8 @@ end # TODO: DGMulti. Fix for curved meshes. # Version for sparse operators and non-symmetric fluxes @inline function hadamard_sum!(du, - A::LinearAlgebra.Adjoint{<:Any, <:AbstractSparseMatrixCSC - }, + A::LinearAlgebra.Adjoint{<:Any, + <:AbstractSparseMatrixCSC}, flux_is_symmetric::False, volume_flux, normal_direction::AbstractVector, u, equations) A_base = parent(A) # the adjoint of a SparseMatrixCSC is basically a SparseMatrixCSR diff --git a/src/solvers/dgmulti/flux_differencing_gauss_sbp.jl b/src/solvers/dgmulti/flux_differencing_gauss_sbp.jl index 2c5505cc4e9..9059caf87f6 100644 --- a/src/solvers/dgmulti/flux_differencing_gauss_sbp.jl +++ b/src/solvers/dgmulti/flux_differencing_gauss_sbp.jl @@ -380,9 +380,8 @@ function create_cache(mesh::DGMultiMesh, equations, # specialized operators to perform tensor product interpolation to faces for Gauss nodes interp_matrix_gauss_to_face = TensorProductGaussFaceOperator(Interpolation(), dg) - projection_matrix_gauss_to_face = TensorProductGaussFaceOperator(Projection{ - Static.False() - }(), dg) + projection_matrix_gauss_to_face = TensorProductGaussFaceOperator(Projection{Static.False()}(), + dg) # `LIFT` matrix for Gauss nodes - this is equivalent to `projection_matrix_gauss_to_face` scaled by `diagm(rd.wf)`, # where `rd.wf` are Gauss node face quadrature weights. diff --git a/src/solvers/dgmulti/sbp.jl b/src/solvers/dgmulti/sbp.jl index d434d3146ce..232555e18b5 100644 --- a/src/solvers/dgmulti/sbp.jl +++ b/src/solvers/dgmulti/sbp.jl @@ -40,26 +40,28 @@ end const DGMultiPeriodicFDSBP{NDIMS, ApproxType, ElemType} = DGMulti{NDIMS, ElemType, ApproxType, SurfaceIntegral, - VolumeIntegral - } where {NDIMS, ElemType, - ApproxType <: - SummationByPartsOperators.AbstractPeriodicDerivativeOperator, - SurfaceIntegral, - VolumeIntegral} + VolumeIntegral} where { + NDIMS, + ElemType, + ApproxType <: + SummationByPartsOperators.AbstractPeriodicDerivativeOperator, + SurfaceIntegral, + VolumeIntegral + } const DGMultiFluxDiffPeriodicFDSBP{NDIMS, ApproxType, ElemType} = DGMulti{NDIMS, ElemType, ApproxType, SurfaceIntegral, - VolumeIntegral - } where {NDIMS, - ElemType, - ApproxType <: - SummationByPartsOperators.AbstractPeriodicDerivativeOperator, - SurfaceIntegral <: - SurfaceIntegralWeakForm, - VolumeIntegral <: - VolumeIntegralFluxDifferencing - } + VolumeIntegral} where { + NDIMS, + ElemType, + ApproxType <: + SummationByPartsOperators.AbstractPeriodicDerivativeOperator, + SurfaceIntegral <: + SurfaceIntegralWeakForm, + VolumeIntegral <: + VolumeIntegralFluxDifferencing + } """ DGMultiMesh(dg::DGMulti) diff --git a/src/solvers/dgmulti/types.jl b/src/solvers/dgmulti/types.jl index ae1eed7fd52..813bc67061e 100644 --- a/src/solvers/dgmulti/types.jl +++ b/src/solvers/dgmulti/types.jl @@ -4,49 +4,46 @@ # `DGMulti` refers to both multiple DG types (polynomial/SBP, simplices/quads/hexes) as well as # the use of multi-dimensional operators in the solver. -const DGMulti{NDIMS, ElemType, ApproxType, SurfaceIntegral, VolumeIntegral} = DG{ - <:RefElemData{ - NDIMS, +const DGMulti{NDIMS, ElemType, ApproxType, SurfaceIntegral, VolumeIntegral} = DG{<:RefElemData{NDIMS, ElemType, - ApproxType - }, + ApproxType}, Mortar, SurfaceIntegral, - VolumeIntegral - } where { - Mortar - } + VolumeIntegral} where { + Mortar + } # Type aliases. The first parameter is `ApproxType` since it is more commonly used for dispatch. const DGMultiWeakForm{ApproxType, ElemType} = DGMulti{NDIMS, ElemType, ApproxType, <:SurfaceIntegralWeakForm, - <:VolumeIntegralWeakForm - } where {NDIMS} + <:VolumeIntegralWeakForm} where {NDIMS + } const DGMultiFluxDiff{ApproxType, ElemType} = DGMulti{NDIMS, ElemType, ApproxType, <:SurfaceIntegralWeakForm, - <:Union{ - VolumeIntegralFluxDifferencing, - VolumeIntegralShockCapturingHG - }} where {NDIMS} + <:Union{VolumeIntegralFluxDifferencing, + VolumeIntegralShockCapturingHG}} where { + NDIMS + } const DGMultiFluxDiffSBP{ApproxType, ElemType} = DGMulti{NDIMS, ElemType, ApproxType, <:SurfaceIntegralWeakForm, - <:Union{ - VolumeIntegralFluxDifferencing, - VolumeIntegralShockCapturingHG - } - } where {NDIMS, - ApproxType <: Union{SBP, - AbstractDerivativeOperator - }} + <:Union{VolumeIntegralFluxDifferencing, + VolumeIntegralShockCapturingHG}} where { + NDIMS, + ApproxType <: + Union{SBP, + AbstractDerivativeOperator} + } const DGMultiSBP{ApproxType, ElemType} = DGMulti{NDIMS, ElemType, ApproxType, - SurfaceIntegral, VolumeIntegral - } where {NDIMS, ElemType, - ApproxType <: Union{SBP, - AbstractDerivativeOperator}, - SurfaceIntegral, VolumeIntegral} + SurfaceIntegral, + VolumeIntegral} where {NDIMS, ElemType, + ApproxType <: + Union{SBP, + AbstractDerivativeOperator}, + SurfaceIntegral, + VolumeIntegral} # By default, Julia/LLVM does not use fused multiply-add operations (FMAs). # Since these FMAs can increase the performance of many numerical algorithms, diff --git a/src/solvers/dgsem/basis_lobatto_legendre.jl b/src/solvers/dgsem/basis_lobatto_legendre.jl index 1b4e5446e44..6a92fd1c066 100644 --- a/src/solvers/dgsem/basis_lobatto_legendre.jl +++ b/src/solvers/dgsem/basis_lobatto_legendre.jl @@ -188,9 +188,9 @@ function MortarL2(basis::LobattoLegendreBasis) reverse_upper = Matrix{RealT}(reverse_upper_) reverse_lower = Matrix{RealT}(reverse_lower_) - LobattoLegendreMortarL2{RealT, nnodes_, typeof(forward_upper), typeof(reverse_upper) - }(forward_upper, forward_lower, - reverse_upper, reverse_lower) + LobattoLegendreMortarL2{RealT, nnodes_, typeof(forward_upper), + typeof(reverse_upper)}(forward_upper, forward_lower, + reverse_upper, reverse_lower) end function Base.show(io::IO, mortar::LobattoLegendreMortarL2) diff --git a/src/solvers/dgsem_p4est/containers.jl b/src/solvers/dgsem_p4est/containers.jl index 5fe68e06710..f9830d0011c 100644 --- a/src/solvers/dgsem_p4est/containers.jl +++ b/src/solvers/dgsem_p4est/containers.jl @@ -454,8 +454,7 @@ mutable struct InitSurfacesIterFaceUserData{Interfaces, Mortars, Boundaries, Mes end function InitSurfacesIterFaceUserData(interfaces, mortars, boundaries, mesh) - return InitSurfacesIterFaceUserData{ - typeof(interfaces), typeof(mortars), + return InitSurfacesIterFaceUserData{typeof(interfaces), typeof(mortars), typeof(boundaries), typeof(mesh)}(interfaces, 1, mortars, 1, boundaries, 1, diff --git a/src/solvers/dgsem_p4est/containers_parallel.jl b/src/solvers/dgsem_p4est/containers_parallel.jl index e7ee1f81478..7c7bd868457 100644 --- a/src/solvers/dgsem_p4est/containers_parallel.jl +++ b/src/solvers/dgsem_p4est/containers_parallel.jl @@ -266,8 +266,7 @@ end function ParallelInitSurfacesIterFaceUserData(interfaces, mortars, boundaries, mpi_interfaces, mpi_mortars, mesh) - return ParallelInitSurfacesIterFaceUserData{ - typeof(interfaces), typeof(mortars), + return ParallelInitSurfacesIterFaceUserData{typeof(interfaces), typeof(mortars), typeof(boundaries), typeof(mpi_interfaces), typeof(mpi_mortars), typeof(mesh)}(interfaces, diff --git a/src/solvers/dgsem_p4est/containers_parallel_2d.jl b/src/solvers/dgsem_p4est/containers_parallel_2d.jl index 8c39e4a69c8..d531d33821b 100644 --- a/src/solvers/dgsem_p4est/containers_parallel_2d.jl +++ b/src/solvers/dgsem_p4est/containers_parallel_2d.jl @@ -6,9 +6,7 @@ #! format: noindent # Initialize node_indices of MPI interface container -@inline function init_mpi_interface_node_indices!(mpi_interfaces::P4estMPIInterfaceContainer{ - 2 - }, +@inline function init_mpi_interface_node_indices!(mpi_interfaces::P4estMPIInterfaceContainer{2}, faces, local_side, orientation, mpi_interface_id) # Align interface in positive coordinate direction of primary element. diff --git a/src/solvers/dgsem_p4est/containers_parallel_3d.jl b/src/solvers/dgsem_p4est/containers_parallel_3d.jl index be4e2bfbfc9..56f0a543b97 100644 --- a/src/solvers/dgsem_p4est/containers_parallel_3d.jl +++ b/src/solvers/dgsem_p4est/containers_parallel_3d.jl @@ -6,9 +6,7 @@ #! format: noindent # Initialize node_indices of MPI interface container -@inline function init_mpi_interface_node_indices!(mpi_interfaces::P4estMPIInterfaceContainer{ - 3 - }, +@inline function init_mpi_interface_node_indices!(mpi_interfaces::P4estMPIInterfaceContainer{3}, faces, local_side, orientation, mpi_interface_id) # Align interface at the primary element (primary element has surface indices (:i_forward, :j_forward)). diff --git a/src/solvers/dgsem_p4est/dg_2d_parabolic.jl b/src/solvers/dgsem_p4est/dg_2d_parabolic.jl index 9dd10df16ae..a7f3345168f 100644 --- a/src/solvers/dgsem_p4est/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_p4est/dg_2d_parabolic.jl @@ -803,8 +803,7 @@ end function calc_boundary_flux_gradients!(cache, t, boundary_condition::Union{BoundaryConditionPeriodic, - BoundaryConditionDoNothing - }, + BoundaryConditionDoNothing}, mesh::P4estMesh, equations, surface_integral, dg::DG) @assert isempty(eachboundary(dg, cache)) end diff --git a/src/solvers/dgsem_p4est/dg_parallel.jl b/src/solvers/dgsem_p4est/dg_parallel.jl index 324bc7f3cd6..712ede2bfce 100644 --- a/src/solvers/dgsem_p4est/dg_parallel.jl +++ b/src/solvers/dgsem_p4est/dg_parallel.jl @@ -342,8 +342,7 @@ function InitNeighborRankConnectivityIterFaceUserData(mpi_interfaces, mpi_mortar global_mortar_ids = fill(-1, nmpimortars(mpi_mortars)) neighbor_ranks_mortar = Vector{Vector{Int}}(undef, nmpimortars(mpi_mortars)) - return InitNeighborRankConnectivityIterFaceUserData{ - typeof(mpi_interfaces), + return InitNeighborRankConnectivityIterFaceUserData{typeof(mpi_interfaces), typeof(mpi_mortars), typeof(mesh)}(mpi_interfaces, 1, global_interface_ids, diff --git a/src/solvers/dgsem_structured/containers.jl b/src/solvers/dgsem_structured/containers.jl index 41eabf7c6bf..8adf005b782 100644 --- a/src/solvers/dgsem_structured/containers.jl +++ b/src/solvers/dgsem_structured/containers.jl @@ -5,8 +5,8 @@ @muladd begin #! format: noindent -struct ElementContainer{NDIMS, RealT <: Real, uEltype <: Real, NDIMSP1, NDIMSP2, NDIMSP3 - } +struct ElementContainer{NDIMS, RealT <: Real, uEltype <: Real, NDIMSP1, NDIMSP2, + NDIMSP3} # Physical coordinates at each node node_coordinates::Array{RealT, NDIMSP2} # [orientation, node_i, node_j, node_k, element] # ID of neighbor element in negative direction in orientation diff --git a/src/solvers/dgsem_tree/dg_1d_parabolic.jl b/src/solvers/dgsem_tree/dg_1d_parabolic.jl index 90007b05b3d..0017f9ca88e 100644 --- a/src/solvers/dgsem_tree/dg_1d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_1d_parabolic.jl @@ -290,10 +290,8 @@ function calc_boundary_flux_gradients!(cache, t, 2, firsts[2], lasts[2]) end -function calc_boundary_flux_by_direction_gradient!(surface_flux_values::AbstractArray{ - <:Any, - 3 - }, +function calc_boundary_flux_by_direction_gradient!(surface_flux_values::AbstractArray{<:Any, + 3}, t, boundary_condition, equations_parabolic::AbstractEquationsParabolic, @@ -358,10 +356,8 @@ function calc_boundary_flux_divergence!(cache, t, dg, cache, 2, firsts[2], lasts[2]) end -function calc_boundary_flux_by_direction_divergence!(surface_flux_values::AbstractArray{ - <:Any, - 3 - }, +function calc_boundary_flux_by_direction_divergence!(surface_flux_values::AbstractArray{<:Any, + 3}, t, boundary_condition, equations_parabolic::AbstractEquationsParabolic, diff --git a/src/solvers/dgsem_tree/dg_2d.jl b/src/solvers/dgsem_tree/dg_2d.jl index 7ecf4c00032..547ed352ef3 100644 --- a/src/solvers/dgsem_tree/dg_2d.jl +++ b/src/solvers/dgsem_tree/dg_2d.jl @@ -391,8 +391,8 @@ end @inline function fv_kernel!(du, u, mesh::Union{TreeMesh{2}, StructuredMesh{2}, - UnstructuredMesh2D, P4estMesh{2}, T8codeMesh{2} - }, + UnstructuredMesh2D, P4estMesh{2}, + T8codeMesh{2}}, nonconservative_terms, equations, volume_flux_fv, dg::DGSEM, cache, element, alpha = true) @unpack fstar1_L_threaded, fstar1_R_threaded, fstar2_L_threaded, fstar2_R_threaded = cache diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 06abff5e85b..3083ae30680 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -384,10 +384,8 @@ function calc_boundary_flux_gradients!(cache, t, cache, 4, firsts[4], lasts[4]) end -function calc_boundary_flux_by_direction_gradient!(surface_flux_values::AbstractArray{ - <:Any, - 4 - }, +function calc_boundary_flux_by_direction_gradient!(surface_flux_values::AbstractArray{<:Any, + 4}, t, boundary_condition, equations_parabolic::AbstractEquationsParabolic, @@ -464,10 +462,8 @@ function calc_boundary_flux_divergence!(cache, t, dg, cache, 4, firsts[4], lasts[4]) end -function calc_boundary_flux_by_direction_divergence!(surface_flux_values::AbstractArray{ - <:Any, - 4 - }, +function calc_boundary_flux_by_direction_divergence!(surface_flux_values::AbstractArray{<:Any, + 4}, t, boundary_condition, equations_parabolic::AbstractEquationsParabolic, diff --git a/src/solvers/dgsem_tree/dg_3d.jl b/src/solvers/dgsem_tree/dg_3d.jl index 3364187e93c..0955dc38655 100644 --- a/src/solvers/dgsem_tree/dg_3d.jl +++ b/src/solvers/dgsem_tree/dg_3d.jl @@ -209,8 +209,8 @@ function rhs!(du, u, t, end function calc_volume_integral!(du, u, - mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3} - }, + mesh::Union{TreeMesh{3}, StructuredMesh{3}, + P4estMesh{3}}, nonconservative_terms, equations, volume_integral::VolumeIntegralWeakForm, dg::DGSEM, cache) @@ -264,8 +264,8 @@ See also https://github.com/trixi-framework/Trixi.jl/issues/1671#issuecomment-17 end function calc_volume_integral!(du, u, - mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3} - }, + mesh::Union{TreeMesh{3}, StructuredMesh{3}, + P4estMesh{3}}, nonconservative_terms, equations, volume_integral::VolumeIntegralFluxDifferencing, dg::DGSEM, cache) @@ -378,8 +378,8 @@ end # TODO: Taal dimension agnostic function calc_volume_integral!(du, u, - mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3} - }, + mesh::Union{TreeMesh{3}, StructuredMesh{3}, + P4estMesh{3}}, nonconservative_terms, equations, volume_integral::VolumeIntegralShockCapturingHG, dg::DGSEM, cache) diff --git a/src/solvers/dgsem_tree/dg_3d_parabolic.jl b/src/solvers/dgsem_tree/dg_3d_parabolic.jl index 2561c5fe5b0..9ad28c6aa8e 100644 --- a/src/solvers/dgsem_tree/dg_3d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_3d_parabolic.jl @@ -454,10 +454,8 @@ function calc_boundary_flux_gradients!(cache, t, 6, firsts[6], lasts[6]) end -function calc_boundary_flux_by_direction_gradient!(surface_flux_values::AbstractArray{ - <:Any, - 5 - }, +function calc_boundary_flux_by_direction_gradient!(surface_flux_values::AbstractArray{<:Any, + 5}, t, boundary_condition, equations_parabolic::AbstractEquationsParabolic, @@ -546,10 +544,8 @@ function calc_boundary_flux_divergence!(cache, t, dg, cache, 6, firsts[6], lasts[6]) end -function calc_boundary_flux_by_direction_divergence!(surface_flux_values::AbstractArray{ - <:Any, - 5 - }, +function calc_boundary_flux_by_direction_divergence!(surface_flux_values::AbstractArray{<:Any, + 5}, t, boundary_condition, equations_parabolic::AbstractEquationsParabolic, diff --git a/src/solvers/dgsem_tree/indicators_1d.jl b/src/solvers/dgsem_tree/indicators_1d.jl index 4006932352e..dff87bfe06c 100644 --- a/src/solvers/dgsem_tree/indicators_1d.jl +++ b/src/solvers/dgsem_tree/indicators_1d.jl @@ -29,8 +29,8 @@ end # full FV element. # # TODO: TrixiShallowWater: move new indicator type -function (indicator_hg::IndicatorHennemannGassnerShallowWater)(u::AbstractArray{<:Any, 3 - }, +function (indicator_hg::IndicatorHennemannGassnerShallowWater)(u::AbstractArray{<:Any, + 3}, mesh, equations::ShallowWaterEquations1D, dg::DGSEM, cache; diff --git a/src/solvers/dgsem_tree/indicators_2d.jl b/src/solvers/dgsem_tree/indicators_2d.jl index 8333bb515d3..fa8ed481eb9 100644 --- a/src/solvers/dgsem_tree/indicators_2d.jl +++ b/src/solvers/dgsem_tree/indicators_2d.jl @@ -33,8 +33,8 @@ end # full FV element. # # TODO: TrixiShallowWater: move new indicator type -function (indicator_hg::IndicatorHennemannGassnerShallowWater)(u::AbstractArray{<:Any, 4 - }, +function (indicator_hg::IndicatorHennemannGassnerShallowWater)(u::AbstractArray{<:Any, + 4}, mesh, equations::ShallowWaterEquations2D, dg::DGSEM, cache; diff --git a/src/solvers/dgsem_tree/subcell_limiters_2d.jl b/src/solvers/dgsem_tree/subcell_limiters_2d.jl index bc69e55f264..384f4178bc9 100644 --- a/src/solvers/dgsem_tree/subcell_limiters_2d.jl +++ b/src/solvers/dgsem_tree/subcell_limiters_2d.jl @@ -8,10 +8,9 @@ # this method is used when the limiter is constructed as for shock-capturing volume integrals function create_cache(limiter::Type{SubcellLimiterIDP}, equations::AbstractEquations{2}, basis::LobattoLegendreBasis, bound_keys) - subcell_limiter_coefficients = Trixi.ContainerSubcellLimiterIDP2D{real(basis) - }(0, - nnodes(basis), - bound_keys) + subcell_limiter_coefficients = Trixi.ContainerSubcellLimiterIDP2D{real(basis)}(0, + nnodes(basis), + bound_keys) # Memory for bounds checking routine with `BoundsCheckCallback`. # The first entry of each vector contains the maximum deviation since the last export. diff --git a/src/visualization/recipes_plots.jl b/src/visualization/recipes_plots.jl index d15f7e542e1..0e9b5a66a8d 100644 --- a/src/visualization/recipes_plots.jl +++ b/src/visualization/recipes_plots.jl @@ -57,11 +57,8 @@ end # Visualize the mesh in a 2D plot # # Note: This is an experimental feature and may be changed in future releases without notice. -RecipesBase.@recipe function f(pm::PlotMesh{ - <:PlotData2DCartesian{<:Any, - <:AbstractVector{ - <:AbstractVector - }}}) +RecipesBase.@recipe function f(pm::PlotMesh{<:PlotData2DCartesian{<:Any, + <:AbstractVector{<:AbstractVector}}}) @unpack plot_data = pm @unpack x, y, mesh_vertices_x, mesh_vertices_y = plot_data diff --git a/test/test_tree_3d_fdsbp.jl b/test/test_tree_3d_fdsbp.jl index 16508df300e..e0e2bfe4b88 100644 --- a/test/test_tree_3d_fdsbp.jl +++ b/test/test_tree_3d_fdsbp.jl @@ -32,8 +32,8 @@ end xmax = 1.0, N = 10) @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"), - l2=[1.3819894522373702e-8], - linf=[3.381866298113323e-8], + l2=[5.228248923012878e-9], + linf=[9.24430243465224e-9], D_SBP=D, initial_refinement_level=0, tspan=(0.0, 5.0)) From 80869fc89f2839101e2d21fd0ecd1a80c702ac22 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 07:40:50 +0100 Subject: [PATCH 193/263] Bump crate-ci/typos from 1.16.21 to 1.16.23 (#1764) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.16.21 to 1.16.23. - [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.16.21...v1.16.23) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Hendrik Ranocha --- .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 fb71fe45af9..366cb1183a0 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.16.21 + uses: crate-ci/typos@v1.16.23 From 75db52133087088e9dd1be4b5c515c35cbc8d967 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 4 Dec 2023 07:42:02 +0100 Subject: [PATCH 194/263] set version to v0.6.3 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 4e2a89dc133..77140fce78b 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.6.3-pre" +version = "0.6.3" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 45e7dc24f975f201c06fec6c7272efb5fb31b8c5 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 4 Dec 2023 07:42:20 +0100 Subject: [PATCH 195/263] set development version to v0.6.4-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 77140fce78b..ace71a50d8b 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.6.3" +version = "0.6.4-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 7a7ce48e5c5f174332b77a8943290e19c9805102 Mon Sep 17 00:00:00 2001 From: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> Date: Wed, 6 Dec 2023 11:13:01 +0100 Subject: [PATCH 196/263] Make error message for unknown boundary name more helpful (#1762) Co-authored-by: Daniel Doehring --- src/solvers/dgsem_unstructured/sort_boundary_conditions.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/solvers/dgsem_unstructured/sort_boundary_conditions.jl b/src/solvers/dgsem_unstructured/sort_boundary_conditions.jl index cad5542aae3..b5388cadc8b 100644 --- a/src/solvers/dgsem_unstructured/sort_boundary_conditions.jl +++ b/src/solvers/dgsem_unstructured/sort_boundary_conditions.jl @@ -56,7 +56,8 @@ function initialize!(boundary_types_container::UnstructuredSortedBoundaryTypes{N for key in keys(boundary_dictionary) if !(key in all_names) println(stderr, - "ERROR: Key $(repr(key)) is not a valid boundary name") + "ERROR: Key $(repr(key)) is not a valid boundary name. " * + "Valid names are $all_names.") MPI.Abort(mpi_comm(), 1) end end @@ -67,7 +68,8 @@ function initialize!(boundary_types_container::UnstructuredSortedBoundaryTypes{N else for key in keys(boundary_dictionary) if !(key in unique_names) - error("Key $(repr(key)) is not a valid boundary name") + error("Key $(repr(key)) is not a valid boundary name. " * + "Valid names are $unique_names.") end end end From 3d899bc3a301bdc40fc57afb95ea9e88ab10c459 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Wed, 6 Dec 2023 21:51:25 +0100 Subject: [PATCH 197/263] Make error norm calculation optional (#1755) * Make error norm calculation optional * test no errors * no errors * comment more clear * shorter version? * add text * update docstring * cut error passing * Update src/callbacks_step/analysis.jl Co-authored-by: Hendrik Ranocha * print in if clause * shorten * Update src/callbacks_step/analysis.jl Co-authored-by: Hendrik Ranocha * Add docstring for default_analysis_errors * Update src/equations/equations.jl --------- Co-authored-by: Hendrik Ranocha --- src/callbacks_step/analysis.jl | 54 ++++++++++++++++++++-------------- src/equations/equations.jl | 7 +++++ test/test_tree_1d_advection.jl | 14 +++++++++ 3 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/callbacks_step/analysis.jl b/src/callbacks_step/analysis.jl index e5b4a01a885..ba232032951 100644 --- a/src/callbacks_step/analysis.jl +++ b/src/callbacks_step/analysis.jl @@ -23,6 +23,13 @@ Additional errors can be computed, e.g. by passing `extra_analysis_errors = (:l2_error_primitive, :linf_error_primitive)` or `extra_analysis_errors = (:conservation_error,)`. +If you want to omit the computation (to safe compute-time) of the [`default_analysis_errors`](@ref), specify +`analysis_errors = Symbol[]`. +Note: `default_analysis_errors` are `:l2_error` and `:linf_error` for all equations. +If you want to compute `extra_analysis_errors` such as `:conservation_error` solely, i.e., +without `:l2_error, :linf_error` you need to specify +`analysis_errors = [:conservation_error]` instead of `extra_analysis_errors = [:conservation_error]`. + Further scalar functions `func` in `extra_analysis_integrals` are applied to the numerical solution and integrated over the computational domain. Some examples for this are [`entropy`](@ref), [`energy_kinetic`](@ref), [`energy_internal`](@ref), and [`energy_total`](@ref). @@ -332,7 +339,8 @@ function (analysis_callback::AnalysisCallback)(u_ode, du_ode, integrator, semi) @notimeit timer() integrator.f(du_ode, u_ode, semi, t) u = wrap_array(u_ode, mesh, equations, solver, cache) du = wrap_array(du_ode, mesh, equations, solver, cache) - l2_error, linf_error = analysis_callback(io, du, u, u_ode, t, semi) + # Compute l2_error, linf_error + analysis_callback(io, du, u, u_ode, t, semi) mpi_println("─"^100) mpi_println() @@ -354,8 +362,7 @@ function (analysis_callback::AnalysisCallback)(u_ode, du_ode, integrator, semi) analysis_callback.start_time_last_analysis = time_ns() analysis_callback.ncalls_rhs_last_analysis = ncalls(semi.performance_counter) - # Return errors for EOC analysis - return l2_error, linf_error + return nothing end # This method is just called internally from `(analysis_callback::AnalysisCallback)(integrator)` @@ -377,28 +384,31 @@ function (analysis_callback::AnalysisCallback)(io, du, u, u_ode, t, semi) println() end - # Calculate L2/Linf errors, which are also returned - l2_error, linf_error = calc_error_norms(u_ode, t, analyzer, semi, cache_analysis) + if :l2_error in analysis_errors || :linf_error in analysis_errors + # Calculate L2/Linf errors + l2_error, linf_error = calc_error_norms(u_ode, t, analyzer, semi, + cache_analysis) - if mpi_isroot() - # L2 error - if :l2_error in analysis_errors - print(" L2 error: ") - for v in eachvariable(equations) - @printf(" % 10.8e", l2_error[v]) - @printf(io, " % 10.8e", l2_error[v]) + if mpi_isroot() + # L2 error + if :l2_error in analysis_errors + print(" L2 error: ") + for v in eachvariable(equations) + @printf(" % 10.8e", l2_error[v]) + @printf(io, " % 10.8e", l2_error[v]) + end + println() end - println() - end - # Linf error - if :linf_error in analysis_errors - print(" Linf error: ") - for v in eachvariable(equations) - @printf(" % 10.8e", linf_error[v]) - @printf(io, " % 10.8e", linf_error[v]) + # Linf error + if :linf_error in analysis_errors + print(" Linf error: ") + for v in eachvariable(equations) + @printf(" % 10.8e", linf_error[v]) + @printf(io, " % 10.8e", linf_error[v]) + end + println() end - println() end end @@ -477,7 +487,7 @@ function (analysis_callback::AnalysisCallback)(io, du, u, u_ode, t, semi) # additional integrals analyze_integrals(analysis_integrals, io, du, u, t, semi) - return l2_error, linf_error + return nothing end # Print level information only if AMR is enabled diff --git a/src/equations/equations.jl b/src/equations/equations.jl index ba2ad1cd1cd..582d672b756 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -260,7 +260,14 @@ combined with certain solvers (e.g., subcell limiting). function n_nonconservative_terms end have_constant_speed(::AbstractEquations) = False() +""" + default_analysis_errors(equations) + +Default analysis errors (`:l2_error` and `:linf_error`) used by the +[`AnalysisCallback`](@ref). +""" default_analysis_errors(::AbstractEquations) = (:l2_error, :linf_error) + """ default_analysis_integrals(equations) diff --git a/test/test_tree_1d_advection.jl b/test/test_tree_1d_advection.jl index 7cfd78e0ade..a580a3b5600 100644 --- a/test/test_tree_1d_advection.jl +++ b/test/test_tree_1d_advection.jl @@ -54,6 +54,20 @@ end end end +@trixi_testset "elixir_advection_basic.jl (No errors)" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), + analysis_callback=AnalysisCallback(semi, interval = 42, + analysis_errors = Symbol[])) + # 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_finite_volume.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_finite_volume.jl"), l2=[0.011662300515980219], From 034b1587807b5098e64043b4711604b481ba2186 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 13 Dec 2023 09:15:37 +0100 Subject: [PATCH 198/263] bump lower compat bound of TimerOutputs.jl to v0.5.7 (#1772) * bump lower compat bound of TimerOutputs.jl to v0.5.7 * format --- Project.toml | 2 +- .../semidiscretization_euler_acoustics.jl | 10 +++++----- .../semidiscretization_euler_gravity.jl | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Project.toml b/Project.toml index ace71a50d8b..65074c5a1ca 100644 --- a/Project.toml +++ b/Project.toml @@ -85,7 +85,7 @@ StrideArrays = "0.1.18" StructArrays = "0.6" SummationByPartsOperators = "0.5.41" T8code = "0.4.3" -TimerOutputs = "0.5" +TimerOutputs = "0.5.7" Triangulate = "2.0" TriplotBase = "0.1" TriplotRecipes = "0.1" diff --git a/src/semidiscretization/semidiscretization_euler_acoustics.jl b/src/semidiscretization/semidiscretization_euler_acoustics.jl index e49fe81177a..173523ff892 100644 --- a/src/semidiscretization/semidiscretization_euler_acoustics.jl +++ b/src/semidiscretization/semidiscretization_euler_acoustics.jl @@ -51,11 +51,11 @@ function SemidiscretizationEulerAcoustics(semi_acoustics::SemiAcoustics, semi_euler::SemiEuler; source_region = x -> true, weights = x -> 1.0) where - {Mesh, - SemiAcoustics <: - SemidiscretizationHyperbolic{Mesh, <:AbstractAcousticPerturbationEquations}, - SemiEuler <: - SemidiscretizationHyperbolic{Mesh, <:AbstractCompressibleEulerEquations}} + {Mesh, + SemiAcoustics <: + SemidiscretizationHyperbolic{Mesh, <:AbstractAcousticPerturbationEquations}, + SemiEuler <: + SemidiscretizationHyperbolic{Mesh, <:AbstractCompressibleEulerEquations}} cache = create_cache(SemidiscretizationEulerAcoustics, source_region, weights, mesh_equations_solver_cache(semi_acoustics)...) diff --git a/src/semidiscretization/semidiscretization_euler_gravity.jl b/src/semidiscretization/semidiscretization_euler_gravity.jl index a9a60a4ff04..4201344df80 100644 --- a/src/semidiscretization/semidiscretization_euler_gravity.jl +++ b/src/semidiscretization/semidiscretization_euler_gravity.jl @@ -117,11 +117,11 @@ Construct a semidiscretization of the compressible Euler equations with self-gra function SemidiscretizationEulerGravity(semi_euler::SemiEuler, semi_gravity::SemiGravity, parameters) where - {Mesh, - SemiEuler <: - SemidiscretizationHyperbolic{Mesh, <:AbstractCompressibleEulerEquations}, - SemiGravity <: - SemidiscretizationHyperbolic{Mesh, <:AbstractHyperbolicDiffusionEquations}} + {Mesh, + SemiEuler <: + SemidiscretizationHyperbolic{Mesh, <:AbstractCompressibleEulerEquations}, + SemiGravity <: + SemidiscretizationHyperbolic{Mesh, <:AbstractHyperbolicDiffusionEquations}} u_ode = compute_coefficients(zero(real(semi_gravity)), semi_gravity) du_ode = similar(u_ode) u_tmp1_ode = similar(u_ode) From 6acc09eaa815ad8cbcc0adaf5d160b3299daf071 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 13 Dec 2023 14:05:14 +0100 Subject: [PATCH 199/263] set version to v0.6.4 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 65074c5a1ca..8be83c7924f 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.6.4-pre" +version = "0.6.4" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 766c7981fdfcbfcbb034888bb627a8f4668259eb Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 13 Dec 2023 14:05:26 +0100 Subject: [PATCH 200/263] set development version to v0.6.5-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 8be83c7924f..539dafc3034 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.6.4" +version = "0.6.5-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 14796ea607ad49f49e2258dac87ff30a6530595d Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Wed, 13 Dec 2023 16:40:21 +0100 Subject: [PATCH 201/263] Central SBP finite difference solver for `UnstructuredMesh2D` (#1773) * containers and kernels for FDSBP solver on UnstructuredMesh2D * add elixirs and corresponding tests * apply formatter to new and edited files * add advection equation test to up coverage * Apply suggestions from code review Co-authored-by: Hendrik Ranocha * update variable name to N --------- Co-authored-by: Hendrik Ranocha --- .../elixir_advection_basic.jl | 69 ++++++ .../elixir_euler_free_stream.jl | 77 ++++++ .../elixir_euler_source_terms.jl | 65 ++++++ src/solvers/dg.jl | 8 +- .../dgsem_unstructured/containers_2d.jl | 15 +- src/solvers/fdsbp_tree/fdsbp_2d.jl | 2 +- .../fdsbp_unstructured/containers_2d.jl | 124 ++++++++++ src/solvers/fdsbp_unstructured/fdsbp.jl | 14 ++ src/solvers/fdsbp_unstructured/fdsbp_2d.jl | 219 ++++++++++++++++++ test/test_unstructured_2d.jl | 61 +++++ 10 files changed, 643 insertions(+), 11 deletions(-) create mode 100644 examples/unstructured_2d_fdsbp/elixir_advection_basic.jl create mode 100644 examples/unstructured_2d_fdsbp/elixir_euler_free_stream.jl create mode 100644 examples/unstructured_2d_fdsbp/elixir_euler_source_terms.jl create mode 100644 src/solvers/fdsbp_unstructured/containers_2d.jl create mode 100644 src/solvers/fdsbp_unstructured/fdsbp.jl create mode 100644 src/solvers/fdsbp_unstructured/fdsbp_2d.jl diff --git a/examples/unstructured_2d_fdsbp/elixir_advection_basic.jl b/examples/unstructured_2d_fdsbp/elixir_advection_basic.jl new file mode 100644 index 00000000000..c181203e7a4 --- /dev/null +++ b/examples/unstructured_2d_fdsbp/elixir_advection_basic.jl @@ -0,0 +1,69 @@ + +using Downloads: download +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear advection equation + +advection_velocity = (0.2, -0.7) +equations = LinearScalarAdvectionEquation2D(advection_velocity) + +############################################################################### +# Get the FDSBP approximation operator + +D_SBP = derivative_operator(SummationByPartsOperators.MattssonAlmquistVanDerWeide2018Accurate(), + derivative_order = 1, accuracy_order = 4, + xmin = -1.0, xmax = 1.0, N = 15) +solver = FDSBP(D_SBP, + surface_integral = SurfaceIntegralStrongForm(flux_lax_friedrichs), + volume_integral = VolumeIntegralStrongForm()) + +############################################################################### +# Get the curved quad mesh from a file (downloads the file if not available locally) + +default_mesh_file = joinpath(@__DIR__, "mesh_periodic_square_with_twist.mesh") +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", + default_mesh_file) +mesh_file = default_mesh_file + +mesh = UnstructuredMesh2D(mesh_file, periodicity = true) + +############################################################################### +# create the semidiscretization object + +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.0, 1.0)) + +# 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.6) + +# 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 + +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/unstructured_2d_fdsbp/elixir_euler_free_stream.jl b/examples/unstructured_2d_fdsbp/elixir_euler_free_stream.jl new file mode 100644 index 00000000000..7ada50c0c65 --- /dev/null +++ b/examples/unstructured_2d_fdsbp/elixir_euler_free_stream.jl @@ -0,0 +1,77 @@ + +using Downloads: download +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations2D(1.4) + +# Free-stream initial condition +initial_condition = initial_condition_constant + +# Boundary conditions for free-stream testing +boundary_condition_free_stream = BoundaryConditionDirichlet(initial_condition) +boundary_conditions = Dict(:Body => boundary_condition_free_stream, + :Button1 => boundary_condition_free_stream, + :Button2 => boundary_condition_free_stream, + :Eye1 => boundary_condition_free_stream, + :Eye2 => boundary_condition_free_stream, + :Smile => boundary_condition_free_stream, + :Bowtie => boundary_condition_free_stream) + +############################################################################### +# Get the FDSBP approximation space + +D_SBP = derivative_operator(SummationByPartsOperators.MattssonAlmquistVanDerWeide2018Accurate(), + derivative_order = 1, accuracy_order = 4, + xmin = -1.0, xmax = 1.0, N = 12) +solver = FDSBP(D_SBP, + surface_integral = SurfaceIntegralStrongForm(flux_hll), + volume_integral = VolumeIntegralStrongForm()) + +############################################################################### +# Get the curved quad mesh from a file (downloads the file if not available locally) + +default_mesh_file = joinpath(@__DIR__, "mesh_gingerbread_man.mesh") +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/2c6440b5f8a57db131061ad7aa78ee2b/raw/1f89fdf2c874ff678c78afb6fe8dc784bdfd421f/mesh_gingerbread_man.mesh", + default_mesh_file) +mesh_file = default_mesh_file + +mesh = UnstructuredMesh2D(mesh_file) + +############################################################################### +# create the semi discretization object + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 5.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true) + +callbacks = CallbackSet(summary_callback, analysis_callback, + alive_callback, save_solution) + +############################################################################### +# run the simulation + +# set small tolerances for the free-stream preservation test +sol = solve(ode, SSPRK43(), abstol = 1.0e-12, reltol = 1.0e-12, + save_everystep = false, callback = callbacks) +summary_callback() # print the timer summary diff --git a/examples/unstructured_2d_fdsbp/elixir_euler_source_terms.jl b/examples/unstructured_2d_fdsbp/elixir_euler_source_terms.jl new file mode 100644 index 00000000000..edcd221bf59 --- /dev/null +++ b/examples/unstructured_2d_fdsbp/elixir_euler_source_terms.jl @@ -0,0 +1,65 @@ + +using Downloads: download +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations2D(1.4) + +initial_condition = initial_condition_convergence_test + +############################################################################### +# Get the FDSBP approximation operator + +D_SBP = derivative_operator(SummationByPartsOperators.MattssonNordström2004(), + derivative_order = 1, accuracy_order = 4, + xmin = -1.0, xmax = 1.0, N = 10) +solver = FDSBP(D_SBP, + surface_integral = SurfaceIntegralStrongForm(flux_lax_friedrichs), + volume_integral = VolumeIntegralStrongForm()) + +############################################################################### +# Get the curved quad mesh from a file (downloads the file if not available locally) + +default_mesh_file = joinpath(@__DIR__, "mesh_periodic_square_with_twist.mesh") +isfile(default_mesh_file) || + download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", + default_mesh_file) +mesh_file = default_mesh_file + +mesh = UnstructuredMesh2D(mesh_file, periodicity = true) + +############################################################################### +# create the semi discretization object + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_convergence_test) + +############################################################################### +# 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) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true) + +callbacks = CallbackSet(summary_callback, analysis_callback, + alive_callback, save_solution) + +############################################################################### +# run the simulation + +sol = solve(ode, SSPRK43(), abstol = 1.0e-9, reltol = 1.0e-9, + save_everystep = false, callback = callbacks) +summary_callback() # print the timer summary diff --git a/src/solvers/dg.jl b/src/solvers/dg.jl index 9e5ebc7f9b5..9b61df62cc3 100644 --- a/src/solvers/dg.jl +++ b/src/solvers/dg.jl @@ -41,8 +41,8 @@ standard textbooks. Applications [doi: 10.1007/978-0-387-72067-8](https://doi.org/10.1007/978-0-387-72067-8) -`VolumeIntegralWeakForm()` is only implemented for conserved terms as -non-conservative terms should always be discretized in conjunction with a flux-splitting scheme, +`VolumeIntegralWeakForm()` is only implemented for conserved terms as +non-conservative terms should always be discretized in conjunction with a flux-splitting scheme, see [`VolumeIntegralFluxDifferencing`](@ref). This treatment is required to achieve, e.g., entropy-stability or well-balancedness. """ @@ -415,7 +415,8 @@ function Base.show(io::IO, mime::MIME"text/plain", dg::DG) summary_line(io, "surface integral", dg.surface_integral |> typeof |> nameof) show(increment_indent(io), mime, dg.surface_integral) summary_line(io, "volume integral", dg.volume_integral |> typeof |> nameof) - if !(dg.volume_integral isa VolumeIntegralWeakForm) + if !(dg.volume_integral isa VolumeIntegralWeakForm) && + !(dg.volume_integral isa VolumeIntegralStrongForm) show(increment_indent(io), mime, dg.volume_integral) end summary_footer(io) @@ -598,6 +599,7 @@ include("dgsem/dgsem.jl") # and boundary conditions weakly. Thus, these methods can re-use a lot of # functionality implemented for DGSEM. include("fdsbp_tree/fdsbp.jl") +include("fdsbp_unstructured/fdsbp.jl") function allocate_coefficients(mesh::AbstractMesh, equations, dg::DG, cache) # We must allocate a `Vector` in order to be able to `resize!` it (AMR). diff --git a/src/solvers/dgsem_unstructured/containers_2d.jl b/src/solvers/dgsem_unstructured/containers_2d.jl index 13eeaeabffb..f51dd09801b 100644 --- a/src/solvers/dgsem_unstructured/containers_2d.jl +++ b/src/solvers/dgsem_unstructured/containers_2d.jl @@ -45,7 +45,7 @@ end eachelement(elements::UnstructuredElementContainer2D) Return an iterator over the indices that specify the location in relevant data structures -for the elements in `elements`. +for the elements in `elements`. In particular, not the elements themselves are returned. """ @inline function eachelement(elements::UnstructuredElementContainer2D) @@ -84,24 +84,25 @@ function init_elements!(elements::UnstructuredElementContainer2D, mesh, basis) # loop through elements and call the correct constructor based on whether the element is curved for element in eachelement(elements) if mesh.element_is_curved[element] - init_element!(elements, element, basis.nodes, + init_element!(elements, element, basis, view(mesh.surface_curves, :, element)) else # straight sided element for i in 1:4, j in 1:2 # pull the (x,y) values of these corners out of the global corners array four_corners[i, j] = mesh.corners[j, mesh.element_node_ids[i, element]] end - init_element!(elements, element, basis.nodes, four_corners) + init_element!(elements, element, basis, four_corners) end end end # initialize all the values in the container of a general element (either straight sided or curved) -function init_element!(elements, element, nodes, corners_or_surface_curves) - calc_node_coordinates!(elements.node_coordinates, element, nodes, +function init_element!(elements, element, basis::LobattoLegendreBasis, + corners_or_surface_curves) + calc_node_coordinates!(elements.node_coordinates, element, get_nodes(basis), corners_or_surface_curves) - calc_metric_terms!(elements.jacobian_matrix, element, nodes, + calc_metric_terms!(elements.jacobian_matrix, element, get_nodes(basis), corners_or_surface_curves) calc_inverse_jacobian!(elements.inverse_jacobian, element, elements.jacobian_matrix) @@ -109,7 +110,7 @@ function init_element!(elements, element, nodes, corners_or_surface_curves) calc_contravariant_vectors!(elements.contravariant_vectors, element, elements.jacobian_matrix) - calc_normal_directions!(elements.normal_directions, element, nodes, + calc_normal_directions!(elements.normal_directions, element, get_nodes(basis), corners_or_surface_curves) return elements diff --git a/src/solvers/fdsbp_tree/fdsbp_2d.jl b/src/solvers/fdsbp_tree/fdsbp_2d.jl index beff605629a..09d18cecd75 100644 --- a/src/solvers/fdsbp_tree/fdsbp_2d.jl +++ b/src/solvers/fdsbp_tree/fdsbp_2d.jl @@ -9,7 +9,7 @@ #! format: noindent # 2D caches -function create_cache(mesh::TreeMesh{2}, equations, +function create_cache(mesh::Union{TreeMesh{2}, UnstructuredMesh2D}, equations, volume_integral::VolumeIntegralStrongForm, dg, uEltype) prototype = Array{SVector{nvariables(equations), uEltype}, ndims(mesh)}(undef, ntuple(_ -> nnodes(dg), diff --git a/src/solvers/fdsbp_unstructured/containers_2d.jl b/src/solvers/fdsbp_unstructured/containers_2d.jl new file mode 100644 index 00000000000..3857c2d8a20 --- /dev/null +++ b/src/solvers/fdsbp_unstructured/containers_2d.jl @@ -0,0 +1,124 @@ +# !!! warning "Experimental implementation (curvilinear FDSBP)" +# This is an experimental feature and may change in future releases. + +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +# initialize all the values in the container of a general FD block (either straight sided or curved) +# OBS! Requires the SBP derivative matrix in order to compute metric terms that are free-stream preserving +function init_element!(elements, element, basis::AbstractDerivativeOperator, + corners_or_surface_curves) + calc_node_coordinates!(elements.node_coordinates, element, get_nodes(basis), + corners_or_surface_curves) + + calc_metric_terms!(elements.jacobian_matrix, element, basis, + elements.node_coordinates) + + calc_inverse_jacobian!(elements.inverse_jacobian, element, elements.jacobian_matrix) + + calc_contravariant_vectors!(elements.contravariant_vectors, element, + elements.jacobian_matrix) + + calc_normal_directions!(elements.normal_directions, element, + elements.jacobian_matrix) + + return elements +end + +# construct the metric terms for a FDSBP element "block". Directly use the derivative matrix +# applied to the node coordinates. +# TODO: FD; How to make this work for the upwind solver because basis has three available derivative matrices +function calc_metric_terms!(jacobian_matrix, element, D_SBP::AbstractDerivativeOperator, + node_coordinates) + + # storage format: + # jacobian_matrix[1,1,:,:,:] <- X_xi + # jacobian_matrix[1,2,:,:,:] <- X_eta + # jacobian_matrix[2,1,:,:,:] <- Y_xi + # jacobian_matrix[2,2,:,:,:] <- Y_eta + + # Compute the xi derivatives by applying D on the left + # This is basically the same as + # jacobian_matrix[1, 1, :, :, element] = Matrix(D_SBP) * node_coordinates[1, :, :, element] + # but uses only matrix-vector products instead of a matrix-matrix product. + for j in eachnode(D_SBP) + mul!(view(jacobian_matrix, 1, 1, :, j, element), D_SBP, + view(node_coordinates, 1, :, j, element)) + end + # jacobian_matrix[2, 1, :, :, element] = Matrix(D_SBP) * node_coordinates[2, :, :, element] + for j in eachnode(D_SBP) + mul!(view(jacobian_matrix, 2, 1, :, j, element), D_SBP, + view(node_coordinates, 2, :, j, element)) + end + + # Compute the eta derivatives by applying transpose of D on the right + # jacobian_matrix[1, 2, :, :, element] = node_coordinates[1, :, :, element] * Matrix(D_SBP)' + for i in eachnode(D_SBP) + mul!(view(jacobian_matrix, 1, 2, i, :, element), D_SBP, + view(node_coordinates, 1, i, :, element)) + end + # jacobian_matrix[2, 2, :, :, element] = node_coordinates[2, :, :, element] * Matrix(D_SBP)' + for i in eachnode(D_SBP) + mul!(view(jacobian_matrix, 2, 2, i, :, element), D_SBP, + view(node_coordinates, 2, i, :, element)) + end + + return jacobian_matrix +end + +# construct the normal direction vectors (but not actually normalized) for a curved sided FDSBP element "block" +# normalization occurs on the fly during the surface flux computation +# OBS! This assumes that the boundary points are included. +function calc_normal_directions!(normal_directions, element, jacobian_matrix) + + # normal directions on the boundary for the left (local side 4) and right (local side 2) + N = size(jacobian_matrix, 4) + for j in 1:N + # +x side or side 2 in the local indexing + X_xi = jacobian_matrix[1, 1, N, j, element] + X_eta = jacobian_matrix[1, 2, N, j, element] + Y_xi = jacobian_matrix[2, 1, N, j, element] + Y_eta = jacobian_matrix[2, 2, N, j, element] + 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) + + # -x side or side 4 in the local indexing + X_xi = jacobian_matrix[1, 1, 1, j, element] + X_eta = jacobian_matrix[1, 2, 1, j, element] + Y_xi = jacobian_matrix[2, 1, 1, j, element] + Y_eta = jacobian_matrix[2, 2, 1, j, element] + Jtemp = X_xi * Y_eta - X_eta * Y_xi + normal_directions[1, j, 4, element] = -sign(Jtemp) * (Y_eta) + normal_directions[2, j, 4, element] = -sign(Jtemp) * (-X_eta) + end + + # normal directions on the boundary for the top (local side 3) and bottom (local side 1) + N = size(jacobian_matrix, 3) + for i in 1:N + # -y side or side 1 in the local indexing + X_xi = jacobian_matrix[1, 1, i, 1, element] + X_eta = jacobian_matrix[1, 2, i, 1, element] + Y_xi = jacobian_matrix[2, 1, i, 1, element] + Y_eta = jacobian_matrix[2, 2, i, 1, element] + 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) + + # +y side or side 3 in the local indexing + X_xi = jacobian_matrix[1, 1, i, N, element] + X_eta = jacobian_matrix[1, 2, i, N, element] + Y_xi = jacobian_matrix[2, 1, i, N, element] + Y_eta = jacobian_matrix[2, 2, i, N, element] + Jtemp = X_xi * Y_eta - X_eta * Y_xi + normal_directions[1, i, 3, element] = sign(Jtemp) * (-Y_xi) + normal_directions[2, i, 3, element] = sign(Jtemp) * (X_xi) + end + + return normal_directions +end +end # @muladd diff --git a/src/solvers/fdsbp_unstructured/fdsbp.jl b/src/solvers/fdsbp_unstructured/fdsbp.jl new file mode 100644 index 00000000000..dee9776abb7 --- /dev/null +++ b/src/solvers/fdsbp_unstructured/fdsbp.jl @@ -0,0 +1,14 @@ +# !!! warning "Experimental implementation (curvilinear FDSBP)" +# This is an experimental feature and may change in future releases. + +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +# dimension specific curvilinear implementations and data structures +include("containers_2d.jl") +include("fdsbp_2d.jl") +end # @muladd diff --git a/src/solvers/fdsbp_unstructured/fdsbp_2d.jl b/src/solvers/fdsbp_unstructured/fdsbp_2d.jl new file mode 100644 index 00000000000..b459f4c42cc --- /dev/null +++ b/src/solvers/fdsbp_unstructured/fdsbp_2d.jl @@ -0,0 +1,219 @@ +# !!! warning "Experimental implementation (curvilinear FDSBP)" +# This is an experimental feature and may change in future releases. + +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +# 2D unstructured cache +function create_cache(mesh::UnstructuredMesh2D, equations, dg::FDSBP, RealT, uEltype) + elements = init_elements(mesh, equations, dg.basis, RealT, uEltype) + + interfaces = init_interfaces(mesh, elements) + + boundaries = init_boundaries(mesh, elements) + + cache = (; elements, interfaces, boundaries) + + # Add specialized parts of the cache required to for efficient flux computations + cache = (; cache..., + create_cache(mesh, equations, dg.volume_integral, dg, uEltype)...) + + return cache +end + +# TODO: FD; Upwind versions of surface / volume integral + +# 2D volume integral contributions for `VolumeIntegralStrongForm` +# OBS! This is the standard (not de-aliased) form of the volume integral. +# So it is not provably stable for variable coefficients due to the the metric terms. +@inline function calc_volume_integral!(du, u, + mesh::UnstructuredMesh2D, + nonconservative_terms::False, equations, + volume_integral::VolumeIntegralStrongForm, + dg::FDSBP, cache) + D = dg.basis # SBP derivative operator + @unpack f_threaded = cache + @unpack contravariant_vectors = cache.elements + + # SBP operators from SummationByPartsOperators.jl implement the basic interface + # of matrix-vector multiplication. Thus, we pass an "array of structures", + # packing all variables per node in an `SVector`. + if nvariables(equations) == 1 + # `reinterpret(reshape, ...)` removes the leading dimension only if more + # than one variable is used. + u_vectors = reshape(reinterpret(SVector{nvariables(equations), eltype(u)}, u), + nnodes(dg), nnodes(dg), nelements(dg, cache)) + du_vectors = reshape(reinterpret(SVector{nvariables(equations), eltype(du)}, + du), + nnodes(dg), nnodes(dg), nelements(dg, cache)) + else + u_vectors = reinterpret(reshape, SVector{nvariables(equations), eltype(u)}, u) + du_vectors = reinterpret(reshape, SVector{nvariables(equations), eltype(du)}, + du) + end + + # Use the tensor product structure to compute the discrete derivatives of + # the contravariant fluxes line-by-line and add them to `du` for each element. + @threaded for element in eachelement(dg, cache) + f_element = f_threaded[Threads.threadid()] + u_element = view(u_vectors, :, :, element) + + # x direction + for j in eachnode(dg) + for i in eachnode(dg) + Ja1 = get_contravariant_vector(1, contravariant_vectors, i, j, element) + f_element[i, j] = flux(u_element[i, j], Ja1, equations) + end + mul!(view(du_vectors, :, j, element), D, view(f_element, :, j), + one(eltype(du)), one(eltype(du))) + end + + # y direction + for i in eachnode(dg) + for j in eachnode(dg) + Ja2 = get_contravariant_vector(2, contravariant_vectors, i, j, element) + f_element[i, j] = flux(u_element[i, j], Ja2, equations) + end + mul!(view(du_vectors, i, :, element), D, view(f_element, i, :), + one(eltype(du)), one(eltype(du))) + end + end + + return nothing +end + +# Note! The local side numbering for the unstructured quadrilateral element implementation differs +# from the structured TreeMesh or StructuredMesh local side numbering: +# +# TreeMesh/StructuredMesh sides versus UnstructuredMesh sides +# 4 3 +# ----------------- ----------------- +# | | | | +# | ^ eta | | ^ eta | +# 1 | | | 2 4 | | | 2 +# | | | | | | +# | ---> xi | | ---> xi | +# ----------------- ----------------- +# 3 1 +# Therefore, we require a different surface integral routine here despite their similar structure. +# Also, the normal directions are already outward pointing for `UnstructuredMesh2D` so all the +# surface contributions are added. +function calc_surface_integral!(du, u, mesh::UnstructuredMesh2D, + equations, surface_integral::SurfaceIntegralStrongForm, + dg::DG, cache) + inv_weight_left = inv(left_boundary_weight(dg.basis)) + inv_weight_right = inv(right_boundary_weight(dg.basis)) + @unpack normal_directions, surface_flux_values = cache.elements + + @threaded for element in eachelement(dg, cache) + for l in eachnode(dg) + # surface at -x + u_node = get_node_vars(u, equations, dg, 1, l, element) + # compute internal flux in normal direction on side 4 + outward_direction = get_node_coords(normal_directions, equations, dg, l, 4, + element) + f_node = flux(u_node, outward_direction, equations) + f_num = get_node_vars(surface_flux_values, equations, dg, l, 4, element) + multiply_add_to_node_vars!(du, inv_weight_left, (f_num - f_node), + equations, dg, 1, l, element) + + # surface at +x + u_node = get_node_vars(u, equations, dg, nnodes(dg), l, element) + # compute internal flux in normal direction on side 2 + outward_direction = get_node_coords(normal_directions, equations, dg, l, 2, + element) + f_node = flux(u_node, outward_direction, equations) + f_num = get_node_vars(surface_flux_values, equations, dg, l, 2, element) + multiply_add_to_node_vars!(du, inv_weight_right, (f_num - f_node), + equations, dg, nnodes(dg), l, element) + + # surface at -y + u_node = get_node_vars(u, equations, dg, l, 1, element) + # compute internal flux in normal direction on side 1 + outward_direction = get_node_coords(normal_directions, equations, dg, l, 1, + element) + f_node = flux(u_node, outward_direction, equations) + f_num = get_node_vars(surface_flux_values, equations, dg, l, 1, element) + multiply_add_to_node_vars!(du, inv_weight_left, (f_num - f_node), + equations, dg, l, 1, element) + + # surface at +y + u_node = get_node_vars(u, equations, dg, l, nnodes(dg), element) + # compute internal flux in normal direction on side 3 + outward_direction = get_node_coords(normal_directions, equations, dg, l, 3, + element) + f_node = flux(u_node, outward_direction, equations) + f_num = get_node_vars(surface_flux_values, equations, dg, l, 3, element) + multiply_add_to_node_vars!(du, inv_weight_right, (f_num - f_node), + equations, dg, l, nnodes(dg), element) + end + end + + return nothing +end + +# AnalysisCallback +function integrate_via_indices(func::Func, u, + mesh::UnstructuredMesh2D, equations, + dg::FDSBP, cache, args...; normalize = true) where {Func} + # TODO: FD. This is rather inefficient right now and allocates... + weights = diag(SummationByPartsOperators.mass_matrix(dg.basis)) + + # Initialize integral with zeros of the right shape + integral = zero(func(u, 1, 1, 1, equations, dg, args...)) + total_volume = zero(real(mesh)) + + # Use quadrature to numerically integrate over entire domain + for element in eachelement(dg, cache) + for j in eachnode(dg), i in eachnode(dg) + volume_jacobian = abs(inv(cache.elements.inverse_jacobian[i, j, element])) + integral += volume_jacobian * weights[i] * weights[j] * + func(u, i, j, element, equations, dg, args...) + total_volume += volume_jacobian * weights[i] * weights[j] + end + end + + # Normalize with total volume + if normalize + integral = integral / total_volume + end + + return integral +end + +function calc_error_norms(func, u, t, analyzer, + mesh::UnstructuredMesh2D, equations, initial_condition, + dg::FDSBP, cache, cache_analysis) + # TODO: FD. This is rather inefficient right now and allocates... + weights = diag(SummationByPartsOperators.mass_matrix(dg.basis)) + @unpack node_coordinates, inverse_jacobian = cache.elements + + # Set up data structures + l2_error = zero(func(get_node_vars(u, equations, dg, 1, 1, 1), equations)) + linf_error = copy(l2_error) + total_volume = zero(real(mesh)) + + # Iterate over all elements for error calculations + for element in eachelement(dg, cache) + for j in eachnode(analyzer), i in eachnode(analyzer) + volume_jacobian = abs(inv(cache.elements.inverse_jacobian[i, j, element])) + u_exact = initial_condition(get_node_coords(node_coordinates, equations, dg, + i, j, element), t, equations) + diff = func(u_exact, equations) - + func(get_node_vars(u, equations, dg, i, j, element), equations) + l2_error += diff .^ 2 * (weights[i] * weights[j] * volume_jacobian) + linf_error = @. max(linf_error, abs(diff)) + total_volume += weights[i] * weights[j] * volume_jacobian + end + end + + # For L2 error, divide by total volume + l2_error = @. sqrt(l2_error / total_volume) + + return l2_error, linf_error +end +end # @muladd diff --git a/test/test_unstructured_2d.jl b/test/test_unstructured_2d.jl index 5341d86a7d1..139b423ead1 100644 --- a/test/test_unstructured_2d.jl +++ b/test/test_unstructured_2d.jl @@ -664,6 +664,67 @@ end @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 end end + +# TODO: FD; for now put the unstructured tests for the 2D FDSBP here. +@trixi_testset "FDSBP (central): elixir_advection_basic.jl" begin + @test_trixi_include(joinpath(pkgdir(Trixi, "examples", "unstructured_2d_fdsbp"), + "elixir_advection_basic.jl"), + l2=[0.0001105211407319266], + linf=[0.0004199363734466166]) + # 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 "FDSBP (central): elixir_euler_source_terms.jl" begin + @test_trixi_include(joinpath(pkgdir(Trixi, "examples", "unstructured_2d_fdsbp"), + "elixir_euler_source_terms.jl"), + l2=[8.155544666380138e-5, + 0.0001477863788446318, + 0.00014778637884460072, + 0.00045584189984542687], + linf=[0.0002670775876922882, + 0.0005683064706873964, + 0.0005683064706762941, + 0.0017770812025146299], + tspan=(0.0, 0.05)) + # 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 "FDSBP (central): elixir_euler_free_stream.jl" begin + @test_trixi_include(joinpath(pkgdir(Trixi, "examples", "unstructured_2d_fdsbp"), + "elixir_euler_free_stream.jl"), + l2=[5.4329175009362306e-14, + 1.0066867437607972e-13, + 6.889210012578449e-14, + 1.568290814572709e-13], + linf=[5.963762816918461e-10, + 5.08869890669672e-11, + 1.1581377523661729e-10, + 4.61017890529547e-11], + tspan=(0.0, 0.1), + atol=1.0e-11) + # 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 c7c4cf7c827177fa3e32942aa58b316468ac0295 Mon Sep 17 00:00:00 2001 From: Krissh Chawla <127906314+KrisshChawla@users.noreply.github.com> Date: Thu, 14 Dec 2023 03:54:19 -0600 Subject: [PATCH 202/263] Compressible Euler Quasi-1D (#1757) * implementation of quasi 1d compressible Euler Equation * added example elixir for quasi 1d compressible Euler equations * added example elixir with a discontinuous initial condition * including and exported CompressibleEulerEquationsQuasi1D * formatting * added entropy conservative test * fixing spelling * formatting * Update examples/tree_1d_dgsem/elixir_euler_quasi_1d_discontinuous.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Update src/equations/compressible_euler_quasi_1d.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Update src/equations/compressible_euler_quasi_1d.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Update src/equations/compressible_euler_quasi_1d.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * updated test_tree_1d_euler.jl and formatting * Update src/equations/compressible_euler_quasi_1d.jl Co-authored-by: Daniel Doehring * Update src/equations/compressible_euler_quasi_1d.jl Co-authored-by: Daniel Doehring * Update src/equations/compressible_euler_quasi_1d.jl Co-authored-by: Daniel Doehring * Update src/equations/compressible_euler_quasi_1d.jl Co-authored-by: Daniel Doehring * Update src/equations/compressible_euler_quasi_1d.jl Co-authored-by: Daniel Doehring * Update src/equations/compressible_euler_quasi_1d.jl Co-authored-by: Daniel Doehring * adding consistency check for flux * Update compressible_euler_quasi_1d.jl * formatting * Update src/equations/compressible_euler_quasi_1d.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Update src/equations/compressible_euler_quasi_1d.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Update src/equations/compressible_euler_quasi_1d.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Update src/equations/compressible_euler_quasi_1d.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Update compressible_euler_quasi_1d and test_tree_1d_euler * formatting * Update examples/tree_1d_dgsem/elixir_euler_quasi_1d_discontinuous.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Update examples/tree_1d_dgsem/elixir_euler_quasi_1d_ec.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Update examples/tree_1d_dgsem/elixir_euler_quasi_1d_source_terms.jl Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Update src/equations/compressible_euler_quasi_1d.jl Co-authored-by: Daniel Doehring * Update src/equations/compressible_euler_quasi_1d.jl Co-authored-by: Daniel Doehring * Update src/equations/compressible_euler_quasi_1d.jl Co-authored-by: Daniel Doehring * update boundary condition slip wall * update compressible_euler_quasi_1d.jl * Update src/equations/compressible_euler_quasi_1d.jl * Update src/equations/compressible_euler_quasi_1d.jl * remove boundary_condition_slip_wall --------- Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> Co-authored-by: Daniel Doehring Co-authored-by: Daniel Doehring Co-authored-by: Hendrik Ranocha --- .../elixir_euler_quasi_1d_discontinuous.jl | 85 +++++ .../tree_1d_dgsem/elixir_euler_quasi_1d_ec.jl | 73 ++++ .../elixir_euler_quasi_1d_source_terms.jl | 60 ++++ src/Trixi.jl | 1 + src/equations/compressible_euler_quasi_1d.jl | 328 ++++++++++++++++++ src/equations/equations.jl | 1 + test/test_tree_1d_euler.jl | 73 ++++ test/test_unit.jl | 13 + 8 files changed, 634 insertions(+) create mode 100644 examples/tree_1d_dgsem/elixir_euler_quasi_1d_discontinuous.jl create mode 100644 examples/tree_1d_dgsem/elixir_euler_quasi_1d_ec.jl create mode 100644 examples/tree_1d_dgsem/elixir_euler_quasi_1d_source_terms.jl create mode 100644 src/equations/compressible_euler_quasi_1d.jl diff --git a/examples/tree_1d_dgsem/elixir_euler_quasi_1d_discontinuous.jl b/examples/tree_1d_dgsem/elixir_euler_quasi_1d_discontinuous.jl new file mode 100644 index 00000000000..cc4535be028 --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_euler_quasi_1d_discontinuous.jl @@ -0,0 +1,85 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# Semidiscretization of the quasi 1d compressible Euler equations +# See Chan et al. https://doi.org/10.48550/arXiv.2307.12089 for details + +equations = CompressibleEulerEquationsQuasi1D(1.4) + +""" + initial_condition_discontinuity(x, t, equations::CompressibleEulerEquations1D) + +A discontinuous initial condition taken from +- Jesse Chan, Khemraj Shukla, Xinhui Wu, Ruofeng Liu, Prani Nalluri (2023) + High order entropy stable schemes for the quasi-one-dimensional + shallow water and compressible Euler equations + [DOI: 10.48550/arXiv.2307.12089](https://doi.org/10.48550/arXiv.2307.12089) +""" +function initial_condition_discontinuity(x, t, + equations::CompressibleEulerEquationsQuasi1D) + rho = (x[1] < 0) ? 3.4718 : 2.0 + v1 = (x[1] < 0) ? -2.5923 : -3.0 + p = (x[1] < 0) ? 5.7118 : 2.639 + a = (x[1] < 0) ? 1.0 : 1.5 + + return prim2cons(SVector(rho, v1, p, a), equations) +end + +initial_condition = initial_condition_discontinuity + +surface_flux = (flux_lax_friedrichs, flux_nonconservative_chan_etal) +volume_flux = (flux_chan_etal, flux_nonconservative_chan_etal) + +basis = LobattoLegendreBasis(3) +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(basis, surface_flux, volume_integral) + +coordinates_min = (-1.0,) +coordinates_max = (1.0,) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 6, + n_cells_max = 10_000) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 2.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 + +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 0.5) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + 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/tree_1d_dgsem/elixir_euler_quasi_1d_ec.jl b/examples/tree_1d_dgsem/elixir_euler_quasi_1d_ec.jl new file mode 100644 index 00000000000..ae1b2b24b62 --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_euler_quasi_1d_ec.jl @@ -0,0 +1,73 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# Semidiscretization of the quasi 1d compressible Euler equations with a discontinuous nozzle width function. +# See Chan et al. https://doi.org/10.48550/arXiv.2307.12089 for details + +equations = CompressibleEulerEquationsQuasi1D(1.4) + +# Setup a truly discontinuous density function and nozzle width for +# this academic testcase of entropy conservation. The errors from the analysis +# callback are not important but the entropy error for this test case +# `∑∂S/∂U ⋅ Uₜ` should be around machine roundoff. +# Works as intended for TreeMesh1D with `initial_refinement_level=6`. If the mesh +# refinement level is changed the initial condition below may need changed as well to +# ensure that the discontinuities lie on an element interface. +function initial_condition_ec(x, t, equations::CompressibleEulerEquationsQuasi1D) + v1 = 0.1 + rho = 2.0 + 0.1 * x[1] + p = 3.0 + a = 2.0 + x[1] + + return prim2cons(SVector(rho, v1, p, a), equations) +end + +initial_condition = initial_condition_ec + +surface_flux = (flux_chan_etal, flux_nonconservative_chan_etal) +volume_flux = surface_flux +solver = DGSEM(polydeg = 4, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = (-1.0,) +coordinates_max = (1.0,) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 6, + n_cells_max = 10_000) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.4) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 + +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 0.8) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + 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/tree_1d_dgsem/elixir_euler_quasi_1d_source_terms.jl b/examples/tree_1d_dgsem/elixir_euler_quasi_1d_source_terms.jl new file mode 100644 index 00000000000..91bb1ba6e8c --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_euler_quasi_1d_source_terms.jl @@ -0,0 +1,60 @@ +using OrdinaryDiffEq +using Trixi +using ForwardDiff + +############################################################################### +# Semidiscretization of the quasi 1d compressible Euler equations +# See Chan et al. https://doi.org/10.48550/arXiv.2307.12089 for details + +equations = CompressibleEulerEquationsQuasi1D(1.4) + +initial_condition = initial_condition_convergence_test + +surface_flux = (flux_chan_etal, flux_nonconservative_chan_etal) +volume_flux = surface_flux +solver = DGSEM(polydeg = 4, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = -1.0 +coordinates_max = 1.0 +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 4, + n_cells_max = 10_000) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_convergence_test) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 2.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:l2_error_primitive, + :linf_error_primitive)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 0.8) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + 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/src/Trixi.jl b/src/Trixi.jl index b8110cf5bdd..e7b849e2642 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -139,6 +139,7 @@ export AcousticPerturbationEquations2D, CompressibleEulerEquations3D, CompressibleEulerMulticomponentEquations1D, CompressibleEulerMulticomponentEquations2D, + CompressibleEulerEquationsQuasi1D, IdealGlmMhdEquations1D, IdealGlmMhdEquations2D, IdealGlmMhdEquations3D, IdealGlmMhdMulticomponentEquations1D, IdealGlmMhdMulticomponentEquations2D, HyperbolicDiffusionEquations1D, HyperbolicDiffusionEquations2D, diff --git a/src/equations/compressible_euler_quasi_1d.jl b/src/equations/compressible_euler_quasi_1d.jl new file mode 100644 index 00000000000..0a543277ee4 --- /dev/null +++ b/src/equations/compressible_euler_quasi_1d.jl @@ -0,0 +1,328 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +@doc raw""" + CompressibleEulerEquationsQuasi1D(gamma) + +The quasi-1d compressible Euler equations (see Chan et al. [DOI: 10.48550/arXiv.2307.12089](https://doi.org/10.48550/arXiv.2307.12089) for details) +```math +\frac{\partial}{\partial t} +\begin{pmatrix} +a \rho \\ a \rho v_1 \\ a e +\end{pmatrix} ++ +\frac{\partial}{\partial x} +\begin{pmatrix} +a \rho v_1 \\ a \rho v_1^2 \\ a v_1 (e +p) +\end{pmatrix} ++ +a \frac{\partial}{\partial x} +\begin{pmatrix} +0 \\ p \\ 0 +\end{pmatrix} += +\begin{pmatrix} +0 \\ 0 \\ 0 +\end{pmatrix} +``` +for an ideal gas with ratio of specific heats `gamma` in one space dimension. +Here, ``\rho`` is the density, ``v_1`` the velocity, ``e`` the specific total energy **rather than** specific internal energy, +``a`` the (possibly) variable nozzle width, and +```math +p = (\gamma - 1) \left( e - \frac{1}{2} \rho v_1^2 \right) +``` +the pressure. + +The nozzle width function ``a(x)`` is set inside the initial condition routine +for a particular problem setup. To test the conservative form of the compressible Euler equations one can set the +nozzle width variable ``a`` to one. + +In addition to the unknowns, Trixi.jl currently stores the nozzle width values at the approximation points +despite being fixed in time. +This affects the implementation and use of these equations in various ways: +* The flux values corresponding to the nozzle width must be zero. +* The nozzle width values must be included when defining initial conditions, boundary conditions or + source terms. +* [`AnalysisCallback`](@ref) analyzes this variable. +* Trixi.jl's visualization tools will visualize the nozzle width by default. +""" +struct CompressibleEulerEquationsQuasi1D{RealT <: Real} <: + AbstractCompressibleEulerEquations{1, 4} + gamma::RealT # ratio of specific heats + inv_gamma_minus_one::RealT # = inv(gamma - 1); can be used to write slow divisions as fast multiplications + + function CompressibleEulerEquationsQuasi1D(gamma) + γ, inv_gamma_minus_one = promote(gamma, inv(gamma - 1)) + new{typeof(γ)}(γ, inv_gamma_minus_one) + end +end + +have_nonconservative_terms(::CompressibleEulerEquationsQuasi1D) = True() +function varnames(::typeof(cons2cons), ::CompressibleEulerEquationsQuasi1D) + ("a_rho", "a_rho_v1", "a_e", "a") +end +function varnames(::typeof(cons2prim), ::CompressibleEulerEquationsQuasi1D) + ("rho", "v1", "p", "a") +end + +""" + initial_condition_convergence_test(x, t, equations::CompressibleEulerEquationsQuasi1D) + +A smooth initial condition used for convergence tests in combination with +[`source_terms_convergence_test`](@ref) +(and [`BoundaryConditionDirichlet(initial_condition_convergence_test)`](@ref) in non-periodic domains). +""" +function initial_condition_convergence_test(x, t, + equations::CompressibleEulerEquationsQuasi1D) + c = 2 + A = 0.1 + L = 2 + f = 1 / L + ω = 2 * pi * f + ini = c + A * sin(ω * (x[1] - t)) + + rho = ini + v1 = 1.0 + e = ini^2 / rho + p = (equations.gamma - 1) * (e - 0.5 * rho * v1^2) + a = 1.5 - 0.5 * cos(x[1] * pi) + + return prim2cons(SVector(rho, v1, p, a), equations) +end + +""" + source_terms_convergence_test(u, x, t, equations::CompressibleEulerEquationsQuasi1D) + +Source terms used for convergence tests in combination with +[`initial_condition_convergence_test`](@ref) +(and [`BoundaryConditionDirichlet(initial_condition_convergence_test)`](@ref) in non-periodic domains). + +This manufactured solution source term is specifically designed for the mozzle width 'a(x) = 1.5 - 0.5 * cos(x[1] * pi)' +as defined in [`initial_condition_convergence_test`](@ref). +""" +@inline function source_terms_convergence_test(u, x, t, + equations::CompressibleEulerEquationsQuasi1D) + # Same settings as in `initial_condition_convergence_test`. + # Derivatives calculated with ForwardDiff.jl + c = 2 + A = 0.1 + L = 2 + f = 1 / L + ω = 2 * pi * f + x1, = x + ini(x1, t) = c + A * sin(ω * (x1 - t)) + + rho(x1, t) = ini(x1, t) + v1(x1, t) = 1.0 + e(x1, t) = ini(x1, t)^2 / rho(x1, t) + p1(x1, t) = (equations.gamma - 1) * (e(x1, t) - 0.5 * rho(x1, t) * v1(x1, t)^2) + a(x1, t) = 1.5 - 0.5 * cos(x1 * pi) + + arho(x1, t) = a(x1, t) * rho(x1, t) + arhou(x1, t) = arho(x1, t) * v1(x1, t) + aE(x1, t) = a(x1, t) * e(x1, t) + + darho_dt(x1, t) = ForwardDiff.derivative(t -> arho(x1, t), t) + darhou_dx(x1, t) = ForwardDiff.derivative(x1 -> arhou(x1, t), x1) + + arhouu(x1, t) = arhou(x1, t) * v1(x1, t) + darhou_dt(x1, t) = ForwardDiff.derivative(t -> arhou(x1, t), t) + darhouu_dx(x1, t) = ForwardDiff.derivative(x1 -> arhouu(x1, t), x1) + dp1_dx(x1, t) = ForwardDiff.derivative(x1 -> p1(x1, t), x1) + + auEp(x1, t) = a(x1, t) * v1(x1, t) * (e(x1, t) + p1(x1, t)) + daE_dt(x1, t) = ForwardDiff.derivative(t -> aE(x1, t), t) + dauEp_dx(x1, t) = ForwardDiff.derivative(x1 -> auEp(x1, t), x1) + + du1 = darho_dt(x1, t) + darhou_dx(x1, t) + du2 = darhou_dt(x1, t) + darhouu_dx(x1, t) + a(x1, t) * dp1_dx(x1, t) + du3 = daE_dt(x1, t) + dauEp_dx(x1, t) + + return SVector(du1, du2, du3, 0.0) +end + +# Calculate 1D flux for a single point +@inline function flux(u, orientation::Integer, + equations::CompressibleEulerEquationsQuasi1D) + a_rho, a_rho_v1, a_e, a = u + rho, v1, p, a = cons2prim(u, equations) + e = a_e / a + + # Ignore orientation since it is always "1" in 1D + f1 = a_rho_v1 + f2 = a_rho_v1 * v1 + f3 = a * v1 * (e + p) + + return SVector(f1, f2, f3, zero(eltype(u))) +end + +""" +@inline function flux_nonconservative_chan_etal(u_ll, u_rr, orientation::Integer, + equations::CompressibleEulerEquationsQuasi1D) + +Non-symmetric two-point volume flux discretizing the nonconservative (source) term +that contains the gradient of the pressure [`CompressibleEulerEquationsQuasi1D`](@ref) +and the nozzle width. + +Further details are available in the paper: +- Jesse Chan, Khemraj Shukla, Xinhui Wu, Ruofeng Liu, Prani Nalluri (2023) + High order entropy stable schemes for the quasi-one-dimensional + shallow water and compressible Euler equations + [DOI: 10.48550/arXiv.2307.12089](https://doi.org/10.48550/arXiv.2307.12089) +""" +@inline function flux_nonconservative_chan_etal(u_ll, u_rr, orientation::Integer, + equations::CompressibleEulerEquationsQuasi1D) + #Variables + _, _, p_ll, a_ll = cons2prim(u_ll, equations) + _, _, p_rr, _ = cons2prim(u_rr, equations) + + # For flux differencing using non-conservative terms, we return the + # non-conservative flux scaled by 2. This cancels with a factor of 0.5 + # in the arithmetic average of {p}. + p_avg = p_ll + p_rr + + z = zero(eltype(u_ll)) + + return SVector(z, a_ll * p_avg, z, z) +end + +""" +@inline function flux_chan_etal(u_ll, u_rr, orientation::Integer, + equations::CompressibleEulerEquationsQuasi1D) + +Conservative (symmetric) part of the entropy conservative flux for quasi 1D compressible Euler equations split form. +This flux is a generalization of [`flux_ranocha`](@ref) for [`CompressibleEulerEquations1D`](@ref). +Further details are available in the paper: +- Jesse Chan, Khemraj Shukla, Xinhui Wu, Ruofeng Liu, Prani Nalluri (2023) + High order entropy stable schemes for the quasi-one-dimensional + shallow water and compressible Euler equations + [DOI: 10.48550/arXiv.2307.12089](https://doi.org/10.48550/arXiv.2307.12089) +""" +@inline function flux_chan_etal(u_ll, u_rr, orientation::Integer, + equations::CompressibleEulerEquationsQuasi1D) + # Unpack left and right state + rho_ll, v1_ll, p_ll, a_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, p_rr, a_rr = cons2prim(u_rr, equations) + + # Compute the necessary mean values + rho_mean = ln_mean(rho_ll, rho_rr) + # Algebraically equivalent to `inv_ln_mean(rho_ll / p_ll, rho_rr / p_rr)` + # in exact arithmetic since + # log((ϱₗ/pₗ) / (ϱᵣ/pᵣ)) / (ϱₗ/pₗ - ϱᵣ/pᵣ) + # = pₗ pᵣ log((ϱₗ pᵣ) / (ϱᵣ pₗ)) / (ϱₗ pᵣ - ϱᵣ pₗ) + inv_rho_p_mean = p_ll * p_rr * inv_ln_mean(rho_ll * p_rr, rho_rr * p_ll) + v1_avg = 0.5 * (v1_ll + v1_rr) + a_v1_avg = 0.5 * (a_ll * v1_ll + a_rr * v1_rr) + p_avg = 0.5 * (p_ll + p_rr) + velocity_square_avg = 0.5 * (v1_ll * v1_rr) + + # Calculate fluxes + # Ignore orientation since it is always "1" in 1D + f1 = rho_mean * a_v1_avg + f2 = rho_mean * a_v1_avg * v1_avg + f3 = f1 * (velocity_square_avg + inv_rho_p_mean * equations.inv_gamma_minus_one) + + 0.5 * (p_ll * a_rr * v1_rr + p_rr * a_ll * v1_ll) + + return SVector(f1, f2, f3, zero(eltype(u_ll))) +end + +# Calculate estimates for maximum wave speed for local Lax-Friedrichs-type dissipation as the +# maximum velocity magnitude plus the maximum speed of sound +@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, + equations::CompressibleEulerEquationsQuasi1D) + a_rho_ll, a_rho_v1_ll, a_e_ll, a_ll = u_ll + a_rho_rr, a_rho_v1_rr, a_e_rr, a_rr = u_rr + + # Calculate primitive variables and speed of sound + rho_ll = a_rho_ll / a_ll + e_ll = a_e_ll / a_ll + v1_ll = a_rho_v1_ll / a_rho_ll + v_mag_ll = abs(v1_ll) + p_ll = (equations.gamma - 1) * (e_ll - 0.5 * rho_ll * v_mag_ll^2) + c_ll = sqrt(equations.gamma * p_ll / rho_ll) + rho_rr = a_rho_rr / a_rr + e_rr = a_e_rr / a_rr + v1_rr = a_rho_v1_rr / a_rho_rr + v_mag_rr = abs(v1_rr) + p_rr = (equations.gamma - 1) * (e_rr - 0.5 * rho_rr * v_mag_rr^2) + c_rr = sqrt(equations.gamma * p_rr / rho_rr) + + λ_max = max(v_mag_ll, v_mag_rr) + max(c_ll, c_rr) +end + +@inline function max_abs_speeds(u, equations::CompressibleEulerEquationsQuasi1D) + a_rho, a_rho_v1, a_e, a = u + rho = a_rho / a + v1 = a_rho_v1 / a_rho + e = a_e / a + p = (equations.gamma - 1) * (e - 0.5 * rho * v1^2) + c = sqrt(equations.gamma * p / rho) + + return (abs(v1) + c,) +end + +# Convert conservative variables to primitive. We use the convention that the primitive +# variables for the quasi-1D equations are `(rho, v1, p)` (i.e., the same as the primitive +# variables for `CompressibleEulerEquations1D`) +@inline function cons2prim(u, equations::CompressibleEulerEquationsQuasi1D) + a_rho, a_rho_v1, a_e, a = u + q = cons2prim(SVector(a_rho, a_rho_v1, a_e) / a, + CompressibleEulerEquations1D(equations.gamma)) + + return SVector(q[1], q[2], q[3], a) +end + +# The entropy for the quasi-1D compressible Euler equations is the entropy for the +# 1D compressible Euler equations scaled by the channel width `a`. +@inline function entropy(u, equations::CompressibleEulerEquationsQuasi1D) + a_rho, a_rho_v1, a_e, a = u + q = a * entropy(SVector(a_rho, a_rho_v1, a_e) / a, + CompressibleEulerEquations1D(equations.gamma)) + + return SVector(q[1], q[2], q[3], a) +end + +# Convert conservative variables to entropy. The entropy variables for the +# quasi-1D compressible Euler equations are identical to the entropy variables +# for the standard Euler equations for an appropriate definition of `entropy`. +@inline function cons2entropy(u, equations::CompressibleEulerEquationsQuasi1D) + a_rho, a_rho_v1, a_e, a = u + w = cons2entropy(SVector(a_rho, a_rho_v1, a_e) / a, + CompressibleEulerEquations1D(equations.gamma)) + + # we follow the convention for other spatially-varying equations such as + # `ShallowWaterEquations1D` and return the spatially varying coefficient + # `a` as the final entropy variable. + return SVector(w[1], w[2], w[3], a) +end + +# Convert primitive to conservative variables +@inline function prim2cons(u, equations::CompressibleEulerEquationsQuasi1D) + rho, v1, p, a = u + q = prim2cons(u, CompressibleEulerEquations1D(equations.gamma)) + + return SVector(a * q[1], a * q[2], a * q[3], a) +end + +@inline function density(u, equations::CompressibleEulerEquationsQuasi1D) + a_rho, _, _, a = u + rho = a_rho / a + return rho +end + +@inline function pressure(u, equations::CompressibleEulerEquationsQuasi1D) + a_rho, a_rho_v1, a_e, a = u + return pressure(SVector(a_rho, a_rho_v1, a_e) / a, + CompressibleEulerEquations1D(equations.gamma)) +end + +@inline function density_pressure(u, equations::CompressibleEulerEquationsQuasi1D) + a_rho, a_rho_v1, a_e, a = u + return density_pressure(SVector(a_rho, a_rho_v1, a_e) / a, + CompressibleEulerEquations1D(equations.gamma)) +end +end # @muladd diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 582d672b756..7a3c326984d 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -409,6 +409,7 @@ abstract type AbstractCompressibleEulerEquations{NDIMS, NVARS} <: include("compressible_euler_1d.jl") include("compressible_euler_2d.jl") include("compressible_euler_3d.jl") +include("compressible_euler_quasi_1d.jl") # CompressibleEulerMulticomponentEquations abstract type AbstractCompressibleEulerMulticomponentEquations{NDIMS, NVARS, NCOMP} <: diff --git a/test/test_tree_1d_euler.jl b/test/test_tree_1d_euler.jl index 6cd7998ab02..39a1f6e30ba 100644 --- a/test/test_tree_1d_euler.jl +++ b/test/test_tree_1d_euler.jl @@ -393,6 +393,79 @@ end @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 end end + +@trixi_testset "elixir_euler_quasi_1d_source_terms.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_quasi_1d_source_terms.jl"), + l2=[ + 3.876288369618363e-7, + 2.2247043122302947e-7, + 2.964004224572679e-7, + 5.2716983399807875e-8, + ], + linf=[ + 2.3925118561862746e-6, + 1.3603693522767912e-6, + 1.821888865105592e-6, + 1.1166012159335992e-7, + ]) + # 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_quasi_1d_discontinuous.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_quasi_1d_discontinuous.jl"), + l2=[ + 0.045510421156346015, + 0.036750584788912195, + 0.2468985959132176, + 0.03684494180829024, + ], + linf=[ + 0.3313374853025697, + 0.11621933362158643, + 1.827403013568638, + 0.28045939999015723, + ]) + # 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_quasi_1d_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_quasi_1d_ec.jl"), + l2=[ + 0.08889113985713998, + 0.16199235348889673, + 0.40316524365054346, + 2.9602775074723667e-16, + ], + linf=[ + 0.28891355898284043, + 0.3752709888964313, + 0.84477102402413, + 8.881784197001252e-16, + ]) + # 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 end # module diff --git a/test/test_unit.jl b/test/test_unit.jl index d2e744da62f..b3ed29d38e3 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -654,6 +654,19 @@ end end end +@timed_testset "Consistency check for flux_chan_etal: CEEQ" begin + + # Set up equations and dummy conservative variables state + equations = CompressibleEulerEquationsQuasi1D(1.4) + u = SVector(1.1, 2.34, 5.5, 2.73) + + orientations = [1] + for orientation in orientations + @test flux_chan_etal(u, u, orientation, equations) ≈ + flux(u, orientation, equations) + end +end + @timed_testset "Consistency check for HLL flux (naive): LEE" begin flux_hll = FluxHLL(min_max_speed_naive) From f19144435650e626c7c57d48060ea0a03e247895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Thu, 14 Dec 2023 13:02:17 +0100 Subject: [PATCH 203/263] Enable save solution with time intervals for SimpleIntegratorSSP (#1677) * First attempt to enable save solution with time intervals for SimpleIntegratorSSP * Importing `add_tstop!` * First working version of SimpleIntegratorSSP with SaveSolutionCallback using time intervals * Improved formatting and updated reference solution for test * Modified initialization of tstops to ensure a stop at the end of the simulation * Added missing docstring * Removed OrdinaryDiffEq from Trixi's dependencies * Empty tstops BinaryHeap during the call to `terminate!(integrator::SimpleIntegratorSSP)` * Fixed bug and added explanatory comments * Updated Project.toml * format --------- Co-authored-by: Hendrik Ranocha --- Project.toml | 2 + .../elixir_euler_shockcapturing_subcell.jl | 2 +- src/Trixi.jl | 4 +- src/time_integration/methods_SSP.jl | 75 +++++++++++++++++-- test/test_tree_2d_euler.jl | 16 ++-- 5 files changed, 82 insertions(+), 17 deletions(-) diff --git a/Project.toml b/Project.toml index 539dafc3034..267a3aa7066 100644 --- a/Project.toml +++ b/Project.toml @@ -6,6 +6,7 @@ version = "0.6.5-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9" +DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" DiffEqCallbacks = "459566f4-90b8-5000-8ac3-15dfb0a30def" EllipsisNotation = "da5c29d0-fa7d-589e-88eb-ea29b0a81949" FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" @@ -52,6 +53,7 @@ TrixiMakieExt = "Makie" [compat] CodeTracking = "1.0.5" ConstructionBase = "1.3" +DataStructures = "0.18.15" DiffEqCallbacks = "2.25" EllipsisNotation = "1.0" FillArrays = "0.13.2, 1" diff --git a/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl b/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl index 282805a0e03..44e63a0872e 100644 --- a/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl +++ b/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl @@ -67,7 +67,7 @@ analysis_callback = AnalysisCallback(semi, interval = analysis_interval) alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval = 100, +save_solution = SaveSolutionCallback(dt = 0.1, save_initial_solution = true, save_final_solution = true, solution_variables = cons2prim) diff --git a/src/Trixi.jl b/src/Trixi.jl index e7b849e2642..e18b2f6415c 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -37,7 +37,8 @@ using SciMLBase: CallbackSet, DiscreteCallback, import SciMLBase: get_du, get_tmp_cache, u_modified!, AbstractODEIntegrator, init, step!, check_error, get_proposed_dt, set_proposed_dt!, - terminate!, remake + terminate!, remake, add_tstop!, has_tstop, first_tstop + using CodeTracking: CodeTracking using ConstructionBase: ConstructionBase using DiffEqCallbacks: PeriodicCallback, PeriodicCallbackAffect @@ -70,6 +71,7 @@ using TriplotBase: TriplotBase using TriplotRecipes: DGTriPseudocolor @reexport using SimpleUnPack: @unpack using SimpleUnPack: @pack! +using DataStructures: BinaryHeap, FasterForward, extract_all! # finite difference SBP operators using SummationByPartsOperators: AbstractDerivativeOperator, diff --git a/src/time_integration/methods_SSP.jl b/src/time_integration/methods_SSP.jl index dbb9e51121b..9d1e06488b4 100644 --- a/src/time_integration/methods_SSP.jl +++ b/src/time_integration/methods_SSP.jl @@ -55,17 +55,25 @@ struct SimpleSSPRK33{StageCallbacks} <: SimpleAlgorithmSSP end # This struct is needed to fake https://github.com/SciML/OrdinaryDiffEq.jl/blob/0c2048a502101647ac35faabd80da8a5645beac7/src/integrators/type.jl#L1 -mutable struct SimpleIntegratorSSPOptions{Callback} +mutable struct SimpleIntegratorSSPOptions{Callback, TStops} callback::Callback # callbacks; used in Trixi adaptive::Bool # whether the algorithm is adaptive; ignored dtmax::Float64 # ignored maxiters::Int # maximal number of time steps - tstops::Vector{Float64} # tstops from https://diffeq.sciml.ai/v6.8/basics/common_solver_opts/#Output-Control-1; ignored + tstops::TStops # tstops from https://diffeq.sciml.ai/v6.8/basics/common_solver_opts/#Output-Control-1; ignored end function SimpleIntegratorSSPOptions(callback, tspan; maxiters = typemax(Int), kwargs...) - SimpleIntegratorSSPOptions{typeof(callback)}(callback, false, Inf, maxiters, - [last(tspan)]) + tstops_internal = BinaryHeap{eltype(tspan)}(FasterForward()) + # We add last(tspan) to make sure that the time integration stops at the end time + push!(tstops_internal, last(tspan)) + # We add 2 * last(tspan) because add_tstop!(integrator, t) is only called by DiffEqCallbacks.jl if tstops contains a time that is larger than t + # (https://github.com/SciML/DiffEqCallbacks.jl/blob/025dfe99029bd0f30a2e027582744528eb92cd24/src/iterative_and_periodic.jl#L92) + push!(tstops_internal, 2 * last(tspan)) + SimpleIntegratorSSPOptions{typeof(callback), typeof(tstops_internal)}(callback, + false, Inf, + maxiters, + tstops_internal) end # This struct is needed to fake https://github.com/SciML/OrdinaryDiffEq.jl/blob/0c2048a502101647ac35faabd80da8a5645beac7/src/integrators/type.jl#L77 @@ -78,6 +86,7 @@ mutable struct SimpleIntegratorSSP{RealT <: Real, uType, Params, Sol, F, Alg, du::uType r0::uType t::RealT + tdir::RealT dt::RealT # current time step dtcache::RealT # ignored iter::Int # current number of time steps (iteration) @@ -87,8 +96,29 @@ mutable struct SimpleIntegratorSSP{RealT <: Real, uType, Params, Sol, F, Alg, alg::Alg opts::SimpleIntegratorSSPOptions finalstep::Bool # added for convenience + dtchangeable::Bool + force_stepfail::Bool end +""" + add_tstop!(integrator::SimpleIntegratorSSP, t) +Add a time stop during the time integration process. +This function is called after the periodic SaveSolutionCallback to specify the next stop to save the solution. +""" +function add_tstop!(integrator::SimpleIntegratorSSP, t) + integrator.tdir * (t - integrator.t) < zero(integrator.t) && + error("Tried to add a tstop that is behind the current time. This is strictly forbidden") + # We need to remove the first entry of tstops when a new entry is added. + # Otherwise, the simulation gets stuck at the previous tstop and dt is adjusted to zero. + if length(integrator.opts.tstops) > 1 + pop!(integrator.opts.tstops) + end + push!(integrator.opts.tstops, integrator.tdir * t) +end + +has_tstop(integrator::SimpleIntegratorSSP) = !isempty(integrator.opts.tstops) +first_tstop(integrator::SimpleIntegratorSSP) = first(integrator.opts.tstops) + # Forward integrator.stats.naccept to integrator.iter (see GitHub PR#771) function Base.getproperty(integrator::SimpleIntegratorSSP, field::Symbol) if field === :stats @@ -113,11 +143,13 @@ function solve(ode::ODEProblem, alg = SimpleSSPRK33()::SimpleAlgorithmSSP; du = similar(u) r0 = similar(u) t = first(ode.tspan) + tdir = sign(ode.tspan[end] - ode.tspan[1]) iter = 0 - integrator = SimpleIntegratorSSP(u, du, r0, t, dt, zero(dt), iter, ode.p, + integrator = SimpleIntegratorSSP(u, du, r0, t, tdir, dt, zero(dt), iter, ode.p, (prob = ode,), ode.f, alg, SimpleIntegratorSSPOptions(callback, ode.tspan; - kwargs...), false) + kwargs...), + false, true, false) # resize container resize!(integrator.p, nelements(integrator.p.solver, integrator.p.cache)) @@ -160,6 +192,8 @@ function solve!(integrator::SimpleIntegratorSSP) terminate!(integrator) end + modify_dt_for_tstops!(integrator) + @. integrator.r0 = integrator.u for stage in eachindex(alg.c) t_stage = integrator.t + integrator.dt * alg.c[stage] @@ -198,6 +232,10 @@ function solve!(integrator::SimpleIntegratorSSP) end end + # Empty the tstops array. + # This cannot be done in terminate!(integrator::SimpleIntegratorSSP) because DiffEqCallbacks.PeriodicCallbackAffect would return at error. + extract_all!(integrator.opts.tstops) + for stage_callback in alg.stage_callbacks finalize_callback(stage_callback, integrator.p) end @@ -226,7 +264,30 @@ end # stop the time integration function terminate!(integrator::SimpleIntegratorSSP) integrator.finalstep = true - empty!(integrator.opts.tstops) +end + +""" + modify_dt_for_tstops!(integrator::SimpleIntegratorSSP) +Modify the time-step size to match the time stops specified in integrator.opts.tstops. +To avoid adding OrdinaryDiffEq to Trixi's dependencies, this routine is a copy of +https://github.com/SciML/OrdinaryDiffEq.jl/blob/d76335281c540ee5a6d1bd8bb634713e004f62ee/src/integrators/integrator_utils.jl#L38-L54 +""" +function modify_dt_for_tstops!(integrator::SimpleIntegratorSSP) + if has_tstop(integrator) + tdir_t = integrator.tdir * integrator.t + tdir_tstop = first_tstop(integrator) + if integrator.opts.adaptive + integrator.dt = integrator.tdir * + min(abs(integrator.dt), abs(tdir_tstop - tdir_t)) # step! to the end + elseif iszero(integrator.dtcache) && integrator.dtchangeable + integrator.dt = integrator.tdir * abs(tdir_tstop - tdir_t) + elseif integrator.dtchangeable && !integrator.force_stepfail + # always try to step! with dtcache, but lower if a tstop + # however, if force_stepfail then don't set to dtcache, and no tstop worry + integrator.dt = integrator.tdir * + min(abs(integrator.dtcache), abs(tdir_tstop - tdir_t)) # step! to the end + end + end end # used for AMR diff --git a/test/test_tree_2d_euler.jl b/test/test_tree_2d_euler.jl index 04a295537a3..65899cd5263 100644 --- a/test/test_tree_2d_euler.jl +++ b/test/test_tree_2d_euler.jl @@ -214,16 +214,16 @@ end @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing_subcell.jl"), l2=[ - 0.08508147906199143, - 0.04510299017724501, - 0.045103019801950375, - 0.6930704343869766, + 0.08508152653623638, + 0.04510301725066843, + 0.04510304668512745, + 0.6930705064715306, ], linf=[ - 0.31123546471463326, - 0.5616274869594462, - 0.5619692712224448, - 2.88670199345138, + 0.31136518019691406, + 0.5617651935473419, + 0.5621200790240503, + 2.8866869108596056, ]) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) From 40e1af41e49747f22908fc07acfc6eac92aec204 Mon Sep 17 00:00:00 2001 From: Yik Haw Teoh <66682196+teohyikhaw@users.noreply.github.com> Date: Thu, 14 Dec 2023 09:08:08 -0800 Subject: [PATCH 204/263] Fixed `cons2entropy` files and implemented `entropy2cons` for `CompressibleEulerMulticomponent1D` and `CompressibleEulerMulticomponent2D` (#1767) * initial bug fix * formatting * Added test cases for entropy2cons and cons2entropy for compressible multicomponent euler 1d and 2d * Fixed total entropy function call * minor typo * Updated formatting Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Updated formatting Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> * Fixed formatting issues * Update test/test_tree_1d_eulermulti.jl * Update test/test_tree_2d_eulermulti.jl --------- Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> --- .../compressible_euler_multicomponent_1d.jl | 78 +++- .../compressible_euler_multicomponent_2d.jl | 80 +++- test/test_tree_1d_eulermulti.jl | 241 +++++----- test/test_tree_2d_eulermulti.jl | 441 +++++++++--------- 4 files changed, 505 insertions(+), 335 deletions(-) diff --git a/src/equations/compressible_euler_multicomponent_1d.jl b/src/equations/compressible_euler_multicomponent_1d.jl index 8ddb0dcd08f..6338e04c3ed 100644 --- a/src/equations/compressible_euler_multicomponent_1d.jl +++ b/src/equations/compressible_euler_multicomponent_1d.jl @@ -461,6 +461,7 @@ end # Convert conservative variables to entropy @inline function cons2entropy(u, equations::CompressibleEulerMulticomponentEquations1D) @unpack cv, gammas, gas_constants = equations + rho_v1, rho_e = u rho = density(u, equations) @@ -480,21 +481,86 @@ end s = log(p) - gamma * log(rho) - log(gas_constant) rho_p = rho / p T = (rho_e - 0.5 * rho * v_square) / (help1) - entrop_rho = SVector{ncomponents(equations), real(equations)}(gas_constant * - ((gamma - s) / - (gamma - 1.0) - - (0.5 * v_square * - rho_p)) + + entrop_rho = SVector{ncomponents(equations), real(equations)}((cv[i] * + (1 - log(T)) + + gas_constants[i] * + (1 + log(u[i + 2])) - + v1^2 / (2 * T)) for i in eachcomponent(equations)) w1 = gas_constant * v1 * rho_p - w2 = gas_constant * (-1.0 * rho_p) + w2 = gas_constant * (-rho_p) entrop_other = SVector{2, real(equations)}(w1, w2) return vcat(entrop_other, entrop_rho) end +# Convert entropy variables to conservative variables +@inline function entropy2cons(w, equations::CompressibleEulerMulticomponentEquations1D) + @unpack gammas, gas_constants, cv, cp = equations + T = -1 / w[2] + v1 = w[1] * T + cons_rho = SVector{ncomponents(equations), real(equations)}(exp(1 / + gas_constants[i] * + (-cv[i] * + log(-w[2]) - + cp[i] + w[i + 2] - + 0.5 * w[1]^2 / + w[2])) + for i in eachcomponent(equations)) + + rho = zero(cons_rho[1]) + help1 = zero(cons_rho[1]) + help2 = zero(cons_rho[1]) + p = zero(cons_rho[1]) + for i in eachcomponent(equations) + rho += cons_rho[i] + help1 += cons_rho[i] * cv[i] * gammas[i] + help2 += cons_rho[i] * cv[i] + p += cons_rho[i] * gas_constants[i] * T + end + u1 = rho * v1 + gamma = help1 / help2 + u2 = p / (gamma - 1) + 0.5 * rho * v1^2 + cons_other = SVector{2, real(equations)}(u1, u2) + return vcat(cons_other, cons_rho) +end + +@inline function total_entropy(u, equations::CompressibleEulerMulticomponentEquations1D) + @unpack cv, gammas, gas_constants = equations + rho_v1, rho_e = u + rho = density(u, equations) + T = temperature(u, equations) + + total_entropy = zero(u[1]) + for i in eachcomponent(equations) + total_entropy -= u[i + 2] * (cv[i] * log(T) - gas_constants[i] * log(u[i + 2])) + end + + return total_entropy +end + +@inline function temperature(u, equations::CompressibleEulerMulticomponentEquations1D) + @unpack cv, gammas, gas_constants = equations + + rho_v1, rho_e = u + + rho = density(u, equations) + help1 = zero(rho) + + for i in eachcomponent(equations) + help1 += u[i + 2] * cv[i] + end + + v1 = rho_v1 / rho + v_square = v1^2 + T = (rho_e - 0.5 * rho * v_square) / help1 + + return T +end + """ totalgamma(u, equations::CompressibleEulerMulticomponentEquations1D) diff --git a/src/equations/compressible_euler_multicomponent_2d.jl b/src/equations/compressible_euler_multicomponent_2d.jl index 940d88b1aa5..60fce222f21 100644 --- a/src/equations/compressible_euler_multicomponent_2d.jl +++ b/src/equations/compressible_euler_multicomponent_2d.jl @@ -665,22 +665,57 @@ end s = log(p) - gamma * log(rho) - log(gas_constant) rho_p = rho / p T = (rho_e - 0.5 * rho * v_square) / (help1) - entrop_rho = SVector{ncomponents(equations), real(equations)}(gas_constant * - ((gamma - s) / - (gamma - 1.0) - - (0.5 * v_square * - rho_p)) + + entrop_rho = SVector{ncomponents(equations), real(equations)}((cv[i] * + (1 - log(T)) + + gas_constants[i] * + (1 + log(u[i + 3])) - + v_square / (2 * T)) for i in eachcomponent(equations)) w1 = gas_constant * v1 * rho_p w2 = gas_constant * v2 * rho_p - w3 = gas_constant * rho_p * (-1) + w3 = gas_constant * (-rho_p) entrop_other = SVector{3, real(equations)}(w1, w2, w3) return vcat(entrop_other, entrop_rho) end +# Convert entropy variables to conservative variables +@inline function entropy2cons(w, equations::CompressibleEulerMulticomponentEquations2D) + @unpack gammas, gas_constants, cp, cv = equations + T = -1 / w[3] + v1 = w[1] * T + v2 = w[2] * T + v_squared = v1^2 + v2^2 + cons_rho = SVector{ncomponents(equations), real(equations)}(exp((w[i + 3] - + cv[i] * + (1 - log(T)) + + v_squared / + (2 * T)) / + gas_constants[i] - + 1) + for i in eachcomponent(equations)) + + rho = zero(cons_rho[1]) + help1 = zero(cons_rho[1]) + help2 = zero(cons_rho[1]) + p = zero(cons_rho[1]) + for i in eachcomponent(equations) + rho += cons_rho[i] + help1 += cons_rho[i] * cv[i] * gammas[i] + help2 += cons_rho[i] * cv[i] + p += cons_rho[i] * gas_constants[i] * T + end + u1 = rho * v1 + u2 = rho * v2 + gamma = help1 / help2 + u3 = p / (gamma - 1) + 0.5 * rho * v_squared + cons_other = SVector{3, real(equations)}(u1, u2, u3) + return vcat(cons_other, cons_rho) +end + # Convert primitive to conservative variables @inline function prim2cons(prim, equations::CompressibleEulerMulticomponentEquations2D) @unpack cv, gammas = equations @@ -700,6 +735,39 @@ end return vcat(cons_other, cons_rho) end +@inline function total_entropy(u, equations::CompressibleEulerMulticomponentEquations2D) + @unpack cv, gammas, gas_constants = equations + rho = density(u, equations) + T = temperature(u, equations) + + total_entropy = zero(u[1]) + for i in eachcomponent(equations) + total_entropy -= u[i + 3] * (cv[i] * log(T) - gas_constants[i] * log(u[i + 3])) + end + + return total_entropy +end + +@inline function temperature(u, equations::CompressibleEulerMulticomponentEquations2D) + @unpack cv, gammas, gas_constants = equations + + rho_v1, rho_v2, rho_e = u + + rho = density(u, equations) + help1 = zero(rho) + + for i in eachcomponent(equations) + help1 += u[i + 3] * cv[i] + end + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v_square = v1^2 + v2^2 + T = (rho_e - 0.5 * rho * v_square) / help1 + + return T +end + """ totalgamma(u, equations::CompressibleEulerMulticomponentEquations2D) diff --git a/test/test_tree_1d_eulermulti.jl b/test/test_tree_1d_eulermulti.jl index bd86de928e3..b6c79ce03d1 100644 --- a/test/test_tree_1d_eulermulti.jl +++ b/test/test_tree_1d_eulermulti.jl @@ -2,136 +2,153 @@ module TestExamples1DEulerMulti using Test using Trixi +using ForwardDiff include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") @testset "Compressible Euler Multicomponent" begin -#! format: noindent + @trixi_testset "Testing entropy2cons and cons2entropy" begin + using ForwardDiff + gammas = (1.3272378792562836, 1.5269959187969864, 1.8362285750521512, + 1.0409061360276926, 1.4652015053812224, 1.3626493264184423) + gas_constants = (1.817636851910076, 6.760820475922636, 5.588953939749113, + 6.31574782981543, 3.362932038038397, 3.212779569399733) + equations = CompressibleEulerMulticomponentEquations1D(gammas = SVector{length(gammas)}(gammas...), + gas_constants = SVector{length(gas_constants)}(gas_constants...)) + u = [-1.4632513788889214, 0.9908786980927811, 0.2909066990257628, + 0.6256623915420473, 0.4905882754313441, 0.14481800501749112, + 1.0333532872771651, 0.6805599818745411] + w = cons2entropy(u, equations) + # test that the entropy variables match the gradients of the total entropy + @test w ≈ ForwardDiff.gradient(u -> Trixi.total_entropy(u, equations), u) + # test that `entropy2cons` is the inverse of `cons2entropy` + @test entropy2cons(w, equations) ≈ u + end -@trixi_testset "elixir_eulermulti_ec.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_ec.jl"), - l2=[0.15330089521538684, 0.4417674632047301, - 0.016888510510282385, 0.03377702102056477, - 0.06755404204112954], - linf=[0.29130548795961864, 0.8847009003152357, - 0.034686525099975274, 0.06937305019995055, - 0.1387461003999011]) - # 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 + @trixi_testset "elixir_eulermulti_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_ec.jl"), + l2=[0.15330089521538684, 0.4417674632047301, + 0.016888510510282385, 0.03377702102056477, + 0.06755404204112954], + linf=[0.29130548795961864, 0.8847009003152357, + 0.034686525099975274, 0.06937305019995055, + 0.1387461003999011]) + # 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 -@trixi_testset "elixir_eulermulti_es.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_es.jl"), - l2=[ - 0.1522380497572071, - 0.43830846465313206, - 0.03907262116499431, - 0.07814524232998862, - ], - linf=[ - 0.24939193075537294, - 0.7139395740052739, - 0.06324208768391237, - 0.12648417536782475, - ]) - # 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 + @trixi_testset "elixir_eulermulti_es.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_es.jl"), + l2=[ + 0.1522380497572071, + 0.43830846465313206, + 0.03907262116499431, + 0.07814524232998862, + ], + linf=[ + 0.24939193075537294, + 0.7139395740052739, + 0.06324208768391237, + 0.12648417536782475, + ]) + # 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 -@trixi_testset "elixir_eulermulti_convergence_ec.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_ec.jl"), - l2=[ - 8.575236038539227e-5, - 0.00016387804318585358, - 1.9412699303977585e-5, - 3.882539860795517e-5, - ], - linf=[ - 0.00030593277277124464, - 0.0006244803933350696, - 7.253121435135679e-5, - 0.00014506242870271358, - ]) - # 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 + @trixi_testset "elixir_eulermulti_convergence_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_ec.jl"), + l2=[ + 8.575236038539227e-5, + 0.00016387804318585358, + 1.9412699303977585e-5, + 3.882539860795517e-5, + ], + linf=[ + 0.00030593277277124464, + 0.0006244803933350696, + 7.253121435135679e-5, + 0.00014506242870271358, + ]) + # 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 -@trixi_testset "elixir_eulermulti_convergence_es.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_es.jl"), - l2=[1.8983933794407234e-5, 6.207744299844731e-5, - 1.5466205761868047e-6, 3.0932411523736094e-6, - 6.186482304747219e-6, 1.2372964609494437e-5], - linf=[0.00012014372605895218, 0.0003313207215800418, - 6.50836791016296e-6, 1.301673582032592e-5, - 2.603347164065184e-5, 5.206694328130368e-5]) - # 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 + @trixi_testset "elixir_eulermulti_convergence_es.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_es.jl"), + l2=[1.8983933794407234e-5, 6.207744299844731e-5, + 1.5466205761868047e-6, 3.0932411523736094e-6, + 6.186482304747219e-6, 1.2372964609494437e-5], + linf=[0.00012014372605895218, 0.0003313207215800418, + 6.50836791016296e-6, 1.301673582032592e-5, + 2.603347164065184e-5, 5.206694328130368e-5]) + # 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 -@trixi_testset "elixir_eulermulti_convergence_es.jl with flux_chandrashekar" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_es.jl"), - l2=[1.888450477353845e-5, 5.4910600482795386e-5, - 9.426737161533622e-7, 1.8853474323067245e-6, - 3.770694864613449e-6, 7.541389729226898e-6], - linf=[0.00011622351152063004, 0.0003079221967086099, - 3.2177423254231563e-6, 6.435484650846313e-6, - 1.2870969301692625e-5, 2.574193860338525e-5], - volume_flux=flux_chandrashekar) - # 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 + @trixi_testset "elixir_eulermulti_convergence_es.jl with flux_chandrashekar" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_es.jl"), + l2=[1.888450477353845e-5, 5.4910600482795386e-5, + 9.426737161533622e-7, 1.8853474323067245e-6, + 3.770694864613449e-6, 7.541389729226898e-6], + linf=[0.00011622351152063004, 0.0003079221967086099, + 3.2177423254231563e-6, 6.435484650846313e-6, + 1.2870969301692625e-5, 2.574193860338525e-5], + volume_flux=flux_chandrashekar) + # 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 -@trixi_testset "elixir_eulermulti_two_interacting_blast_waves.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_eulermulti_two_interacting_blast_waves.jl"), - l2=[1.288867611915533, 82.71335258388848, 0.00350680272313187, - 0.013698784353152794, - 0.019179518517518084], - linf=[29.6413044707026, 1322.5844802186496, 0.09191919374782143, - 0.31092970966717925, - 0.4417989757182038], - tspan=(0.0, 0.0001)) - # 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 + @trixi_testset "elixir_eulermulti_two_interacting_blast_waves.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_eulermulti_two_interacting_blast_waves.jl"), + l2=[1.288867611915533, 82.71335258388848, 0.00350680272313187, + 0.013698784353152794, + 0.019179518517518084], + linf=[29.6413044707026, 1322.5844802186496, 0.09191919374782143, + 0.31092970966717925, + 0.4417989757182038], + tspan=(0.0, 0.0001)) + # 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 -end end # module diff --git a/test/test_tree_2d_eulermulti.jl b/test/test_tree_2d_eulermulti.jl index 30d52b37b96..7c4a4e722e3 100644 --- a/test/test_tree_2d_eulermulti.jl +++ b/test/test_tree_2d_eulermulti.jl @@ -8,234 +8,253 @@ include("test_trixi.jl") EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") @testset "Compressible Euler Multicomponent" begin -#! format: noindent + @trixi_testset "Testing entropy2cons and cons2entropy" begin + using ForwardDiff + gammas = (1.1546412974182538, 1.1171560258914812, 1.097107661471476, + 1.0587601652669245, 1.6209889683979308, 1.6732209755396386, + 1.2954303574165822) + gas_constants = (5.969461071171914, 3.6660802003290183, 6.639008614675539, + 8.116604827140456, 6.190706056680031, 1.6795013743693712, + 2.197737590916966) + equations = CompressibleEulerMulticomponentEquations2D(gammas = SVector{length(gammas)}(gammas...), + gas_constants = SVector{length(gas_constants)}(gas_constants...)) + u = [-1.7433292819144075, 0.8844413258376495, 0.6050737175812364, + 0.8261998359817043, 1.0801186290896465, 0.505654488367698, + 0.6364415555805734, 0.851669392285058, 0.31219606420306223, + 1.0930477805612038] + w = cons2entropy(u, equations) + # test that the entropy variables match the gradients of the total entropy + @test w ≈ ForwardDiff.gradient(u -> Trixi.total_entropy(u, equations), u) + # test that `entropy2cons` is the inverse of `cons2entropy` + @test entropy2cons(w, equations) ≈ u + end -# NOTE: Some of the L2/Linf errors are comparably large. This is due to the fact that some of the -# simulations are set up with dimensional states. For example, the reference pressure in SI -# units is 101325 Pa, i.e., pressure has values of O(10^5) + # NOTE: Some of the L2/Linf errors are comparably large. This is due to the fact that some of the + # simulations are set up with dimensional states. For example, the reference pressure in SI + # units is 101325 Pa, i.e., pressure has values of O(10^5) -@trixi_testset "elixir_eulermulti_shock_bubble.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_shock_bubble.jl"), - l2=[ - 73.78467629094177, - 0.9174752929795251, - 57942.83587826468, - 0.1828847253029943, - 0.011127037850925347, - ], - linf=[ - 196.81051991521073, - 7.8456811648529605, - 158891.88930113698, - 0.811379581519794, - 0.08011973559187913, - ], - tspan=(0.0, 0.001)) - # 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 + @trixi_testset "elixir_eulermulti_shock_bubble.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_shock_bubble.jl"), + l2=[ + 73.78467629094177, + 0.9174752929795251, + 57942.83587826468, + 0.1828847253029943, + 0.011127037850925347, + ], + linf=[ + 196.81051991521073, + 7.8456811648529605, + 158891.88930113698, + 0.811379581519794, + 0.08011973559187913, + ], + tspan=(0.0, 0.001)) + # 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 -@trixi_testset "elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl" begin - rm("out/deviations.txt", force = true) - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl"), - l2=[ - 81.52845664909304, - 2.5455678559421346, - 63229.190712645846, - 0.19929478404550321, - 0.011068604228443425, - ], - linf=[ - 249.21708417382013, - 40.33299887640794, - 174205.0118831558, - 0.6881458768113586, - 0.11274401158173972, - ], - initial_refinement_level=3, - tspan=(0.0, 0.001), - output_directory="out") - lines = readlines("out/deviations.txt") - @test lines[1] == "# iter, simu_time, rho1_min, rho2_min" - @test startswith(lines[end], "1") - # 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)) < 15000 + @trixi_testset "elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl" begin + rm("out/deviations.txt", force = true) + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl"), + l2=[ + 81.52845664909304, + 2.5455678559421346, + 63229.190712645846, + 0.19929478404550321, + 0.011068604228443425, + ], + linf=[ + 249.21708417382013, + 40.33299887640794, + 174205.0118831558, + 0.6881458768113586, + 0.11274401158173972, + ], + initial_refinement_level=3, + tspan=(0.0, 0.001), + output_directory="out") + lines = readlines("out/deviations.txt") + @test lines[1] == "# iter, simu_time, rho1_min, rho2_min" + @test startswith(lines[end], "1") + # 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)) < 15000 + end end -end -@trixi_testset "elixir_eulermulti_shock_bubble_shockcapturing_subcell_minmax.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_eulermulti_shock_bubble_shockcapturing_subcell_minmax.jl"), - l2=[ - 73.10832638093902, - 1.4599215762968585, - 57176.014861335476, - 0.17812843581838675, - 0.010123079422717837, - ], - linf=[ - 214.50568817511956, - 25.40392579616452, - 152862.41011222568, - 0.564195553101797, - 0.0956331651771212, - ], - initial_refinement_level=3, - tspan=(0.0, 0.001)) - # 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)) < 15000 + @trixi_testset "elixir_eulermulti_shock_bubble_shockcapturing_subcell_minmax.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_eulermulti_shock_bubble_shockcapturing_subcell_minmax.jl"), + l2=[ + 73.10832638093902, + 1.4599215762968585, + 57176.014861335476, + 0.17812843581838675, + 0.010123079422717837, + ], + linf=[ + 214.50568817511956, + 25.40392579616452, + 152862.41011222568, + 0.564195553101797, + 0.0956331651771212, + ], + initial_refinement_level=3, + tspan=(0.0, 0.001)) + # 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)) < 15000 + end end -end -@trixi_testset "elixir_eulermulti_ec.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_ec.jl"), - l2=[ - 0.050182236154087095, - 0.050189894464434635, - 0.2258715597305131, - 0.06175171559771687, - ], - linf=[ - 0.3108124923284472, - 0.3107380389947733, - 1.054035804988521, - 0.29347582879608936, - ]) - # 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 + @trixi_testset "elixir_eulermulti_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_ec.jl"), + l2=[ + 0.050182236154087095, + 0.050189894464434635, + 0.2258715597305131, + 0.06175171559771687, + ], + linf=[ + 0.3108124923284472, + 0.3107380389947733, + 1.054035804988521, + 0.29347582879608936, + ]) + # 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 -@trixi_testset "elixir_eulermulti_es.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_es.jl"), - l2=[ - 0.0496546258404055, - 0.04965550099933263, - 0.22425206549856372, - 0.004087155041747821, - 0.008174310083495642, - 0.016348620166991283, - 0.032697240333982566, - ], - linf=[ - 0.2488251110766228, - 0.24832493304479406, - 0.9310354690058298, - 0.017452870465607374, - 0.03490574093121475, - 0.0698114818624295, - 0.139622963724859, - ]) - # 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 + @trixi_testset "elixir_eulermulti_es.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_es.jl"), + l2=[ + 0.0496546258404055, + 0.04965550099933263, + 0.22425206549856372, + 0.004087155041747821, + 0.008174310083495642, + 0.016348620166991283, + 0.032697240333982566, + ], + linf=[ + 0.2488251110766228, + 0.24832493304479406, + 0.9310354690058298, + 0.017452870465607374, + 0.03490574093121475, + 0.0698114818624295, + 0.139622963724859, + ]) + # 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 -@trixi_testset "elixir_eulermulti_convergence_ec.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_ec.jl"), - l2=[ - 0.00012290225488326508, - 0.00012290225488321876, - 0.00018867397906337653, - 4.8542321753649044e-5, - 9.708464350729809e-5, - ], - linf=[ - 0.0006722819239133315, - 0.0006722819239128874, - 0.0012662292789555885, - 0.0002843844182700561, - 0.0005687688365401122, - ]) - # 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 + @trixi_testset "elixir_eulermulti_convergence_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_ec.jl"), + l2=[ + 0.00012290225488326508, + 0.00012290225488321876, + 0.00018867397906337653, + 4.8542321753649044e-5, + 9.708464350729809e-5, + ], + linf=[ + 0.0006722819239133315, + 0.0006722819239128874, + 0.0012662292789555885, + 0.0002843844182700561, + 0.0005687688365401122, + ]) + # 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 -@trixi_testset "elixir_eulermulti_convergence_es.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_es.jl"), - l2=[ - 2.2661773867001696e-6, - 2.266177386666318e-6, - 6.593514692980009e-6, - 8.836308667348217e-7, - 1.7672617334696433e-6, - ], - linf=[ - 1.4713170997993075e-5, - 1.4713170997104896e-5, - 5.115618808515521e-5, - 5.3639516094383666e-6, - 1.0727903218876733e-5, - ]) - # 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 + @trixi_testset "elixir_eulermulti_convergence_es.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_es.jl"), + l2=[ + 2.2661773867001696e-6, + 2.266177386666318e-6, + 6.593514692980009e-6, + 8.836308667348217e-7, + 1.7672617334696433e-6, + ], + linf=[ + 1.4713170997993075e-5, + 1.4713170997104896e-5, + 5.115618808515521e-5, + 5.3639516094383666e-6, + 1.0727903218876733e-5, + ]) + # 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 -@trixi_testset "elixir_eulermulti_convergence_es.jl with flux_chandrashekar" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_es.jl"), - l2=[ - 1.8621737639352465e-6, - 1.862173764098385e-6, - 5.942585713809631e-6, - 6.216263279534722e-7, - 1.2432526559069443e-6, - ], - linf=[ - 1.6235495582606063e-5, - 1.6235495576388814e-5, - 5.854523678827661e-5, - 5.790274858807898e-6, - 1.1580549717615796e-5, - ], - volume_flux=flux_chandrashekar) - # 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 + @trixi_testset "elixir_eulermulti_convergence_es.jl with flux_chandrashekar" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulermulti_convergence_es.jl"), + l2=[ + 1.8621737639352465e-6, + 1.862173764098385e-6, + 5.942585713809631e-6, + 6.216263279534722e-7, + 1.2432526559069443e-6, + ], + linf=[ + 1.6235495582606063e-5, + 1.6235495576388814e-5, + 5.854523678827661e-5, + 5.790274858807898e-6, + 1.1580549717615796e-5, + ], + volume_flux=flux_chandrashekar) + # 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 -end end # module From 318e145e72110fe2acf0fd1f685bffe21e4df965 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 15 Dec 2023 17:09:16 +0100 Subject: [PATCH 205/263] CompatHelper: bump compat for T8code to 0.5, (keep existing compat) (#1775) Co-authored-by: CompatHelper Julia Co-authored-by: Hendrik Ranocha --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 267a3aa7066..a834ddeea73 100644 --- a/Project.toml +++ b/Project.toml @@ -86,7 +86,7 @@ StaticArrays = "1" StrideArrays = "0.1.18" StructArrays = "0.6" SummationByPartsOperators = "0.5.41" -T8code = "0.4.3" +T8code = "0.4.3, 0.5" TimerOutputs = "0.5.7" Triangulate = "2.0" TriplotBase = "0.1" From 6bef107cd322f7a31b50770219327de4345d93bc Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Sat, 16 Dec 2023 15:06:09 +0100 Subject: [PATCH 206/263] Add get_proposed_dt to custom integrators (#1776) --- src/time_integration/methods_2N.jl | 5 +++++ src/time_integration/methods_3Sstar.jl | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/time_integration/methods_2N.jl b/src/time_integration/methods_2N.jl index d2f22679c4f..f3b09b01e97 100644 --- a/src/time_integration/methods_2N.jl +++ b/src/time_integration/methods_2N.jl @@ -204,6 +204,11 @@ function set_proposed_dt!(integrator::SimpleIntegrator2N, dt) integrator.dt = dt end +# Required e.g. for `glm_speed_callback` +function get_proposed_dt(integrator::SimpleIntegrator2N) + return integrator.dt +end + # stop the time integration function terminate!(integrator::SimpleIntegrator2N) integrator.finalstep = true diff --git a/src/time_integration/methods_3Sstar.jl b/src/time_integration/methods_3Sstar.jl index b0ce5930514..7b70466606c 100644 --- a/src/time_integration/methods_3Sstar.jl +++ b/src/time_integration/methods_3Sstar.jl @@ -282,6 +282,11 @@ function set_proposed_dt!(integrator::SimpleIntegrator3Sstar, dt) integrator.dt = dt end +# Required e.g. for `glm_speed_callback` +function get_proposed_dt(integrator::SimpleIntegrator3Sstar) + return integrator.dt +end + # stop the time integration function terminate!(integrator::SimpleIntegrator3Sstar) integrator.finalstep = true From b5d0a50214abb9b33dc4a4859a4a12c6e3149cb1 Mon Sep 17 00:00:00 2001 From: Jesse Chan <1156048+jlchan@users.noreply.github.com> Date: Mon, 18 Dec 2023 08:36:23 -0600 Subject: [PATCH 207/263] Update NEWS.md (#1780) --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 265979c3508..abd9fd27882 100644 --- a/NEWS.md +++ b/NEWS.md @@ -38,7 +38,7 @@ for human readability. - Capability to set truly discontinuous initial conditions in 1D. - Wetting and drying feature and examples for 1D and 2D shallow water equations - Implementation of the polytropic Euler equations in 2D -- Implementation of the quasi-1D shallow water equations +- Implementation of the quasi-1D shallow water and compressible Euler equations - Subcell (positivity and local min/max) limiting support for conservative variables in 2D for `TreeMesh` - AMR for hyperbolic-parabolic equations on 2D/3D `TreeMesh` From 5a5424c1fcefe602b4854477bebf96dc77c2e9b7 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 20 Dec 2023 07:33:30 +0100 Subject: [PATCH 208/263] set version to v0.6.5 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index a834ddeea73..1ef9ee13516 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.6.5-pre" +version = "0.6.5" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 622740a9db3c3e1b9bb1f5b0520b18b616d250e6 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 20 Dec 2023 07:33:42 +0100 Subject: [PATCH 209/263] set development version to v0.6.6-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 1ef9ee13516..6bedec18c78 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.6.5" +version = "0.6.6-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 24a365dbf2eb029b9dbd2be3e8404538bc54e89d Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Thu, 21 Dec 2023 09:13:10 +0100 Subject: [PATCH 210/263] hotfix: restrict DiffEqBase.jl to let CI pass (#1788) * hotfix: restrict DiffEqBase.jl to let CI pass * restrict DiffEqBase.jl in main Project.toml * Update Project.toml --- Project.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Project.toml b/Project.toml index 6bedec18c78..faf9f82d335 100644 --- a/Project.toml +++ b/Project.toml @@ -7,6 +7,7 @@ version = "0.6.6-pre" CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" DiffEqCallbacks = "459566f4-90b8-5000-8ac3-15dfb0a30def" EllipsisNotation = "da5c29d0-fa7d-589e-88eb-ea29b0a81949" FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" @@ -54,6 +55,7 @@ TrixiMakieExt = "Makie" CodeTracking = "1.0.5" ConstructionBase = "1.3" DataStructures = "0.18.15" +DiffEqBase = "6 - 6.143" DiffEqCallbacks = "2.25" EllipsisNotation = "1.0" FillArrays = "0.13.2, 1" From 96c5bef1a68729ae61be5a6644d7b7b4756aac8e Mon Sep 17 00:00:00 2001 From: Ahmad Peyvan <115842305+apey236@users.noreply.github.com> Date: Sat, 23 Dec 2023 10:18:42 -0500 Subject: [PATCH 211/263] Parabolic Mortar for AMR `P4estMesh{3}` (#1765) * Clean branch * Un-Comment * un-comment * test coarsen * remove redundancy * Remove support for passive terms * expand resize * comments * format * Avoid code duplication * Update src/callbacks_step/amr_dg1d.jl Co-authored-by: Michael Schlottke-Lakemper * comment * comment & format * Try to increase coverage * Slightly more expressive names * Apply suggestions from code review * add specifier for 1d * Structs for resizing parabolic helpers * check if mortars are present * reuse `reinitialize_containers!` * resize calls for parabolic helpers * update analysis callbacks * Velocities for compr euler * Init container * correct copy-paste error * resize each dim * add dispatch * Add AMR for shear layer * USe only amr shear layer * first steps towards p4est parabolic amr * Add tests * remove plots * Format * remove redundant line * platform independent tests * No need for different flux_viscous comps after adding container_viscous to p4est * Laplace 3d * Longer times to allow converage to hit coarsen! * Increase testing of Laplace 3D * Add tests for velocities * remove comment * add elixir for amr testing * adding commented out mortar routines in 2D * Adding Mortar to 2d dg parabolic term * remove testing snippet * fix comments * add more arguments for dispatch * add some temporary todo notes * some updates for AP and KS * specialize mortar_fluxes_to_elements * BUGFIX: apply_jacobian_parabolic! was incorrect for P4estMesh * fixed rhs_parabolic! for mortars * more changes to elixir * indexing bug * comments * Adding the example for nonperiodic BCs with amr * hopefully this fixes AMR boundaries for parabolic terms * add elixir * Example with non periodic bopundary conditions * remove cruft * 3D parabolic amr * TGV elixir * Creating test for AMR 3D parabolic * Formatting * test formatting * Update src/Trixi.jl * Update src/equations/compressible_euler_1d.jl * Update src/equations/compressible_euler_2d.jl * Update src/equations/compressible_euler_3d.jl * Update src/solvers/dgsem_tree/container_viscous_2d.jl * Update src/solvers/dgsem_tree/container_viscous_2d.jl * Update src/solvers/dgsem_tree/container_viscous_2d.jl * Update src/solvers/dgsem_tree/container_viscous_3d.jl * Update src/solvers/dgsem_tree/container_viscous_3d.jl * Update src/solvers/dgsem_tree/container_viscous_3d.jl * Update src/solvers/dgsem_p4est/dg_2d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_2d_parabolic.jl * Update src/solvers/dgsem_tree/dg_2d_parabolic.jl * Update src/solvers/dgsem_tree/dg_2d_parabolic.jl * Update src/solvers/dgsem_tree/dg_2d_parabolic.jl * Update src/solvers/dgsem_tree/dg_2d_parabolic.jl * Update src/solvers/dgsem_tree/dg_2d_parabolic.jl * Update src/solvers/dgsem_tree/dg_2d_parabolic.jl * Update src/solvers/dgsem_tree/dg_2d_parabolic.jl * Update src/solvers/dgsem_tree/dg_2d_parabolic.jl * Update src/solvers/dgsem_tree/dg_2d_parabolic.jl * Update test/test_parabolic_3d.jl * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_3d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_3d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_3d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_3d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_2d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_2d.jl * Update src/solvers/dgsem_p4est/dg_2d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_2d_parabolic.jl * Update test/test_parabolic_3d.jl * Update test/test_parabolic_3d.jl * Update test/test_parabolic_3d.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_3d_blast_wave_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_3d_blast_wave_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_3d_blast_wave_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_3d_blast_wave_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_3d_blast_wave_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_3d_blast_wave_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex_amr.jl * Update dg_3d_parabolic.jl * Update test_parabolic_3d.jl * Update elixir_navierstokes_3d_blast_wave_amr.jl * Update elixir_navierstokes_taylor_green_vortex_amr.jl * Update dg_3d_parabolic.jl * Update test_parabolic_3d.jl * Update test_parabolic_3d.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_3d_blast_wave_amr.jl * Update elixir_navierstokes_3d_blast_wave_amr.jl * Update elixir_navierstokes_taylor_green_vortex_amr.jl * Update dg_3d_parabolic.jl * Update test_parabolic_3d.jl * Delete examples/p4est_3d_dgsem/elixir_navierstokes_3d_blast_wave_amr.jl * Create elixir_navierstokes_blast_wave_amr.jl * Update test_parabolic_3d.jl * Update NEWS.md * Update NEWS.md * Update src/solvers/dgsem_p4est/dg_3d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_3d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_3d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_3d_parabolic.jl --------- Co-authored-by: Daniel_Doehring Co-authored-by: Daniel Doehring Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> Co-authored-by: Jesse Chan --- NEWS.md | 5 + .../elixir_navierstokes_blast_wave_amr.jl | 113 ++++++ ...ir_navierstokes_taylor_green_vortex_amr.jl | 106 ++++++ src/callbacks_step/amr_dg2d.jl | 4 +- src/equations/laplace_diffusion_3d.jl | 1 + src/solvers/dgsem_p4est/dg_3d_parabolic.jl | 347 +++++++++++++++++- test/test_parabolic_3d.jl | 67 ++++ 7 files changed, 637 insertions(+), 6 deletions(-) create mode 100644 examples/p4est_3d_dgsem/elixir_navierstokes_blast_wave_amr.jl create mode 100644 examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex_amr.jl diff --git a/NEWS.md b/NEWS.md index abd9fd27882..e7bdd14eab2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,11 @@ 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.6 lifecycle + +#### Added +- AMR for hyperbolic-parabolic equations on 3D `P4estMesh` + ## Changes when updating to v0.6 from v0.5.x #### Added diff --git a/examples/p4est_3d_dgsem/elixir_navierstokes_blast_wave_amr.jl b/examples/p4est_3d_dgsem/elixir_navierstokes_blast_wave_amr.jl new file mode 100644 index 00000000000..5df89fbcdf2 --- /dev/null +++ b/examples/p4est_3d_dgsem/elixir_navierstokes_blast_wave_amr.jl @@ -0,0 +1,113 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Navier-Stokes equations + +# TODO: parabolic; unify names of these accessor functions +prandtl_number() = 0.72 +mu() = 6.25e-4 # equivalent to Re = 1600 + +equations = CompressibleEulerEquations3D(1.4) +equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu = mu(), + Prandtl = prandtl_number()) + +function initial_condition_3d_blast_wave(x, t, equations::CompressibleEulerEquations3D) + rho_c = 1.0 + p_c = 1.0 + u_c = 0.0 + + rho_o = 0.125 + p_o = 0.1 + u_o = 0.0 + + rc = 0.5 + r = sqrt(x[1]^2 + x[2]^2 + x[3]^2) + if r < rc + rho = rho_c + v1 = u_c + v2 = u_c + v3 = u_c + p = p_c + else + rho = rho_o + v1 = u_o + v2 = u_o + v3 = u_o + p = p_o + end + + return prim2cons(SVector(rho, v1, v2, v3, p), equations) +end +initial_condition = initial_condition_3d_blast_wave + +surface_flux = flux_lax_friedrichs +volume_flux = flux_ranocha +polydeg = 3 +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) + +coordinates_min = (-1.0, -1.0, -1.0) .* pi +coordinates_max = (1.0, 1.0, 1.0) .* pi + +trees_per_dimension = (4, 4, 4) + +mesh = P4estMesh(trees_per_dimension, polydeg = 3, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + periodicity = (true, true, true), initial_refinement_level = 1) + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.8) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) +save_solution = SaveSolutionCallback(interval = analysis_interval, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +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 = 3, max_threshold = 0.1) +amr_callback = AMRCallback(semi, amr_controller, + interval = 10, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + amr_callback, + save_solution) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) +summary_callback() # print the timer summary diff --git a/examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex_amr.jl b/examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex_amr.jl new file mode 100644 index 00000000000..c15227a1c29 --- /dev/null +++ b/examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex_amr.jl @@ -0,0 +1,106 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Navier-Stokes equations + +# TODO: parabolic; unify names of these accessor functions +prandtl_number() = 0.72 +mu() = 6.25e-4 # equivalent to Re = 1600 + +equations = CompressibleEulerEquations3D(1.4) +equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu = mu(), + Prandtl = prandtl_number()) + +""" + initial_condition_taylor_green_vortex(x, t, equations::CompressibleEulerEquations3D) + +The classical Taylor-Green vortex. +""" +function initial_condition_taylor_green_vortex(x, t, + equations::CompressibleEulerEquations3D) + A = 1.0 # magnitude of speed + Ms = 0.1 # maximum Mach number + + rho = 1.0 + v1 = A * sin(x[1]) * cos(x[2]) * cos(x[3]) + v2 = -A * cos(x[1]) * sin(x[2]) * cos(x[3]) + v3 = 0.0 + p = (A / Ms)^2 * rho / equations.gamma # scaling to get Ms + p = p + + 1.0 / 16.0 * A^2 * rho * + (cos(2 * x[1]) * cos(2 * x[3]) + 2 * cos(2 * x[2]) + 2 * cos(2 * x[1]) + + cos(2 * x[2]) * cos(2 * x[3])) + + return prim2cons(SVector(rho, v1, v2, v3, p), equations) +end +initial_condition = initial_condition_taylor_green_vortex + +@inline function vel_mag(u, equations::CompressibleEulerEquations3D) + rho, rho_v1, rho_v2, rho_v3, _ = u + return sqrt(rho_v1^2 + rho_v2^2 + rho_v3^2) / rho +end + +volume_flux = flux_ranocha +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = (-1.0, -1.0, -1.0) .* pi +coordinates_max = (1.0, 1.0, 1.0) .* pi + +trees_per_dimension = (2, 2, 2) + +mesh = P4estMesh(trees_per_dimension, polydeg = 3, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + periodicity = (true, true, true), initial_refinement_level = 0) + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.5) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 50 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_integrals = (energy_kinetic, + energy_internal, + enstrophy)) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +amr_indicator = IndicatorLöhner(semi, variable = vel_mag) + +amr_controller = ControllerThreeLevel(semi, amr_indicator, + base_level = 0, + med_level = 1, med_threshold = 0.1, + max_level = 3, max_threshold = 0.2) + +amr_callback = AMRCallback(semi, amr_controller, + interval = 5, + adapt_initial_condition = false, + adapt_initial_condition_only_refine = false) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + amr_callback, + save_solution) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol, + ode_default_options()..., callback = callbacks) +summary_callback() # print the timer summary diff --git a/src/callbacks_step/amr_dg2d.jl b/src/callbacks_step/amr_dg2d.jl index 969f9c564f3..98e531295b7 100644 --- a/src/callbacks_step/amr_dg2d.jl +++ b/src/callbacks_step/amr_dg2d.jl @@ -137,7 +137,7 @@ function refine!(u_ode::AbstractVector, adaptor, mesh::Union{TreeMesh{2}, P4estM end function refine!(u_ode::AbstractVector, adaptor, - mesh::Union{TreeMesh{2}, P4estMesh{2}, TreeMesh{3}}, + mesh::Union{TreeMesh{2}, P4estMesh{2}, TreeMesh{3}, P4estMesh{3}}, equations, dg::DGSEM, cache, cache_parabolic, elements_to_refine) # Call `refine!` for the hyperbolic part, which does the heavy lifting of @@ -299,7 +299,7 @@ function coarsen!(u_ode::AbstractVector, adaptor, end function coarsen!(u_ode::AbstractVector, adaptor, - mesh::Union{TreeMesh{2}, P4estMesh{2}, TreeMesh{3}}, + mesh::Union{TreeMesh{2}, P4estMesh{2}, TreeMesh{3}, P4estMesh{3}}, equations, dg::DGSEM, cache, cache_parabolic, elements_to_remove) # Call `coarsen!` for the hyperbolic part, which does the heavy lifting of diff --git a/src/equations/laplace_diffusion_3d.jl b/src/equations/laplace_diffusion_3d.jl index 457e742430b..3988ce7144b 100644 --- a/src/equations/laplace_diffusion_3d.jl +++ b/src/equations/laplace_diffusion_3d.jl @@ -18,6 +18,7 @@ function varnames(variable_mapping, equations_parabolic::LaplaceDiffusion3D) varnames(variable_mapping, equations_parabolic.equations_hyperbolic) end +# no orientation specified since the flux is vector-valued function flux(u, gradients, orientation::Integer, equations_parabolic::LaplaceDiffusion3D) dudx, dudy, dudz = gradients if orientation == 1 diff --git a/src/solvers/dgsem_p4est/dg_3d_parabolic.jl b/src/solvers/dgsem_p4est/dg_3d_parabolic.jl index b06cdd42127..0bb97c7af02 100644 --- a/src/solvers/dgsem_p4est/dg_3d_parabolic.jl +++ b/src/solvers/dgsem_p4est/dg_3d_parabolic.jl @@ -102,8 +102,20 @@ function rhs_parabolic!(du, u, t, mesh::P4estMesh{3}, dg.surface_integral, dg) end - # TODO: parabolic; extend to mortars - @assert nmortars(dg, cache) == 0 + # Prolong solution to mortars (specialized for AbstractEquationsParabolic) + # !!! NOTE: we reuse the hyperbolic cache here since it contains "mortars" and "u_threaded" + # !!! Is this OK? + @trixi_timeit timer() "prolong2mortars" begin + prolong2mortars_divergence!(cache, flux_viscous, mesh, equations_parabolic, + dg.mortar, dg.surface_integral, dg) + end + + # Calculate mortar fluxes (specialized for AbstractEquationsParabolic) + @trixi_timeit timer() "mortar flux" begin + calc_mortar_flux_divergence!(cache_parabolic.elements.surface_flux_values, + mesh, equations_parabolic, dg.mortar, + dg.surface_integral, dg, cache) + end # Calculate surface integrals @trixi_timeit timer() "surface integral" begin @@ -230,8 +242,23 @@ function calc_gradient!(gradients, u_transformed, t, mesh, equations_parabolic, dg.surface_integral, dg) end - # TODO: parabolic; mortars - @assert nmortars(dg, cache) == 0 + # 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`. + # !!! should we have a separate mortars/u_threaded in cache_parabolic? + @trixi_timeit timer() "prolong2mortars" begin + prolong2mortars!(cache, u_transformed, mesh, equations_parabolic, + dg.mortar, dg.surface_integral, dg) + 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. + @trixi_timeit timer() "mortar flux" begin + calc_mortar_flux!(cache_parabolic.elements.surface_flux_values, + mesh, False(), # False() = no nonconservative terms + equations_parabolic, + dg.mortar, dg.surface_integral, dg, cache) + end # Calculate surface integrals @trixi_timeit timer() "surface integral" begin @@ -324,6 +351,93 @@ function calc_gradient!(gradients, u_transformed, t, return nothing 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 +# 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}, + equations::AbstractEquationsParabolic, + mortar_l2::LobattoLegendreMortarL2, + dg::DGSEM, cache, mortar, fstar, u_buffer, + fstar_tmp) + @unpack neighbor_ids, node_indices = cache.mortars + index_range = eachnode(dg) + # Copy solution small to small + small_indices = node_indices[1, mortar] + small_direction = indices2direction(small_indices) + + for position in 1:4 # Loop over small elements + element = neighbor_ids[position, mortar] + for j in eachnode(dg), i in eachnode(dg) + for v in eachvariable(equations) + surface_flux_values[v, i, j, small_direction, element] = fstar[v, i, j, + position] + end + end + end + + # Project small fluxes to large element. + multiply_dimensionwise!(u_buffer, + mortar_l2.reverse_lower, mortar_l2.reverse_lower, + view(fstar, .., 1), + fstar_tmp) + add_multiply_dimensionwise!(u_buffer, + mortar_l2.reverse_upper, mortar_l2.reverse_lower, + view(fstar, .., 2), + fstar_tmp) + add_multiply_dimensionwise!(u_buffer, + mortar_l2.reverse_lower, mortar_l2.reverse_upper, + view(fstar, .., 3), + fstar_tmp) + add_multiply_dimensionwise!(u_buffer, + mortar_l2.reverse_upper, mortar_l2.reverse_upper, + view(fstar, .., 4), + fstar_tmp) + + # The flux is calculated in the outward direction of the small elements, + # so the sign must be switched to get the flux in outward direction + # of the large element. + # The contravariant vectors of the large element (and therefore the normal + # vectors of the large element as well) are twice as large as the + # contravariant vectors of the small elements. Therefore, the flux needs + # to be scaled by a factor of 2 to obtain the flux of the large element. + # u_buffer .*= 0.5 + + # Copy interpolated flux values from buffer to large element face in the + # correct orientation. + # Note that the index of the small sides will always run forward but + # the index of the large side might need to run backwards for flipped sides. + large_element = neighbor_ids[5, mortar] + large_indices = node_indices[2, mortar] + large_direction = indices2direction(large_indices) + large_surface_indices = surface_indices(large_indices) + + i_large_start, i_large_step_i, i_large_step_j = index_to_start_step_3d(large_surface_indices[1], + index_range) + j_large_start, j_large_step_i, j_large_step_j = index_to_start_step_3d(large_surface_indices[2], + index_range) + + # Note that the indices of the small sides will always run forward but + # the large indices might need to run backwards for flipped sides. + i_large = i_large_start + j_large = j_large_start + for j in eachnode(dg) + for i in eachnode(dg) + for v in eachvariable(equations) + surface_flux_values[v, i_large, j_large, large_direction, large_element] = u_buffer[v, + i, + j] + end + i_large += i_large_step_i + j_large += j_large_step_i + end + i_large += i_large_step_j + j_large += j_large_step_j + end + + return nothing +end + # This version is used for parabolic gradient computations @inline function calc_interface_flux!(surface_flux_values, mesh::P4estMesh{3}, nonconservative_terms::False, @@ -603,6 +717,231 @@ function calc_interface_flux!(surface_flux_values, return nothing end +function prolong2mortars_divergence!(cache, flux_viscous, + mesh::Union{P4estMesh{3}, T8codeMesh{3}}, equations, + mortar_l2::LobattoLegendreMortarL2, + surface_integral, dg::DGSEM) + @unpack neighbor_ids, node_indices = cache.mortars + @unpack fstar_tmp_threaded = cache + @unpack contravariant_vectors = cache.elements + index_range = eachnode(dg) + + flux_viscous_x, flux_viscous_y, flux_viscous_z = flux_viscous + + @threaded for mortar in eachmortar(dg, cache) + # Copy solution data from the small elements using "delayed indexing" with + # a start value and a step size to get the correct face and orientation. + small_indices = node_indices[1, mortar] + direction_index = indices2direction(small_indices) + + i_small_start, i_small_step_i, i_small_step_j = index_to_start_step_3d(small_indices[1], + index_range) + j_small_start, j_small_step_i, j_small_step_j = index_to_start_step_3d(small_indices[2], + index_range) + k_small_start, k_small_step_i, k_small_step_j = index_to_start_step_3d(small_indices[3], + index_range) + + for position in 1:4 # Loop over small elements + i_small = i_small_start + j_small = j_small_start + k_small = k_small_start + element = neighbor_ids[position, mortar] + for j in eachnode(dg) + for i in eachnode(dg) + normal_direction = get_normal_direction(direction_index, + contravariant_vectors, + i_small, j_small, k_small, + element) + + for v in eachvariable(equations) + flux_viscous = SVector(flux_viscous_x[v, i_small, j_small, k_small, + element], + flux_viscous_y[v, i_small, j_small, k_small, + element], + flux_viscous_z[v, i_small, j_small, k_small, + element]) + + cache.mortars.u[1, v, position, i, j, mortar] = dot(flux_viscous, + normal_direction) + end + i_small += i_small_step_i + j_small += j_small_step_i + k_small += k_small_step_i + end + i_small += i_small_step_j + j_small += j_small_step_j + k_small += k_small_step_j + end + end + + # Buffer to copy solution values of the large element in the correct orientation + # before interpolating + u_buffer = cache.u_threaded[Threads.threadid()] + + # temporary buffer for projections + fstar_tmp = fstar_tmp_threaded[Threads.threadid()] + + # Copy solution of large element face to buffer in the + # correct orientation + large_indices = node_indices[2, mortar] + + i_large_start, i_large_step_i, i_large_step_j = index_to_start_step_3d(large_indices[1], + index_range) + j_large_start, j_large_step_i, j_large_step_j = index_to_start_step_3d(large_indices[2], + index_range) + k_large_start, k_large_step_i, k_large_step_j = index_to_start_step_3d(large_indices[3], + index_range) + + i_large = i_large_start + j_large = j_large_start + k_large = k_large_start + element = neighbor_ids[5, mortar] # Large element + for j in eachnode(dg) + for i in eachnode(dg) + normal_direction = get_normal_direction(direction_index, + contravariant_vectors, + i_large, j_large, k_large, element) + + for v in eachvariable(equations) + flux_viscous = SVector(flux_viscous_x[v, i_large, j_large, k_large, + element], + flux_viscous_y[v, i_large, j_large, k_large, + element], + 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 + # element (these normal directions are "scaled" by the surface Jacobian) + u_buffer[v, i, j] = -0.5 * dot(flux_viscous, normal_direction) + end + i_large += i_large_step_i + j_large += j_large_step_i + k_large += k_large_step_i + end + i_large += i_large_step_j + j_large += j_large_step_j + k_large += k_large_step_j + end + + # Interpolate large element face data from buffer to small face locations + multiply_dimensionwise!(view(cache.mortars.u, 2, :, 1, :, :, mortar), + mortar_l2.forward_lower, + mortar_l2.forward_lower, + u_buffer, + fstar_tmp) + multiply_dimensionwise!(view(cache.mortars.u, 2, :, 2, :, :, mortar), + mortar_l2.forward_upper, + mortar_l2.forward_lower, + u_buffer, + fstar_tmp) + multiply_dimensionwise!(view(cache.mortars.u, 2, :, 3, :, :, mortar), + mortar_l2.forward_lower, + mortar_l2.forward_upper, + u_buffer, + fstar_tmp) + multiply_dimensionwise!(view(cache.mortars.u, 2, :, 4, :, :, mortar), + mortar_l2.forward_upper, + mortar_l2.forward_upper, + u_buffer, + fstar_tmp) + end + + return nothing +end + +# 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, + mortar_l2::LobattoLegendreMortarL2, + surface_integral, dg::DG, cache) + @unpack neighbor_ids, node_indices = cache.mortars + @unpack contravariant_vectors = cache.elements + @unpack fstar_threaded, fstar_tmp_threaded = cache + index_range = eachnode(dg) + + @threaded for mortar in eachmortar(dg, cache) + # Choose thread-specific pre-allocated container + fstar = fstar_threaded[Threads.threadid()] + fstar_tmp = fstar_tmp_threaded[Threads.threadid()] + + # Get index information on the small elements + small_indices = node_indices[1, mortar] + small_direction = indices2direction(small_indices) + + i_small_start, i_small_step_i, i_small_step_j = index_to_start_step_3d(small_indices[1], + index_range) + j_small_start, j_small_step_i, j_small_step_j = index_to_start_step_3d(small_indices[2], + index_range) + k_small_start, k_small_step_i, k_small_step_j = index_to_start_step_3d(small_indices[3], + index_range) + + for position in 1:4 # Loop over small elements + i_small = i_small_start + j_small = j_small_start + k_small = k_small_start + element = neighbor_ids[position, mortar] + for j in eachnode(dg) + for i in eachnode(dg) + for v in eachvariable(equations) + viscous_flux_normal_ll = cache.mortars.u[1, v, position, i, j, + mortar] + viscous_flux_normal_rr = cache.mortars.u[2, v, position, i, j, + mortar] + + # TODO: parabolic; only BR1 at the moment + fstar[v, i, j, position] = 0.5 * (viscous_flux_normal_ll + + viscous_flux_normal_rr) + end + + i_small += i_small_step_i + j_small += j_small_step_i + k_small += k_small_step_i + end + i_small += i_small_step_j + j_small += j_small_step_j + k_small += k_small_step_j + end + end + + # Buffer to interpolate flux values of the large element to before + # copying in the correct orientation + u_buffer = cache.u_threaded[Threads.threadid()] + + # this reuses the hyperbolic version of `mortar_fluxes_to_elements!` + mortar_fluxes_to_elements!(surface_flux_values, + mesh, equations, mortar_l2, dg, cache, + mortar, fstar, u_buffer, fstar_tmp) + end + + return nothing +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 +# hyperbolic terms with conserved terms only, i.e., no nonconservative terms. +@inline function calc_mortar_flux!(fstar, + mesh::P4estMesh{3}, + nonconservative_terms::False, + equations::AbstractEquationsParabolic, + surface_integral, dg::DG, cache, + mortar_index, position_index, normal_direction, + i_node_index, j_node_index) + @unpack u = cache.mortars + @unpack surface_flux = surface_integral + + u_ll, u_rr = get_surface_node_vars(u, equations, dg, position_index, i_node_index, + j_node_index, mortar_index) + + # TODO: parabolic; only BR1 at the moment + flux_ = 0.5 * (u_ll + u_rr) + # Copy flux to buffer + set_node_vars!(fstar, flux_, equations, dg, i_node_index, j_node_index, position_index) +end + # TODO: parabolic, finish implementing `calc_boundary_flux_gradients!` and `calc_boundary_flux_divergence!` function prolong2boundaries!(cache_parabolic, flux_viscous, mesh::P4estMesh{3}, diff --git a/test/test_parabolic_3d.jl b/test/test_parabolic_3d.jl index d6c720cf0d9..6fbfb8259d4 100644 --- a/test/test_parabolic_3d.jl +++ b/test/test_parabolic_3d.jl @@ -429,6 +429,14 @@ end "elixir_advection_diffusion_amr.jl"), l2=[0.000355780485397024], linf=[0.0010810770271614256]) + # 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 "TreeMesh3D: elixir_advection_diffusion_nonperiodic.jl" begin @@ -436,6 +444,65 @@ end "elixir_advection_diffusion_nonperiodic.jl"), l2=[0.0009808996243280868], linf=[0.01732621559135459]) + # 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 "P4estMesh3D: elixir_navierstokes_taylor_green_vortex_amr.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_3d_dgsem", + "elixir_navierstokes_taylor_green_vortex_amr.jl"), + initial_refinement_level=0, tspan=(0.0, 0.5), + l2=[ + 0.0016588740573444188, + 0.03437058632045721, + 0.03437058632045671, + 0.041038898400430075, + 0.30978593009044153, + ], + linf=[ + 0.004173569912012121, + 0.09168674832979556, + 0.09168674832975021, + 0.12129218723807476, + 0.8433893297612087, + ]) + # 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 "P4estMesh3D: elixir_navierstokes_blast_wave_amr.jl" begin + @test_trixi_include(joinpath(examples_dir(), "p4est_3d_dgsem", + "elixir_navierstokes_blast_wave_amr.jl"), + tspan=(0.0, 0.01), + l2=[ + 0.009472104410520866, 0.0017883742549557149, + 0.0017883742549557147, 0.0017883742549557196, + 0.024388540048562748, + ], + linf=[ + 0.6782397526873181, 0.17663702154066238, + 0.17663702154066266, 0.17663702154066238, 1.7327849844825238, + ]) + # 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 From dc8e9272d4e2f4b8df7fc4e72e12a786666fde47 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Sun, 24 Dec 2023 13:12:13 +0100 Subject: [PATCH 212/263] reset the timer also on non-root MPI processes (#1787) Co-authored-by: Michael Schlottke-Lakemper --- src/callbacks_step/summary.jl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/callbacks_step/summary.jl b/src/callbacks_step/summary.jl index 566f2c03418..21c7fc780a5 100644 --- a/src/callbacks_step/summary.jl +++ b/src/callbacks_step/summary.jl @@ -152,7 +152,13 @@ function initialize_summary_callback(cb::DiscreteCallback, u, t, integrator; Polyester.reset_threads!() end - mpi_isroot() || return nothing + # The summary callback should only print information on the root process. + # However, all other MPI processes should also reset the timer so that + # it can be used to diagnose performance. + if !mpi_isroot() + reset_timer!(timer()) + return nothing + end print_startup_message() From a633f9c30b89bca886278a716cafd98c6046becd Mon Sep 17 00:00:00 2001 From: Benedict <135045760+bgeihe@users.noreply.github.com> Date: Sat, 30 Dec 2023 15:49:50 +0100 Subject: [PATCH 213/263] Add HLLC flux for non-cartesian meshes to CompressibleEulerEquations{2,3}D (#1790) * add HLLC flux for non-cartesian meshes * add tests for HLLC flux * Add 2D test with HLLC * Update test_p4est_3d.jl * Update test_p4est_2d.jl * Update test_p4est_3d.jl * Update src/equations/compressible_euler_3d.jl Co-authored-by: Hendrik Ranocha * Update src/equations/compressible_euler_2d.jl Co-authored-by: Hendrik Ranocha * Update compressible_euler_2d.jl * Update compressible_euler_3d.jl * Update test_p4est_2d.jl * Update test_p4est_3d.jl * Update compressible_euler_2d.jl * Update compressible_euler_2d.jl --------- Co-authored-by: Daniel Doehring Co-authored-by: Hendrik Ranocha --- NEWS.md | 1 + src/equations/compressible_euler_2d.jl | 102 +++++++++++++++++++-- src/equations/compressible_euler_3d.jl | 119 +++++++++++++++++++++++-- test/test_p4est_2d.jl | 26 ++++++ test/test_p4est_3d.jl | 28 ++++++ test/test_unit.jl | 46 +++++++++- 6 files changed, 305 insertions(+), 17 deletions(-) diff --git a/NEWS.md b/NEWS.md index e7bdd14eab2..cf695912ed7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,6 +8,7 @@ for human readability. #### Added - AMR for hyperbolic-parabolic equations on 3D `P4estMesh` +- `flux_hllc` on non-cartesian meshes for `CompressibleEulerEquations{2,3}D` ## Changes when updating to v0.6 from v0.5.x diff --git a/src/equations/compressible_euler_2d.jl b/src/equations/compressible_euler_2d.jl index a992f99eaf4..b0fd5c53f45 100644 --- a/src/equations/compressible_euler_2d.jl +++ b/src/equations/compressible_euler_2d.jl @@ -1150,7 +1150,7 @@ end end """ - flux_hllc(u_ll, u_rr, orientation, equations::CompressibleEulerEquations2D) + flux_hllc(u_ll, u_rr, orientation_or_normal_direction, equations::CompressibleEulerEquations2D) Computes the HLLC flux (HLL with Contact) for compressible Euler equations developed by E.F. Toro [Lecture slides](http://www.prague-sum.com/download/2012/Toro_2-HLLC-RiemannSolver.pdf) @@ -1185,18 +1185,18 @@ function flux_hllc(u_ll, u_rr, orientation::Integer, if orientation == 1 # x-direction vel_L = v1_ll vel_R = v1_rr - ekin_roe = (sqrt_rho_ll * v2_ll + sqrt_rho_rr * v2_rr)^2 elseif orientation == 2 # y-direction vel_L = v2_ll vel_R = v2_rr - ekin_roe = (sqrt_rho_ll * v1_ll + sqrt_rho_rr * v1_rr)^2 end vel_roe = (sqrt_rho_ll * vel_L + sqrt_rho_rr * vel_R) / sum_sqrt_rho - ekin_roe = 0.5 * (vel_roe^2 + ekin_roe / sum_sqrt_rho^2) + v1_roe = sqrt_rho_ll * v1_ll + sqrt_rho_rr * v1_rr + v2_roe = sqrt_rho_ll * v2_ll + sqrt_rho_rr * v2_rr + vel_roe_mag = (v1_roe^2 + v2_roe^2) / sum_sqrt_rho^2 H_ll = (rho_e_ll + p_ll) / rho_ll H_rr = (rho_e_rr + p_rr) / rho_rr H_roe = (sqrt_rho_ll * H_ll + sqrt_rho_rr * H_rr) / sum_sqrt_rho - c_roe = sqrt((equations.gamma - 1) * (H_roe - ekin_roe)) + c_roe = sqrt((equations.gamma - 1) * (H_roe - 0.5 * vel_roe_mag)) Ssl = min(vel_L - c_ll, vel_roe - c_roe) Ssr = max(vel_R + c_rr, vel_roe + c_roe) sMu_L = Ssl - vel_L @@ -1252,6 +1252,98 @@ function flux_hllc(u_ll, u_rr, orientation::Integer, return SVector(f1, f2, f3, f4) end +function flux_hllc(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleEulerEquations2D) + # Calculate primitive variables and speed of sound + rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations) + + v_dot_n_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] + v_dot_n_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] + + norm_ = norm(normal_direction) + norm_sq = norm_ * norm_ + inv_norm_sq = inv(norm_sq) + + c_ll = sqrt(equations.gamma * p_ll / rho_ll) * norm_ + c_rr = sqrt(equations.gamma * p_rr / rho_rr) * norm_ + + # Obtain left and right fluxes + f_ll = flux(u_ll, normal_direction, equations) + f_rr = flux(u_rr, normal_direction, equations) + + # Compute Roe averages + sqrt_rho_ll = sqrt(rho_ll) + sqrt_rho_rr = sqrt(rho_rr) + sum_sqrt_rho = sqrt_rho_ll + sqrt_rho_rr + + v1_roe = (sqrt_rho_ll * v1_ll + sqrt_rho_rr * v1_rr) / sum_sqrt_rho + v2_roe = (sqrt_rho_ll * v2_ll + sqrt_rho_rr * v2_rr) / sum_sqrt_rho + vel_roe = v1_roe * normal_direction[1] + v2_roe * normal_direction[2] + vel_roe_mag = v1_roe^2 + v2_roe^2 + + e_ll = u_ll[4] / rho_ll + e_rr = u_rr[4] / rho_rr + + H_ll = (u_ll[4] + p_ll) / rho_ll + H_rr = (u_rr[4] + p_rr) / rho_rr + + H_roe = (sqrt_rho_ll * H_ll + sqrt_rho_rr * H_rr) / sum_sqrt_rho + c_roe = sqrt((equations.gamma - 1) * (H_roe - 0.5 * vel_roe_mag)) * norm_ + + Ssl = min(v_dot_n_ll - c_ll, vel_roe - c_roe) + Ssr = max(v_dot_n_rr + c_rr, vel_roe + c_roe) + sMu_L = Ssl - v_dot_n_ll + sMu_R = Ssr - v_dot_n_rr + + if Ssl >= 0.0 + f1 = f_ll[1] + f2 = f_ll[2] + f3 = f_ll[3] + f4 = f_ll[4] + elseif Ssr <= 0.0 + f1 = f_rr[1] + f2 = f_rr[2] + f3 = f_rr[3] + f4 = f_rr[4] + else + SStar = (rho_ll * v_dot_n_ll * sMu_L - rho_rr * v_dot_n_rr * sMu_R + + (p_rr - p_ll) * norm_sq) / (rho_ll * sMu_L - rho_rr * sMu_R) + if Ssl <= 0.0 <= SStar + densStar = rho_ll * sMu_L / (Ssl - SStar) + enerStar = e_ll + + (SStar - v_dot_n_ll) * + (SStar * inv_norm_sq + p_ll / (rho_ll * sMu_L)) + UStar1 = densStar + UStar2 = densStar * + (v1_ll + (SStar - v_dot_n_ll) * normal_direction[1] * inv_norm_sq) + UStar3 = densStar * + (v2_ll + (SStar - v_dot_n_ll) * normal_direction[2] * inv_norm_sq) + UStar4 = densStar * enerStar + f1 = f_ll[1] + Ssl * (UStar1 - u_ll[1]) + f2 = f_ll[2] + Ssl * (UStar2 - u_ll[2]) + f3 = f_ll[3] + Ssl * (UStar3 - u_ll[3]) + f4 = f_ll[4] + Ssl * (UStar4 - u_ll[4]) + else + densStar = rho_rr * sMu_R / (Ssr - SStar) + enerStar = e_rr + + (SStar - v_dot_n_rr) * + (SStar * inv_norm_sq + p_rr / (rho_rr * sMu_R)) + UStar1 = densStar + UStar2 = densStar * + (v1_rr + (SStar - v_dot_n_rr) * normal_direction[1] * inv_norm_sq) + UStar3 = densStar * + (v2_rr + (SStar - v_dot_n_rr) * normal_direction[2] * inv_norm_sq) + UStar4 = densStar * enerStar + f1 = f_rr[1] + Ssr * (UStar1 - u_rr[1]) + f2 = f_rr[2] + Ssr * (UStar2 - u_rr[2]) + f3 = f_rr[3] + Ssr * (UStar3 - u_rr[3]) + f4 = f_rr[4] + Ssr * (UStar4 - u_rr[4]) + end + end + return SVector(f1, f2, f3, f4) +end + """ min_max_speed_einfeldt(u_ll, u_rr, orientation, equations::CompressibleEulerEquations2D) diff --git a/src/equations/compressible_euler_3d.jl b/src/equations/compressible_euler_3d.jl index fc56f58025b..82c4a7efa32 100644 --- a/src/equations/compressible_euler_3d.jl +++ b/src/equations/compressible_euler_3d.jl @@ -1192,7 +1192,7 @@ end end """ - flux_hllc(u_ll, u_rr, orientation, equations::CompressibleEulerEquations3D) + flux_hllc(u_ll, u_rr, orientation_or_normal_direction, equations::CompressibleEulerEquations3D) Computes the HLLC flux (HLL with Contact) for compressible Euler equations developed by E.F. Toro [Lecture slides](http://www.prague-sum.com/download/2012/Toro_2-HLLC-RiemannSolver.pdf) @@ -1231,25 +1231,22 @@ function flux_hllc(u_ll, u_rr, orientation::Integer, if orientation == 1 # x-direction vel_L = v1_ll vel_R = v1_rr - ekin_roe = (sqrt_rho_ll * v2_ll + sqrt_rho_rr * v2_rr)^2 + - (sqrt_rho_ll * v3_ll + sqrt_rho_rr * v3_rr)^2 elseif orientation == 2 # y-direction vel_L = v2_ll vel_R = v2_rr - ekin_roe = (sqrt_rho_ll * v1_ll + sqrt_rho_rr * v1_rr)^2 + - (sqrt_rho_ll * v3_ll + sqrt_rho_rr * v3_rr)^2 else # z-direction vel_L = v3_ll vel_R = v3_rr - ekin_roe = (sqrt_rho_ll * v1_ll + sqrt_rho_rr * v1_rr)^2 + - (sqrt_rho_ll * v2_ll + sqrt_rho_rr * v2_rr)^2 end vel_roe = (sqrt_rho_ll * vel_L + sqrt_rho_rr * vel_R) / sum_sqrt_rho - ekin_roe = 0.5 * (vel_roe^2 + ekin_roe / sum_sqrt_rho^2) + v1_roe = sqrt_rho_ll * v1_ll + sqrt_rho_rr * v1_rr + v2_roe = sqrt_rho_ll * v2_ll + sqrt_rho_rr * v2_rr + v3_roe = sqrt_rho_ll * v3_ll + sqrt_rho_rr * v3_rr + vel_roe_mag = (v1_roe^2 + v2_roe^2 + v3_roe^2) / sum_sqrt_rho^2 H_ll = (rho_e_ll + p_ll) / rho_ll H_rr = (rho_e_rr + p_rr) / rho_rr H_roe = (sqrt_rho_ll * H_ll + sqrt_rho_rr * H_rr) / sum_sqrt_rho - c_roe = sqrt((equations.gamma - 1) * (H_roe - ekin_roe)) + c_roe = sqrt((equations.gamma - 1) * (H_roe - 0.5 * vel_roe_mag)) Ssl = min(vel_L - c_ll, vel_roe - c_roe) Ssr = max(vel_R + c_rr, vel_roe + c_roe) sMu_L = Ssl - vel_L @@ -1321,6 +1318,110 @@ function flux_hllc(u_ll, u_rr, orientation::Integer, return SVector(f1, f2, f3, f4, f5) end +function flux_hllc(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleEulerEquations3D) + # Calculate primitive variables and speed of sound + rho_ll, v1_ll, v2_ll, v3_ll, p_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr, v3_rr, p_rr = cons2prim(u_rr, equations) + + v_dot_n_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] + + v3_ll * normal_direction[3] + v_dot_n_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] + + v3_rr * normal_direction[3] + + norm_ = norm(normal_direction) + norm_sq = norm_ * norm_ + inv_norm_sq = inv(norm_sq) + + c_ll = sqrt(equations.gamma * p_ll / rho_ll) * norm_ + c_rr = sqrt(equations.gamma * p_rr / rho_rr) * norm_ + + # Obtain left and right fluxes + f_ll = flux(u_ll, normal_direction, equations) + f_rr = flux(u_rr, normal_direction, equations) + + # Compute Roe averages + sqrt_rho_ll = sqrt(rho_ll) + sqrt_rho_rr = sqrt(rho_rr) + sum_sqrt_rho = sqrt_rho_ll + sqrt_rho_rr + + v1_roe = (sqrt_rho_ll * v1_ll + sqrt_rho_rr * v1_rr) / sum_sqrt_rho + v2_roe = (sqrt_rho_ll * v2_ll + sqrt_rho_rr * v2_rr) / sum_sqrt_rho + v3_roe = (sqrt_rho_ll * v3_ll + sqrt_rho_rr * v3_rr) / sum_sqrt_rho + vel_roe = v1_roe * normal_direction[1] + v2_roe * normal_direction[2] + + v3_roe * normal_direction[3] + vel_roe_mag = v1_roe^2 + v2_roe^2 + v3_roe^2 + + e_ll = u_ll[5] / rho_ll + e_rr = u_rr[5] / rho_rr + + H_ll = (u_ll[5] + p_ll) / rho_ll + H_rr = (u_rr[5] + p_rr) / rho_rr + + H_roe = (sqrt_rho_ll * H_ll + sqrt_rho_rr * H_rr) / sum_sqrt_rho + c_roe = sqrt((equations.gamma - 1) * (H_roe - 0.5 * vel_roe_mag)) * norm_ + + Ssl = min(v_dot_n_ll - c_ll, vel_roe - c_roe) + Ssr = max(v_dot_n_rr + c_rr, vel_roe + c_roe) + sMu_L = Ssl - v_dot_n_ll + sMu_R = Ssr - v_dot_n_rr + + if Ssl >= 0.0 + f1 = f_ll[1] + f2 = f_ll[2] + f3 = f_ll[3] + f4 = f_ll[4] + f5 = f_ll[5] + elseif Ssr <= 0.0 + f1 = f_rr[1] + f2 = f_rr[2] + f3 = f_rr[3] + f4 = f_rr[4] + f5 = f_rr[5] + else + SStar = (rho_ll * v_dot_n_ll * sMu_L - rho_rr * v_dot_n_rr * sMu_R + + (p_rr - p_ll) * norm_sq) / (rho_ll * sMu_L - rho_rr * sMu_R) + if Ssl <= 0.0 <= SStar + densStar = rho_ll * sMu_L / (Ssl - SStar) + enerStar = e_ll + + (SStar - v_dot_n_ll) * + (SStar * inv_norm_sq + p_ll / (rho_ll * sMu_L)) + UStar1 = densStar + UStar2 = densStar * + (v1_ll + (SStar - v_dot_n_ll) * normal_direction[1] * inv_norm_sq) + UStar3 = densStar * + (v2_ll + (SStar - v_dot_n_ll) * normal_direction[2] * inv_norm_sq) + UStar4 = densStar * + (v3_ll + (SStar - v_dot_n_ll) * normal_direction[3] * inv_norm_sq) + UStar5 = densStar * enerStar + f1 = f_ll[1] + Ssl * (UStar1 - u_ll[1]) + f2 = f_ll[2] + Ssl * (UStar2 - u_ll[2]) + f3 = f_ll[3] + Ssl * (UStar3 - u_ll[3]) + f4 = f_ll[4] + Ssl * (UStar4 - u_ll[4]) + f5 = f_ll[5] + Ssl * (UStar5 - u_ll[5]) + else + densStar = rho_rr * sMu_R / (Ssr - SStar) + enerStar = e_rr + + (SStar - v_dot_n_rr) * + (SStar * inv_norm_sq + p_rr / (rho_rr * sMu_R)) + UStar1 = densStar + UStar2 = densStar * + (v1_rr + (SStar - v_dot_n_rr) * normal_direction[1] * inv_norm_sq) + UStar3 = densStar * + (v2_rr + (SStar - v_dot_n_rr) * normal_direction[2] * inv_norm_sq) + UStar4 = densStar * + (v3_rr + (SStar - v_dot_n_rr) * normal_direction[3] * inv_norm_sq) + UStar5 = densStar * enerStar + f1 = f_rr[1] + Ssr * (UStar1 - u_rr[1]) + f2 = f_rr[2] + Ssr * (UStar2 - u_rr[2]) + f3 = f_rr[3] + Ssr * (UStar3 - u_rr[3]) + f4 = f_rr[4] + Ssr * (UStar4 - u_rr[4]) + f5 = f_rr[5] + Ssr * (UStar5 - u_rr[5]) + end + end + return SVector(f1, f2, f3, f4, f5) +end + """ min_max_speed_einfeldt(u_ll, u_rr, orientation, equations::CompressibleEulerEquations3D) diff --git a/test/test_p4est_2d.jl b/test/test_p4est_2d.jl index db34aecc168..cebc2917d52 100644 --- a/test/test_p4est_2d.jl +++ b/test/test_p4est_2d.jl @@ -203,6 +203,32 @@ end end end +@trixi_testset "elixir_euler_sedov.jl with HLLC Flux" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov.jl"), + l2=[ + 0.4229948321239887, + 0.2559038337457483, + 0.2559038337457484, + 1.2990046683564136, + ], + linf=[ + 1.4989357969730492, + 1.325456585141623, + 1.3254565851416251, + 6.331283015053501, + ], + surface_flux=flux_hllc, + tspan=(0.0, 0.3)) + # 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 (HLLE)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov.jl"), l2=[ diff --git a/test/test_p4est_3d.jl b/test/test_p4est_3d.jl index f2467f30204..4a2d2112c99 100644 --- a/test/test_p4est_3d.jl +++ b/test/test_p4est_3d.jl @@ -234,6 +234,34 @@ end 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=[ + 8.444868392439035e-16, + 4.889826056731442e-15, + 2.2921260987087585e-15, + 4.268460455702414e-15, + 1.1356712092620279e-14, + ], + linf=[ + 7.749356711883593e-14, + 4.513472928735496e-13, + 2.9790059308254513e-13, + 1.057154364048074e-12, + 1.6271428648906294e-12, + ], + tspan=(0.0, 0.1), + surface_flux=flux_hllc) + # 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_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), l2=[ diff --git a/test/test_unit.jl b/test/test_unit.jl index b3ed29d38e3..817b4cd550d 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1076,6 +1076,46 @@ end end end +@timed_testset "Consistency check for HLLC flux: CEE" begin + # Set up equations and dummy conservative variables state + equations = CompressibleEulerEquations2D(1.4) + u = SVector(1.1, -0.5, 2.34, 5.5) + + orientations = [1, 2] + for orientation in orientations + @test flux_hllc(u, u, orientation, equations) ≈ flux(u, orientation, equations) + end + + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + + for normal_direction in normal_directions + @test flux_hllc(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) + end + + equations = CompressibleEulerEquations3D(1.4) + u = SVector(1.1, -0.5, 2.34, 2.4, 5.5) + + orientations = [1, 2, 3] + for orientation in orientations + @test flux_hllc(u, u, orientation, equations) ≈ flux(u, orientation, equations) + end + + normal_directions = [SVector(1.0, 0.0, 0.0), + SVector(0.0, 1.0, 0.0), + SVector(0.0, 0.0, 1.0), + SVector(0.5, -0.5, 0.2), + SVector(-1.2, 0.3, 1.4)] + + for normal_direction in normal_directions + @test flux_hllc(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) + end +end + @timed_testset "Consistency check for Godunov flux" begin # Set up equations and dummy conservative variables state # Burgers' Equation @@ -1280,7 +1320,7 @@ end u_values = [SVector(1.0, 0.5, -0.7, 1.0), SVector(1.5, -0.2, 0.1, 5.0)] fluxes = [flux_central, flux_ranocha, flux_shima_etal, flux_kennedy_gruber, - flux_hll, FluxHLL(min_max_speed_davis), flux_hlle] + flux_hll, FluxHLL(min_max_speed_davis), flux_hlle, flux_hllc] for f_std in fluxes f_rot = FluxRotated(f_std) @@ -1303,8 +1343,8 @@ end u_values = [SVector(1.0, 0.5, -0.7, 0.1, 1.0), SVector(1.5, -0.2, 0.1, 0.2, 5.0)] fluxes = [flux_central, flux_ranocha, flux_shima_etal, flux_kennedy_gruber, - FluxLMARS(340), - flux_hll, FluxHLL(min_max_speed_davis), flux_hlle] + FluxLMARS(340), flux_hll, FluxHLL(min_max_speed_davis), flux_hlle, flux_hllc, + ] for f_std in fluxes f_rot = FluxRotated(f_std) From ad384c6530b2539175167350b6e56a9365d3521c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jan 2024 07:24:11 +0100 Subject: [PATCH 214/263] Bump crate-ci/typos from 1.16.23 to 1.16.26 (#1793) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.16.23 to 1.16.26. - [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.16.23...v1.16.26) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-type: direct:production update-type: version-update:semver-patch ... 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 366cb1183a0..a780e975155 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.16.23 + uses: crate-ci/typos@v1.16.26 From 1b6a4a941f72f0e9b95437cbfa2d5ba0ca4550bf Mon Sep 17 00:00:00 2001 From: Jesse Chan <1156048+jlchan@users.noreply.github.com> Date: Thu, 4 Jan 2024 13:00:05 -0600 Subject: [PATCH 215/263] Extend `CompressibleEulerQuasi1D` and `ShallowWaterQuasi1D` to `DGMulti` (#1797) * adding DGMulti versions of fluxes * remove incorrect factor of 2 * add example and test * formatting * add comment * revert removing factor of 2 * formatting * add SWE quasi-1D test d * enable quasi1D SWE for DGMulti * add docstrings * formatting * Update src/equations/compressible_euler_quasi_1d.jl Co-authored-by: Hendrik Ranocha * adding comments explaining why `normal_direction` is included in 1D * Apply suggestions from code review Co-authored-by: Daniel Doehring --------- Co-authored-by: Hendrik Ranocha Co-authored-by: Daniel Doehring --- examples/dgmulti_1d/elixir_euler_quasi_1d.jl | 49 +++++++++++++++++ .../elixir_shallow_water_quasi_1d.jl | 49 +++++++++++++++++ src/equations/compressible_euler_1d.jl | 5 ++ src/equations/compressible_euler_quasi_1d.jl | 38 ++++++++++++- src/equations/shallow_water_quasi_1d.jl | 35 ++++++++++++ test/test_dgmulti_1d.jl | 53 +++++++++++++++++++ 6 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 examples/dgmulti_1d/elixir_euler_quasi_1d.jl create mode 100644 examples/dgmulti_1d/elixir_shallow_water_quasi_1d.jl diff --git a/examples/dgmulti_1d/elixir_euler_quasi_1d.jl b/examples/dgmulti_1d/elixir_euler_quasi_1d.jl new file mode 100644 index 00000000000..19269fa925b --- /dev/null +++ b/examples/dgmulti_1d/elixir_euler_quasi_1d.jl @@ -0,0 +1,49 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# Semidiscretization of the quasi 1d compressible Euler equations +# See Chan et al. https://doi.org/10.48550/arXiv.2307.12089 for details + +equations = CompressibleEulerEquationsQuasi1D(1.4) + +initial_condition = initial_condition_convergence_test + +surface_flux = (flux_chan_etal, flux_nonconservative_chan_etal) +volume_flux = surface_flux +dg = DGMulti(polydeg = 4, element_type = Line(), approximation_type = SBP(), + surface_integral = SurfaceIntegralWeakForm(surface_flux), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +cells_per_dimension = (8,) +mesh = DGMultiMesh(dg, cells_per_dimension, + coordinates_min = (-1.0,), coordinates_max = (1.0,), periodicity = true) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg; + source_terms = source_terms_convergence_test) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 2.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) +stepsize_callback = StepsizeCallback(cfl = 0.8) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_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/dgmulti_1d/elixir_shallow_water_quasi_1d.jl b/examples/dgmulti_1d/elixir_shallow_water_quasi_1d.jl new file mode 100644 index 00000000000..85741f9dbd3 --- /dev/null +++ b/examples/dgmulti_1d/elixir_shallow_water_quasi_1d.jl @@ -0,0 +1,49 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# Semidiscretization of the quasi 1d shallow water equations +# See Chan et al. https://doi.org/10.48550/arXiv.2307.12089 for details + +equations = ShallowWaterEquationsQuasi1D(gravity_constant = 9.81) + +initial_condition = initial_condition_convergence_test + +volume_flux = (flux_chan_etal, flux_nonconservative_chan_etal) +surface_flux = (FluxPlusDissipation(flux_chan_etal, DissipationLocalLaxFriedrichs()), + flux_nonconservative_chan_etal) + +dg = DGMulti(polydeg = 4, element_type = Line(), approximation_type = SBP(), + surface_integral = SurfaceIntegralWeakForm(surface_flux), + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +cells_per_dimension = (8,) +mesh = DGMultiMesh(dg, cells_per_dimension, + coordinates_min = (0.0,), coordinates_max = (sqrt(2),), + periodicity = true) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, dg; + source_terms = source_terms_convergence_test) + +############################################################################### +# 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, uEltype = real(dg)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback) + +############################################################################### +# run the simulation + +sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-8, reltol = 1.0e-8, + ode_default_options()..., callback = callbacks) +summary_callback() # print the timer summary diff --git a/src/equations/compressible_euler_1d.jl b/src/equations/compressible_euler_1d.jl index 05c38ce791d..a50c896cd1c 100644 --- a/src/equations/compressible_euler_1d.jl +++ b/src/equations/compressible_euler_1d.jl @@ -408,6 +408,11 @@ See also return SVector(f1, f2, f3) end +# While `normal_direction` isn't strictly necessary in 1D, certain solvers assume that +# the normal component is incorporated into the numerical flux. +# +# See `flux(u, normal_direction::AbstractVector, equations::AbstractEquations{1})` for a +# similar implementation. @inline function flux_ranocha(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleEulerEquations1D) return normal_direction[1] * flux_ranocha(u_ll, u_rr, 1, equations) diff --git a/src/equations/compressible_euler_quasi_1d.jl b/src/equations/compressible_euler_quasi_1d.jl index 0a543277ee4..6844bf9bee5 100644 --- a/src/equations/compressible_euler_quasi_1d.jl +++ b/src/equations/compressible_euler_quasi_1d.jl @@ -161,8 +161,12 @@ end end """ -@inline function flux_nonconservative_chan_etal(u_ll, u_rr, orientation::Integer, - equations::CompressibleEulerEquationsQuasi1D) + flux_nonconservative_chan_etal(u_ll, u_rr, orientation::Integer, + equations::CompressibleEulerEquationsQuasi1D) + flux_nonconservative_chan_etal(u_ll, u_rr, normal_direction, + equations::CompressibleEulerEquationsQuasi1D) + flux_nonconservative_chan_etal(u_ll, u_rr, normal_ll, normal_rr, + equations::CompressibleEulerEquationsQuasi1D) Non-symmetric two-point volume flux discretizing the nonconservative (source) term that contains the gradient of the pressure [`CompressibleEulerEquationsQuasi1D`](@ref) @@ -190,6 +194,26 @@ Further details are available in the paper: return SVector(z, a_ll * p_avg, z, z) end +# While `normal_direction` isn't strictly necessary in 1D, certain solvers assume that +# the normal component is incorporated into the numerical flux. +# +# See `flux(u, normal_direction::AbstractVector, equations::AbstractEquations{1})` for a +# similar implementation. +@inline function flux_nonconservative_chan_etal(u_ll, u_rr, + normal_direction::AbstractVector, + equations::CompressibleEulerEquationsQuasi1D) + return normal_direction[1] * + flux_nonconservative_chan_etal(u_ll, u_rr, 1, equations) +end + +@inline function flux_nonconservative_chan_etal(u_ll, u_rr, + normal_ll::AbstractVector, + normal_rr::AbstractVector, + equations::CompressibleEulerEquationsQuasi1D) + # normal_ll should be equal to normal_rr in 1D + return flux_nonconservative_chan_etal(u_ll, u_rr, normal_ll, equations) +end + """ @inline function flux_chan_etal(u_ll, u_rr, orientation::Integer, equations::CompressibleEulerEquationsQuasi1D) @@ -230,6 +254,16 @@ Further details are available in the paper: return SVector(f1, f2, f3, zero(eltype(u_ll))) end +# While `normal_direction` isn't strictly necessary in 1D, certain solvers assume that +# the normal component is incorporated into the numerical flux. +# +# See `flux(u, normal_direction::AbstractVector, equations::AbstractEquations{1})` for a +# similar implementation. +@inline function flux_chan_etal(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleEulerEquationsQuasi1D) + return normal_direction[1] * flux_chan_etal(u_ll, u_rr, 1, equations) +end + # Calculate estimates for maximum wave speed for local Lax-Friedrichs-type dissipation as the # maximum velocity magnitude plus the maximum speed of sound @inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, diff --git a/src/equations/shallow_water_quasi_1d.jl b/src/equations/shallow_water_quasi_1d.jl index d3935f0e75f..d52fbab841d 100644 --- a/src/equations/shallow_water_quasi_1d.jl +++ b/src/equations/shallow_water_quasi_1d.jl @@ -152,6 +152,11 @@ end """ flux_nonconservative_chan_etal(u_ll, u_rr, orientation::Integer, equations::ShallowWaterEquationsQuasi1D) + flux_nonconservative_chan_etal(u_ll, u_rr, normal_direction::AbstractVector, + equations::ShallowWaterEquationsQuasi1D) + flux_nonconservative_chan_etal(u_ll, u_rr, + normal_ll::AbstractVector, normal_rr::AbstractVector, + equations::ShallowWaterEquationsQuasi1D) Non-symmetric two-point volume flux discretizing the nonconservative (source) term that contains the gradient of the bottom topography [`ShallowWaterEquationsQuasi1D`](@ref) @@ -176,6 +181,26 @@ Further details are available in the paper: return SVector(z, equations.gravity * a_ll * h_ll * (h_rr + b_rr), z, z) end +# While `normal_direction` isn't strictly necessary in 1D, certain solvers assume that +# the normal component is incorporated into the numerical flux. +# +# See `flux(u, normal_direction::AbstractVector, equations::AbstractEquations{1})` for a +# similar implementation. +@inline function flux_nonconservative_chan_etal(u_ll, u_rr, + normal_direction::AbstractVector, + equations::ShallowWaterEquationsQuasi1D) + return normal_direction[1] * + flux_nonconservative_chan_etal(u_ll, u_rr, 1, equations) +end + +@inline function flux_nonconservative_chan_etal(u_ll, u_rr, + normal_ll::AbstractVector, + normal_rr::AbstractVector, + equations::ShallowWaterEquationsQuasi1D) + # normal_ll should be equal to normal_rr + return flux_nonconservative_chan_etal(u_ll, u_rr, normal_ll, equations) +end + """ flux_chan_etal(u_ll, u_rr, orientation, equations::ShallowWaterEquationsQuasi1D) @@ -204,6 +229,16 @@ Further details are available in the paper: return SVector(f1, f2, zero(eltype(u_ll)), zero(eltype(u_ll))) end +# While `normal_direction` isn't strictly necessary in 1D, certain solvers assume that +# the normal component is incorporated into the numerical flux. +# +# See `flux(u, normal_direction::AbstractVector, equations::AbstractEquations{1})` for a +# similar implementation. +@inline function flux_chan_etal(u_ll, u_rr, normal_direction::AbstractVector, + equations::ShallowWaterEquationsQuasi1D) + return normal_direction[1] * flux_chan_etal(u_ll, u_rr, 1, equations) +end + # Calculate maximum wave speed for local Lax-Friedrichs-type dissipation as the # maximum velocity magnitude plus the maximum speed of sound @inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, diff --git a/test/test_dgmulti_1d.jl b/test/test_dgmulti_1d.jl index 79ad64075b4..0363086341f 100644 --- a/test/test_dgmulti_1d.jl +++ b/test/test_dgmulti_1d.jl @@ -162,6 +162,59 @@ end @test minimum(dg.basis.rst[1]) ≈ -1 @test maximum(dg.basis.rst[1])≈1 atol=0.35 end + +# test non-conservative systems +@trixi_testset "elixir_shallow_water_quasi_1d.jl (SBP) " begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallow_water_quasi_1d.jl"), + cells_per_dimension=(8,), + approximation_type=SBP(), + l2=[ + 3.03001101100507e-6, + 1.692177335948727e-5, + 3.002634351734614e-16, + 1.1636653574178203e-15, + ], + linf=[ + 1.2043401988570679e-5, + 5.346847010329059e-5, + 9.43689570931383e-16, + 2.220446049250313e-15, + ]) + # 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_quasi_1d.jl (SBP) " begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_quasi_1d.jl"), + cells_per_dimension=(8,), + approximation_type=SBP(), + l2=[ + 1.633271343738687e-5, + 9.575385661756332e-6, + 1.2700331443128421e-5, + 0.0, + ], + linf=[ + 7.304984704381567e-5, + 5.2365944135601694e-5, + 6.469559594934893e-5, + 0.0, + ]) + # 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 a1e3e73c634563e3cde3f11d8ad3a66e6a611281 Mon Sep 17 00:00:00 2001 From: Patrick Ersing <114223904+patrickersing@users.noreply.github.com> Date: Tue, 9 Jan 2024 07:03:30 +0100 Subject: [PATCH 216/263] Fix boundary_condition_slip_wall for SWE (#1798) * fix_wall_bc * add test * apply formatter * adjust some comments * update elixir and test; add topography --- .../tree_2d_dgsem/elixir_shallowwater_wall.jl | 82 +++++++++++++++++++ src/equations/shallow_water_2d.jl | 8 +- test/test_tree_2d_shallowwater.jl | 25 ++++++ 3 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 examples/tree_2d_dgsem/elixir_shallowwater_wall.jl diff --git a/examples/tree_2d_dgsem/elixir_shallowwater_wall.jl b/examples/tree_2d_dgsem/elixir_shallowwater_wall.jl new file mode 100644 index 00000000000..b8dbad50680 --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_shallowwater_wall.jl @@ -0,0 +1,82 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# Semidiscretization of the shallow water equations + +equations = ShallowWaterEquations2D(gravity_constant = 9.81, H0 = 3.25) + +# An initial condition with a bottom topography and a perturbation in the waterheight to test +# boundary_condition_slip_wall +function initial_condition_perturbation(x, t, equations::ShallowWaterEquations2D) + # Set the background values + H = equations.H0 + v1 = 0.0 + v2 = 0.0 + + # Bottom topography + b = 1.5 * exp(-0.5 * ((x[1])^2 + (x[2])^2)) + # Waterheight perturbation + H = H + 0.5 * exp(-10.0 * ((x[1])^2 + (x[2])^2)) + + return prim2cons(SVector(H, v1, v2, b), equations) +end + +initial_condition = initial_condition_perturbation + +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) +solver = DGSEM(polydeg = 3, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +############################################################################### +# Get the TreeMesh and setup a non-periodic mesh + +coordinates_min = (-1.0, -1.0) +coordinates_max = (1.0, 1.0) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 4, + n_cells_max = 10_000, + periodicity = false) + +# create the semi discretization object +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_condition) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.25) +ode = semidiscretize(semi, tspan) + +############################################################################### +# 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.0) + +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, + 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/src/equations/shallow_water_2d.jl b/src/equations/shallow_water_2d.jl index e75c92a27d0..6728d7d5553 100644 --- a/src/equations/shallow_water_2d.jl +++ b/src/equations/shallow_water_2d.jl @@ -236,8 +236,12 @@ Should be used together with [`TreeMesh`](@ref). u_boundary = SVector(u_inner[1], u_inner[2], -u_inner[3], u_inner[4]) end - # compute and return the flux using `boundary_condition_slip_wall` routine above - flux = surface_flux_function(u_inner, u_boundary, orientation, equations) + # Calculate boundary flux + if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary + flux = surface_flux_function(u_inner, u_boundary, orientation, equations) + else # u_boundary is "left" of boundary, u_inner is "right" of boundary + flux = surface_flux_function(u_boundary, u_inner, orientation, equations) + end return flux end diff --git a/test/test_tree_2d_shallowwater.jl b/test/test_tree_2d_shallowwater.jl index 58db7c5f35f..1f3dfbf5267 100644 --- a/test/test_tree_2d_shallowwater.jl +++ b/test/test_tree_2d_shallowwater.jl @@ -327,6 +327,31 @@ end @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 end end + +@trixi_testset "elixir_shallowwater_wall.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_wall.jl"), + l2=[ + 0.13517233723296504, + 0.20010876311162215, + 0.20010876311162223, + 2.719538414346464e-7, + ], + linf=[ + 0.5303607982988336, + 0.5080989745682338, + 0.5080989745682352, + 1.1301675764130437e-6, + ], + tspan=(0.0, 0.25)) + # 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 end # module From 7168d90aef7e07b4f0360cf805ace72532d980ae Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Tue, 9 Jan 2024 16:47:36 +0100 Subject: [PATCH 217/263] comments explaining usage of `ForwardDiff.jacobian` (#1800) --- src/semidiscretization/semidiscretization.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/semidiscretization/semidiscretization.jl b/src/semidiscretization/semidiscretization.jl index fe7858e31ee..8518cf27fd3 100644 --- a/src/semidiscretization/semidiscretization.jl +++ b/src/semidiscretization/semidiscretization.jl @@ -253,6 +253,9 @@ end function _jacobian_ad_forward(semi, t0, u0_ode, du_ode, config) new_semi = remake(semi, uEltype = eltype(config)) + # Create anonymous function passed as first argument to `ForwardDiff.jacobian` to match + # `ForwardDiff.jacobian(f!, y::AbstractArray, x::AbstractArray, + # cfg::JacobianConfig = JacobianConfig(f!, y, x), check=Val{true}())` J = ForwardDiff.jacobian(du_ode, u0_ode, config) do du_ode, u_ode Trixi.rhs!(du_ode, u_ode, new_semi, t0) end @@ -279,6 +282,9 @@ end function _jacobian_ad_forward_structarrays(semi, t0, u0_ode_plain, du_ode_plain, config) new_semi = remake(semi, uEltype = eltype(config)) + # Create anonymous function passed as first argument to `ForwardDiff.jacobian` to match + # `ForwardDiff.jacobian(f!, y::AbstractArray, x::AbstractArray, + # cfg::JacobianConfig = JacobianConfig(f!, y, x), check=Val{true}())` J = ForwardDiff.jacobian(du_ode_plain, u0_ode_plain, config) do du_ode_plain, u_ode_plain u_ode = StructArray{SVector{nvariables(semi), eltype(config)}}(ntuple(v -> view(u_ode_plain, From 994bb4b088fbd08cf59296b8c5c6b3d33b810536 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 16:48:15 +0100 Subject: [PATCH 218/263] Bump actions/upload-artifact from 3 to 4 (#1795) * Bump actions/upload-artifact from 3 to 4 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * bump download-artifact to v4 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Hendrik Ranocha --- .github/workflows/benchmark.yml | 2 +- .github/workflows/ci.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 2ea30d6fddb..6aa4809c1c2 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -45,7 +45,7 @@ jobs: run: julia --project=benchmark/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' - name: Run benchmarks run: julia --project=benchmark/ --color=yes benchmark/run_benchmarks.jl - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: my-artifact path: benchmark/results*.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cf8107736e9..2c0ea798b49 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -153,7 +153,7 @@ jobs: - shell: bash run: | cp ./lcov.info ./lcov-${{ matrix.trixi_test }}-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.arch }}.info - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: lcov-${{ matrix.trixi_test }}-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.arch }} path: ./lcov-${{ matrix.trixi_test }}-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.arch }}.info @@ -176,7 +176,7 @@ jobs: # At first, we check out the repository and download all artifacts # (and list files for debugging). - uses: actions/checkout@v4 - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 - run: ls -R # Next, we merge the individual coverage files and upload # the combined results to Coveralls. @@ -199,7 +199,7 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} path-to-lcov: ./lcov.info # Upload merged coverage data as artifact for debugging - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: lcov path: ./lcov.info From 08ae0f200f0e89ceae1a260ffed38539ad507c55 Mon Sep 17 00:00:00 2001 From: Benjamin Bolm <74359358+bennibolm@users.noreply.github.com> Date: Thu, 11 Jan 2024 16:34:15 +0100 Subject: [PATCH 219/263] Fix link to download notebook badge in documentation (#1801) * Add random change * Fix download links * Update link and rename variables * Update introduction file with new links --- docs/literate/make.jl | 10 +++++----- docs/literate/src/files/index.jl | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/literate/make.jl b/docs/literate/make.jl index a04d8a0b333..84e4fbdced6 100644 --- a/docs/literate/make.jl +++ b/docs/literate/make.jl @@ -10,17 +10,17 @@ function create_files(title, file, repo_src, pages_dir, notebooks_dir; folder="" end binder_logo = "https://mybinder.org/badge_logo.svg" - nbviewer_logo = "https://raw.githubusercontent.com/jupyter/design/master/logos/Badges/nbviewer_badge.svg" - download_logo = "https://camo.githubusercontent.com/aea75103f6d9f690a19cb0e17c06f984ab0f472d9e6fe4eadaa0cc438ba88ada/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646f776e6c6f61642d6e6f7465626f6f6b2d627269676874677265656e" + nbviewer_logo = "https://img.shields.io/badge/render-nbviewer-f37726" + raw_notebook_logo = "https://img.shields.io/badge/raw-notebook-4cc61e" notebook_path = "tutorials/notebooks/$notebook_filename" binder_url = "https://mybinder.org/v2/gh/trixi-framework/Trixi.jl/tutorial_notebooks?filepath=$notebook_path" nbviewer_url = "https://nbviewer.jupyter.org/github/trixi-framework/Trixi.jl/blob/tutorial_notebooks/$notebook_path" - download_url = "https://raw.githubusercontent.com/trixi-framework/Trixi.jl/tutorial_notebooks/$notebook_path" + raw_notebook_url = "https://raw.githubusercontent.com/trixi-framework/Trixi.jl/tutorial_notebooks/$notebook_path" binder_badge = "# [![]($binder_logo)]($binder_url)" nbviewer_badge = "# [![]($nbviewer_logo)]($nbviewer_url)" - download_badge = "# [![]($download_logo)]($download_url)" + raw_notebook_badge = "# [![]($raw_notebook_logo)]($raw_notebook_url)" # Generate notebook file function preprocess_notebook(content) @@ -32,7 +32,7 @@ function create_files(title, file, repo_src, pages_dir, notebooks_dir; folder="" # Generate markdown file function preprocess_docs(content) - return string("# # [$title](@id $(splitext(file)[1]))\n $binder_badge\n $nbviewer_badge\n $download_badge\n\n", content) + return string("# # [$title](@id $(splitext(file)[1]))\n $binder_badge\n $nbviewer_badge\n $raw_notebook_badge\n\n", content) end Literate.markdown(joinpath(repo_src, folder, file), joinpath(pages_dir, folder); preprocess=preprocess_docs,) end diff --git a/docs/literate/src/files/index.jl b/docs/literate/src/files/index.jl index d42695611f6..e259d25fb2f 100644 --- a/docs/literate/src/files/index.jl +++ b/docs/literate/src/files/index.jl @@ -5,9 +5,9 @@ # Right now, you are using the classic documentation. The corresponding interactive notebooks can # be opened in [Binder](https://mybinder.org/) and viewed in [nbviewer](https://nbviewer.jupyter.org/) -# via the icons ![](https://mybinder.org/badge_logo.svg) and ![](https://raw.githubusercontent.com/jupyter/design/master/logos/Badges/nbviewer_badge.svg) +# via the icons ![](https://mybinder.org/badge_logo.svg) and ![](https://img.shields.io/badge/render-nbviewer-f37726) # in the respective tutorial. -# You can download the raw notebooks from GitHub via ![](https://camo.githubusercontent.com/aea75103f6d9f690a19cb0e17c06f984ab0f472d9e6fe4eadaa0cc438ba88ada/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646f776e6c6f61642d6e6f7465626f6f6b2d627269676874677265656e). +# You can also open the raw notebook files via ![](https://img.shields.io/badge/raw-notebook-4cc61e). # **Note:** To improve responsiveness via caching, the notebooks are updated only once a week. They are only # available for the latest stable release of Trixi.jl at the time of caching. From eb0f1252df72faa82f1a39cadeb26352c03e5d01 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Thu, 11 Jan 2024 17:01:46 +0100 Subject: [PATCH 220/263] set version to v0.6.6 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index faf9f82d335..b840b636c05 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.6.6-pre" +version = "0.6.6" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 148e5b0559f51cc2e16fc67d03ae51aa5df3334e Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Thu, 11 Jan 2024 17:02:10 +0100 Subject: [PATCH 221/263] set development version to v0.6.7-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index b840b636c05..f246bdfdab4 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.6.6" +version = "0.6.7-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 2463b38d60fd2bd463cd46252a29c08e706f1a5e Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 12 Jan 2024 11:16:21 +0100 Subject: [PATCH 222/263] use julia-actions/cache also for Documenter (#1802) --- .github/workflows/Documenter.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/Documenter.yml b/.github/workflows/Documenter.yml index 129c41a3b5c..8f8d674ffa9 100644 --- a/.github/workflows/Documenter.yml +++ b/.github/workflows/Documenter.yml @@ -38,6 +38,7 @@ jobs: with: version: '1.9' show-versioninfo: true + - uses: julia-actions/cache@v1 - uses: julia-actions/julia-buildpkg@v1 env: PYTHON: "" From 4bb74f8505220b8f42ef15622097f96276584c13 Mon Sep 17 00:00:00 2001 From: Benedict <135045760+bgeihe@users.noreply.github.com> Date: Fri, 12 Jan 2024 13:30:31 +0100 Subject: [PATCH 223/263] Add dry air warm bubble test case (#1779) * add LMARS flux in 2D * add dry air warm bubble test case * get formatting right * remove += * add DOI * cleaned up variables (naming, scope) * reduce run time of test case * Revert "reduce run time of test case" This reverts commit b6e527bd63767e0a124a274d57e986df9a88b766. * change output folder * change energy term in LMARS solver to use p_l/r * add lmars consistency checks * switched to kennedy gruber flux * add euler warm bubble elixir to tests * adapt errors due to change flux * add warm bubble test with TreeMesh * fix unit test * fix format * adapt polynomial degree and CFL number * fix format * adapt tests due to changed parameters * Update src/equations/compressible_euler_2d.jl Co-authored-by: Andrew Winters * Update src/equations/compressible_euler_2d.jl Co-authored-by: Andrew Winters * Update src/equations/compressible_euler_3d.jl Co-authored-by: Andrew Winters * Update src/equations/compressible_euler_3d.jl Co-authored-by: Andrew Winters * correct test result * use callable struct to hold parameters Thanks sloede! * Update examples/structured_2d_dgsem/elixir_euler_warm_bubble.jl Co-authored-by: Hendrik Ranocha * Update examples/tree_2d_dgsem/elixir_euler_warm_bubble.jl Co-authored-by: Hendrik Ranocha * year of Wicker paper, comment on tspan [no ci] * add comment on speed of sound --------- Co-authored-by: Andrew Winters Co-authored-by: Hendrik Ranocha --- .../elixir_euler_warm_bubble.jl | 146 +++++++++++++++++ .../tree_2d_dgsem/elixir_euler_warm_bubble.jl | 150 ++++++++++++++++++ src/equations/compressible_euler_2d.jl | 92 +++++++++++ src/equations/compressible_euler_3d.jl | 25 +-- test/test_p4est_3d.jl | 40 ++--- test/test_structured_2d.jl | 27 ++++ test/test_tree_2d_euler.jl | 26 +++ test/test_unit.jl | 46 +++++- 8 files changed, 519 insertions(+), 33 deletions(-) create mode 100644 examples/structured_2d_dgsem/elixir_euler_warm_bubble.jl create mode 100644 examples/tree_2d_dgsem/elixir_euler_warm_bubble.jl diff --git a/examples/structured_2d_dgsem/elixir_euler_warm_bubble.jl b/examples/structured_2d_dgsem/elixir_euler_warm_bubble.jl new file mode 100644 index 00000000000..05c09d57530 --- /dev/null +++ b/examples/structured_2d_dgsem/elixir_euler_warm_bubble.jl @@ -0,0 +1,146 @@ +using OrdinaryDiffEq +using Trixi + +# Warm bubble test case from +# - Wicker, L. J., and Skamarock, W. C. (1998) +# A time-splitting scheme for the elastic equations incorporating +# second-order Runge–Kutta time differencing +# [DOI: 10.1175/1520-0493(1998)126%3C1992:ATSSFT%3E2.0.CO;2](https://doi.org/10.1175/1520-0493(1998)126%3C1992:ATSSFT%3E2.0.CO;2) +# See also +# - Bryan and Fritsch (2002) +# A Benchmark Simulation for Moist Nonhydrostatic Numerical Models +# [DOI: 10.1175/1520-0493(2002)130<2917:ABSFMN>2.0.CO;2](https://doi.org/10.1175/1520-0493(2002)130<2917:ABSFMN>2.0.CO;2) +# - Carpenter, Droegemeier, Woodward, Hane (1990) +# Application of the Piecewise Parabolic Method (PPM) to +# Meteorological Modeling +# [DOI: 10.1175/1520-0493(1990)118<0586:AOTPPM>2.0.CO;2](https://doi.org/10.1175/1520-0493(1990)118<0586:AOTPPM>2.0.CO;2) +struct WarmBubbleSetup + # Physical constants + g::Float64 # gravity of earth + c_p::Float64 # heat capacity for constant pressure (dry air) + c_v::Float64 # heat capacity for constant volume (dry air) + gamma::Float64 # heat capacity ratio (dry air) + + function WarmBubbleSetup(; g = 9.81, c_p = 1004.0, c_v = 717.0, gamma = c_p / c_v) + new(g, c_p, c_v, gamma) + end +end + +# Initial condition +function (setup::WarmBubbleSetup)(x, t, equations::CompressibleEulerEquations2D) + @unpack g, c_p, c_v = setup + + # center of perturbation + center_x = 10000.0 + center_z = 2000.0 + # radius of perturbation + radius = 2000.0 + # distance of current x to center of perturbation + r = sqrt((x[1] - center_x)^2 + (x[2] - center_z)^2) + + # perturbation in potential temperature + potential_temperature_ref = 300.0 + potential_temperature_perturbation = 0.0 + if r <= radius + potential_temperature_perturbation = 2 * cospi(0.5 * r / radius)^2 + end + potential_temperature = potential_temperature_ref + potential_temperature_perturbation + + # Exner pressure, solves hydrostatic equation for x[2] + exner = 1 - g / (c_p * potential_temperature) * x[2] + + # pressure + p_0 = 100_000.0 # reference pressure + R = c_p - c_v # gas constant (dry air) + p = p_0 * exner^(c_p / R) + + # temperature + T = potential_temperature * exner + + # density + rho = p / (R * T) + + v1 = 20.0 + v2 = 0.0 + E = c_v * T + 0.5 * (v1^2 + v2^2) + return SVector(rho, rho * v1, rho * v2, rho * E) +end + +# Source terms +@inline function (setup::WarmBubbleSetup)(u, x, t, equations::CompressibleEulerEquations2D) + @unpack g = setup + rho, _, rho_v2, _ = u + return SVector(zero(eltype(u)), zero(eltype(u)), -g * rho, -g * rho_v2) +end + +############################################################################### +# semidiscretization of the compressible Euler equations +warm_bubble_setup = WarmBubbleSetup() + +equations = CompressibleEulerEquations2D(warm_bubble_setup.gamma) + +boundary_conditions = (x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_slip_wall, + y_pos = boundary_condition_slip_wall) + +polydeg = 3 +basis = LobattoLegendreBasis(polydeg) + +# This is a good estimate for the speed of sound in this example. +# Other values between 300 and 400 should work as well. +surface_flux = FluxLMARS(340.0) + +volume_flux = flux_kennedy_gruber +volume_integral = VolumeIntegralFluxDifferencing(volume_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + +coordinates_min = (0.0, 0.0) +coordinates_max = (20_000.0, 10_000.0) + +cells_per_dimension = (64, 32) +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) + +semi = SemidiscretizationHyperbolic(mesh, equations, warm_bubble_setup, solver, + source_terms = warm_bubble_setup, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 1000.0) # 1000 seconds final time + +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 + +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:entropy_conservation_error,)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = analysis_interval, + save_initial_solution = true, + save_final_solution = true, + output_directory = "out", + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) + +############################################################################### +# run the simulation +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + maxiters = 1.0e7, + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); + +summary_callback() diff --git a/examples/tree_2d_dgsem/elixir_euler_warm_bubble.jl b/examples/tree_2d_dgsem/elixir_euler_warm_bubble.jl new file mode 100644 index 00000000000..f2e14273ae7 --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_euler_warm_bubble.jl @@ -0,0 +1,150 @@ +using OrdinaryDiffEq +using Trixi + +# Warm bubble test case from +# - Wicker, L. J., and Skamarock, W. C. (1998) +# A time-splitting scheme for the elastic equations incorporating +# second-order Runge–Kutta time differencing +# [DOI: 10.1175/1520-0493(1998)126%3C1992:ATSSFT%3E2.0.CO;2](https://doi.org/10.1175/1520-0493(1998)126%3C1992:ATSSFT%3E2.0.CO;2) +# See also +# - Bryan and Fritsch (2002) +# A Benchmark Simulation for Moist Nonhydrostatic Numerical Models +# [DOI: 10.1175/1520-0493(2002)130<2917:ABSFMN>2.0.CO;2](https://doi.org/10.1175/1520-0493(2002)130<2917:ABSFMN>2.0.CO;2) +# - Carpenter, Droegemeier, Woodward, Hane (1990) +# Application of the Piecewise Parabolic Method (PPM) to +# Meteorological Modeling +# [DOI: 10.1175/1520-0493(1990)118<0586:AOTPPM>2.0.CO;2](https://doi.org/10.1175/1520-0493(1990)118<0586:AOTPPM>2.0.CO;2) +struct WarmBubbleSetup + # Physical constants + g::Float64 # gravity of earth + c_p::Float64 # heat capacity for constant pressure (dry air) + c_v::Float64 # heat capacity for constant volume (dry air) + gamma::Float64 # heat capacity ratio (dry air) + + function WarmBubbleSetup(; g = 9.81, c_p = 1004.0, c_v = 717.0, gamma = c_p / c_v) + new(g, c_p, c_v, gamma) + end +end + +# Initial condition +function (setup::WarmBubbleSetup)(x, t, equations::CompressibleEulerEquations2D) + @unpack g, c_p, c_v = setup + + # center of perturbation + center_x = 10000.0 + center_z = 2000.0 + # radius of perturbation + radius = 2000.0 + # distance of current x to center of perturbation + r = sqrt((x[1] - center_x)^2 + (x[2] - center_z)^2) + + # perturbation in potential temperature + potential_temperature_ref = 300.0 + potential_temperature_perturbation = 0.0 + if r <= radius + potential_temperature_perturbation = 2 * cospi(0.5 * r / radius)^2 + end + potential_temperature = potential_temperature_ref + potential_temperature_perturbation + + # Exner pressure, solves hydrostatic equation for x[2] + exner = 1 - g / (c_p * potential_temperature) * x[2] + + # pressure + p_0 = 100_000.0 # reference pressure + R = c_p - c_v # gas constant (dry air) + p = p_0 * exner^(c_p / R) + + # temperature + T = potential_temperature * exner + + # density + rho = p / (R * T) + + v1 = 20.0 + v2 = 0.0 + E = c_v * T + 0.5 * (v1^2 + v2^2) + return SVector(rho, rho * v1, rho * v2, rho * E) +end + +# Source terms +@inline function (setup::WarmBubbleSetup)(u, x, t, equations::CompressibleEulerEquations2D) + @unpack g = setup + rho, _, rho_v2, _ = u + return SVector(zero(eltype(u)), zero(eltype(u)), -g * rho, -g * rho_v2) +end + +############################################################################### +# semidiscretization of the compressible Euler equations +warm_bubble_setup = WarmBubbleSetup() + +equations = CompressibleEulerEquations2D(warm_bubble_setup.gamma) + +boundary_conditions = (x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_slip_wall, + y_pos = boundary_condition_slip_wall) + +polydeg = 3 +basis = LobattoLegendreBasis(polydeg) + +# This is a good estimate for the speed of sound in this example. +# Other values between 300 and 400 should work as well. +surface_flux = FluxLMARS(340.0) + +volume_flux = flux_kennedy_gruber +volume_integral = VolumeIntegralFluxDifferencing(volume_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + +coordinates_min = (0.0, 0.0) +coordinates_max = (20_000.0, 10_000.0) + +# Same coordinates as in examples/structured_2d_dgsem/elixir_euler_warm_bubble.jl +# However TreeMesh will generate a 20_000 x 20_000 square domain instead +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 6, + n_cells_max = 10_000, + periodicity = (true, false)) + +semi = SemidiscretizationHyperbolic(mesh, equations, warm_bubble_setup, solver, + source_terms = warm_bubble_setup, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 1000.0) # 1000 seconds final time + +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 + +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:entropy_conservation_error,)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = analysis_interval, + save_initial_solution = true, + save_final_solution = true, + output_directory = "out", + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) + +############################################################################### +# run the simulation +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + maxiters = 1.0e7, + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); + +summary_callback() diff --git a/src/equations/compressible_euler_2d.jl b/src/equations/compressible_euler_2d.jl index b0fd5c53f45..3c6f759db2b 100644 --- a/src/equations/compressible_euler_2d.jl +++ b/src/equations/compressible_euler_2d.jl @@ -809,6 +809,98 @@ end return SVector(f1m, f2m, f3m, f4m) end +""" + FluxLMARS(c)(u_ll, u_rr, orientation_or_normal_direction, + equations::CompressibleEulerEquations2D) + +Low Mach number approximate Riemann solver (LMARS) for atmospheric flows using +an estimate `c` of the speed of sound. + +References: +- Xi Chen et al. (2013) + A Control-Volume Model of the Compressible Euler Equations with a Vertical + Lagrangian Coordinate + [DOI: 10.1175/MWR-D-12-00129.1](https://doi.org/10.1175/mwr-d-12-00129.1) +""" +struct FluxLMARS{SpeedOfSound} + # Estimate for the speed of sound + speed_of_sound::SpeedOfSound +end + +@inline function (flux_lmars::FluxLMARS)(u_ll, u_rr, orientation::Integer, + equations::CompressibleEulerEquations2D) + c = flux_lmars.speed_of_sound + + # Unpack left and right state + rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations) + + if orientation == 1 + v_ll = v1_ll + v_rr = v1_rr + else # orientation == 2 + v_ll = v2_ll + v_rr = v2_rr + end + + rho = 0.5 * (rho_ll + rho_rr) + p = 0.5 * (p_ll + p_rr) - 0.5 * c * rho * (v_rr - v_ll) + v = 0.5 * (v_ll + v_rr) - 1 / (2 * c * rho) * (p_rr - p_ll) + + # We treat the energy term analogous to the potential temperature term in the paper by + # Chen et al., i.e. we use p_ll and p_rr, and not p + if v >= 0 + f1, f2, f3, f4 = v * u_ll + f4 = f4 + p_ll * v + else + f1, f2, f3, f4 = v * u_rr + f4 = f4 + p_rr * v + end + + if orientation == 1 + f2 = f2 + p + else # orientation == 2 + f3 = f3 + p + end + + return SVector(f1, f2, f3, f4) +end + +@inline function (flux_lmars::FluxLMARS)(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleEulerEquations2D) + c = flux_lmars.speed_of_sound + + # Unpack left and right state + rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations) + + v_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] + v_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] + + # Note that this is the same as computing v_ll and v_rr with a normalized normal vector + # and then multiplying v by `norm_` again, but this version is slightly faster. + norm_ = norm(normal_direction) + + rho = 0.5 * (rho_ll + rho_rr) + p = 0.5 * (p_ll + p_rr) - 0.5 * c * rho * (v_rr - v_ll) / norm_ + v = 0.5 * (v_ll + v_rr) - 1 / (2 * c * rho) * (p_rr - p_ll) * norm_ + + # We treat the energy term analogous to the potential temperature term in the paper by + # Chen et al., i.e. we use p_ll and p_rr, and not p + if v >= 0 + f1, f2, f3, f4 = u_ll * v + f4 = f4 + p_ll * v + else + f1, f2, f3, f4 = u_rr * v + f4 = f4 + p_rr * v + end + + return SVector(f1, + f2 + p * normal_direction[1], + f3 + p * normal_direction[2], + f4) +end + """ splitting_vanleer_haenel(u, orientation::Integer, equations::CompressibleEulerEquations2D) diff --git a/src/equations/compressible_euler_3d.jl b/src/equations/compressible_euler_3d.jl index 82c4a7efa32..292b912f009 100644 --- a/src/equations/compressible_euler_3d.jl +++ b/src/equations/compressible_euler_3d.jl @@ -944,11 +944,6 @@ References: Lagrangian Coordinate [DOI: 10.1175/MWR-D-12-00129.1](https://doi.org/10.1175/mwr-d-12-00129.1) """ -struct FluxLMARS{SpeedOfSound} - # Estimate for the speed of sound - speed_of_sound::SpeedOfSound -end - @inline function (flux_lmars::FluxLMARS)(u_ll, u_rr, orientation::Integer, equations::CompressibleEulerEquations3D) c = flux_lmars.speed_of_sound @@ -972,10 +967,14 @@ end p = 0.5 * (p_ll + p_rr) - 0.5 * c * rho * (v_rr - v_ll) v = 0.5 * (v_ll + v_rr) - 1 / (2 * c * rho) * (p_rr - p_ll) + # We treat the energy term analogous to the potential temperature term in the paper by + # Chen et al., i.e. we use p_ll and p_rr, and not p if v >= 0 f1, f2, f3, f4, f5 = v * u_ll + f5 = f5 + p_ll * v else f1, f2, f3, f4, f5 = v * u_rr + f5 = f5 + p_rr * v end if orientation == 1 @@ -985,7 +984,6 @@ end else # orientation == 3 f4 += p end - f5 += p * v return SVector(f1, f2, f3, f4, f5) end @@ -1011,18 +1009,21 @@ end p = 0.5 * (p_ll + p_rr) - 0.5 * c * rho * (v_rr - v_ll) / norm_ v = 0.5 * (v_ll + v_rr) - 1 / (2 * c * rho) * (p_rr - p_ll) * norm_ + # We treat the energy term analogous to the potential temperature term in the paper by + # Chen et al., i.e. we use p_ll and p_rr, and not p if v >= 0 f1, f2, f3, f4, f5 = v * u_ll + f5 = f5 + p_ll * v else f1, f2, f3, f4, f5 = v * u_rr + f5 = f5 + p_rr * v end - f2 += p * normal_direction[1] - f3 += p * normal_direction[2] - f4 += p * normal_direction[3] - f5 += p * v - - return SVector(f1, f2, f3, f4, f5) + return SVector(f1, + f2 + p * normal_direction[1], + f3 + p * normal_direction[2], + f4 + p * normal_direction[3], + f5) end # Calculate maximum wave speed for local Lax-Friedrichs-type dissipation as the diff --git a/test/test_p4est_3d.jl b/test/test_p4est_3d.jl index 4a2d2112c99..dc5d32b5a04 100644 --- a/test/test_p4est_3d.jl +++ b/test/test_p4est_3d.jl @@ -380,18 +380,18 @@ end @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_circular_wind_nonconforming.jl"), l2=[ - 1.573832094977477e-7, - 3.863090659429634e-5, - 3.867293305754584e-5, - 3.686550296950078e-5, - 0.05508968493733932, + 1.5737711609657832e-7, + 3.8630261900166194e-5, + 3.8672287531936816e-5, + 3.6865116098660796e-5, + 0.05508620970403884, ], linf=[ - 2.2695202613887133e-6, - 0.0005314968179916946, - 0.0005314969614147458, - 0.0005130280733059617, - 0.7944959432352334, + 2.268845333053271e-6, + 0.000531462302113539, + 0.0005314624461298934, + 0.0005129931254772464, + 0.7942778058932163, ], tspan=(0.0, 2e2), coverage_override=(trees_per_cube_face = (1, 1), polydeg = 3)) # Prevent long compile time in CI @@ -409,18 +409,18 @@ end @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_baroclinic_instability.jl"), l2=[ - 6.725065410642336e-7, - 0.00021710117340245454, - 0.000438679759422352, - 0.00020836356588024185, - 0.07602006689579247, + 6.725093801700048e-7, + 0.00021710076010951073, + 0.0004386796338203878, + 0.00020836270267103122, + 0.07601887903440395, ], linf=[ - 1.9101671995258585e-5, - 0.029803626911022396, - 0.04847630924006063, - 0.022001371349740104, - 4.847761006938526, + 1.9107530539574924e-5, + 0.02980358831035801, + 0.048476331898047564, + 0.02200137344113612, + 4.848310144356219, ], tspan=(0.0, 1e2), # Decrease tolerance of adaptive time stepping to get similar results across different systems diff --git a/test/test_structured_2d.jl b/test/test_structured_2d.jl index 1addc29e3e6..e5d45ebcc07 100644 --- a/test/test_structured_2d.jl +++ b/test/test_structured_2d.jl @@ -611,6 +611,33 @@ end end end +@trixi_testset "elixir_euler_warm_bubble.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_warm_bubble.jl"), + l2=[ + 0.00019387402388722496, + 0.03086514388623955, + 0.04541427917165, + 43.892826583444716, + ], + linf=[ + 0.0015942305974430138, + 0.17449778969139373, + 0.3729704262394843, + 307.6706958565337, + ], + cells_per_dimension=(32, 16), + tspan=(0.0, 10.0)) + # 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)) < 100 + end +end + @trixi_testset "elixir_eulerpolytropic_convergence.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulerpolytropic_convergence.jl"), l2=[ diff --git a/test/test_tree_2d_euler.jl b/test/test_tree_2d_euler.jl index 65899cd5263..61b5c54b5e9 100644 --- a/test/test_tree_2d_euler.jl +++ b/test/test_tree_2d_euler.jl @@ -834,6 +834,32 @@ end end end +@trixi_testset "elixir_euler_warm_bubble.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_warm_bubble.jl"), + l2=[ + 0.0001379946769624388, + 0.02078779689715382, + 0.033237241571263176, + 31.36068872331705, + ], + linf=[ + 0.0016286690573188434, + 0.15623770697198225, + 0.3341371832270615, + 334.5373488726036, + ], + tspan=(0.0, 10.0), + initial_refinement_level=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)) < 100 + end +end + # Coverage test for all initial conditions @testset "Compressible Euler: Tests for initial conditions" begin @trixi_testset "elixir_euler_vortex.jl one step with initial_condition_constant" begin diff --git a/test/test_unit.jl b/test/test_unit.jl index 817b4cd550d..e8a8effbe29 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1287,6 +1287,49 @@ end end end +@timed_testset "Consistency check for LMARS flux" begin + equations = CompressibleEulerEquations2D(1.4) + flux_lmars = FluxLMARS(340) + + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + orientations = [1, 2] + u_values = [SVector(1.0, 0.5, -0.7, 1.0), + SVector(1.5, -0.2, 0.1, 5.0)] + + for u in u_values, orientation in orientations + @test flux_lmars(u, u, orientation, equations) ≈ + flux(u, orientation, equations) + end + + for u in u_values, normal_direction in normal_directions + @test flux_lmars(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) + end + + equations = CompressibleEulerEquations3D(1.4) + normal_directions = [SVector(1.0, 0.0, 0.0), + SVector(0.0, 1.0, 0.0), + SVector(0.0, 0.0, 1.0), + SVector(0.5, -0.5, 0.2), + SVector(-1.2, 0.3, 1.4)] + orientations = [1, 2, 3] + u_values = [SVector(1.0, 0.5, -0.7, 0.1, 1.0), + SVector(1.5, -0.2, 0.1, 0.2, 5.0)] + + for u in u_values, orientation in orientations + @test flux_lmars(u, u, orientation, equations) ≈ + flux(u, orientation, equations) + end + + for u in u_values, normal_direction in normal_directions + @test flux_lmars(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) + end +end + @testset "FluxRotated vs. direct implementation" begin @timed_testset "CompressibleEulerMulticomponentEquations2D" begin equations = CompressibleEulerMulticomponentEquations2D(gammas = (1.4, 1.4), @@ -1320,7 +1363,8 @@ end u_values = [SVector(1.0, 0.5, -0.7, 1.0), SVector(1.5, -0.2, 0.1, 5.0)] fluxes = [flux_central, flux_ranocha, flux_shima_etal, flux_kennedy_gruber, - flux_hll, FluxHLL(min_max_speed_davis), flux_hlle, flux_hllc] + FluxLMARS(340), flux_hll, FluxHLL(min_max_speed_davis), flux_hlle, flux_hllc, + ] for f_std in fluxes f_rot = FluxRotated(f_std) From 1946f9d515ed65c98f2fa36ad6e4be88e33a8237 Mon Sep 17 00:00:00 2001 From: Johannes Markert <10619309+jmark@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:45:53 +0100 Subject: [PATCH 224/263] Feature t8code: Extending to 3D (#1535) * Initial commit for the new feature using t8code as meshing backend. * Delete t8code_2d_dgsem * Added new examples and tests. Testing updates for T8code.jl. * Worked in the comments. * Fixed spelling. * Update src/auxiliary/auxiliary.jl Co-authored-by: Hendrik Ranocha * Added whitespace in Unions. * Adapted commented out code block reporting the no. of elements per level. * Added dummy save mesh support for . * Added test . * Added to method signature. * Deleted unnecessary comments. * Removed commented out tests. * Fixed Morton ordering bug in 2D at mortar interfaces. * Disabled `save_solution` callbacks and added more tests. * Added more tests. * Updated code according to the review. * Update src/auxiliary/t8code.jl Co-authored-by: Hendrik Ranocha * Update src/auxiliary/t8code.jl Co-authored-by: Hendrik Ranocha * Update src/auxiliary/t8code.jl Co-authored-by: Hendrik Ranocha * Update src/auxiliary/t8code.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/solvers/dgsem_t8code/containers_2d.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Code cleanup. * Updated to T8code@0.3.0 * Fixing minor issues. * Fixed typo. * Code cleanup. * Enabled `set_ghost` in examples. * Generalized type info in function signature. * Added namespace qualifier. * Updated comments. * Refactored code and deleted lots of it. * Removed a copy operation. * Initial commit. * Fxinig minor bugs. * Fixed minor typo. * Added first 3d example and fixed segfault. * Added many 3D examples and tests. * Backup. * Fixed merging issues. * Adding more tests. * Fixed some merging issues and formatting. * Fixed spelling. * Fixed spelling and changed assert macro. * Applied automatic formatting. * Applied automatic formatting. * Backup. * Removed superfluous outer constructor for T8codeMesh. * Added return statement for consistency. * Fixed wrong indentation by autoformatter. * Added comments. * Made sure an exception is thrown. * Changed flags for sc_init for t8code initialization. * Updated formatting. * Workaround for error about calling MPI routines after MPI has been finalized. * Upped to T8code v0.4.1. * Added mpi_finailize_hook for proper memory cleanup. * Added t8code to test_threaded.jl * Added a `save_mesh_file` call in order to satisfy code coverage. * Improved finalizer logic for T8coeMesh. * Refined code. * Restructured to do blocks. * Moved save_mesh_file call to test file. * Fixed spelling error. * Made sc_finalize optional. * Fixed spelling. * Cleaned up examples. * Updated and cleaned t8code solver codes. * Updated tests for t8code 3D code. * Fixed spelling. * Update elixir_euler_source_terms_nonconforming_unstructured_curved.jl * Update elixir_euler_source_terms_nonconforming_unstructured_curved.jl * Fixed indentation. * Update src/solvers/dgsem_structured/dg_3d.jl Co-authored-by: Hendrik Ranocha * Update src/solvers/dgsem_t8code/containers_3d.jl Co-authored-by: Andrew Winters * Update src/callbacks_step/amr_dg3d.jl Co-authored-by: Andrew Winters * Update examples/t8code_3d_dgsem/elixir_euler_ec.jl Co-authored-by: Andrew Winters * Update examples/t8code_3d_dgsem/elixir_advection_unstructured_curved.jl Co-authored-by: Andrew Winters * Update examples/t8code_3d_dgsem/elixir_advection_amr_unstructured_curved.jl Co-authored-by: Andrew Winters * Update src/solvers/dgsem_structured/dg_3d.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/callbacks_step/analysis_dg3d.jl Co-authored-by: Hendrik Ranocha * Update examples/t8code_3d_dgsem/elixir_euler_free_stream.jl Co-authored-by: Andrew Winters * Removed NDIMS from T8codeMesh construction in case of p4est/p8est connectivity input. * Aligned T8codeMesh constructur with other mesh constructors. * Update examples/t8code_3d_dgsem/elixir_euler_sedov.jl Co-authored-by: Andrew Winters * Update examples/t8code_3d_dgsem/elixir_euler_sedov.jl Co-authored-by: Andrew Winters * Cleanup up. * Added @allocated test. * Fixed formatting. * Applied formatter. * Code cleanup. * Removed unused member variable. * Apply suggestions from code review Co-authored-by: Daniel Doehring * suggestions from review * fix format (strange?) * Added comments to help interpreting the source code. * Update src/callbacks_step/amr_dg3d.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Adhered to unified mesh constructor calling scheme. * Applied formatter. * Switched to Float64 instead of Cdouble. * Update src/meshes/t8code_mesh.jl Co-authored-by: Daniel Doehring * Refactored negative volume check. * Applied formatter. * Fixed typo resp. bug. * Apply suggestions from code review Co-authored-by: Hendrik Ranocha * add missing allocation checks * Some refactoring. * Deleted msh file. * Fixed a bug. * Code cleanup. * Ignore gmsh files. * Removed adapt! from global namespace. * Added documentation. * Added @test_warn to test. * Applied formatter. * Apply suggestions from code review Co-authored-by: Hendrik Ranocha Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Turned @warn to @info. * Code cleanup and added @deprecated routines in order to avoid breaking release. * Applied formatter. * Added formatter pragmas to avoid ugly formatting. --------- Co-authored-by: Johannes Markert Co-authored-by: Hendrik Ranocha Co-authored-by: Andrew Winters Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> Co-authored-by: Daniel Doehring Co-authored-by: Benedict Geihe Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> --- .github/workflows/ci.yml | 1 + .gitignore | 1 + ...ixir_advection_amr_solution_independent.jl | 4 +- .../elixir_advection_amr_unstructured_flag.jl | 6 +- .../t8code_2d_dgsem/elixir_advection_basic.jl | 4 +- .../elixir_advection_nonconforming_flag.jl | 52 +-- .../elixir_advection_unstructured_flag.jl | 6 +- .../elixir_euler_free_stream.jl | 45 +- .../t8code_2d_dgsem/elixir_euler_sedov.jl | 4 +- .../elixir_euler_shockcapturing_ec.jl | 4 +- ...e_terms_nonconforming_unstructured_flag.jl | 45 +- .../elixir_eulergravity_convergence.jl | 4 +- .../t8code_2d_dgsem/elixir_mhd_alfven_wave.jl | 5 +- examples/t8code_2d_dgsem/elixir_mhd_rotor.jl | 6 +- .../elixir_shallowwater_source_terms.jl | 4 +- .../t8code_3d_dgsem/elixir_advection_amr.jl | 66 +++ ...lixir_advection_amr_unstructured_curved.jl | 105 +++++ .../t8code_3d_dgsem/elixir_advection_basic.jl | 59 +++ .../elixir_advection_nonconforming.jl | 85 ++++ .../elixir_advection_unstructured_curved.jl | 98 +++++ examples/t8code_3d_dgsem/elixir_euler_ec.jl | 92 +++++ .../elixir_euler_free_stream.jl | 118 ++++++ .../elixir_euler_free_stream_extruded.jl | 106 +++++ .../t8code_3d_dgsem/elixir_euler_sedov.jl | 97 +++++ ...terms_nonconforming_unstructured_curved.jl | 120 ++++++ .../elixir_euler_source_terms_nonperiodic.jl | 62 +++ src/auxiliary/t8code.jl | 101 +---- src/callbacks_step/amr_dg2d.jl | 2 +- src/callbacks_step/amr_dg3d.jl | 77 +++- src/callbacks_step/analysis_dg3d.jl | 19 +- src/callbacks_step/stepsize_dg3d.jl | 4 +- src/meshes/t8code_mesh.jl | 387 +++++++++++++++--- src/solvers/dgsem_p4est/containers_3d.jl | 5 +- src/solvers/dgsem_p4est/dg_3d.jl | 29 +- src/solvers/dgsem_structured/dg_3d.jl | 17 +- src/solvers/dgsem_t8code/containers_2d.jl | 19 + src/solvers/dgsem_t8code/containers_3d.jl | 235 +++++++++++ src/solvers/dgsem_t8code/dg.jl | 1 + src/solvers/dgsem_tree/dg_3d.jl | 30 +- src/solvers/dgsem_tree/indicators_3d.jl | 3 +- test/runtests.jl | 4 + test/test_t8code_2d.jl | 26 ++ test/test_t8code_3d.jl | 279 +++++++++++++ 43 files changed, 2102 insertions(+), 335 deletions(-) create mode 100644 examples/t8code_3d_dgsem/elixir_advection_amr.jl create mode 100644 examples/t8code_3d_dgsem/elixir_advection_amr_unstructured_curved.jl create mode 100644 examples/t8code_3d_dgsem/elixir_advection_basic.jl create mode 100644 examples/t8code_3d_dgsem/elixir_advection_nonconforming.jl create mode 100644 examples/t8code_3d_dgsem/elixir_advection_unstructured_curved.jl create mode 100644 examples/t8code_3d_dgsem/elixir_euler_ec.jl create mode 100644 examples/t8code_3d_dgsem/elixir_euler_free_stream.jl create mode 100644 examples/t8code_3d_dgsem/elixir_euler_free_stream_extruded.jl create mode 100644 examples/t8code_3d_dgsem/elixir_euler_sedov.jl create mode 100644 examples/t8code_3d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_curved.jl create mode 100644 examples/t8code_3d_dgsem/elixir_euler_source_terms_nonperiodic.jl create mode 100644 src/solvers/dgsem_t8code/containers_3d.jl create mode 100644 test/test_t8code_3d.jl diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c0ea798b49..f287cc5feb2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -70,6 +70,7 @@ jobs: - p4est_part1 - p4est_part2 - t8code_part1 + - t8code_part2 - unstructured_dgmulti - parabolic - paper_self_gravitating_gas_dynamics diff --git a/.gitignore b/.gitignore index 3132b9af38b..b4f1cf6bb47 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ *.mesh *.bson *.inp +*.msh **/Manifest.toml out*/ docs/build 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 653bab41e2d..0589e76a6a9 100644 --- a/examples/t8code_2d_dgsem/elixir_advection_amr_solution_independent.jl +++ b/examples/t8code_2d_dgsem/elixir_advection_amr_solution_independent.jl @@ -93,12 +93,10 @@ solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-5.0, -5.0) coordinates_max = (5.0, 5.0) -mapping = Trixi.coordinates2mapping(coordinates_min, coordinates_max) - trees_per_dimension = (1, 1) mesh = T8codeMesh(trees_per_dimension, polydeg = 3, - mapping = mapping, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, initial_refinement_level = 1) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) 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 adf1d009a59..f285d24fc6c 100644 --- a/examples/t8code_2d_dgsem/elixir_advection_amr_unstructured_flag.jl +++ b/examples/t8code_2d_dgsem/elixir_advection_amr_unstructured_flag.jl @@ -41,9 +41,9 @@ isfile(mesh_file) || # we can create a t8code mesh. conn = Trixi.read_inp_p4est(mesh_file, Val(2)) -mesh = T8codeMesh{2}(conn, polydeg = 3, - mapping = mapping_flag, - initial_refinement_level = 1) +mesh = T8codeMesh(conn, polydeg = 3, + mapping = mapping_flag, + initial_refinement_level = 1) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions = boundary_conditions) diff --git a/examples/t8code_2d_dgsem/elixir_advection_basic.jl b/examples/t8code_2d_dgsem/elixir_advection_basic.jl index efc51226586..26ced0970fe 100644 --- a/examples/t8code_2d_dgsem/elixir_advection_basic.jl +++ b/examples/t8code_2d_dgsem/elixir_advection_basic.jl @@ -16,12 +16,10 @@ solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) coordinates_max = (1.0, 1.0) # maximum coordinates (max(x), max(y)) -mapping = Trixi.coordinates2mapping(coordinates_min, coordinates_max) - trees_per_dimension = (8, 8) mesh = T8codeMesh(trees_per_dimension, polydeg = 3, - mapping = mapping, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, initial_refinement_level = 1) # A semidiscretization collects data structures and functions for the spatial discretization diff --git a/examples/t8code_2d_dgsem/elixir_advection_nonconforming_flag.jl b/examples/t8code_2d_dgsem/elixir_advection_nonconforming_flag.jl index 31a8bc93697..a39f3a7e195 100644 --- a/examples/t8code_2d_dgsem/elixir_advection_nonconforming_flag.jl +++ b/examples/t8code_2d_dgsem/elixir_advection_nonconforming_flag.jl @@ -20,31 +20,28 @@ f4(s) = SVector(s, 1.0 + sin(0.5 * pi * s)) faces = (f1, f2, f3, f4) mapping = Trixi.transfinite_mapping(faces) -# Create P4estMesh with 3 x 2 trees and 6 x 4 elements, +# Create T8codeMesh with 3 x 2 trees and 6 x 4 elements, # approximate the geometry with a smaller polydeg for testing. trees_per_dimension = (3, 2) mesh = T8codeMesh(trees_per_dimension, polydeg = 3, mapping = mapping, initial_refinement_level = 1) -function adapt_callback(forest, - forest_from, - which_tree, - lelement_id, - ts, - is_family, - num_elements, - elements_ptr)::Cint - vertex = Vector{Cdouble}(undef, 3) - - elements = unsafe_wrap(Array, elements_ptr, num_elements) - - Trixi.t8_element_vertex_reference_coords(ts, elements[1], 0, pointer(vertex)) +# Note: This is actually a `p4est_quadrant_t` which is much bigger than the +# following struct. But we only need the first three fields for our purpose. +struct t8_dquad_t + x::Int32 + y::Int32 + level::Int8 + # [...] # See `p4est.h` in `p4est` for more info. +end - level = Trixi.t8_element_level(ts, elements[1]) +# Refine quadrants of each tree at lower left edge to level 4. +function adapt_callback(forest, ltreeid, eclass_scheme, lelemntid, elements, is_family, + user_data) + el = unsafe_load(Ptr{t8_dquad_t}(elements[1])) - # TODO: Make this condition more general. - if vertex[1] < 1e-8 && vertex[2] < 1e-8 && level < 4 + if el.x == 0 && el.y == 0 && el.level < 4 # return true (refine) return 1 else @@ -53,26 +50,7 @@ function adapt_callback(forest, end end -Trixi.@T8_ASSERT(Trixi.t8_forest_is_committed(mesh.forest)!=0); - -# Init new forest. -new_forest_ref = Ref{Trixi.t8_forest_t}() -Trixi.t8_forest_init(new_forest_ref); -new_forest = new_forest_ref[] - -# Check out `examples/t8_step4_partition_balance_ghost.jl` in -# https://github.com/DLR-AMR/T8code.jl for detailed explanations. -let set_from = C_NULL, recursive = 1, set_for_coarsening = 0, no_repartition = 0 - Trixi.t8_forest_set_user_data(new_forest, C_NULL) - Trixi.t8_forest_set_adapt(new_forest, mesh.forest, - Trixi.@t8_adapt_callback(adapt_callback), recursive) - Trixi.t8_forest_set_balance(new_forest, set_from, no_repartition) - Trixi.t8_forest_set_partition(new_forest, set_from, set_for_coarsening) - Trixi.t8_forest_set_ghost(new_forest, 1, Trixi.T8_GHOST_FACES) - Trixi.t8_forest_commit(new_forest) -end - -mesh.forest = new_forest +Trixi.adapt!(mesh, adapt_callback) # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, diff --git a/examples/t8code_2d_dgsem/elixir_advection_unstructured_flag.jl b/examples/t8code_2d_dgsem/elixir_advection_unstructured_flag.jl index df9cbc26f6e..5ba1ab15489 100644 --- a/examples/t8code_2d_dgsem/elixir_advection_unstructured_flag.jl +++ b/examples/t8code_2d_dgsem/elixir_advection_unstructured_flag.jl @@ -38,9 +38,9 @@ isfile(mesh_file) || # we can create a t8code mesh. conn = Trixi.read_inp_p4est(mesh_file, Val(2)) -mesh = T8codeMesh{2}(conn, polydeg = 3, - mapping = mapping_flag, - initial_refinement_level = 2) +mesh = T8codeMesh(conn, polydeg = 3, + mapping = mapping_flag, + initial_refinement_level = 2) # A semidiscretization collects data structures and functions for the spatial discretization. semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, diff --git a/examples/t8code_2d_dgsem/elixir_euler_free_stream.jl b/examples/t8code_2d_dgsem/elixir_euler_free_stream.jl index 01e0449c67e..37d15f38566 100644 --- a/examples/t8code_2d_dgsem/elixir_euler_free_stream.jl +++ b/examples/t8code_2d_dgsem/elixir_euler_free_stream.jl @@ -40,25 +40,17 @@ isfile(mesh_file) || # we can create a t8code mesh. conn = Trixi.read_inp_p4est(mesh_file, Val(2)) -mesh = T8codeMesh{2}(conn, polydeg = 3, - mapping = mapping, - initial_refinement_level = 1) - -function adapt_callback(forest, - forest_from, - which_tree, - lelement_id, - ts, - is_family, - num_elements, - elements_ptr)::Cint - vertex = Vector{Cdouble}(undef, 3) +mesh = T8codeMesh(conn, polydeg = 3, + mapping = mapping, + initial_refinement_level = 1) - elements = unsafe_wrap(Array, elements_ptr, num_elements) +function adapt_callback(forest, ltreeid, eclass_scheme, lelemntid, elements, is_family, + user_data) + vertex = Vector{Cdouble}(undef, 3) - Trixi.t8_element_vertex_reference_coords(ts, elements[1], 0, pointer(vertex)) + Trixi.t8_element_vertex_reference_coords(eclass_scheme, elements[1], 0, vertex) - level = Trixi.t8_element_level(ts, elements[1]) + level = Trixi.t8_element_level(eclass_scheme, elements[1]) # TODO: Make this condition more general. if vertex[1] < 1e-8 && vertex[2] < 1e-8 && level < 3 @@ -70,26 +62,7 @@ function adapt_callback(forest, end end -Trixi.@T8_ASSERT(Trixi.t8_forest_is_committed(mesh.forest)!=0); - -# Init new forest. -new_forest_ref = Ref{Trixi.t8_forest_t}() -Trixi.t8_forest_init(new_forest_ref); -new_forest = new_forest_ref[] - -# Check out `examples/t8_step4_partition_balance_ghost.jl` in -# https://github.com/DLR-AMR/T8code.jl for detailed explanations. -let set_from = C_NULL, recursive = 1, set_for_coarsening = 0, no_repartition = 0 - Trixi.t8_forest_set_user_data(new_forest, C_NULL) - Trixi.t8_forest_set_adapt(new_forest, mesh.forest, - Trixi.@t8_adapt_callback(adapt_callback), recursive) - Trixi.t8_forest_set_balance(new_forest, set_from, no_repartition) - Trixi.t8_forest_set_partition(new_forest, set_from, set_for_coarsening) - Trixi.t8_forest_set_ghost(new_forest, 1, Trixi.T8_GHOST_FACES) - Trixi.t8_forest_commit(new_forest) -end - -mesh.forest = new_forest +Trixi.adapt!(mesh, adapt_callback) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions = Dict(:all => BoundaryConditionDirichlet(initial_condition))) diff --git a/examples/t8code_2d_dgsem/elixir_euler_sedov.jl b/examples/t8code_2d_dgsem/elixir_euler_sedov.jl index 965d794f8dc..82770a4050b 100644 --- a/examples/t8code_2d_dgsem/elixir_euler_sedov.jl +++ b/examples/t8code_2d_dgsem/elixir_euler_sedov.jl @@ -58,12 +58,10 @@ solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, coordinates_min = (-1.0, -1.0) coordinates_max = (1.0, 1.0) -mapping = Trixi.coordinates2mapping(coordinates_min, coordinates_max) - trees_per_dimension = (4, 4) mesh = T8codeMesh(trees_per_dimension, polydeg = 4, - mapping = mapping, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, initial_refinement_level = 2, periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) diff --git a/examples/t8code_2d_dgsem/elixir_euler_shockcapturing_ec.jl b/examples/t8code_2d_dgsem/elixir_euler_shockcapturing_ec.jl index 55a9063a001..9ebbd1d28c4 100644 --- a/examples/t8code_2d_dgsem/elixir_euler_shockcapturing_ec.jl +++ b/examples/t8code_2d_dgsem/elixir_euler_shockcapturing_ec.jl @@ -29,12 +29,10 @@ solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, coordinates_min = (-1.0, -1.0) coordinates_max = (1.0, 1.0) -mapping = Trixi.coordinates2mapping(coordinates_min, coordinates_max) - trees_per_dimension = (4, 4) mesh = T8codeMesh(trees_per_dimension, polydeg = 4, - mapping = mapping, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, initial_refinement_level = 2, periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) 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 21f26d79ba8..bcc1abc560e 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 @@ -40,25 +40,17 @@ isfile(mesh_file) || # we can create a t8code mesh. conn = Trixi.read_inp_p4est(mesh_file, Val(2)) -mesh = T8codeMesh{2}(conn, polydeg = 3, - mapping = mapping_flag, - initial_refinement_level = 1) - -function adapt_callback(forest, - forest_from, - which_tree, - lelement_id, - ts, - is_family, - num_elements, - elements_ptr)::Cint - vertex = Vector{Cdouble}(undef, 3) +mesh = T8codeMesh(conn, polydeg = 3, + mapping = mapping_flag, + initial_refinement_level = 1) - elements = unsafe_wrap(Array, elements_ptr, num_elements) +function adapt_callback(forest, ltreeid, eclass_scheme, lelemntid, elements, is_family, + user_data) + vertex = Vector{Cdouble}(undef, 3) - Trixi.t8_element_vertex_reference_coords(ts, elements[1], 0, pointer(vertex)) + Trixi.t8_element_vertex_reference_coords(eclass_scheme, elements[1], 0, pointer(vertex)) - level = Trixi.t8_element_level(ts, elements[1]) + level = Trixi.t8_element_level(eclass_scheme, elements[1]) # TODO: Make this condition more general. if vertex[1] < 1e-8 && vertex[2] < 1e-8 && level < 2 @@ -70,26 +62,7 @@ function adapt_callback(forest, end end -@assert(Trixi.t8_forest_is_committed(mesh.forest)!=0); - -# Init new forest. -new_forest_ref = Ref{Trixi.t8_forest_t}() -Trixi.t8_forest_init(new_forest_ref); -new_forest = new_forest_ref[] - -# Check out `examples/t8_step4_partition_balance_ghost.jl` in -# https://github.com/DLR-AMR/T8code.jl for detailed explanations. -let set_from = C_NULL, recursive = 1, set_for_coarsening = 0, no_repartition = 0 - Trixi.t8_forest_set_user_data(new_forest, C_NULL) - Trixi.t8_forest_set_adapt(new_forest, mesh.forest, - Trixi.@t8_adapt_callback(adapt_callback), recursive) - Trixi.t8_forest_set_balance(new_forest, set_from, no_repartition) - Trixi.t8_forest_set_partition(new_forest, set_from, set_for_coarsening) - Trixi.t8_forest_set_ghost(new_forest, 1, Trixi.T8_GHOST_FACES) - Trixi.t8_forest_commit(new_forest) -end - -mesh.forest = new_forest +Trixi.adapt!(mesh, adapt_callback) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, source_terms = source_terms, diff --git a/examples/t8code_2d_dgsem/elixir_eulergravity_convergence.jl b/examples/t8code_2d_dgsem/elixir_eulergravity_convergence.jl index 6d6bb27e0c3..98a9a5521a9 100644 --- a/examples/t8code_2d_dgsem/elixir_eulergravity_convergence.jl +++ b/examples/t8code_2d_dgsem/elixir_eulergravity_convergence.jl @@ -16,10 +16,8 @@ coordinates_max = (2.0, 2.0) trees_per_dimension = (1, 1) -mapping = Trixi.coordinates2mapping(coordinates_min, coordinates_max) - mesh = T8codeMesh(trees_per_dimension, polydeg = 1, - mapping = mapping, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, initial_refinement_level = 2) semi_euler = SemidiscretizationHyperbolic(mesh, equations_euler, initial_condition, diff --git a/examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl b/examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl index 1e2362a123c..e184cb3fd05 100644 --- a/examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl +++ b/examples/t8code_2d_dgsem/elixir_mhd_alfven_wave.jl @@ -11,18 +11,17 @@ initial_condition = initial_condition_convergence_test # Get the DG approximation space volume_flux = (flux_central, flux_nonconservative_powell) + solver = DGSEM(polydeg = 4, surface_flux = (flux_hlle, flux_nonconservative_powell), volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (0.0, 0.0) coordinates_max = (sqrt(2.0), sqrt(2.0)) -mapping = Trixi.coordinates2mapping(coordinates_min, coordinates_max) - trees_per_dimension = (8, 8) mesh = T8codeMesh(trees_per_dimension, polydeg = 3, - mapping = mapping, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, initial_refinement_level = 0, periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) diff --git a/examples/t8code_2d_dgsem/elixir_mhd_rotor.jl b/examples/t8code_2d_dgsem/elixir_mhd_rotor.jl index 9a4bd99e444..adb154948fb 100644 --- a/examples/t8code_2d_dgsem/elixir_mhd_rotor.jl +++ b/examples/t8code_2d_dgsem/elixir_mhd_rotor.jl @@ -78,9 +78,9 @@ isfile(mesh_file) || # we can create a t8code mesh. conn = Trixi.read_inp_p4est(mesh_file, Val(2)) -mesh = T8codeMesh{2}(conn, polydeg = 4, - mapping = mapping_twist, - initial_refinement_level = 1) +mesh = T8codeMesh(conn, polydeg = 4, + mapping = mapping_twist, + initial_refinement_level = 1) boundary_condition = BoundaryConditionDirichlet(initial_condition) boundary_conditions = Dict(:all => boundary_condition) diff --git a/examples/t8code_2d_dgsem/elixir_shallowwater_source_terms.jl b/examples/t8code_2d_dgsem/elixir_shallowwater_source_terms.jl index b2d5097036f..3610639d554 100644 --- a/examples/t8code_2d_dgsem/elixir_shallowwater_source_terms.jl +++ b/examples/t8code_2d_dgsem/elixir_shallowwater_source_terms.jl @@ -22,12 +22,10 @@ solver = DGSEM(polydeg = 3, coordinates_min = (0.0, 0.0) # minimum coordinates (min(x), min(y)) coordinates_max = (sqrt(2.0), sqrt(2.0)) # maximum coordinates (max(x), max(y)) -mapping = Trixi.coordinates2mapping(coordinates_min, coordinates_max) - trees_per_dimension = (8, 8) mesh = T8codeMesh(trees_per_dimension, polydeg = 3, - mapping = mapping, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, initial_refinement_level = 1) # A semidiscretization collects data structures and functions for the spatial discretization diff --git a/examples/t8code_3d_dgsem/elixir_advection_amr.jl b/examples/t8code_3d_dgsem/elixir_advection_amr.jl new file mode 100644 index 00000000000..5a4b2218d57 --- /dev/null +++ b/examples/t8code_3d_dgsem/elixir_advection_amr.jl @@ -0,0 +1,66 @@ +# The same setup as tree_3d_dgsem/elixir_advection_amr.jl +# to verify the T8codeMesh implementation against TreeMesh. + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear advection equation + +advection_velocity = (0.2, -0.7, 0.5) +equations = LinearScalarAdvectionEquation3D(advection_velocity) + +initial_condition = initial_condition_gauss +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) + +coordinates_min = (-5.0, -5.0, -5.0) +coordinates_max = (5.0, 5.0, 5.0) +trees_per_dimension = (1, 1, 1) + +# Note that it is not necessary to use mesh polydeg lower than the solver polydeg +# on a Cartesian mesh. +# See https://doi.org/10.1007/s10915-018-00897-9, Section 6. +mesh = T8codeMesh(trees_per_dimension, polydeg = 1, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + initial_refinement_level = 4) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.3) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first), + base_level = 4, + med_level = 5, med_threshold = 0.1, + max_level = 6, max_threshold = 0.6) +amr_callback = AMRCallback(semi, amr_controller, + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) + +stepsize_callback = StepsizeCallback(cfl = 1.2) + +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_3d_dgsem/elixir_advection_amr_unstructured_curved.jl b/examples/t8code_3d_dgsem/elixir_advection_amr_unstructured_curved.jl new file mode 100644 index 00000000000..617736afbdd --- /dev/null +++ b/examples/t8code_3d_dgsem/elixir_advection_amr_unstructured_curved.jl @@ -0,0 +1,105 @@ +using Downloads: download +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear advection equation + +advection_velocity = (0.2, -0.7, 0.5) +equations = LinearScalarAdvectionEquation3D(advection_velocity) + +# Solver with polydeg=4 to ensure free stream preservation (FSP) on non-conforming meshes. +# The polydeg of the solver must be at least twice as big as the polydeg of the mesh. +# See https://doi.org/10.1007/s10915-018-00897-9, Section 6. +solver = DGSEM(polydeg = 4, surface_flux = flux_lax_friedrichs) + +initial_condition = initial_condition_gauss +boundary_condition = BoundaryConditionDirichlet(initial_condition) + +boundary_conditions = Dict(:all => boundary_condition) + +# Mapping as described in https://arxiv.org/abs/2012.12040 but with less warping. +# The mapping will be interpolated at tree level, and then refined without changing +# the geometry interpolant. The original mapping applied to this unstructured mesh +# causes some Jacobians to be negative, which makes the mesh invalid. +function mapping(xi, eta, zeta) + # Don't transform input variables between -1 and 1 onto [0,3] to obtain curved boundaries + # xi = 1.5 * xi_ + 1.5 + # eta = 1.5 * eta_ + 1.5 + # zeta = 1.5 * zeta_ + 1.5 + + y = eta + + 1 / 4 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + x = xi + + 1 / 4 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + z = zeta + + 1 / 4 * (cos(0.5 * pi * (2 * x - 3) / 3) * + cos(pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + # Transform the weird deformed cube to be approximately the size of [-5,5]^3 to match IC + return SVector(5 * x, 5 * y, 5 * z) +end + +# Unstructured mesh with 48 cells of the cube domain [-1, 1]^3 +mesh_file = joinpath(@__DIR__, "cube_unstructured_2.inp") +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", + mesh_file) + +# INP mesh files are only support by p4est. Hence, we +# create a p4est connectivity object first from which +# we can create a t8code mesh. +conn = Trixi.read_inp_p4est(mesh_file, Val(3)) + +mesh = T8codeMesh(conn, polydeg = 2, + mapping = mapping, + initial_refinement_level = 1) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 8.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_integrals = (entropy,)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first), + base_level = 1, + med_level = 2, med_threshold = 0.1, + max_level = 3, max_threshold = 0.6) +amr_callback = AMRCallback(semi, amr_controller, + interval = 5, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) + +stepsize_callback = StepsizeCallback(cfl = 1.2) + +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_3d_dgsem/elixir_advection_basic.jl b/examples/t8code_3d_dgsem/elixir_advection_basic.jl new file mode 100644 index 00000000000..f49462035aa --- /dev/null +++ b/examples/t8code_3d_dgsem/elixir_advection_basic.jl @@ -0,0 +1,59 @@ +# The same setup as tree_3d_dgsem/elixir_advection_basic.jl +# to verify the T8codeMesh implementation against TreeMesh + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear advection equation + +advection_velocity = (0.2, -0.7, 0.5) +equations = LinearScalarAdvectionEquation3D(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) + +coordinates_min = (-1.0, -1.0, -1.0) # minimum coordinates (min(x), min(y), min(z)) +coordinates_max = (1.0, 1.0, 1.0) # maximum coordinates (max(x), max(y), max(z)) + +# Create P4estMesh with 8 x 8 x 8 elements (note `refinement_level=1`) +trees_per_dimension = (4, 4, 4) +mesh = T8codeMesh(trees_per_dimension, polydeg = 3, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + initial_refinement_level = 1) + +# 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 +tspan = (0.0, 1.0) +ode = semidiscretize(semi, tspan) + +# 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 StepsizeCallback handles the re-calculation of the maximum Δt after each time step +stepsize_callback = StepsizeCallback(cfl = 1.2) + +# Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver +callbacks = CallbackSet(summary_callback, analysis_callback, + 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.0, # 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/t8code_3d_dgsem/elixir_advection_nonconforming.jl b/examples/t8code_3d_dgsem/elixir_advection_nonconforming.jl new file mode 100644 index 00000000000..8d7a48370f5 --- /dev/null +++ b/examples/t8code_3d_dgsem/elixir_advection_nonconforming.jl @@ -0,0 +1,85 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# Semidiscretization of the linear advection equation. + +advection_velocity = (0.2, -0.7, 0.5) +equations = LinearScalarAdvectionEquation3D(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) + +coordinates_min = (-1.0, -1.0, -1.0) # minimum coordinates (min(x), min(y), min(z)) +coordinates_max = (1.0, 1.0, 1.0) # maximum coordinates (max(x), max(y), max(z)) +trees_per_dimension = (1, 1, 1) + +# Note that it is not necessary to use mesh polydeg lower than the solver polydeg +# on a Cartesian mesh. +# See https://doi.org/10.1007/s10915-018-00897-9, Section 6. +mesh = T8codeMesh(trees_per_dimension, polydeg = 3, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + initial_refinement_level = 2) + +# Note: This is actually a `p8est_quadrant_t` which is much bigger than the +# following struct. But we only need the first four fields for our purpose. +struct t8_dhex_t + x::Int32 + y::Int32 + z::Int32 + level::Int8 + # [...] # See `p8est.h` in `p4est` for more info. +end + +# Refine bottom left quadrant of each second tree to level 2 +function adapt_callback(forest, ltreeid, eclass_scheme, lelemntid, elements, is_family, + user_data) + el = unsafe_load(Ptr{t8_dhex_t}(elements[1])) + + if iseven(convert(Int, ltreeid)) && el.x == 0 && el.y == 0 && el.z == 0 && + el.level < 3 + # return true (refine) + return 1 + else + # return false (don't refine) + return 0 + end +end + +Trixi.adapt!(mesh, adapt_callback) + +# 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 +tspan = (0.0, 1.0) +ode = semidiscretize(semi, tspan) + +# 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 StepsizeCallback handles the re-calculation of the maximum Δt after each time step +stepsize_callback = StepsizeCallback(cfl = 1.6) + +# Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver +callbacks = CallbackSet(summary_callback, analysis_callback, + 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.0, # 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/t8code_3d_dgsem/elixir_advection_unstructured_curved.jl b/examples/t8code_3d_dgsem/elixir_advection_unstructured_curved.jl new file mode 100644 index 00000000000..df358435c9a --- /dev/null +++ b/examples/t8code_3d_dgsem/elixir_advection_unstructured_curved.jl @@ -0,0 +1,98 @@ +using Downloads: download +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear advection equation + +advection_velocity = (0.2, -0.7, 0.5) +equations = LinearScalarAdvectionEquation3D(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) + +initial_condition = initial_condition_convergence_test + +boundary_condition = BoundaryConditionDirichlet(initial_condition) +boundary_conditions = Dict(:all => boundary_condition) + +# Mapping as described in https://arxiv.org/abs/2012.12040 but with less warping. +# The mapping will be interpolated at tree level, and then refined without changing +# the geometry interpolant. The original mapping applied to this unstructured mesh +# causes some Jacobians to be negative, which makes the mesh invalid. +function mapping(xi, eta, zeta) + # Don't transform input variables between -1 and 1 onto [0,3] to obtain curved boundaries + # xi = 1.5 * xi_ + 1.5 + # eta = 1.5 * eta_ + 1.5 + # zeta = 1.5 * zeta_ + 1.5 + + y = eta + + 1 / 6 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + x = xi + + 1 / 6 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + z = zeta + + 1 / 6 * (cos(0.5 * pi * (2 * x - 3) / 3) * + cos(pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + return SVector(x, y, z) +end + +# Unstructured mesh with 68 cells of the cube domain [-1, 1]^3 +mesh_file = joinpath(@__DIR__, "cube_unstructured_1.inp") +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", + mesh_file) + +# INP mesh files are only support by p4est. Hence, we +# create a p4est connectivity object first from which +# we can create a t8code mesh. +conn = Trixi.read_inp_p4est(mesh_file, Val(3)) + +mesh = T8codeMesh(conn, polydeg = 3, + mapping = mapping, + initial_refinement_level = 2) + +# A semidiscretization collects data structures and functions for the spatial discretization +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span from 0.0 to 0.1 +ode = semidiscretize(semi, (0.0, 0.1)); + +# 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_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +# The StepsizeCallback handles the re-calculation of the maximum Δt after each time step +stepsize_callback = StepsizeCallback(cfl = 1.2) + +# Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, + 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.0, # 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/t8code_3d_dgsem/elixir_euler_ec.jl b/examples/t8code_3d_dgsem/elixir_euler_ec.jl new file mode 100644 index 00000000000..07745c3ac56 --- /dev/null +++ b/examples/t8code_3d_dgsem/elixir_euler_ec.jl @@ -0,0 +1,92 @@ +using Downloads: download +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations3D(5 / 3) + +initial_condition = initial_condition_weak_blast_wave + +boundary_conditions = Dict(:all => boundary_condition_slip_wall) + +# Get the DG approximation space + +volume_flux = flux_ranocha +solver = DGSEM(polydeg = 5, surface_flux = flux_ranocha, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +# Get the curved quad mesh from a file + +# Mapping as described in https://arxiv.org/abs/2012.12040 +function mapping(xi_, eta_, zeta_) + # Transform input variables between -1 and 1 onto [0,3] + xi = 1.5 * xi_ + 1.5 + eta = 1.5 * eta_ + 1.5 + zeta = 1.5 * zeta_ + 1.5 + + y = eta + + 3 / 8 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + x = xi + + 3 / 8 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + z = zeta + + 3 / 8 * (cos(0.5 * pi * (2 * x - 3) / 3) * + cos(pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + return SVector(x, y, z) +end + +# Unstructured mesh with 48 cells of the cube domain [-1, 1]^3 +mesh_file = joinpath(@__DIR__, "cube_unstructured_2.inp") +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", + mesh_file) + +# INP mesh files are only support by p4est. Hence, we +# create a p4est connectivity object first from which +# we can create a t8code mesh. +conn = Trixi.read_inp_p4est(mesh_file, Val(3)) + +mesh = T8codeMesh(conn, polydeg = 5, + mapping = mapping, + initial_refinement_level = 0) + +# Create the semidiscretization object. +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 2.0) +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.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_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_3d_dgsem/elixir_euler_free_stream.jl b/examples/t8code_3d_dgsem/elixir_euler_free_stream.jl new file mode 100644 index 00000000000..e135d464810 --- /dev/null +++ b/examples/t8code_3d_dgsem/elixir_euler_free_stream.jl @@ -0,0 +1,118 @@ +using Downloads: download +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations3D(1.4) + +initial_condition = initial_condition_constant + +boundary_conditions = Dict(:all => BoundaryConditionDirichlet(initial_condition)) + +# Solver with polydeg=4 to ensure free stream preservation (FSP) on non-conforming meshes. +# The polydeg of the solver must be at least twice as big as the polydeg of the mesh. +# See https://doi.org/10.1007/s10915-018-00897-9, Section 6. +solver = DGSEM(polydeg = 4, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralWeakForm()) + +# Mapping as described in https://arxiv.org/abs/2012.12040 but with less warping. +# The mapping will be interpolated at tree level, and then refined without changing +# the geometry interpolant. This can yield problematic geometries if the unrefined mesh +# is not fine enough. +function mapping(xi_, eta_, zeta_) + # Transform input variables between -1 and 1 onto [0,3] + xi = 1.5 * xi_ + 1.5 + eta = 1.5 * eta_ + 1.5 + zeta = 1.5 * zeta_ + 1.5 + + y = eta + + 1 / 6 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + x = xi + + 1 / 6 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + z = zeta + + 1 / 6 * (cos(0.5 * pi * (2 * x - 3) / 3) * + cos(pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + return SVector(x, y, z) +end + +# Unstructured mesh with 68 cells of the cube domain [-1, 1]^3 +mesh_file = joinpath(@__DIR__, "cube_unstructured_1.inp") +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", + mesh_file) + +# INP mesh files are only support by p4est. Hence, we +# create a p4est connectivity object first from which +# we can create a t8code mesh. +conn = Trixi.read_inp_p4est(mesh_file, Val(3)) + +mesh = T8codeMesh(conn, polydeg = 2, + mapping = mapping, + initial_refinement_level = 0) + +# Note: This is actually a `p8est_quadrant_t` which is much bigger than the +# following struct. But we only need the first four fields for our purpose. +struct t8_dhex_t + x::Int32 + y::Int32 + z::Int32 + level::Int8 + # [...] # See `p8est.h` in `p4est` for more info. +end + +# Refine bottom left quadrant of each second tree to level 2 +function adapt_callback(forest, ltreeid, eclass_scheme, lelemntid, elements, is_family, + user_data) + el = unsafe_load(Ptr{t8_dhex_t}(elements[1])) + + if iseven(convert(Int, ltreeid)) && el.x == 0 && el.y == 0 && el.z == 0 && + el.level < 2 + # return true (refine) + return 1 + else + # return false (don't refine) + return 0 + end +end + +Trixi.adapt!(mesh, adapt_callback) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) + +############################################################################### +# 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) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +stepsize_callback = StepsizeCallback(cfl = 1.2) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_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_3d_dgsem/elixir_euler_free_stream_extruded.jl b/examples/t8code_3d_dgsem/elixir_euler_free_stream_extruded.jl new file mode 100644 index 00000000000..d129b59826e --- /dev/null +++ b/examples/t8code_3d_dgsem/elixir_euler_free_stream_extruded.jl @@ -0,0 +1,106 @@ +using Downloads: download +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations3D(1.4) + +initial_condition = initial_condition_constant + +boundary_conditions = Dict(:all => BoundaryConditionDirichlet(initial_condition)) + +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralWeakForm()) + +# Mapping as described in https://arxiv.org/abs/2012.12040 but reduced to 2D. +# This particular mesh is unstructured in the yz-plane, but extruded in x-direction. +# Apply the warping mapping in the yz-plane to get a curved 2D mesh that is extruded +# in x-direction to ensure free stream preservation on a non-conforming mesh. +# See https://doi.org/10.1007/s10915-018-00897-9, Section 6. +function mapping(xi, eta_, zeta_) + # Transform input variables between -1 and 1 onto [0,3] + eta = 1.5 * eta_ + 1.5 + zeta = 1.5 * zeta_ + 1.5 + + z = zeta + + 1 / 6 * (cos(1.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + y = eta + 1 / 6 * (cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(2 * pi * (2 * z - 3) / 3)) + + return SVector(xi, y, z) +end + +# Unstructured mesh with 48 cells of the cube domain [-1, 1]^3 +mesh_file = joinpath(@__DIR__, "cube_unstructured_2.inp") +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", + mesh_file) + +# INP mesh files are only support by p4est. Hence, we +# create a p4est connecvity object first from which +# we can create a t8code mesh. +conn = Trixi.read_inp_p4est(mesh_file, Val(3)) + +mesh = T8codeMesh(conn, polydeg = 3, + mapping = mapping, + initial_refinement_level = 0) + +# Note: This is actually a `p8est_quadrant_t` which is much bigger than the +# following struct. But we only need the first four fields for our purpose. +struct t8_dhex_t + x::Int32 + y::Int32 + z::Int32 + level::Int8 + # [...] # See `p8est.h` in `p4est` for more info. +end + +# Refine quadrants in y-direction of each tree at one edge to level 2 +function adapt_callback(forest, ltreeid, eclass_scheme, lelemntid, elements, is_family, + user_data) + el = unsafe_load(Ptr{t8_dhex_t}(elements[1])) + + if convert(Int, ltreeid) < 4 && el.x == 0 && el.y == 0 && el.level < 2 + # return true (refine) + return 1 + else + # return false (don't refine) + return 0 + end +end + +Trixi.adapt!(mesh, adapt_callback) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) + +############################################################################### +# 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) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +stepsize_callback = StepsizeCallback(cfl = 1.2) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + stepsize_callback) + +############################################################################### +# run the simulation + +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 diff --git a/examples/t8code_3d_dgsem/elixir_euler_sedov.jl b/examples/t8code_3d_dgsem/elixir_euler_sedov.jl new file mode 100644 index 00000000000..618b170b661 --- /dev/null +++ b/examples/t8code_3d_dgsem/elixir_euler_sedov.jl @@ -0,0 +1,97 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations3D(1.4) + +""" + initial_condition_medium_sedov_blast_wave(x, t, equations::CompressibleEulerEquations3D) + +The Sedov blast wave setup based on Flash +- https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 +with smaller strength of the initial discontinuity. +""" +function initial_condition_medium_sedov_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) + + # Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000 + r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6) + E = 1.0 + p0_inner = 3 * (equations.gamma - 1) * E / (4 * pi * r0^2) + p0_outer = 1.0e-3 + + # Calculate primitive variables + rho = 1.0 + 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_medium_sedov_blast_wave + +surface_flux = flux_lax_friedrichs +volume_flux = flux_ranocha +polydeg = 5 +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) + +coordinates_min = (-1.0, -1.0, -1.0) +coordinates_max = (1.0, 1.0, 1.0) + +trees_per_dimension = (4, 4, 4) +mesh = T8codeMesh(trees_per_dimension, + polydeg = 4, initial_refinement_level = 0, + coordinates_min = coordinates_min, coordinates_max = coordinates_max, + periodicity = true) + +# create the semi discretization object +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 12.5) +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 = 0.5) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_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_3d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_curved.jl b/examples/t8code_3d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_curved.jl new file mode 100644 index 00000000000..d4664522bea --- /dev/null +++ b/examples/t8code_3d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_curved.jl @@ -0,0 +1,120 @@ +using Downloads: download +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations3D(1.4) + +initial_condition = initial_condition_convergence_test + +boundary_condition = BoundaryConditionDirichlet(initial_condition) +boundary_conditions = Dict(:all => boundary_condition) + +# Solver with polydeg=4 to ensure free stream preservation (FSP) on non-conforming meshes. +# The polydeg of the solver must be at least twice as big as the polydeg of the mesh. +# See https://doi.org/10.1007/s10915-018-00897-9, Section 6. +solver = DGSEM(polydeg = 4, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralWeakForm()) + +# Mapping as described in https://arxiv.org/abs/2012.12040 but with less warping. +# The mapping will be interpolated at tree level, and then refined without changing +# the geometry interpolant. The original mapping applied to this unstructured mesh +# causes some Jacobians to be negative, which makes the mesh invalid. +function mapping(xi, eta, zeta) + # Don't transform input variables between -1 and 1 onto [0,3] to obtain curved boundaries + # xi = 1.5 * xi_ + 1.5 + # eta = 1.5 * eta_ + 1.5 + # zeta = 1.5 * zeta_ + 1.5 + + y = eta + + 1 / 6 * (cos(1.5 * pi * (2 * xi - 3) / 3) * + cos(0.5 * pi * (2 * eta - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + x = xi + + 1 / 6 * (cos(0.5 * pi * (2 * xi - 3) / 3) * + cos(2 * pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + z = zeta + + 1 / 6 * (cos(0.5 * pi * (2 * x - 3) / 3) * + cos(pi * (2 * y - 3) / 3) * + cos(0.5 * pi * (2 * zeta - 3) / 3)) + + # Transform the weird deformed cube to be approximately the cube [0,2]^3 + return SVector(x + 1, y + 1, z + 1) +end + +# Unstructured mesh with 68 cells of the cube domain [-1, 1]^3 +mesh_file = joinpath(@__DIR__, "cube_unstructured_1.inp") +isfile(mesh_file) || + download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", + mesh_file) + +# INP mesh files are only support by p4est. Hence, we +# create a p4est connecvity object first from which +# we can create a t8code mesh. +conn = Trixi.read_inp_p4est(mesh_file, Val(3)) + +# Mesh polydeg of 2 (half the solver polydeg) to ensure FSP (see above). +mesh = T8codeMesh(conn, polydeg = 2, + mapping = mapping, + initial_refinement_level = 0) + +# Note: This is actually a `p8est_quadrant_t` which is much bigger than the +# following struct. But we only need the first four fields for our purpose. +struct t8_dhex_t + x::Int32 + y::Int32 + z::Int32 + level::Int8 + # [...] # See `p8est.h` in `p4est` for more info. +end + +function adapt_callback(forest, ltreeid, eclass_scheme, lelemntid, elements, is_family, + user_data) + el = unsafe_load(Ptr{t8_dhex_t}(elements[1])) + + if el.x == 0 && el.y == 0 && el.z == 0 && el.level < 2 + # return true (refine) + return 1 + else + # return false (don't refine) + return 0 + end +end + +Trixi.adapt!(mesh, adapt_callback) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_convergence_test, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.045) +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 = 0.6) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_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_3d_dgsem/elixir_euler_source_terms_nonperiodic.jl b/examples/t8code_3d_dgsem/elixir_euler_source_terms_nonperiodic.jl new file mode 100644 index 00000000000..7cb03bb312d --- /dev/null +++ b/examples/t8code_3d_dgsem/elixir_euler_source_terms_nonperiodic.jl @@ -0,0 +1,62 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations3D(1.4) + +initial_condition = initial_condition_convergence_test + +boundary_condition = BoundaryConditionDirichlet(initial_condition) +boundary_conditions = Dict(:x_neg => boundary_condition, + :x_pos => boundary_condition, + :y_neg => boundary_condition, + :y_pos => boundary_condition, + :z_neg => boundary_condition, + :z_pos => boundary_condition) + +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs, + volume_integral = VolumeIntegralWeakForm()) + +coordinates_min = (0.0, 0.0, 0.0) +coordinates_max = (2.0, 2.0, 2.0) + +trees_per_dimension = (2, 2, 2) + +mapping = Trixi.coordinates2mapping(coordinates_min, coordinates_max) + +mesh = T8codeMesh(trees_per_dimension, polydeg = 1, + mapping = mapping, + periodicity = false, initial_refinement_level = 1) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_convergence_test, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 5.0) +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 = 0.6) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_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/src/auxiliary/t8code.jl b/src/auxiliary/t8code.jl index bd781b21c1e..db01476bb86 100644 --- a/src/auxiliary/t8code.jl +++ b/src/auxiliary/t8code.jl @@ -35,7 +35,7 @@ function init_t8code() # production runs this is not mandatory, but is helpful during # development. Hence, this option is only activated when environment # variable TRIXI_T8CODE_SC_FINALIZE exists. - @warn "T8code.jl: sc_finalize will be called during shutdown of Trixi.jl." + @info "T8code.jl: `sc_finalize` will be called during shutdown of Trixi.jl." MPI.add_finalize_hook!(T8code.Libt8.sc_finalize) end else @@ -116,7 +116,6 @@ function trixi_t8_count_interfaces(forest) elseif level < neighbor_level local_num_mortars += 1 end - else local_num_boundary += 1 end @@ -219,38 +218,9 @@ function trixi_t8_fill_mesh_info(forest, elements, interfaces, mortars, boundari interfaces.neighbor_ids[1, interface_id] = current_index + 1 interfaces.neighbor_ids[2, interface_id] = neighbor_ielements[1] + 1 - # Iterate over primary and secondary element. - for side in 1:2 - # Align interface in positive coordinate direction of primary element. - # For orientation == 1, the secondary element needs to be indexed backwards - # relative to the interface. - if side == 1 || orientation == 0 - # Forward indexing - indexing = :i_forward - else - # Backward indexing - indexing = :i_backward - end - - if faces[side] == 0 - # Index face in negative x-direction - interfaces.node_indices[side, interface_id] = (:begin, - indexing) - elseif faces[side] == 1 - # Index face in positive x-direction - interfaces.node_indices[side, interface_id] = (:end, - indexing) - elseif faces[side] == 2 - # Index face in negative y-direction - interfaces.node_indices[side, interface_id] = (indexing, - :begin) - else # faces[side] == 3 - # Index face in positive y-direction - interfaces.node_indices[side, interface_id] = (indexing, - :end) - end - end - + # Save interfaces.node_indices dimension specific in containers_3d.jl. + init_interface_node_indices!(interfaces, faces, orientation, + interface_id) # Non-conforming interface. elseif level < neighbor_level local_num_mortars += 1 @@ -262,42 +232,13 @@ function trixi_t8_fill_mesh_info(forest, elements, interfaces, mortars, boundari # Last entry is the large element. mortars.neighbor_ids[end, mortar_id] = current_index + 1 - # First `1:end-1` entries are the smaller elements. - mortars.neighbor_ids[1:(end - 1), mortar_id] .= neighbor_ielements .+ - 1 - - for side in 1:2 - # Align mortar in positive coordinate direction of small side. - # For orientation == 1, the large side needs to be indexed backwards - # relative to the mortar. - if side == 1 || orientation == 0 - # Forward indexing for small side or orientation == 0. - indexing = :i_forward - else - # Backward indexing for large side with reversed orientation. - indexing = :i_backward - # Since the orientation is reversed we have to account for this - # when filling the `neighbor_ids` array. - mortars.neighbor_ids[1, mortar_id] = neighbor_ielements[2] + - 1 - mortars.neighbor_ids[2, mortar_id] = neighbor_ielements[1] + - 1 - end - - if faces[side] == 0 - # Index face in negative x-direction - mortars.node_indices[side, mortar_id] = (:begin, indexing) - elseif faces[side] == 1 - # Index face in positive x-direction - mortars.node_indices[side, mortar_id] = (:end, indexing) - elseif faces[side] == 2 - # Index face in negative y-direction - mortars.node_indices[side, mortar_id] = (indexing, :begin) - else # faces[side] == 3 - # Index face in positive y-direction - mortars.node_indices[side, mortar_id] = (indexing, :end) - end - end + # Fill in the `mortars.neighbor_ids` array and reorder if necessary. + init_mortar_neighbor_ids!(mortars, faces[2], faces[1], + orientation, neighbor_ielements, + mortar_id) + + # Fill in the `mortars.node_indices` array. + init_mortar_node_indices!(mortars, faces, orientation, mortar_id) # else: "level > neighbor_level" is skipped since we visit the mortar interface only once. end @@ -309,19 +250,7 @@ function trixi_t8_fill_mesh_info(forest, elements, interfaces, mortars, boundari boundaries.neighbor_ids[boundary_id] = current_index + 1 - if iface == 0 - # Index face in negative x-direction. - boundaries.node_indices[boundary_id] = (:begin, :i_forward) - elseif iface == 1 - # Index face in positive x-direction. - boundaries.node_indices[boundary_id] = (:end, :i_forward) - elseif iface == 2 - # Index face in negative y-direction. - boundaries.node_indices[boundary_id] = (:i_forward, :begin) - else # iface == 3 - # Index face in positive y-direction. - boundaries.node_indices[boundary_id] = (:i_forward, :end) - end + init_boundary_node_indices!(boundaries, iface, boundary_id) # One-based indexing. boundaries.name[boundary_id] = boundary_names[iface + 1, itree + 1] @@ -420,13 +349,15 @@ function trixi_t8_adapt_new(old_forest, indicators) t8_forest_init(new_forest_ref) new_forest = new_forest_ref[] - let set_from = C_NULL, recursive = 0, set_for_coarsening = 0, no_repartition = 0 + let set_from = C_NULL, recursive = 0, set_for_coarsening = 0, no_repartition = 0, + do_ghost = 1 + t8_forest_set_user_data(new_forest, pointer(indicators)) t8_forest_set_adapt(new_forest, old_forest, @t8_adapt_callback(adapt_callback), recursive) t8_forest_set_balance(new_forest, set_from, no_repartition) t8_forest_set_partition(new_forest, set_from, set_for_coarsening) - t8_forest_set_ghost(new_forest, 1, T8_GHOST_FACES) # Note: MPI support not available yet so it is a dummy call. + t8_forest_set_ghost(new_forest, do_ghost, T8_GHOST_FACES) # Note: MPI support not available yet so it is a dummy call. t8_forest_commit(new_forest) end diff --git a/src/callbacks_step/amr_dg2d.jl b/src/callbacks_step/amr_dg2d.jl index 98e531295b7..b816bc06e65 100644 --- a/src/callbacks_step/amr_dg2d.jl +++ b/src/callbacks_step/amr_dg2d.jl @@ -396,7 +396,7 @@ function adapt!(u_ode::AbstractVector, adaptor, mesh::T8codeMesh{2}, equations, old_index = 1 new_index = 1 - # Note: This is true for `quads` only. + # Note: This is true for `quads`. T8_CHILDREN = 4 # Retain current solution data. diff --git a/src/callbacks_step/amr_dg3d.jl b/src/callbacks_step/amr_dg3d.jl index c8abe6fdb05..392cbba9e28 100644 --- a/src/callbacks_step/amr_dg3d.jl +++ b/src/callbacks_step/amr_dg3d.jl @@ -304,9 +304,84 @@ end # this method is called when an `ControllerThreeLevel` is constructed function create_cache(::Type{ControllerThreeLevel}, - mesh::Union{TreeMesh{3}, P4estMesh{3}}, + mesh::Union{TreeMesh{3}, P4estMesh{3}, T8codeMesh{3}}, equations, dg::DG, cache) controller_value = Vector{Int}(undef, nelements(dg, cache)) return (; controller_value) end + +# Coarsen and refine elements in the DG solver based on a difference list. +function adapt!(u_ode::AbstractVector, adaptor, mesh::T8codeMesh{3}, equations, + dg::DGSEM, cache, difference) + + # Return early if there is nothing to do. + if !any(difference .!= 0) + return nothing + end + + # Number of (local) cells/elements. + old_nelems = nelements(dg, cache) + new_nelems = ncells(mesh) + + # Local element indices. + old_index = 1 + new_index = 1 + + # Note: This is only true for `hexs`. + T8_CHILDREN = 8 + + # Retain current solution data. + old_u_ode = copy(u_ode) + + GC.@preserve old_u_ode begin + old_u = wrap_array(old_u_ode, mesh, equations, dg, cache) + + reinitialize_containers!(mesh, equations, 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), + nnodes(dg), nnodes(dg)) + u_tmp2 = Array{eltype(u), 4}(undef, nvariables(equations), nnodes(dg), + nnodes(dg), nnodes(dg)) + + while old_index <= old_nelems && new_index <= new_nelems + if difference[old_index] > 0 # Refine. + + # Refine element and store solution directly in new data structure. + refine_element!(u, new_index, old_u, old_index, adaptor, equations, dg, + u_tmp1, u_tmp2) + + old_index += 1 + new_index += T8_CHILDREN + + elseif difference[old_index] < 0 # Coarsen. + + # If an element is to be removed, sanity check if the following elements + # are also marked - otherwise there would be an error in the way the + # cells/elements are sorted. + @assert all(difference[old_index:(old_index + T8_CHILDREN - 1)] .< 0) "bad cell/element order" + + # Coarsen elements and store solution directly in new data structure. + coarsen_elements!(u, new_index, old_u, old_index, adaptor, equations, + dg, u_tmp1, u_tmp2) + + 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] + + old_index += 1 + new_index += 1 + end + end # while + end # GC.@preserve old_u_ode + + return nothing +end end # @muladd diff --git a/src/callbacks_step/analysis_dg3d.jl b/src/callbacks_step/analysis_dg3d.jl index 81d0795a159..27e8a2b722f 100644 --- a/src/callbacks_step/analysis_dg3d.jl +++ b/src/callbacks_step/analysis_dg3d.jl @@ -35,7 +35,9 @@ function create_cache_analysis(analyzer, mesh::TreeMesh{3}, return (; u_local, u_tmp1, u_tmp2, x_local, x_tmp1, x_tmp2) end -function create_cache_analysis(analyzer, mesh::Union{StructuredMesh{3}, P4estMesh{3}}, +function create_cache_analysis(analyzer, + mesh::Union{StructuredMesh{3}, P4estMesh{3}, + T8codeMesh{3}}, equations, dg::DG, cache, RealT, uEltype) @@ -118,7 +120,7 @@ function calc_error_norms(func, u, t, analyzer, end function calc_error_norms(func, u, t, analyzer, - mesh::Union{StructuredMesh{3}, P4estMesh{3}}, + mesh::Union{StructuredMesh{3}, P4estMesh{3}, T8codeMesh{3}}, equations, initial_condition, dg::DGSEM, cache, cache_analysis) @unpack vandermonde, weights = analyzer @@ -190,7 +192,8 @@ function integrate_via_indices(func::Func, u, end function integrate_via_indices(func::Func, u, - mesh::Union{StructuredMesh{3}, P4estMesh{3}}, + mesh::Union{StructuredMesh{3}, P4estMesh{3}, + T8codeMesh{3}}, equations, dg::DGSEM, cache, args...; normalize = true) where {Func} @unpack weights = dg.basis @@ -218,7 +221,8 @@ function integrate_via_indices(func::Func, u, end function integrate(func::Func, u, - mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3}}, + mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3}, + T8codeMesh{3}}, equations, dg::DG, cache; normalize = true) where {Func} integrate_via_indices(u, mesh, equations, dg, cache; normalize = normalize) do u, i, j, k, element, equations, dg @@ -248,7 +252,8 @@ function integrate(func::Func, u, end function analyze(::typeof(entropy_timederivative), du, u, t, - mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3}}, + mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3}, + T8codeMesh{3}}, equations, dg::DG, cache) # Calculate ∫(∂S/∂u ⋅ ∂u/∂t)dΩ integrate_via_indices(u, mesh, equations, dg, cache, @@ -277,7 +282,7 @@ function analyze(::Val{:l2_divb}, du, u, t, end function analyze(::Val{:l2_divb}, du, u, t, - mesh::Union{StructuredMesh{3}, P4estMesh{3}}, + mesh::Union{StructuredMesh{3}, P4estMesh{3}, T8codeMesh{3}}, equations::IdealGlmMhdEquations3D, dg::DGSEM, cache) @unpack contravariant_vectors = cache.elements @@ -333,7 +338,7 @@ function analyze(::Val{:linf_divb}, du, u, t, end function analyze(::Val{:linf_divb}, du, u, t, - mesh::Union{StructuredMesh{3}, P4estMesh{3}}, + mesh::Union{StructuredMesh{3}, P4estMesh{3}, T8codeMesh{3}}, equations::IdealGlmMhdEquations3D, dg::DGSEM, cache) @unpack derivative_matrix, weights = dg.basis diff --git a/src/callbacks_step/stepsize_dg3d.jl b/src/callbacks_step/stepsize_dg3d.jl index c9ab7c478a8..822ab2f87ec 100644 --- a/src/callbacks_step/stepsize_dg3d.jl +++ b/src/callbacks_step/stepsize_dg3d.jl @@ -44,7 +44,7 @@ function max_dt(u, t, mesh::TreeMesh{3}, return 2 / (nnodes(dg) * max_scaled_speed) end -function max_dt(u, t, mesh::Union{StructuredMesh{3}, P4estMesh{3}}, +function max_dt(u, t, mesh::Union{StructuredMesh{3}, P4estMesh{3}, T8codeMesh{3}}, constant_speed::False, equations, dg::DG, cache) # to avoid a division by zero if the speed vanishes everywhere, # e.g. for steady-state linear advection @@ -82,7 +82,7 @@ function max_dt(u, t, mesh::Union{StructuredMesh{3}, P4estMesh{3}}, return 2 / (nnodes(dg) * max_scaled_speed) end -function max_dt(u, t, mesh::Union{StructuredMesh{3}, P4estMesh{3}}, +function max_dt(u, t, mesh::Union{StructuredMesh{3}, P4estMesh{3}, T8codeMesh{3}}, constant_speed::True, equations, dg::DG, cache) # to avoid a division by zero if the speed vanishes everywhere, # e.g. for steady-state linear advection diff --git a/src/meshes/t8code_mesh.jl b/src/meshes/t8code_mesh.jl index 13edcc29711..c9665a22af9 100644 --- a/src/meshes/t8code_mesh.jl +++ b/src/meshes/t8code_mesh.jl @@ -115,19 +115,49 @@ Non-periodic boundaries will be called ':x_neg', ':x_pos', ':y_neg', ':y_pos', ' - 'polydeg::Integer': polynomial degree used to store the geometry of the mesh. The mapping will be approximated by an interpolation polynomial of the specified degree for each tree. -- 'mapping': a function of 'NDIMS' variables to describe the mapping that transforms - the reference mesh ('[-1, 1]^n') to the physical domain. +- `mapping`: a function of `NDIMS` variables to describe the mapping that transforms + the reference mesh (`[-1, 1]^n`) to the physical domain. + Use only one of `mapping`, `faces` and `coordinates_min`/`coordinates_max`. +- `faces::NTuple{2*NDIMS}`: a tuple of `2 * NDIMS` functions that describe the faces of the domain. + Each function must take `NDIMS-1` arguments. + `faces[1]` describes the face onto which the face in negative x-direction + of the unit hypercube is mapped. The face in positive x-direction of + the unit hypercube will be mapped onto the face described by `faces[2]`. + `faces[3:4]` describe the faces in positive and negative y-direction respectively + (in 2D and 3D). + `faces[5:6]` describe the faces in positive and negative z-direction respectively (in 3D). + Use only one of `mapping`, `faces` and `coordinates_min`/`coordinates_max`. +- `coordinates_min`: vector or tuple of the coordinates of the corner in the negative direction of each dimension + to create a rectangular mesh. + Use only one of `mapping`, `faces` and `coordinates_min`/`coordinates_max`. +- `coordinates_max`: vector or tuple of the coordinates of the corner in the positive direction of each dimension + to create a rectangular mesh. + Use only one of `mapping`, `faces` and `coordinates_min`/`coordinates_max`. - '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. - 'periodicity': either a 'Bool' deciding if all of the boundaries are periodic or an 'NTuple{NDIMS, Bool}' deciding for each dimension if the boundaries in this dimension are periodic. """ -function T8codeMesh(trees_per_dimension; polydeg, - mapping = coordinates2mapping((-1.0, -1.0), (1.0, 1.0)), - RealT = Float64, initial_refinement_level = 0, periodicity = true) - NDIMS = length(trees_per_dimension) +function T8codeMesh(trees_per_dimension; polydeg = 1, + mapping = nothing, faces = nothing, coordinates_min = nothing, + coordinates_max = nothing, + RealT = Float64, initial_refinement_level = 0, + periodicity = true) + @assert ((coordinates_min === nothing)===(coordinates_max === nothing)) "Either both or none of coordinates_min and coordinates_max must be specified" + + @assert count(i -> i !== nothing, + (mapping, faces, coordinates_min))==1 "Exactly one of mapping, faces and coordinates_min/max must be specified" + + # Extract mapping + if faces !== nothing + validate_faces(faces) + mapping = transfinite_mapping(faces) + elseif coordinates_min !== nothing + mapping = coordinates2mapping(coordinates_min, coordinates_max) + end - @assert NDIMS == 2 # Only support for NDIMS = 2 yet. + NDIMS = length(trees_per_dimension) + @assert (NDIMS == 2||NDIMS == 3) "NDIMS should be 2 or 3." # Convert periodicity to a Tuple of a Bool for every dimension if all(periodicity) @@ -141,10 +171,18 @@ function T8codeMesh(trees_per_dimension; polydeg, periodicity = Tuple(periodicity) end - conn = T8code.Libt8.p4est_connectivity_new_brick(trees_per_dimension..., periodicity...) do_partition = 0 - cmesh = t8_cmesh_new_from_p4est(conn, mpi_comm(), do_partition) - T8code.Libt8.p4est_connectivity_destroy(conn) + if NDIMS == 2 + conn = T8code.Libt8.p4est_connectivity_new_brick(trees_per_dimension..., + periodicity...) + cmesh = t8_cmesh_new_from_p4est(conn, mpi_comm(), do_partition) + T8code.Libt8.p4est_connectivity_destroy(conn) + elseif NDIMS == 3 + conn = T8code.Libt8.p8est_connectivity_new_brick(trees_per_dimension..., + periodicity...) + cmesh = t8_cmesh_new_from_p8est(conn, mpi_comm(), do_partition) + T8code.Libt8.p8est_connectivity_destroy(conn) + end scheme = t8_scheme_new_default_cxx() forest = t8_forest_new_uniform(cmesh, scheme, initial_refinement_level, 0, mpi_comm()) @@ -156,28 +194,48 @@ function T8codeMesh(trees_per_dimension; polydeg, ntuple(_ -> length(nodes), NDIMS)..., prod(trees_per_dimension)) - # Get cell length in reference mesh: Omega_ref = [-1,1]^2. - dx = 2 / trees_per_dimension[1] - dy = 2 / trees_per_dimension[2] + # Get cell length in reference mesh: Omega_ref = [-1,1]^NDIMS. + dx = [2 / n for n in trees_per_dimension] num_local_trees = t8_cmesh_get_num_local_trees(cmesh) # Non-periodic boundaries. boundary_names = fill(Symbol("---"), 2 * NDIMS, prod(trees_per_dimension)) + if mapping === nothing + mapping_ = coordinates2mapping(ntuple(_ -> -1.0, NDIMS), ntuple(_ -> 1.0, NDIMS)) + else + mapping_ = mapping + end + for itree in 1:num_local_trees veptr = t8_cmesh_get_tree_vertices(cmesh, itree - 1) verts = unsafe_wrap(Array, veptr, (3, 1 << NDIMS)) # Calculate node coordinates of reference mesh. - cell_x_offset = (verts[1, 1] - 1 / 2 * (trees_per_dimension[1] - 1)) * dx - cell_y_offset = (verts[2, 1] - 1 / 2 * (trees_per_dimension[2] - 1)) * dy - - for j in eachindex(nodes), i in eachindex(nodes) - tree_node_coordinates[:, i, j, itree] .= mapping(cell_x_offset + - dx * nodes[i] / 2, - cell_y_offset + - dy * nodes[j] / 2) + if NDIMS == 2 + cell_x_offset = (verts[1, 1] - 0.5 * (trees_per_dimension[1] - 1)) * dx[1] + cell_y_offset = (verts[2, 1] - 0.5 * (trees_per_dimension[2] - 1)) * dx[2] + + for j in eachindex(nodes), i in eachindex(nodes) + tree_node_coordinates[:, i, j, itree] .= mapping_(cell_x_offset + + dx[1] * nodes[i] / 2, + cell_y_offset + + dx[2] * nodes[j] / 2) + end + elseif NDIMS == 3 + cell_x_offset = (verts[1, 1] - 0.5 * (trees_per_dimension[1] - 1)) * dx[1] + cell_y_offset = (verts[2, 1] - 0.5 * (trees_per_dimension[2] - 1)) * dx[2] + cell_z_offset = (verts[3, 1] - 0.5 * (trees_per_dimension[3] - 1)) * dx[3] + + for k in eachindex(nodes), j in eachindex(nodes), i in eachindex(nodes) + tree_node_coordinates[:, i, j, k, itree] .= mapping_(cell_x_offset + + dx[1] * nodes[i] / 2, + cell_y_offset + + dx[2] * nodes[j] / 2, + cell_z_offset + + dx[3] * nodes[k] / 2) + end end if !periodicity[1] @@ -189,6 +247,13 @@ function T8codeMesh(trees_per_dimension; polydeg, boundary_names[3, itree] = :y_neg boundary_names[4, itree] = :y_pos end + + if NDIMS > 2 + if !periodicity[3] + boundary_names[5, itree] = :z_neg + boundary_names[6, itree] = :z_pos + end + end end return T8codeMesh{NDIMS}(cmesh, scheme, forest, tree_node_coordinates, nodes, @@ -196,9 +261,9 @@ function T8codeMesh(trees_per_dimension; polydeg, end """ - T8codeMesh{NDIMS}(cmesh::Ptr{t8_cmesh}, - mapping=nothing, polydeg=1, RealT=Float64, - initial_refinement_level=0) + T8codeMesh(cmesh::Ptr{t8_cmesh}, + mapping=nothing, polydeg=1, RealT=Float64, + initial_refinement_level=0) Main mesh constructor for the `T8codeMesh` that imports an unstructured, conforming mesh from a `t8_cmesh` data structure. @@ -215,10 +280,15 @@ conforming mesh from a `t8_cmesh` data structure. - `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. """ -function T8codeMesh{NDIMS}(cmesh::Ptr{t8_cmesh}; - mapping = nothing, polydeg = 1, RealT = Float64, - initial_refinement_level = 0) where {NDIMS} - @assert NDIMS == 2 # Only support for NDIMS = 2 yet. +function T8codeMesh(cmesh::Ptr{t8_cmesh}; + mapping = nothing, polydeg = 1, RealT = Float64, + initial_refinement_level = 0) + @assert (t8_cmesh_get_num_trees(cmesh)>0) "Given `cmesh` does not contain any trees." + + # Infer NDIMS from the geometry of the first tree. + NDIMS = Int(t8_geom_get_dimension(t8_cmesh_get_tree_geometry(cmesh, 0))) + + @assert (NDIMS == 2||NDIMS == 3) "NDIMS should be 2 or 3." scheme = t8_scheme_new_default_cxx() forest = t8_forest_new_uniform(cmesh, scheme, initial_refinement_level, 0, mpi_comm()) @@ -234,34 +304,84 @@ function T8codeMesh{NDIMS}(cmesh::Ptr{t8_cmesh}; nodes_in = [-1.0, 1.0] matrix = polynomial_interpolation_matrix(nodes_in, nodes) - data_in = Array{RealT, 3}(undef, 2, 2, 2) - tmp1 = zeros(RealT, 2, length(nodes), length(nodes_in)) - for itree in 0:(num_local_trees - 1) - veptr = t8_cmesh_get_tree_vertices(cmesh, itree) - verts = unsafe_wrap(Array, veptr, (3, 1 << NDIMS)) + if NDIMS == 2 + data_in = Array{RealT, 3}(undef, 2, 2, 2) + tmp1 = zeros(RealT, 2, length(nodes), length(nodes_in)) + verts = zeros(3, 4) - u = verts[:, 2] - verts[:, 1] - v = verts[:, 3] - verts[:, 1] - w = [0.0, 0.0, 1.0] + for itree in 0:(num_local_trees - 1) + veptr = t8_cmesh_get_tree_vertices(cmesh, itree) - vol = dot(cross(u, v), w) + # Note, `verts = unsafe_wrap(Array, veptr, (3, 1 << NDIMS))` + # sometimes does not work since `veptr` is not necessarily properly + # aligned to 8 bytes. + for icorner in 1:4 + verts[1, icorner] = unsafe_load(veptr, (icorner - 1) * 3 + 1) + verts[2, icorner] = unsafe_load(veptr, (icorner - 1) * 3 + 2) + end - if vol < 0.0 - @warn "Discovered negative volumes in `cmesh`: vol = $vol" + # Check if tree's node ordering is right-handed or print a warning. + let z = zero(eltype(verts)), o = one(eltype(verts)) + u = verts[:, 2] - verts[:, 1] + v = verts[:, 3] - verts[:, 1] + w = [z, z, o] + + # Triple product gives signed volume of spanned parallelepiped. + vol = dot(cross(u, v), w) + + if vol < z + @warn "Discovered negative volumes in `cmesh`: vol = $vol" + end + end + + # Tree vertices are stored in z-order. + @views data_in[:, 1, 1] .= verts[1:2, 1] + @views data_in[:, 2, 1] .= verts[1:2, 2] + @views data_in[:, 1, 2] .= verts[1:2, 3] + @views data_in[:, 2, 2] .= verts[1:2, 4] + + # Interpolate corner coordinates to specified nodes. + multiply_dimensionwise!(view(tree_node_coordinates, :, :, :, itree + 1), + matrix, matrix, + data_in, + tmp1) end - # Tree vertices are stored in z-order. - @views data_in[:, 1, 1] .= verts[1:2, 1] - @views data_in[:, 2, 1] .= verts[1:2, 2] - @views data_in[:, 1, 2] .= verts[1:2, 3] - @views data_in[:, 2, 2] .= verts[1:2, 4] - - # Interpolate corner coordinates to specified nodes. - multiply_dimensionwise!(view(tree_node_coordinates, :, :, :, itree + 1), - matrix, matrix, - data_in, - tmp1) + elseif NDIMS == 3 + data_in = Array{RealT, 4}(undef, 3, 2, 2, 2) + tmp1 = zeros(RealT, 3, length(nodes), length(nodes_in), length(nodes_in)) + verts = zeros(3, 8) + + for itree in 0:(num_local_trees - 1) + veptr = t8_cmesh_get_tree_vertices(cmesh, itree) + + # Note, `verts = unsafe_wrap(Array, veptr, (3, 1 << NDIMS))` + # sometimes does not work since `veptr` is not necessarily properly + # aligned to 8 bytes. + for icorner in 1:8 + verts[1, icorner] = unsafe_load(veptr, (icorner - 1) * 3 + 1) + verts[2, icorner] = unsafe_load(veptr, (icorner - 1) * 3 + 2) + verts[3, icorner] = unsafe_load(veptr, (icorner - 1) * 3 + 3) + end + + # Tree vertices are stored in z-order. + @views data_in[:, 1, 1, 1] .= verts[1:3, 1] + @views data_in[:, 2, 1, 1] .= verts[1:3, 2] + @views data_in[:, 1, 2, 1] .= verts[1:3, 3] + @views data_in[:, 2, 2, 1] .= verts[1:3, 4] + + @views data_in[:, 1, 1, 2] .= verts[1:3, 5] + @views data_in[:, 2, 1, 2] .= verts[1:3, 6] + @views data_in[:, 1, 2, 2] .= verts[1:3, 7] + @views data_in[:, 2, 2, 2] .= verts[1:3, 8] + + # Interpolate corner coordinates to specified nodes. + multiply_dimensionwise!(view(tree_node_coordinates, :, :, :, :, itree + 1), + matrix, matrix, matrix, + data_in, + tmp1) + end end map_node_coordinates!(tree_node_coordinates, mapping) @@ -274,9 +394,7 @@ function T8codeMesh{NDIMS}(cmesh::Ptr{t8_cmesh}; end """ - T8codeMesh{NDIMS}(conn::Ptr{p4est_connectivity}, - mapping=nothing, polydeg=1, RealT=Float64, - initial_refinement_level=0) + T8codeMesh(conn::Ptr{p4est_connectivity}; kwargs...) Main mesh constructor for the `T8codeMesh` that imports an unstructured, conforming mesh from a `p4est_connectivity` data structure. @@ -293,24 +411,45 @@ conforming mesh from a `p4est_connectivity` data structure. - `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. """ -function T8codeMesh{NDIMS}(conn::Ptr{p4est_connectivity}; kwargs...) where {NDIMS} - @assert NDIMS == 2 # Only support for NDIMS = 2 yet. - +function T8codeMesh(conn::Ptr{p4est_connectivity}; kwargs...) cmesh = t8_cmesh_new_from_p4est(conn, mpi_comm(), 0) - return T8codeMesh{NDIMS}(cmesh; kwargs...) + return T8codeMesh(cmesh; kwargs...) +end + +""" + T8codeMesh(conn::Ptr{p8est_connectivity}; kwargs...) + +Main mesh constructor for the `T8codeMesh` that imports an unstructured, +conforming mesh from a `p4est_connectivity` data structure. + +# Arguments +- `conn::Ptr{p4est_connectivity}`: Pointer to a P4est connectivity object. +- `mapping`: a function of `NDIMS` variables to describe the mapping that transforms + the imported mesh to the physical domain. Use `nothing` for the identity map. +- `polydeg::Integer`: polynomial degree used to store the geometry of the mesh. + The mapping will be approximated by an interpolation polynomial + of the specified degree for each tree. + The default of `1` creates an uncurved geometry. Use a higher value if the mapping + will curve the imported uncurved mesh. +- `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. +""" +function T8codeMesh(conn::Ptr{p8est_connectivity}; kwargs...) + cmesh = t8_cmesh_new_from_p8est(conn, mpi_comm(), 0) + + return T8codeMesh(cmesh; kwargs...) end """ - T8codeMesh{NDIMS}(meshfile::String; - mapping=nothing, polydeg=1, RealT=Float64, - initial_refinement_level=0) + T8codeMesh{NDIMS}(meshfile::String; kwargs...) Main mesh constructor for the `T8codeMesh` that imports an unstructured, conforming mesh from a Gmsh mesh file (`.msh`). # Arguments - `meshfile::String`: path to a Gmsh mesh file. +- `ndims`: Mesh file dimension: `2` or `3`. - `mapping`: a function of `NDIMS` variables to describe the mapping that transforms the imported mesh to the physical domain. Use `nothing` for the identity map. - `polydeg::Integer`: polynomial degree used to store the geometry of the mesh. @@ -321,17 +460,130 @@ mesh from a Gmsh mesh file (`.msh`). - `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. """ -function T8codeMesh{NDIMS}(meshfile::String; kwargs...) where {NDIMS} - @assert NDIMS == 2 # Only support for NDIMS = 2 yet. +function T8codeMesh(meshfile::String, ndims; kwargs...) # Prevent `t8code` from crashing Julia if the file doesn't exist. @assert isfile(meshfile) meshfile_prefix, meshfile_suffix = splitext(meshfile) - cmesh = t8_cmesh_from_msh_file(meshfile_prefix, 0, mpi_comm(), NDIMS, 0, 0) + cmesh = t8_cmesh_from_msh_file(meshfile_prefix, 0, mpi_comm(), ndims, 0, 0) + + return T8codeMesh(cmesh; kwargs...) +end + +struct adapt_callback_passthrough + adapt_callback::Function + user_data::Any +end - return T8codeMesh{NDIMS}(cmesh; kwargs...) +# Callback function prototype to decide for refining and coarsening. +# If `is_family` equals 1, the first `num_elements` in elements +# form a family and we decide whether this family should be coarsened +# or only the first element should be refined. +# Otherwise `is_family` must equal zero and we consider the first entry +# of the element array for refinement. +# Entries of the element array beyond the first `num_elements` are undefined. +# \param [in] forest the forest to which the new elements belong +# \param [in] forest_from the forest that is adapted. +# \param [in] which_tree the local tree containing `elements` +# \param [in] lelement_id the local element id in `forest_old` in the tree of the current element +# \param [in] ts the eclass scheme of the tree +# \param [in] is_family if 1, the first `num_elements` entries in `elements` form a family. If 0, they do not. +# \param [in] num_elements the number of entries in `elements` that are defined +# \param [in] elements Pointers to a family or, if `is_family` is zero, +# pointer to one element. +# \return greater zero if the first entry in `elements` should be refined, +# smaller zero if the family `elements` shall be coarsened, +# zero else. +function adapt_callback_wrapper(forest, + forest_from, + which_tree, + lelement_id, + ts, + is_family, + num_elements, + elements_ptr)::Cint + passthrough = unsafe_pointer_to_objref(t8_forest_get_user_data(forest))[] + + elements = unsafe_wrap(Array, elements_ptr, num_elements) + + return passthrough.adapt_callback(forest_from, which_tree, ts, lelement_id, elements, + Bool(is_family), passthrough.user_data) +end + +""" + Trixi.adapt!(mesh::T8codeMesh, adapt_callback; kwargs...) + +Adapt a `T8codeMesh` according to a user-defined `adapt_callback`. + +# Arguments +- `mesh::T8codeMesh`: Initialized mesh object. +- `adapt_callback`: A user-defined callback which tells the adaption routines + if an element should be refined, coarsened or stay unchanged. + + The expected callback signature is as follows: + + `adapt_callback(forest, ltreeid, eclass_scheme, lelemntid, elements, is_family, user_data)` + # Arguments + - `forest`: Pointer to the analyzed forest. + - `ltreeid`: Local index of the current tree where the analyzed elements are part of. + - `eclass_scheme`: Element class of `elements`. + - `lelemntid`: Local index of the first element in `elements`. + - `elements`: Array of elements. If consecutive elements form a family + they are passed together, otherwise `elements` consists of just one element. + - `is_family`: Boolean signifying if `elements` represents a family or not. + - `user_data`: Void pointer to some arbitrary user data. Default value is `C_NULL`. + # Returns + -1 : Coarsen family of elements. + 0 : Stay unchanged. + 1 : Refine element. + +- `kwargs`: + - `recursive = true`: Adapt the forest recursively. If true the caller must ensure that the callback + returns 0 for every analyzed element at some point to stop the recursion. + - `balance = true`: Make sure the adapted forest is 2^(NDIMS-1):1 balanced. + - `partition = true`: Partition the forest to redistribute elements evenly among MPI ranks. + - `ghost = true`: Create a ghost layer for MPI data exchange. + - `user_data = C_NULL`: Pointer to some arbitrary user-defined data. +""" +function adapt!(mesh::T8codeMesh, adapt_callback; recursive = true, balance = true, + partition = true, ghost = true, user_data = C_NULL) + # Check that forest is a committed, that is valid and usable, forest. + @assert t8_forest_is_committed(mesh.forest) != 0 + + # Init new forest. + new_forest_ref = Ref{t8_forest_t}() + t8_forest_init(new_forest_ref) + new_forest = new_forest_ref[] + + # Check out `examples/t8_step4_partition_balance_ghost.jl` in + # https://github.com/DLR-AMR/T8code.jl for detailed explanations. + let set_from = C_NULL, set_for_coarsening = 0, no_repartition = !partition + t8_forest_set_user_data(new_forest, + pointer_from_objref(Ref(adapt_callback_passthrough(adapt_callback, + user_data)))) + t8_forest_set_adapt(new_forest, mesh.forest, + @t8_adapt_callback(adapt_callback_wrapper), + recursive) + if balance + t8_forest_set_balance(new_forest, set_from, no_repartition) + end + + if partition + t8_forest_set_partition(new_forest, set_from, set_for_coarsening) + end + + t8_forest_set_ghost(new_forest, ghost, T8_GHOST_FACES) # Note: MPI support not available yet so it is a dummy call. + + # The old forest is destroyed here. + # Call `t8_forest_ref(Ref(mesh.forest))` to keep it. + t8_forest_commit(new_forest) + end + + mesh.forest = new_forest + + return nothing end # TODO: Just a placeholder. Will be implemented later when MPI is supported. @@ -343,3 +595,10 @@ end function partition!(mesh::T8codeMesh; allow_coarsening = true, weight_fn = C_NULL) return nothing end + +#! format: off +@deprecate T8codeMesh{2}(conn::Ptr{p4est_connectivity}; kwargs...) T8codeMesh(conn::Ptr{p4est_connectivity}; kwargs...) +@deprecate T8codeMesh{3}(conn::Ptr{p8est_connectivity}; kwargs...) T8codeMesh(conn::Ptr{p8est_connectivity}; kwargs...) +@deprecate T8codeMesh{2}(meshfile::String; kwargs...) T8codeMesh(meshfile::String, 2; kwargs...) +@deprecate T8codeMesh{3}(meshfile::String; kwargs...) T8codeMesh(meshfile::String, 3; kwargs...) +#! format: on diff --git a/src/solvers/dgsem_p4est/containers_3d.jl b/src/solvers/dgsem_p4est/containers_3d.jl index e9994fe4569..7e383924ba7 100644 --- a/src/solvers/dgsem_p4est/containers_3d.jl +++ b/src/solvers/dgsem_p4est/containers_3d.jl @@ -6,7 +6,8 @@ #! format: noindent # Initialize data structures in element container -function init_elements!(elements, mesh::P4estMesh{3}, basis::LobattoLegendreBasis) +function init_elements!(elements, mesh::Union{P4estMesh{3}, T8codeMesh{3}}, + basis::LobattoLegendreBasis) @unpack node_coordinates, jacobian_matrix, contravariant_vectors, inverse_jacobian = elements @@ -26,7 +27,7 @@ end # Interpolate tree_node_coordinates to each quadrant at the nodes of the specified basis function calc_node_coordinates!(node_coordinates, - mesh::P4estMesh{3}, + mesh::Union{P4estMesh{3}, T8codeMesh{3}}, basis::LobattoLegendreBasis) # Hanging nodes will cause holes in the mesh if its polydeg is higher # than the polydeg of the solver. diff --git a/src/solvers/dgsem_p4est/dg_3d.jl b/src/solvers/dgsem_p4est/dg_3d.jl index 4c0845ba9af..5b3c5ae5ca8 100644 --- a/src/solvers/dgsem_p4est/dg_3d.jl +++ b/src/solvers/dgsem_p4est/dg_3d.jl @@ -7,8 +7,8 @@ # The methods below are specialized on the mortar type # and called from the basic `create_cache` method at the top. -function create_cache(mesh::P4estMesh{3}, equations, mortar_l2::LobattoLegendreMortarL2, - uEltype) +function create_cache(mesh::Union{P4estMesh{3}, T8codeMesh{3}}, equations, + mortar_l2::LobattoLegendreMortarL2, uEltype) # TODO: Taal compare performance of different types fstar_threaded = [Array{uEltype, 4}(undef, nvariables(equations), nnodes(mortar_l2), nnodes(mortar_l2), 4) @@ -88,7 +88,7 @@ end # We pass the `surface_integral` argument solely for dispatch function prolong2interfaces!(cache, u, - mesh::P4estMesh{3}, + mesh::Union{P4estMesh{3}, T8codeMesh{3}}, equations, surface_integral, dg::DG) @unpack interfaces = cache index_range = eachnode(dg) @@ -163,7 +163,7 @@ function prolong2interfaces!(cache, u, end function calc_interface_flux!(surface_flux_values, - mesh::P4estMesh{3}, + mesh::Union{P4estMesh{3}, T8codeMesh{3}}, nonconservative_terms, equations, surface_integral, dg::DG, cache) @unpack neighbor_ids, node_indices = cache.interfaces @@ -244,7 +244,7 @@ end # Inlined function for interface flux computation for conservative flux terms @inline function calc_interface_flux!(surface_flux_values, - mesh::P4estMesh{3}, + mesh::Union{P4estMesh{3}, T8codeMesh{3}}, nonconservative_terms::False, equations, surface_integral, dg::DG, cache, interface_index, normal_direction, @@ -271,7 +271,7 @@ end # Inlined function for interface flux computation for flux + nonconservative terms @inline function calc_interface_flux!(surface_flux_values, - mesh::P4estMesh{3}, + mesh::Union{P4estMesh{3}, T8codeMesh{3}}, nonconservative_terms::True, equations, surface_integral, dg::DG, cache, interface_index, normal_direction, @@ -314,7 +314,7 @@ end end function prolong2boundaries!(cache, u, - mesh::P4estMesh{3}, + mesh::Union{P4estMesh{3}, T8codeMesh{3}}, equations, surface_integral, dg::DG) @unpack boundaries = cache index_range = eachnode(dg) @@ -355,7 +355,7 @@ function prolong2boundaries!(cache, u, end function calc_boundary_flux!(cache, t, boundary_condition, boundary_indexing, - mesh::P4estMesh{3}, + mesh::Union{P4estMesh{3}, T8codeMesh{3}}, equations, surface_integral, dg::DG) @unpack boundaries = cache @unpack surface_flux_values, node_coordinates, contravariant_vectors = cache.elements @@ -417,7 +417,7 @@ function calc_boundary_flux!(cache, t, boundary_condition, boundary_indexing, end function prolong2mortars!(cache, u, - mesh::P4estMesh{3}, equations, + mesh::Union{P4estMesh{3}, T8codeMesh{3}}, equations, mortar_l2::LobattoLegendreMortarL2, surface_integral, dg::DGSEM) @unpack fstar_tmp_threaded = cache @@ -521,7 +521,7 @@ function prolong2mortars!(cache, u, end function calc_mortar_flux!(surface_flux_values, - mesh::P4estMesh{3}, + mesh::Union{P4estMesh{3}, T8codeMesh{3}}, nonconservative_terms, equations, mortar_l2::LobattoLegendreMortarL2, surface_integral, dg::DG, cache) @@ -595,7 +595,7 @@ end # Inlined version of the mortar flux computation on small elements for conservation fluxes @inline function calc_mortar_flux!(fstar, - mesh::P4estMesh{3}, + mesh::Union{P4estMesh{3}, T8codeMesh{3}}, nonconservative_terms::False, equations, surface_integral, dg::DG, cache, mortar_index, position_index, normal_direction, @@ -616,7 +616,7 @@ end # Inlined version of the mortar flux computation on small elements for conservation fluxes # with nonconservative terms @inline function calc_mortar_flux!(fstar, - mesh::P4estMesh{3}, + mesh::Union{P4estMesh{3}, T8codeMesh{3}}, nonconservative_terms::True, equations, surface_integral, dg::DG, cache, mortar_index, position_index, normal_direction, @@ -643,7 +643,8 @@ end end @inline function mortar_fluxes_to_elements!(surface_flux_values, - mesh::P4estMesh{3}, equations, + mesh::Union{P4estMesh{3}, T8codeMesh{3}}, + equations, mortar_l2::LobattoLegendreMortarL2, dg::DGSEM, cache, mortar, fstar, u_buffer, fstar_tmp) @@ -727,7 +728,7 @@ end end function calc_surface_integral!(du, u, - mesh::P4estMesh{3}, + mesh::Union{P4estMesh{3}, T8codeMesh{3}}, equations, surface_integral::SurfaceIntegralWeakForm, dg::DGSEM, cache) diff --git a/src/solvers/dgsem_structured/dg_3d.jl b/src/solvers/dgsem_structured/dg_3d.jl index cdb085e9008..1df9f408895 100644 --- a/src/solvers/dgsem_structured/dg_3d.jl +++ b/src/solvers/dgsem_structured/dg_3d.jl @@ -58,7 +58,8 @@ See also https://github.com/trixi-framework/Trixi.jl/issues/1671#issuecomment-17 =# @inline function weak_form_kernel!(du, u, element, - mesh::Union{StructuredMesh{3}, P4estMesh{3}}, + mesh::Union{StructuredMesh{3}, P4estMesh{3}, + T8codeMesh{3}}, nonconservative_terms::False, equations, dg::DGSEM, cache, alpha = true) # true * [some floating point value] == [exactly the same floating point value] @@ -115,7 +116,8 @@ end # the physical fluxes in each Cartesian direction @inline function flux_differencing_kernel!(du, u, element, - mesh::Union{StructuredMesh{3}, P4estMesh{3}}, + mesh::Union{StructuredMesh{3}, P4estMesh{3}, + T8codeMesh{3}}, nonconservative_terms::False, equations, volume_flux, dg::DGSEM, cache, alpha = true) # true * [some floating point value] == [exactly the same floating point value] @@ -189,7 +191,8 @@ end @inline function flux_differencing_kernel!(du, u, element, - mesh::Union{StructuredMesh{3}, P4estMesh{3}}, + mesh::Union{StructuredMesh{3}, P4estMesh{3}, + T8codeMesh{3}}, nonconservative_terms::True, equations, volume_flux, dg::DGSEM, cache, alpha = true) @unpack derivative_split = dg.basis @@ -274,7 +277,8 @@ end # [arXiv: 2008.12044v2](https://arxiv.org/pdf/2008.12044) @inline function calcflux_fv!(fstar1_L, fstar1_R, fstar2_L, fstar2_R, fstar3_L, fstar3_R, u, - mesh::Union{StructuredMesh{3}, P4estMesh{3}}, + mesh::Union{StructuredMesh{3}, P4estMesh{3}, + T8codeMesh{3}}, nonconservative_terms::False, equations, volume_flux_fv, dg::DGSEM, element, cache) @unpack contravariant_vectors = cache.elements @@ -369,7 +373,8 @@ end # # Calculate the finite volume fluxes inside curvilinear elements (**with non-conservative terms**). @inline function calcflux_fv!(fstar1_L, fstar1_R, fstar2_L, fstar2_R, fstar3_L, fstar3_R, u, - mesh::Union{StructuredMesh{3}, P4estMesh{3}}, + mesh::Union{StructuredMesh{3}, P4estMesh{3}, + T8codeMesh{3}}, nonconservative_terms::True, equations, volume_flux_fv, dg::DGSEM, element, cache) @unpack contravariant_vectors = cache.elements @@ -783,7 +788,7 @@ function calc_boundary_flux!(cache, u, t, boundary_conditions::NamedTuple, end function apply_jacobian!(du, - mesh::Union{StructuredMesh{3}, P4estMesh{3}}, + mesh::Union{StructuredMesh{3}, P4estMesh{3}, T8codeMesh{3}}, equations, dg::DG, cache) @threaded for element in eachelement(dg, cache) for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg) diff --git a/src/solvers/dgsem_t8code/containers_2d.jl b/src/solvers/dgsem_t8code/containers_2d.jl index 029e6674afb..bf77826a34b 100644 --- a/src/solvers/dgsem_t8code/containers_2d.jl +++ b/src/solvers/dgsem_t8code/containers_2d.jl @@ -1,3 +1,7 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. @muladd begin #! format: noindent @@ -27,6 +31,9 @@ function calc_node_coordinates!(node_coordinates, element = t8_forest_get_element_in_tree(mesh.forest, itree, ielement) element_level = t8_element_level(eclass_scheme, element) + # Note, `t8_quad_len` is encoded as an integer (Morton encoding) in + # relation to `t8_quad_root_len`. This line transforms the + # "integer" length to a float in relation to the unit interval [0,1]. element_length = t8_quad_len(element_level) / t8_quad_root_len element_coords = Array{Float64}(undef, 3) @@ -55,4 +62,16 @@ function calc_node_coordinates!(node_coordinates, return node_coordinates end + +function init_mortar_neighbor_ids!(mortars::P4estMortarContainer{2}, my_face, + other_face, orientation, neighbor_ielements, + mortar_id) + if orientation == 0 + mortars.neighbor_ids[1, mortar_id] = neighbor_ielements[1] + 1 + mortars.neighbor_ids[2, mortar_id] = neighbor_ielements[2] + 1 + else + mortars.neighbor_ids[1, mortar_id] = neighbor_ielements[2] + 1 + mortars.neighbor_ids[2, mortar_id] = neighbor_ielements[1] + 1 + end +end end # @muladd diff --git a/src/solvers/dgsem_t8code/containers_3d.jl b/src/solvers/dgsem_t8code/containers_3d.jl new file mode 100644 index 00000000000..f2d54ff07da --- /dev/null +++ b/src/solvers/dgsem_t8code/containers_3d.jl @@ -0,0 +1,235 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +# Interpolate tree_node_coordinates to each quadrant at the specified nodes +function calc_node_coordinates!(node_coordinates, + mesh::T8codeMesh{3}, + nodes::AbstractVector) + # We use `StrideArray`s here since these buffers are used in performance-critical + # places and the additional information passed to the compiler makes them faster + # than native `Array`s. + tmp1 = StrideArray(undef, real(mesh), + StaticInt(3), static_length(nodes), static_length(mesh.nodes), + static_length(mesh.nodes)) + matrix1 = StrideArray(undef, real(mesh), + static_length(nodes), static_length(mesh.nodes)) + matrix2 = similar(matrix1) + matrix3 = similar(matrix1) + baryweights_in = barycentric_weights(mesh.nodes) + + num_local_trees = t8_forest_get_num_local_trees(mesh.forest) + + current_index = 0 + for itree in 0:(num_local_trees - 1) + tree_class = t8_forest_get_tree_class(mesh.forest, itree) + eclass_scheme = t8_forest_get_eclass_scheme(mesh.forest, tree_class) + num_elements_in_tree = t8_forest_get_tree_num_elements(mesh.forest, itree) + + for ielement in 0:(num_elements_in_tree - 1) + element = t8_forest_get_element_in_tree(mesh.forest, itree, ielement) + element_level = t8_element_level(eclass_scheme, element) + + # Note, `t8_hex_len` is encoded as an integer (Morton encoding) in + # relation to `t8_hex_root_len`. This line transforms the + # "integer" length to a float in relation to the unit interval [0,1]. + element_length = t8_hex_len(element_level) / t8_hex_root_len + + element_coords = Vector{Float64}(undef, 3) + t8_element_vertex_reference_coords(eclass_scheme, element, 0, + pointer(element_coords)) + + nodes_out_x = (2 * + (element_length * 0.5 * (nodes .+ 1) .+ element_coords[1]) .- + 1) + nodes_out_y = (2 * + (element_length * 0.5 * (nodes .+ 1) .+ element_coords[2]) .- + 1) + nodes_out_z = (2 * + (element_length * 0.5 * (nodes .+ 1) .+ element_coords[3]) .- + 1) + + polynomial_interpolation_matrix!(matrix1, mesh.nodes, nodes_out_x, + baryweights_in) + polynomial_interpolation_matrix!(matrix2, mesh.nodes, nodes_out_y, + baryweights_in) + polynomial_interpolation_matrix!(matrix3, mesh.nodes, nodes_out_z, + baryweights_in) + + multiply_dimensionwise!(view(node_coordinates, :, :, :, :, + current_index += 1), + matrix1, matrix2, matrix3, + view(mesh.tree_node_coordinates, :, :, :, :, + itree + 1), + tmp1) + end + end + + return node_coordinates +end + +# This routine was copied and adapted from `src/dgsem_p4est/containers_3d.jl`: `orientation_to_indices_p4est`. +function init_mortar_neighbor_ids!(mortars::P4estMortarContainer{3}, my_face, + other_face, orientation, neighbor_ielements, + mortar_id) + # my_face and other_face are the face directions (zero-based) + # of "my side" and "other side" respectively. + # Face corner 0 of the face with the lower face direction connects to a corner of the other face. + # The number of this corner is the orientation code in `p4est`. + lower = my_face <= other_face + + # x_pos, y_neg, and z_pos are the directions in which the face has right-handed coordinates + # when looked at from the outside. + my_right_handed = my_face in (1, 2, 5) + other_right_handed = other_face in (1, 2, 5) + + # If both or none are right-handed when looked at from the outside, they will have different + # orientations when looked at from the same side of the interface. + flipped = my_right_handed == other_right_handed + + # In the following illustrations, the face corner numbering of `p4est` is shown. + # ξ and η are the local coordinates of the respective face. + # We're looking at both faces from the same side of the interface, so that "other side" + # (in the illustrations on the left) has right-handed coordinates. + if !flipped + if orientation == 0 + # Corner 0 of other side matches corner 0 of my side + # 2┌──────┐3 2┌──────┐3 + # │ │ │ │ + # │ │ │ │ + # 0└──────┘1 0└──────┘1 + # η η + # ↑ ↑ + # │ │ + # └───> ξ └───> ξ + + mortars.neighbor_ids[1, mortar_id] = neighbor_ielements[1] + 1 + mortars.neighbor_ids[2, mortar_id] = neighbor_ielements[2] + 1 + mortars.neighbor_ids[3, mortar_id] = neighbor_ielements[3] + 1 + mortars.neighbor_ids[4, mortar_id] = neighbor_ielements[4] + 1 + + elseif ((lower && orientation == 2) # Corner 0 of my side matches corner 2 of other side + || + (!lower && orientation == 1)) # Corner 0 of other side matches corner 1 of my side + # 2┌──────┐3 0┌──────┐2 + # │ │ │ │ + # │ │ │ │ + # 0└──────┘1 1└──────┘3 + # η ┌───> η + # ↑ │ + # │ ↓ + # └───> ξ ξ + + mortars.neighbor_ids[1, mortar_id] = neighbor_ielements[2] + 1 + mortars.neighbor_ids[2, mortar_id] = neighbor_ielements[4] + 1 + mortars.neighbor_ids[3, mortar_id] = neighbor_ielements[1] + 1 + mortars.neighbor_ids[4, mortar_id] = neighbor_ielements[3] + 1 + + elseif ((lower && orientation == 1) # Corner 0 of my side matches corner 1 of other side + || + (!lower && orientation == 2)) # Corner 0 of other side matches corner 2 of my side + # 2┌──────┐3 3┌──────┐1 + # │ │ │ │ + # │ │ │ │ + # 0└──────┘1 2└──────┘0 + # η ξ + # ↑ ↑ + # │ │ + # └───> ξ η <───┘ + + mortars.neighbor_ids[1, mortar_id] = neighbor_ielements[3] + 1 + mortars.neighbor_ids[2, mortar_id] = neighbor_ielements[1] + 1 + mortars.neighbor_ids[3, mortar_id] = neighbor_ielements[4] + 1 + mortars.neighbor_ids[4, mortar_id] = neighbor_ielements[2] + 1 + + else # orientation == 3 + # Corner 0 of my side matches corner 3 of other side and + # corner 0 of other side matches corner 3 of my side. + # 2┌──────┐3 1┌──────┐0 + # │ │ │ │ + # │ │ │ │ + # 0└──────┘1 3└──────┘2 + # η ξ <───┐ + # ↑ │ + # │ ↓ + # └───> ξ η + + mortars.neighbor_ids[1, mortar_id] = neighbor_ielements[4] + 1 + mortars.neighbor_ids[2, mortar_id] = neighbor_ielements[3] + 1 + mortars.neighbor_ids[3, mortar_id] = neighbor_ielements[2] + 1 + mortars.neighbor_ids[4, mortar_id] = neighbor_ielements[1] + 1 + end + else # flipped + if orientation == 0 + # Corner 0 of other side matches corner 0 of my side + # 2┌──────┐3 1┌──────┐3 + # │ │ │ │ + # │ │ │ │ + # 0└──────┘1 0└──────┘2 + # η ξ + # ↑ ↑ + # │ │ + # └───> ξ └───> η + + mortars.neighbor_ids[1, mortar_id] = neighbor_ielements[1] + 1 + mortars.neighbor_ids[2, mortar_id] = neighbor_ielements[3] + 1 + mortars.neighbor_ids[3, mortar_id] = neighbor_ielements[2] + 1 + mortars.neighbor_ids[4, mortar_id] = neighbor_ielements[4] + 1 + + elseif orientation == 2 + # Corner 0 of my side matches corner 2 of other side and + # corner 0 of other side matches corner 2 of my side. + # 2┌──────┐3 0┌──────┐1 + # │ │ │ │ + # │ │ │ │ + # 0└──────┘1 2└──────┘3 + # η ┌───> ξ + # ↑ │ + # │ ↓ + # └───> ξ η + + mortars.neighbor_ids[1, mortar_id] = neighbor_ielements[3] + 1 + mortars.neighbor_ids[2, mortar_id] = neighbor_ielements[4] + 1 + mortars.neighbor_ids[3, mortar_id] = neighbor_ielements[1] + 1 + mortars.neighbor_ids[4, mortar_id] = neighbor_ielements[2] + 1 + + elseif orientation == 1 + # Corner 0 of my side matches corner 1 of other side and + # corner 0 of other side matches corner 1 of my side. + # 2┌──────┐3 3┌──────┐2 + # │ │ │ │ + # │ │ │ │ + # 0└──────┘1 1└──────┘0 + # η η + # ↑ ↑ + # │ │ + # └───> ξ ξ <───┘ + + mortars.neighbor_ids[1, mortar_id] = neighbor_ielements[2] + 1 + mortars.neighbor_ids[2, mortar_id] = neighbor_ielements[1] + 1 + mortars.neighbor_ids[3, mortar_id] = neighbor_ielements[4] + 1 + mortars.neighbor_ids[4, mortar_id] = neighbor_ielements[3] + 1 + + else # orientation == 3 + # Corner 0 of my side matches corner 3 of other side and + # corner 0 of other side matches corner 3 of my side. + # 2┌──────┐3 2┌──────┐0 + # │ │ │ │ + # │ │ │ │ + # 0└──────┘1 3└──────┘1 + # η η <───┐ + # ↑ │ + # │ ↓ + # └───> ξ ξ + + mortars.neighbor_ids[1, mortar_id] = neighbor_ielements[4] + 1 + mortars.neighbor_ids[2, mortar_id] = neighbor_ielements[2] + 1 + mortars.neighbor_ids[3, mortar_id] = neighbor_ielements[3] + 1 + mortars.neighbor_ids[4, mortar_id] = neighbor_ielements[1] + 1 + end + end +end +end # @muladd diff --git a/src/solvers/dgsem_t8code/dg.jl b/src/solvers/dgsem_t8code/dg.jl index 16a9d7d35b1..6e9660c917d 100644 --- a/src/solvers/dgsem_t8code/dg.jl +++ b/src/solvers/dgsem_t8code/dg.jl @@ -28,4 +28,5 @@ end include("containers.jl") include("containers_2d.jl") +include("containers_3d.jl") end # @muladd diff --git a/src/solvers/dgsem_tree/dg_3d.jl b/src/solvers/dgsem_tree/dg_3d.jl index 0955dc38655..02ff338e912 100644 --- a/src/solvers/dgsem_tree/dg_3d.jl +++ b/src/solvers/dgsem_tree/dg_3d.jl @@ -36,13 +36,15 @@ end # The methods below are specialized on the volume integral type # and called from the basic `create_cache` method at the top. -function create_cache(mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3}}, +function create_cache(mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3}, + T8codeMesh{3}}, equations, volume_integral::VolumeIntegralFluxDifferencing, dg::DG, uEltype) NamedTuple() end -function create_cache(mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3}}, +function create_cache(mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3}, + T8codeMesh{3}}, equations, volume_integral::VolumeIntegralShockCapturingHG, dg::DG, uEltype) element_ids_dg = Int[] @@ -79,8 +81,8 @@ function create_cache(mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3}}, fstar2_L_threaded, fstar2_R_threaded, fstar3_L_threaded, fstar3_R_threaded) end -function create_cache(mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3}}, - equations, +function create_cache(mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3}, + T8codeMesh{3}}, equations, volume_integral::VolumeIntegralPureLGLFiniteVolume, dg::DG, uEltype) A4dp1_x = Array{uEltype, 4} @@ -112,7 +114,8 @@ end # The methods below are specialized on the mortar type # and called from the basic `create_cache` method at the top. -function create_cache(mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3}}, +function create_cache(mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3}, + T8codeMesh{3}}, equations, mortar_l2::LobattoLegendreMortarL2, uEltype) # TODO: Taal compare performance of different types A3d = Array{uEltype, 3} @@ -140,7 +143,7 @@ end # TODO: Taal discuss/refactor timer, allowing users to pass a custom timer? function rhs!(du, u, t, - mesh::Union{TreeMesh{3}, P4estMesh{3}}, equations, + mesh::Union{TreeMesh{3}, P4estMesh{3}, T8codeMesh{3}}, equations, initial_condition, boundary_conditions, source_terms::Source, dg::DG, cache) where {Source} # Reset du @@ -209,8 +212,8 @@ function rhs!(du, u, t, end function calc_volume_integral!(du, u, - mesh::Union{TreeMesh{3}, StructuredMesh{3}, - P4estMesh{3}}, + mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3}, + T8codeMesh{3}}, nonconservative_terms, equations, volume_integral::VolumeIntegralWeakForm, dg::DGSEM, cache) @@ -264,8 +267,8 @@ See also https://github.com/trixi-framework/Trixi.jl/issues/1671#issuecomment-17 end function calc_volume_integral!(du, u, - mesh::Union{TreeMesh{3}, StructuredMesh{3}, - P4estMesh{3}}, + mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3}, + T8codeMesh{3}}, nonconservative_terms, equations, volume_integral::VolumeIntegralFluxDifferencing, dg::DGSEM, cache) @@ -378,8 +381,8 @@ end # TODO: Taal dimension agnostic function calc_volume_integral!(du, u, - mesh::Union{TreeMesh{3}, StructuredMesh{3}, - P4estMesh{3}}, + mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3}, + T8codeMesh{3}}, nonconservative_terms, equations, volume_integral::VolumeIntegralShockCapturingHG, dg::DGSEM, cache) @@ -437,7 +440,8 @@ function calc_volume_integral!(du, u, end @inline function fv_kernel!(du, u, - mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3}}, + mesh::Union{TreeMesh{3}, StructuredMesh{3}, P4estMesh{3}, + T8codeMesh{3}}, nonconservative_terms, equations, volume_flux_fv, dg::DGSEM, cache, element, alpha = true) @unpack fstar1_L_threaded, fstar1_R_threaded, fstar2_L_threaded, fstar2_R_threaded, fstar3_L_threaded, fstar3_R_threaded = cache diff --git a/src/solvers/dgsem_tree/indicators_3d.jl b/src/solvers/dgsem_tree/indicators_3d.jl index 40362889397..a11a8e06e4b 100644 --- a/src/solvers/dgsem_tree/indicators_3d.jl +++ b/src/solvers/dgsem_tree/indicators_3d.jl @@ -101,7 +101,8 @@ end alpha[element] = min(alpha_max, alpha_element) end -function apply_smoothing!(mesh::Union{TreeMesh{3}, P4estMesh{3}}, alpha, alpha_tmp, dg, +function apply_smoothing!(mesh::Union{TreeMesh{3}, P4estMesh{3}, T8codeMesh{3}}, alpha, + alpha_tmp, dg, cache) # Diffuse alpha values by setting each alpha to at least 50% of neighboring elements' alpha diff --git a/test/runtests.jl b/test/runtests.jl index 7e195fe7402..49f0977bb70 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -89,6 +89,10 @@ const TRIXI_NTHREADS = clamp(Sys.CPU_THREADS, 2, 3) include("test_t8code_2d.jl") end + @time if TRIXI_TEST == "all" || TRIXI_TEST == "t8code_part2" + include("test_t8code_3d.jl") + end + @time if TRIXI_TEST == "all" || TRIXI_TEST == "unstructured_dgmulti" include("test_unstructured_2d.jl") include("test_dgmulti_1d.jl") diff --git a/test/test_t8code_2d.jl b/test/test_t8code_2d.jl index b3e19471323..ab95e068d02 100644 --- a/test/test_t8code_2d.jl +++ b/test/test_t8code_2d.jl @@ -30,7 +30,21 @@ mkdir(outdir) end end +@trixi_testset "test check_for_negative_volumes" begin + @test_warn "Discovered negative volumes" begin + # Unstructured mesh with six cells which have left-handed node ordering. + mesh_file = joinpath(EXAMPLES_DIR, "rectangle_with_negative_volumes.msh") + isfile(mesh_file) || + download("https://gist.githubusercontent.com/jmark/bfe0d45f8e369298d6cc637733819013/raw/cecf86edecc736e8b3e06e354c494b2052d41f7a/rectangle_with_negative_volumes.msh", + mesh_file) + + # This call should throw a warning about negative volumes detected. + mesh = T8codeMesh(mesh_file, 2) + end +end + @trixi_testset "elixir_advection_basic.jl" begin + # This test is identical to the one in `test_p4est_2d.jl`. @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), # Expected errors are exactly the same as with TreeMesh! l2=[8.311947673061856e-6], @@ -46,6 +60,7 @@ end end @trixi_testset "elixir_advection_nonconforming_flag.jl" begin + # This test is identical to the one in `test_p4est_2d.jl`. @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_nonconforming_flag.jl"), l2=[3.198940059144588e-5], @@ -61,6 +76,7 @@ end end @trixi_testset "elixir_advection_unstructured_flag.jl" begin + # This test is identical to the one in `test_p4est_2d.jl`. @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_unstructured_flag.jl"), l2=[0.0005379687442422346], linf=[0.007438525029884735]) @@ -91,6 +107,7 @@ end end @trixi_testset "elixir_advection_amr_solution_independent.jl" begin + # This test is identical to the one in `test_p4est_2d.jl`. @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_solution_independent.jl"), # Expected errors are exactly the same as with StructuredMesh! @@ -108,6 +125,7 @@ end end @trixi_testset "elixir_euler_source_terms_nonconforming_unstructured_flag.jl" begin + # This test is identical to the one in `test_p4est_2d.jl`. @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), l2=[ @@ -133,6 +151,7 @@ end end @trixi_testset "elixir_euler_free_stream.jl" begin + # This test is identical to the one in `test_p4est_2d.jl`. @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_free_stream.jl"), l2=[ 2.063350241405049e-15, @@ -153,6 +172,7 @@ end end @trixi_testset "elixir_euler_shockcapturing_ec.jl" begin + # This test is identical to the one in `test_p4est_2d.jl`. @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing_ec.jl"), l2=[ 9.53984675e-02, @@ -178,6 +198,8 @@ end end @trixi_testset "elixir_euler_sedov.jl" begin + # 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_euler_sedov.jl"), l2=[ 3.76149952e-01, @@ -203,6 +225,7 @@ end end @trixi_testset "elixir_shallowwater_source_terms.jl" begin + # This test is identical to the one in `test_p4est_2d.jl`. @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_shallowwater_source_terms.jl"), l2=[ 9.168126407325352e-5, @@ -228,6 +251,7 @@ end end @trixi_testset "elixir_mhd_alfven_wave.jl" begin + # This test is identical to the one in `test_p4est_2d.jl`. @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave.jl"), l2=[1.0513414461545583e-5, 1.0517900957166411e-6, 1.0517900957304043e-6, 1.511816606372376e-6, @@ -250,6 +274,8 @@ end end @trixi_testset "elixir_mhd_rotor.jl" begin + # 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, 0.0, diff --git a/test/test_t8code_3d.jl b/test/test_t8code_3d.jl new file mode 100644 index 00000000000..4232cf04094 --- /dev/null +++ b/test/test_t8code_3d.jl @@ -0,0 +1,279 @@ +module TestExamplesT8codeMesh3D + +using Test +using Trixi + +include("test_trixi.jl") + +EXAMPLES_DIR = joinpath(examples_dir(), "t8code_3d_dgsem") + +# Start with a clean environment: remove Trixi.jl output directory if it exists +outdir = "out" +isdir(outdir) && rm(outdir, recursive = true) +mkdir(outdir) + +@testset "T8codeMesh3D" begin + # This test is identical to the one in `test_p4est_3d.jl`. + @trixi_testset "elixir_advection_basic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), + # Expected errors are exactly the same as with TreeMesh! + l2=[0.00016263963870641478], + linf=[0.0014537194925779984]) + # 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 + + # This test is identical to the one in `test_p4est_3d.jl`. + @trixi_testset "elixir_advection_unstructured_curved.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_unstructured_curved.jl"), + l2=[0.0004750004258546538], + linf=[0.026527551737137167]) + # 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 + + # This test is identical to the one in `test_p4est_3d.jl`. + @trixi_testset "elixir_advection_nonconforming.jl" begin + @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 + # (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 + + # This test is identical to the one in `test_p4est_3d.jl` besides minor + # deviations from the expected error norms. + @trixi_testset "elixir_advection_amr.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr.jl"), + # Expected errors are exactly the same as with TreeMesh! + l2=[1.1302812803902801e-5], + 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 + # (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 + + # This test is identical to the one in `test_p4est_3d.jl` besides minor + # deviations from the expected error norms. + @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], + 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 + # (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 + + # This test is identical to the one in `test_p4est_3d.jl`. + @trixi_testset "elixir_euler_source_terms_nonconforming_unstructured_curved.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonconforming_unstructured_curved.jl"), + l2=[ + 4.070355207909268e-5, + 4.4993257426833716e-5, + 5.10588457841744e-5, + 5.102840924036687e-5, + 0.00019986264001630542, + ], + linf=[ + 0.0016987332417202072, + 0.003622956808262634, + 0.002029576258317789, + 0.0024206977281964193, + 0.008526972236273522, + ], + tspan=(0.0, 0.01)) + # 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 + + # This test is identical to the one in `test_p4est_3d.jl`. + @trixi_testset "elixir_euler_source_terms_nonperiodic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonperiodic.jl"), + l2=[ + 0.0015106060984283647, + 0.0014733349038567685, + 0.00147333490385685, + 0.001473334903856929, + 0.0028149479453087093, + ], + linf=[ + 0.008070806335238156, + 0.009007245083113125, + 0.009007245083121784, + 0.009007245083102688, + 0.01562861968368434, + ], + tspan=(0.0, 1.0)) + # 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 + + # This test is identical to the one in `test_p4est_3d.jl`. + @trixi_testset "elixir_euler_free_stream.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_free_stream.jl"), + l2=[ + 5.162664597942288e-15, + 1.941857343642486e-14, + 2.0232366394187278e-14, + 2.3381518645408552e-14, + 7.083114561232324e-14, + ], + linf=[ + 7.269740365245525e-13, + 3.289868377720495e-12, + 4.440087186807773e-12, + 3.8686831516088205e-12, + 9.412914891981927e-12, + ], + tspan=(0.0, 0.03)) + # 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 + + # This test is identical to the one in `test_p4est_3d.jl`. + @trixi_testset "elixir_euler_free_stream_extruded.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_free_stream_extruded.jl"), + l2=[ + 8.444868392439035e-16, + 4.889826056731442e-15, + 2.2921260987087585e-15, + 4.268460455702414e-15, + 1.1356712092620279e-14, + ], + linf=[ + 7.749356711883593e-14, + 2.8792246364872653e-13, + 1.1121659149182506e-13, + 3.3228975127030935e-13, + 9.592326932761353e-13, + ], + tspan=(0.0, 0.1)) + # 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 + + # This test is identical to the one in `test_p4est_3d.jl`. + @trixi_testset "elixir_euler_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), + l2=[ + 0.010380390326164493, + 0.006192950051354618, + 0.005970674274073704, + 0.005965831290564327, + 0.02628875593094754, + ], + linf=[ + 0.3326911600075694, + 0.2824952141320467, + 0.41401037398065543, + 0.45574161423218573, + 0.8099577682187109, + ], + tspan=(0.0, 0.2), + coverage_override=(polydeg = 3,)) # Prevent long compile time in CI + # 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 + + # This test is identical to the one in `test_p4est_3d.jl` besides minor + # deviations in the expected error norms. + @trixi_testset "elixir_euler_sedov.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov.jl"), + l2=[ + 7.82070951e-02, + 4.33260474e-02, + 4.33260474e-02, + 4.33260474e-02, + 3.75260911e-01, + ], + linf=[ + 7.45329845e-01, + 3.21754792e-01, + 3.21754792e-01, + 3.21754792e-01, + 4.76151527e+00, + ], + tspan=(0.0, 0.3), + coverage_override=(polydeg = 3,)) # Prevent long compile time in CI + # 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 +@test_nowarn rm(outdir, recursive = true) + +end # module From 43dac2c68f255d2e1aa209da4b441fc9f4bae6ac Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Mon, 22 Jan 2024 17:33:19 +0100 Subject: [PATCH 225/263] Remove duplicate code (`rhs_parabolic!`) for 2D, 3D (#1810) * Remove duplicate code * comment --- src/solvers/dgsem_p4est/dg_2d_parabolic.jl | 26 ++++- src/solvers/dgsem_p4est/dg_3d_parabolic.jl | 112 --------------------- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 2 +- src/solvers/dgsem_tree/dg_3d_parabolic.jl | 108 -------------------- 4 files changed, 24 insertions(+), 224 deletions(-) diff --git a/src/solvers/dgsem_p4est/dg_2d_parabolic.jl b/src/solvers/dgsem_p4est/dg_2d_parabolic.jl index a7f3345168f..299f2f6140a 100644 --- a/src/solvers/dgsem_p4est/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_p4est/dg_2d_parabolic.jl @@ -19,9 +19,29 @@ function create_cache_parabolic(mesh::P4estMesh{2}, equations_hyperbolic::Abstra return cache end -# TODO: Remove in favor of the implementation for the TreeMesh -# once the P4estMesh can handle mortars as well -function rhs_parabolic!(du, u, t, mesh::P4estMesh{2}, +#= +Reusing `rhs_parabolic!` for `TreeMesh`es is not easily possible as +for `P4estMesh`es we call + + ``` + prolong2mortars_divergence!(cache, flux_viscous, mesh, equations_parabolic, + dg.mortar, dg.surface_integral, dg) + + calc_mortar_flux_divergence!(cache_parabolic.elements.surface_flux_values, + mesh, equations_parabolic, dg.mortar, + dg.surface_integral, dg, cache) + ``` +instead of + ``` + prolong2mortars!(cache, flux_viscous, mesh, equations_parabolic, + dg.mortar, dg.surface_integral, dg) + + calc_mortar_flux!(cache_parabolic.elements.surface_flux_values, mesh, + equations_parabolic, + dg.mortar, dg.surface_integral, dg, cache) + ``` +=# +function rhs_parabolic!(du, u, t, mesh::Union{P4estMesh{2}, P4estMesh{3}}, equations_parabolic::AbstractEquationsParabolic, initial_condition, boundary_conditions_parabolic, source_terms, dg::DG, parabolic_scheme, cache, cache_parabolic) diff --git a/src/solvers/dgsem_p4est/dg_3d_parabolic.jl b/src/solvers/dgsem_p4est/dg_3d_parabolic.jl index 0bb97c7af02..83d663809a7 100644 --- a/src/solvers/dgsem_p4est/dg_3d_parabolic.jl +++ b/src/solvers/dgsem_p4est/dg_3d_parabolic.jl @@ -19,118 +19,6 @@ function create_cache_parabolic(mesh::P4estMesh{3}, equations_hyperbolic::Abstra return cache end -# This file collects all methods that have been updated to work with parabolic systems of equations -# -# assumptions: parabolic terms are of the form div(f(u, grad(u))) and -# will be discretized first order form as follows: -# 1. compute grad(u) -# 2. compute f(u, grad(u)) -# 3. compute div(f(u, grad(u))) (i.e., the "regular" rhs! call) -# boundary conditions will be applied to both grad(u) and div(f(u, grad(u))). -# TODO: Remove in favor of the implementation for the TreeMesh -# once the P4estMesh can handle mortars as well -function rhs_parabolic!(du, u, t, mesh::P4estMesh{3}, - equations_parabolic::AbstractEquationsParabolic, - initial_condition, boundary_conditions_parabolic, source_terms, - dg::DG, parabolic_scheme, cache, cache_parabolic) - @unpack viscous_container = cache_parabolic - @unpack u_transformed, gradients, flux_viscous = viscous_container - - # Convert conservative variables to a form more suitable for viscous flux calculations - @trixi_timeit timer() "transform variables" begin - transform_variables!(u_transformed, u, mesh, equations_parabolic, - dg, parabolic_scheme, cache, cache_parabolic) - end - - # Compute the gradients of the transformed variables - @trixi_timeit timer() "calculate gradient" begin - calc_gradient!(gradients, u_transformed, t, mesh, equations_parabolic, - boundary_conditions_parabolic, dg, cache, cache_parabolic) - end - - # Compute and store the viscous fluxes - @trixi_timeit timer() "calculate viscous fluxes" begin - calc_viscous_fluxes!(flux_viscous, gradients, u_transformed, mesh, - equations_parabolic, dg, cache, cache_parabolic) - end - - # The remainder of this function is essentially a regular rhs! for parabolic - # equations (i.e., it computes the divergence of the viscous fluxes) - # - # OBS! In `calc_viscous_fluxes!`, the viscous flux values at the volume nodes of each element have - # been computed and stored in `fluxes_viscous`. In the following, we *reuse* (abuse) the - # `interfaces` and `boundaries` containers in `cache_parabolic` to interpolate and store the - # *fluxes* at the element surfaces, as opposed to interpolating and storing the *solution* (as it - # is done in the hyperbolic operator). That is, `interfaces.u`/`boundaries.u` store *viscous flux values* - # and *not the solution*. The advantage is that a) we do not need to allocate more storage, b) we - # do not need to recreate the existing data structure only with a different name, and c) we do not - # need to interpolate solutions *and* gradients to the surfaces. - - # TODO: parabolic; reconsider current data structure reuse strategy - - # Reset du - @trixi_timeit timer() "reset ∂u/∂t" reset_du!(du, dg, cache) - - # Calculate volume integral - @trixi_timeit timer() "volume integral" begin - calc_volume_integral!(du, flux_viscous, mesh, equations_parabolic, dg, cache) - end - - # Prolong solution to interfaces - @trixi_timeit timer() "prolong2interfaces" begin - prolong2interfaces!(cache_parabolic, flux_viscous, mesh, equations_parabolic, - dg.surface_integral, dg, cache) - end - - # Calculate interface fluxes - @trixi_timeit timer() "interface flux" begin - calc_interface_flux!(cache_parabolic.elements.surface_flux_values, mesh, - equations_parabolic, dg, cache_parabolic) - end - - # Prolong solution to boundaries - @trixi_timeit timer() "prolong2boundaries" begin - prolong2boundaries!(cache_parabolic, flux_viscous, mesh, equations_parabolic, - dg.surface_integral, dg, cache) - end - - # Calculate boundary fluxes - @trixi_timeit timer() "boundary flux" begin - calc_boundary_flux_divergence!(cache_parabolic, t, - boundary_conditions_parabolic, - mesh, equations_parabolic, - dg.surface_integral, dg) - end - - # Prolong solution to mortars (specialized for AbstractEquationsParabolic) - # !!! NOTE: we reuse the hyperbolic cache here since it contains "mortars" and "u_threaded" - # !!! Is this OK? - @trixi_timeit timer() "prolong2mortars" begin - prolong2mortars_divergence!(cache, flux_viscous, mesh, equations_parabolic, - dg.mortar, dg.surface_integral, dg) - end - - # Calculate mortar fluxes (specialized for AbstractEquationsParabolic) - @trixi_timeit timer() "mortar flux" begin - calc_mortar_flux_divergence!(cache_parabolic.elements.surface_flux_values, - mesh, equations_parabolic, dg.mortar, - dg.surface_integral, dg, cache) - end - - # Calculate surface integrals - @trixi_timeit timer() "surface integral" begin - calc_surface_integral!(du, u, mesh, equations_parabolic, - dg.surface_integral, dg, cache_parabolic) - end - - # Apply Jacobian from mapping to reference element - @trixi_timeit timer() "Jacobian" begin - apply_jacobian_parabolic!(du, mesh, equations_parabolic, dg, cache_parabolic) - end - - return nothing -end - function calc_gradient!(gradients, u_transformed, t, mesh::P4estMesh{3}, equations_parabolic, boundary_conditions_parabolic, dg::DG, diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 3083ae30680..b1c27343999 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -13,7 +13,7 @@ # 2. compute f(u, grad(u)) # 3. compute div(f(u, grad(u))) (i.e., the "regular" rhs! call) # boundary conditions will be applied to both grad(u) and div(f(u, grad(u))). -function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, +function rhs_parabolic!(du, u, t, mesh::Union{TreeMesh{2}, TreeMesh{3}}, equations_parabolic::AbstractEquationsParabolic, initial_condition, boundary_conditions_parabolic, source_terms, dg::DG, parabolic_scheme, cache, cache_parabolic) diff --git a/src/solvers/dgsem_tree/dg_3d_parabolic.jl b/src/solvers/dgsem_tree/dg_3d_parabolic.jl index 9ad28c6aa8e..ee0e7c6b069 100644 --- a/src/solvers/dgsem_tree/dg_3d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_3d_parabolic.jl @@ -5,114 +5,6 @@ @muladd begin #! format: noindent -# This file collects all methods that have been updated to work with parabolic systems of equations -# -# assumptions: parabolic terms are of the form div(f(u, grad(u))) and -# will be discretized first order form as follows: -# 1. compute grad(u) -# 2. compute f(u, grad(u)) -# 3. compute div(f(u, grad(u))) (i.e., the "regular" rhs! call) -# boundary conditions will be applied to both grad(u) and div(f(u, grad(u))). -function rhs_parabolic!(du, u, t, mesh::TreeMesh{3}, - equations_parabolic::AbstractEquationsParabolic, - initial_condition, boundary_conditions_parabolic, source_terms, - dg::DG, parabolic_scheme, cache, cache_parabolic) - @unpack viscous_container = cache_parabolic - @unpack u_transformed, gradients, flux_viscous = viscous_container - - # Convert conservative variables to a form more suitable for viscous flux calculations - @trixi_timeit timer() "transform variables" begin - transform_variables!(u_transformed, u, mesh, equations_parabolic, - dg, parabolic_scheme, cache, cache_parabolic) - end - - # Compute the gradients of the transformed variables - @trixi_timeit timer() "calculate gradient" begin - calc_gradient!(gradients, u_transformed, t, mesh, equations_parabolic, - boundary_conditions_parabolic, dg, cache, cache_parabolic) - end - - # Compute and store the viscous fluxes - @trixi_timeit timer() "calculate viscous fluxes" begin - calc_viscous_fluxes!(flux_viscous, gradients, u_transformed, mesh, - equations_parabolic, dg, cache, cache_parabolic) - end - - # The remainder of this function is essentially a regular rhs! for parabolic - # equations (i.e., it computes the divergence of the viscous fluxes) - # - # OBS! In `calc_viscous_fluxes!`, the viscous flux values at the volume nodes of each element have - # been computed and stored in `fluxes_viscous`. In the following, we *reuse* (abuse) the - # `interfaces` and `boundaries` containers in `cache_parabolic` to interpolate and store the - # *fluxes* at the element surfaces, as opposed to interpolating and storing the *solution* (as it - # is done in the hyperbolic operator). That is, `interfaces.u`/`boundaries.u` store *viscous flux values* - # and *not the solution*. The advantage is that a) we do not need to allocate more storage, b) we - # do not need to recreate the existing data structure only with a different name, and c) we do not - # need to interpolate solutions *and* gradients to the surfaces. - - # TODO: parabolic; reconsider current data structure reuse strategy - - # Reset du - @trixi_timeit timer() "reset ∂u/∂t" reset_du!(du, dg, cache) - - # Calculate volume integral - @trixi_timeit timer() "volume integral" begin - calc_volume_integral!(du, flux_viscous, mesh, equations_parabolic, dg, cache) - end - - # Prolong solution to interfaces - @trixi_timeit timer() "prolong2interfaces" begin - prolong2interfaces!(cache_parabolic, flux_viscous, mesh, equations_parabolic, - dg.surface_integral, dg, cache) - end - - # Calculate interface fluxes - @trixi_timeit timer() "interface flux" begin - calc_interface_flux!(cache_parabolic.elements.surface_flux_values, mesh, - equations_parabolic, dg, cache_parabolic) - end - - # Prolong solution to boundaries - @trixi_timeit timer() "prolong2boundaries" begin - prolong2boundaries!(cache_parabolic, flux_viscous, mesh, equations_parabolic, - dg.surface_integral, dg, cache) - end - - # Calculate boundary fluxes - @trixi_timeit timer() "boundary flux" begin - calc_boundary_flux_divergence!(cache_parabolic, t, - boundary_conditions_parabolic, - mesh, equations_parabolic, - dg.surface_integral, dg) - end - - # Prolong solution to mortars - @trixi_timeit timer() "prolong2mortars" begin - prolong2mortars!(cache, flux_viscous, mesh, equations_parabolic, - dg.mortar, dg.surface_integral, dg) - end - - # Calculate mortar fluxes - @trixi_timeit timer() "mortar flux" begin - calc_mortar_flux!(cache_parabolic.elements.surface_flux_values, mesh, - equations_parabolic, - dg.mortar, dg.surface_integral, dg, cache) - end - - # Calculate surface integrals - @trixi_timeit timer() "surface integral" begin - calc_surface_integral!(du, u, mesh, equations_parabolic, - dg.surface_integral, dg, cache_parabolic) - end - - # Apply Jacobian from mapping to reference element - @trixi_timeit timer() "Jacobian" begin - apply_jacobian_parabolic!(du, mesh, equations_parabolic, dg, cache_parabolic) - end - - return nothing -end - # Transform solution variables prior to taking the gradient # (e.g., conservative to primitive variables). Defaults to doing nothing. # TODO: can we avoid copying data? From ba812be5ae6fb7170a85b9207253c8c89168ea76 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Tue, 23 Jan 2024 16:04:58 +0100 Subject: [PATCH 226/263] Add Link to Paper for Weakly Enforced BCs to Docs (#1811) * Add Paper for Weakly Enforced BCs to Docs * spelling --- docs/literate/src/files/non_periodic_boundaries.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/literate/src/files/non_periodic_boundaries.jl b/docs/literate/src/files/non_periodic_boundaries.jl index 7ed6324ff99..3b238ad4533 100644 --- a/docs/literate/src/files/non_periodic_boundaries.jl +++ b/docs/literate/src/files/non_periodic_boundaries.jl @@ -16,6 +16,8 @@ # state as arguments, and solves an approximate Riemann problem to introduce dissipation (and # hence stabilization) at the boundary. Hence, the performance of the Dirichlet BC depends on the # fidelity of the numerical surface flux. +# An easy-to read introductory reference on this topic is the paper by +# [Mengaldo et al.](https://doi.org/10.2514/6.2014-2923). # The passed boundary value function is called with the same arguments as an initial condition # function, i.e. From 585fb93cfba5712401fee00d06aeeedf8db5fe7e Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Thu, 25 Jan 2024 10:13:00 +0100 Subject: [PATCH 227/263] Different Boundary Conditions for Standard Abaqus (#1799) * first take on BCs for standard Abaqus * simplify * Couple comments, example * comments * shorten code * refactor * fmt * refactor * 3D * tests and fmt * comment * news * comment * stick to polydeg * polydeg 3 * polydeg * Update examples/p4est_2d_dgsem/elixir_euler_airfoil_mach2.jl Co-authored-by: Andrew Winters * Update examples/p4est_2d_dgsem/elixir_euler_airfoil_mach2.jl Co-authored-by: Andrew Winters * Update src/meshes/p4est_mesh.jl Co-authored-by: Andrew Winters * Update NEWS.md Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * Update examples/p4est_3d_dgsem/elixir_euler_free_stream_boundaries.jl * improve (?) formatting * fmt * split constructor * comment * two boundaries * comment * comment * rename elixir, change mesh * comments * add doc * avoid unicode * improve doc * Add tutorial * typos * Update docs/src/meshes/p4est_mesh.md Co-authored-by: Andrew Winters * Update docs/literate/src/files/p4est_from_gmsh.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/p4est_from_gmsh.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/p4est_from_gmsh.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/src/meshes/p4est_mesh.md Co-authored-by: Andrew Winters * Update docs/src/meshes/p4est_mesh.md Co-authored-by: Andrew Winters * Update docs/src/meshes/p4est_mesh.md Co-authored-by: Andrew Winters * Update docs/src/meshes/p4est_mesh.md Co-authored-by: Andrew Winters * Update docs/src/meshes/p4est_mesh.md Co-authored-by: Andrew Winters * Update docs/literate/src/files/p4est_from_gmsh.jl Co-authored-by: Andrew Winters * Update docs/literate/src/files/p4est_from_gmsh.jl Co-authored-by: Andrew Winters * Update docs/src/meshes/p4est_mesh.md Co-authored-by: Andrew Winters * Update docs/src/meshes/p4est_mesh.md * Update docs/literate/src/files/p4est_from_gmsh.jl * Update docs/literate/src/files/p4est_from_gmsh.jl * Update docs/literate/src/files/p4est_from_gmsh.jl * Update docs/literate/src/files/p4est_from_gmsh.jl * Update docs/literate/src/files/p4est_from_gmsh.jl * Update docs/literate/src/files/p4est_from_gmsh.jl * Apply suggestions from code review Polish * Update docs/literate/src/files/p4est_from_gmsh.jl Co-authored-by: Andrew Winters * Comments * Update p4est_mesh.jl * Update src/meshes/p4est_mesh.jl Co-authored-by: Johannes Markert <10619309+jmark@users.noreply.github.com> * Update docs/src/meshes/p4est_mesh.md Co-authored-by: Johannes Markert <10619309+jmark@users.noreply.github.com> * Update docs/src/meshes/p4est_mesh.md Co-authored-by: Johannes Markert <10619309+jmark@users.noreply.github.com> * Update docs/src/meshes/p4est_mesh.md Co-authored-by: Johannes Markert <10619309+jmark@users.noreply.github.com> * Update docs/src/meshes/p4est_mesh.md Co-authored-by: Johannes Markert <10619309+jmark@users.noreply.github.com> * more robust parsing * print warning if there has been a bc name supplied for which no nodes have been found * Update docs/literate/src/files/p4est_from_gmsh.jl Co-authored-by: Hendrik Ranocha * Update docs/literate/src/files/p4est_from_gmsh.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/p4est_mesh.jl Co-authored-by: Hendrik Ranocha * Update docs/literate/src/files/p4est_from_gmsh.jl --------- Co-authored-by: Andrew Winters Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Co-authored-by: Johannes Markert <10619309+jmark@users.noreply.github.com> Co-authored-by: Hendrik Ranocha --- NEWS.md | 2 + docs/literate/src/files/p4est_from_gmsh.jl | 459 ++++++++++++++++++ docs/make.jl | 1 + docs/src/meshes/p4est_mesh.md | 256 +++++++++- .../elixir_euler_NACA6412airfoil_mach2.jl | 108 +++++ .../elixir_euler_free_stream_boundaries.jl | 60 +++ src/meshes/p4est_mesh.jl | 226 ++++++++- test/test_p4est_2d.jl | 21 + test/test_p4est_3d.jl | 23 + 9 files changed, 1145 insertions(+), 11 deletions(-) create mode 100644 docs/literate/src/files/p4est_from_gmsh.jl create mode 100644 examples/p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl create mode 100644 examples/p4est_3d_dgsem/elixir_euler_free_stream_boundaries.jl diff --git a/NEWS.md b/NEWS.md index cf695912ed7..3a3a504a911 100644 --- a/NEWS.md +++ b/NEWS.md @@ -9,6 +9,8 @@ for human readability. #### Added - AMR for hyperbolic-parabolic equations on 3D `P4estMesh` - `flux_hllc` on non-cartesian meshes for `CompressibleEulerEquations{2,3}D` +- Different boundary conditions for quad/hex meshes in Abaqus format, even if not generated by HOHQMesh, + can now be digested by Trixi in 2D and 3D. ## Changes when updating to v0.6 from v0.5.x diff --git a/docs/literate/src/files/p4est_from_gmsh.jl b/docs/literate/src/files/p4est_from_gmsh.jl new file mode 100644 index 00000000000..356339cdd47 --- /dev/null +++ b/docs/literate/src/files/p4est_from_gmsh.jl @@ -0,0 +1,459 @@ +#src # `P4estMesh` from [`gmsh`](https://gmsh.info/) + +# Trixi.jl supports numerical approximations from structured and unstructured quadrilateral meshes +# with the [`P4estMesh`](@ref) mesh type. + +# The purpose of this tutorial is to demonstrate how to use the `P4estMesh` +# functionality of Trixi.jl for existing meshes with straight-sided (bilinear) elements/cells. +# This begins by running and visualizing an available unstructured quadrilateral mesh example. +# Then, the tutorial will cover how to use existing meshes generated by [`gmsh`](https://gmsh.info/) +# or any other meshing software that can export to the Abaqus input `.inp` format. + +# ## Running the simulation of a near-field flow around an airfoil + +# Trixi.jl supports solving hyperbolic-parabolic problems on several mesh types. +# A somewhat complex example that employs the `P4estMesh` is the near-field simulation of a +# Mach 2 flow around the NACA6412 airfoil. + +using Trixi +redirect_stdio(stdout=devnull, stderr=devnull) do # code that prints annoying stuff we don't want to see here #hide #md +trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_euler_NACA6412airfoil_mach2.jl"), tspan=(0.0, 0.5)) +end #hide #md + +# Conveniently, we use the Plots package to have a first look at the results: +# ```julia +# using Plots +# pd = PlotData2D(sol) +# plot(pd["rho"]) +# plot!(getmesh(pd)) +# ``` + +# ## Creating a mesh using `gmsh` + +# The creation of an unstructured quadrilateral mesh using `gmsh` is driven by a **geometry file**. +# There are plenty of possibilities for the user, see the [documentation](https://gmsh.info/doc/texinfo/gmsh.html) and [tutorials](https://gitlab.onelab.info/gmsh/gmsh/tree/master/tutorials). + +# To begin, we provide a complete geometry file for the NACA6412 airfoil bounded by a rectangular box. After this we give a breakdown +# of the most important parts required for successful mesh generation that can later be used by the `p4est` library +# and Trixi.jl. +# We emphasize that this near-field mesh should only be used for instructive purposes and not for actual production runs. + +# The associated `NACA6412.geo` file is given below: +# ```c++ +# // GMSH geometry script for a NACA 6412 airfoil with 11 degree angle of attack +# // in a box (near-field mesh). +# // see https://github.com/cfsengineering/GMSH-Airfoil-2D +# // for software to generate gmsh `.geo` geometry files for NACA airfoils. +# +# // outer bounding box +# Point(1) = {-1.25, -0.5, 0, 1.0}; +# Point(2) = {1.25, -0.5, 0, 1.0}; +# Point(3) = {1.25, 0.5, 0, 1.0}; +# Point(4) = {-1.25, 0.5, 0, 1.0}; +# +# // lines of the bounding box +# Line(1) = {1, 2}; +# Line(2) = {2, 3}; +# Line(3) = {3, 4}; +# Line(4) = {4, 1}; +# // outer box +# Line Loop(8) = {1, 2, 3, 4}; +# +# // Settings +# // This value gives the global element size factor (lower -> finer mesh) +# Mesh.CharacteristicLengthFactor = 1.0 * 2^(-3); +# // Insist on quads instead of default triangles +# Mesh.RecombineAll = 1; +# // Violet instead of green base color for better visibility +# Mesh.ColorCarousel = 0; +# +# // points of the airfoil contour +# // Format: {x, y, z, DesiredCellSize}. See the documentation: https://gmsh.info/doc/texinfo/gmsh.html#Points +# // These concrete points are generated using the tool from https://github.com/cfsengineering/GMSH-Airfoil-2D +# Point(5) = {-0.4900332889206208, 0.09933466539753061, 0, 0.125}; +# Point(6) = {-0.4900274857651495, 0.1021542752054094, 0, 0.125}; +# Point(7) = {-0.4894921489729144, 0.1049830248247787, 0, 0.125}; +# Point(8) = {-0.4884253336670712, 0.1078191282319664, 0, 0.125}; +# Point(9) = {-0.4868257975566199, 0.1106599068424483, 0, 0.125}; +# Point(10) = {-0.4846930063965668, 0.1135018003016681, 0, 0.125}; +# Point(11) = {-0.4820271400142729, 0.1163403835785654, 0, 0.125}; +# Point(12) = {-0.4788290988083472, 0.1191703902233889, 0, 0.125}; +# Point(13) = {-0.4751005105908123, 0.1219857416089041, 0, 0.125}; +# Point(14) = {-0.4708437376101668, 0.1247795819332056, 0, 0.125}; +# Point(15) = {-0.4660618835629463, 0.1275443187232316, 0, 0.125}; +# Point(16) = {-0.4607588003749649, 0.1302716685409717, 0, 0.125}; +# Point(17) = {-0.4549390945110529, 0.132952707559475, 0, 0.125}; +# Point(18) = {-0.448608132554204, 0.1355779266432996, 0, 0.125}; +# Point(19) = {-0.4417720457819508, 0.138137290538182, 0, 0.125}; +# Point(20) = {-0.4344377334597768, 0.140620300747629, 0, 0.125}; +# Point(21) = {-0.4266128645686593, 0.1430160616500159, 0, 0.125}; +# Point(22) = {-0.4183058776865576, 0.1453133493887722, 0, 0.125}; +# Point(23) = {-0.4095259787518715, 0.147500683050503, 0, 0.125}; +# Point(24) = {-0.4002831364505879, 0.1495663976315875, 0, 0.125}; +# Point(25) = {-0.3905880749878933, 0.1514987182830453, 0, 0.125}; +# Point(26) = {-0.3804522640292948, 0.1532858353164163, 0, 0.125}; +# Point(27) = {-0.3698879056254708, 0.1549159794501833, 0, 0.125}; +# Point(28) = {-0.3589079179688306, 0.1563774967770029, 0, 0.125}; +# Point(29) = {-0.3475259158676376, 0.1576589229368209, 0, 0.125}; +# Point(30) = {-0.3357561878650377, 0.158749055989923, 0, 0.125}; +# Point(31) = {-0.3236136699747923, 0.1596370274972017, 0, 0.125}; +# Point(32) = {-0.3111139160522804, 0.1603123713324616, 0, 0.125}; +# Point(33) = {-0.298273064867608, 0.160765089773461, 0, 0.125}; +# Point(34) = {-0.2851078039966239, 0.1609857164445887, 0, 0.125}; +# Point(35) = {-0.2716353306943914, 0.160965375714529, 0, 0.125}; +# Point(36) = {-0.2578733099632437, 0.1606958381868515, 0, 0.125}; +# Point(37) = {-0.2438398300730194, 0.1601695719599709, 0, 0.125}; +# Point(38) = {-0.2295533558334121, 0.1593797893750759, 0, 0.125}; +# Point(39) = {-0.2150326799566391, 0.1583204890160489, 0, 0.125}; +# Point(40) = {-0.2002968728818922, 0.1569864927736143, 0, 0.125}; +# Point(41) = {-0.18536523146042, 0.1553734778363979, 0, 0.125}; +# Point(42) = {-0.1702572269208345, 0.1534780035235666, 0, 0.125}; +# Point(43) = {-0.1549924525477129, 0.1512975329264932, 0, 0.125}; +# Point(44) = {-0.1395905715122586, 0.1488304493795921, 0, 0.125}; +# Point(45) = {-0.1240712652914332, 0.1460760678321895, 0, 0.125}; +# Point(46) = {-0.1084541831014299, 0.1430346412430583, 0, 0.125}; +# Point(47) = {-0.09275889275279087, 0.1397073621660917, 0, 0.125}; +# Point(48) = {-0.07700483330818747, 0.1360963597385416, 0, 0.125}; +# Point(49) = {-0.06151286635366404, 0.1323050298149023, 0, 0.125}; +# Point(50) = {-0.04602933219022032, 0.1283521764905442, 0, 0.125}; +# Point(51) = {-0.03051345534800332, 0.1242331665904082, 0, 0.125}; +# Point(52) = {-0.01498163190522334, 0.1199540932779839, 0, 0.125}; +# Point(53) = {0.0005498526140696458, 0.1155214539466913, 0, 0.125}; +# Point(54) = {0.01606484191716884, 0.1109421303284033, 0, 0.125}; +# Point(55) = {0.03154732664394777, 0.106223368423828, 0, 0.125}; +# Point(56) = {0.0469814611314705, 0.1013727584299359, 0, 0.125}; +# Point(57) = {0.06235157928986135, 0.09639821481480275, 0, 0.125}; +# Point(58) = {0.07764220964363855, 0.09130795666388933, 0, 0.125}; +# Point(59) = {0.09283808959671735, 0.08611048839446452, 0, 0.125}; +# Point(60) = {0.1079241789809607, 0.08081458090718853, 0, 0.125}; +# Point(61) = {0.1228856729475325, 0.07542925321638272, 0, 0.125}; +# Point(62) = {0.1377080142575372, 0.06996375457378261, 0, 0.125}; +# Point(63) = {0.1523769050236616, 0.06442754707512513, 0, 0.125}; +# Point(64) = {0.1668783179480157, 0.05883028871526293, 0, 0.125}; +# Point(65) = {0.1811985070933818, 0.05318181683604975, 0, 0.125}; +# Point(66) = {0.1953240182159306, 0.04749213189240609, 0, 0.125}; +# Point(67) = {0.2092416986775084, 0.04177138144606024, 0, 0.125}; +# Point(68) = {0.2229387069452062, 0.03602984428372727, 0, 0.125}; +# Point(69) = {0.2364025216754475, 0.03027791454712048, 0, 0.125}; +# Point(70) = {0.2496209503696738, 0.02452608575629232, 0, 0.125}; +# Point(71) = {0.2625821375791982, 0.01878493460541621, 0, 0.125}; +# Point(72) = {0.2752745726282818, 0.01306510441121807, 0, 0.125}; +# Point(73) = {0.28768709681727, 0.007377288098728577, 0, 0.125}; +# Point(74) = {0.2998089100619555, 0.001732210616722449, 0, 0.125}; +# Point(75) = {0.3116295769214332, -0.003859389314124759, 0, 0.125}; +# Point(76) = {0.3231390319647309, -0.009386778203927332, 0, 0.125}; +# Point(77) = {0.3343275844265582, -0.01483924761490708, 0, 0.125}; +# Point(78) = {0.3451859221046181, -0.02020613485126957, 0, 0.125}; +# Point(79) = {0.3557051144551212, -0.02547684454806881, 0, 0.125}; +# Point(80) = {0.3658766148492779, -0.03064087116872238, 0, 0.125}; +# Point(81) = {0.3756922619615632, -0.0356878223992288, 0, 0.125}; +# Point(82) = {0.3851442802702071, -0.0406074434050937, 0, 0.125}; +# Point(83) = {0.394225279661484, -0.04538964189492445, 0, 0.125}; +# Point(84) = {0.4029282541416501, -0.05002451391298904, 0, 0.125}; +# Point(85) = {0.4112465796735204, -0.05450237026215737, 0, 0.125}; +# Point(86) = {0.4191740111683733, -0.05881376343890812, 0, 0.125}; +# Point(87) = {0.4267046786777481, -0.06294951494382847, 0, 0.125}; +# Point(88) = {0.4338330828434404, -0.06690074281456823, 0, 0.125}; +# Point(89) = {0.4405540896772232, -0.07065888921378868, 0, 0.125}; +# Point(90) = {0.4468629247542237, -0.07421574789251445, 0, 0.125}; +# Point(91) = {0.4527551669150955, -0.0775634913396257, 0, 0.125}; +# Point(92) = {0.4582267415819197, -0.08069469742118066, 0, 0.125}; +# Point(93) = {0.4632739138007936, -0.08360237530891265, 0, 0.125}; +# Point(94) = {0.4678932811302005, -0.08627999049569551, 0, 0.125}; +# Point(95) = {0.4720817664982195, -0.08872148869699745, 0, 0.125}; +# Point(96) = {0.4758366111533843, -0.09092131844134463, 0, 0.125}; +# Point(97) = {0.4791553678333992, -0.09287445215953141, 0, 0.125}; +# Point(98) = {0.4820358942729613, -0.09457640559161551, 0, 0.125}; +# Point(99) = {0.4844763471666588, -0.09602325534252773, 0, 0.125}; +# Point(100) = {0.4864751766953637, -0.09721165443119822, 0, 0.125}; +# Point(101) = {0.4880311217148797, -0.09813884569428721, 0, 0.125}; +# Point(102) = {0.4891432056939881, -0.09880267292366274, 0, 0.125}; +# Point(103) = {0.4898107334756874, -0.09920158963645126, 0, 0.125}; +# Point(104) = {0.4900332889206208, -0.09933466539753058, 0, 0.125}; +# Point(105) = {0.4897824225031319, -0.09926905587549506, 0, 0.125}; +# Point(106) = {0.4890301110661922, -0.09907236506934192, 0, 0.125}; +# Point(107) = {0.4877772173496635, -0.09874500608402761, 0, 0.125}; +# Point(108) = {0.48602517690576, -0.09828766683852558, 0, 0.125}; +# Point(109) = {0.4837759946062035, -0.09770130916007558, 0, 0.125}; +# Point(110) = {0.4810322398085871, -0.09698716747297723, 0, 0.125}; +# Point(111) = {0.4777970402368822, -0.09614674703990023, 0, 0.125}; +# Point(112) = {0.4740740746447117, -0.09518182170326678, 0, 0.125}; +# Point(113) = {0.4698675643422793, -0.09409443106501386, 0, 0.125}; +# Point(114) = {0.4651822636784212, -0.09288687703518478, 0, 0.125}; +# Point(115) = {0.460023449577924, -0.09156171967354482, 0, 0.125}; +# Point(116) = {0.4543969102408585, -0.09012177224394632, 0, 0.125}; +# Point(117) = {0.4483089331151018, -0.08857009539864649, 0, 0.125}; +# Point(118) = {0.4417662922553667, -0.08690999040934186, 0, 0.125}; +# Point(119) = {0.4347762351819332, -0.0851449913634191, 0, 0.125}; +# Point(120) = {0.4273464693498908, -0.08327885624791403, 0, 0.125}; +# Point(121) = {0.419485148335155, -0.08131555684993674, 0, 0.125}; +# Point(122) = {0.411200857836944, -0.07925926741086739, 0, 0.125}; +# Point(123) = {0.4025026015879757, -0.07711435198240155, 0, 0.125}; +# Point(124) = {0.3933997872536054, -0.07488535044544484, 0, 0.125}; +# Point(125) = {0.3839022123897198, -0.07257696316779733, 0, 0.125}; +# Point(126) = {0.3740200505167618, -0.07019403429336624, 0, 0.125}; +# Point(127) = {0.3637638373540689, -0.06774153367408606, 0, 0.125}; +# Point(128) = {0.3531444572451353, -0.06522453747557577, 0, 0.125}; +# Point(129) = {0.3421731297908021, -0.06264820750853495, 0, 0.125}; +# Point(130) = {0.3308613966940724, -0.06001776935966011, 0, 0.125}; +# Point(131) = {0.3192211088076166, -0.05733848941811218, 0, 0.125}; +# Point(132) = {0.3072644133633567, -0.05461565091590426, 0, 0.125}; +# Point(133) = {0.2950037413531683, -0.05185452912263369, 0, 0.125}; +# Point(134) = {0.2824517950208982, -0.04906036585632723, 0, 0.125}; +# Point(135) = {0.2696215354188702, -0.04623834349241404, 0, 0.125}; +# Point(136) = {0.2565261699769623, -0.04339355867155523, 0, 0.125}; +# Point(137) = {0.2431791400293651, -0.04053099592384862, 0, 0.125}; +# Point(138) = {0.2295941082432855, -0.03765550144139543, 0, 0.125}; +# Point(139) = {0.2157849458952252, -0.03477175724299444, 0, 0.125}; +# Point(140) = {0.2017657199439165, -0.03188425598348005, 0, 0.125}; +# Point(141) = {0.187550679854507, -0.02899727666564914, 0, 0.125}; +# Point(142) = {0.1731542441359161, -0.02611486151457043, 0, 0.125}; +# Point(143) = {0.1585909865622793, -0.02324079427214604, 0, 0.125}; +# Point(144) = {0.1438756220597465, -0.02037858016395433, 0, 0.125}; +# Point(145) = {0.129022992251319, -0.0175314277805827, 0, 0.125}; +# Point(146) = {0.1140480506645569, -0.01470223310184333, 0, 0.125}; +# Point(147) = {0.09896584761949168, -0.01189356587453844, 0, 0.125}; +# Point(148) = {0.08379151482656089, -0.009107658532933174, 0, 0.125}; +# Point(149) = {0.06854024973648176, -0.006346397826038436, 0, 0.125}; +# Point(150) = {0.05322729969528361, -0.003611319287478529, 0, 0.125}; +# Point(151) = {0.03786794596792287, -0.00090360465249055, 0, 0.125}; +# Point(152) = {0.0224774877026287, 0.00177591770710904, 0, 0.125}; +# Point(153) = {0.007071225915134205, 0.004426769294862437, 0, 0.125}; +# Point(154) = {-0.00833555242305456, 0.007048814950562587, 0, 0.125}; +# Point(155) = {-0.02372759010533726, 0.009642253300220296, 0, 0.125}; +# Point(156) = {-0.03908967513210498, 0.01220760427359278, 0, 0.125}; +# Point(157) = {-0.05440665578848514, 0.01474569380579989, 0, 0.125}; +# Point(158) = {-0.06966345527617318, 0.01725763587663899, 0, 0.125}; +# Point(159) = {-0.08484508582421563, 0.01974481207672138, 0, 0.125}; +# Point(160) = {-0.09987987792382108, 0.02219618763023203, 0, 0.125}; +# Point(161) = {-0.1145078729404739, 0.02450371976411331, 0, 0.125}; +# Point(162) = {-0.1290321771824579, 0.0267015185742735, 0, 0.125}; +# Point(163) = {-0.143440065923266, 0.02879471001709845, 0, 0.125}; +# Point(164) = {-0.1577189448447794, 0.03078883518202784, 0, 0.125}; +# Point(165) = {-0.1718563428491159, 0.03268980457290044, 0, 0.125}; +# Point(166) = {-0.1858399037768357, 0.03450385196323842, 0, 0.125}; +# Point(167) = {-0.1996573773370766, 0.03623748825421298, 0, 0.125}; +# Point(168) = {-0.2132966095779342, 0.03789745574015834, 0, 0.125}; +# Point(169) = {-0.2267455332406906, 0.0394906831577609, 0, 0.125}; +# Point(170) = {-0.2399921583489679, 0.04102424186233269, 0, 0.125}; +# Point(171) = {-0.2530245633834605, 0.04250530343879837, 0, 0.125}; +# Point(172) = {-0.2658308873846617, 0.04394109901707172, 0, 0.125}; +# Point(173) = {-0.2783993233102972, 0.04533888052223981, 0, 0.125}; +# Point(174) = {-0.2907181129514687, 0.04670588405019788, 0, 0.125}; +# Point(175) = {-0.3027755436824813, 0.0480492955198111, 0, 0.125}; +# Point(176) = {-0.3145599472847223, 0.04937621871394801, 0, 0.125}; +# Point(177) = {-0.3260597010456697, 0.05069364578437131, 0, 0.125}; +# Point(178) = {-0.337263231291058, 0.05200843025992359, 0, 0.125}; +# Point(179) = {-0.3481590194623916, 0.05332726256406103, 0, 0.125}; +# Point(180) = {-0.3587356108043638, 0.05465664801682354, 0, 0.125}; +# Point(181) = {-0.3689816256782782, 0.0560028872679817, 0, 0.125}; +# Point(182) = {-0.3788857734692287, 0.05737205908247899, 0, 0.125}; +# Point(183) = {-0.3884368690074614, 0.05877000537646382, 0, 0.125}; +# Point(184) = {-0.3976238513788748, 0.06020231838219783, 0, 0.125}; +# Point(185) = {-0.40643580495675, 0.06167432980291591, 0, 0.125}; +# Point(186) = {-0.4148619824472646, 0.06319110180426264, 0, 0.125}; +# Point(187) = {-0.4228918297057104, 0.06475741967717524, 0, 0.125}; +# Point(188) = {-0.43051501204915, 0.06637778599795482, 0, 0.125}; +# Point(189) = {-0.4377214417649294, 0.06805641610468524, 0, 0.125}; +# Point(190) = {-0.4445013064933708, 0.06979723470503821, 0, 0.125}; +# Point(191) = {-0.4508450981473512, 0.07160387342876083, 0, 0.125}; +# Point(192) = {-0.4567436420215075, 0.073479669138689, 0, 0.125}; +# Point(193) = {-0.4621881257395756, 0.07542766281688272, 0, 0.125}; +# Point(194) = {-0.4671701276898881, 0.07745059884734995, 0, 0.125}; +# Point(195) = {-0.471681644606229, 0.07955092452372269, 0, 0.125}; +# Point(196) = {-0.4757151179639407, 0.0817307896190848, 0, 0.125}; +# Point(197) = {-0.4792634588791559, 0.0839920458658267, 0, 0.125}; +# Point(198) = {-0.4823200712220043, 0.08633624620581726, 0, 0.125}; +# Point(199) = {-0.4848788726822436, 0.08876464368523246, 0, 0.125}; +# Point(200) = {-0.4869343135575803, 0.09127818988394577, 0, 0.125}; +# Point(201) = {-0.4884813930704814, 0.09387753278635144, 0, 0.125}; +# Point(202) = {-0.4895156730580155, 0.09656301401871749, 0, 0.125}; +# +# // splines of the airfoil +# Spline(5) = {5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104}; +# Spline(6) = {104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,5}; +# +# // airfoil +# Line Loop(9) = {5, 6}; +# // complete domain +# Plane Surface(1) = {8, 9}; +# +# // labeling of the boundary parts +# Physical Line(1) = {4}; // inflow +# Physical Line(2) = {2}; // outflow +# Physical Line(3) = {1, 3}; // airfoil +# Physical Line(4) = {5, 6}; // upper/lower wall +# Physical Surface(1) = {10}; +# ``` +# From which we can construct a mesh like this: +# ![mesh_screenshot](https://github.com/trixi-framework/Trixi.jl/assets/75639095/67adfe3d-d403-4cd3-acaa-971a34df0709) +# +# The first four points define the bounding box = (near-field) domain: +# ```c++ +# // outer bounding box +# Point(1) = {-1.25, -0.5, 0, 1.0}; +# Point(2) = {1.25, -0.5, 0, 1.0}; +# Point(3) = {1.25, 0.5, 0, 1.0}; +# Point(4) = {-1.25, 0.5, 0, 1.0}; +# ``` +# which is constructed from connecting the points in lines: +# ```c++ +# // outer box +# Line(1) = {1, 2}; +# Line(2) = {2, 3}; +# Line(3) = {3, 4}; +# Line(4) = {4, 1}; +# // outer box +# Line Loop(8) = {1, 2, 3, 4}; +# ``` +# +# This is followed by a couple (in principle optional) settings where the most important one is +# ```c++ +# // Insist on quads instead of default triangles +# Mesh.RecombineAll = 1; +# ``` +# which forces `gmsh` to generate quadrilateral elements instead of the default triangles. +# This is strictly required to be able to use the mesh later with `p4est`, which supports only straight-sided quads, +# i.e., `C2D4, CPS4, S4` in 2D and `C3D` in 3D. +# See for more details the (short) [documentation](https://p4est.github.io/p4est-howto.pdf) on the interaction of `p4est` with `.inp` files. +# In principle, it should also be possible to use the `recombine` function of `gmsh` to convert the triangles to quads, +# but this is observed to be less robust than enforcing quads from the beginning. +# +# Then the airfoil is defined by a set of points: +# ```c++ +# // points of the airfoil contour +# Point(5) = {-0.4900332889206208, 0.09933466539753061, 0, 0.125}; +# Point(6) = {-0.4900274857651495, 0.1021542752054094, 0, 0.125}; +# ... +# ``` +# which are connected by splines for the upper and lower part of the airfoil: +# ```c++ +# // splines of the airfoil +# Spline(5) = {5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20, +# ... +# 96,97,98,99,100,101,102,103,104}; +# Spline(6) = {104,105,106,107,108,109,110,111,112,113,114,115, +# ... +# 200,201,202,5}; +# ``` +# which are then connected to form a single line loop for easy physical group assignment: +# ```c++ +# // airfoil +# Line Loop(9) = {5, 6}; +# ``` +# +# At the end of the file the physical groups are defined: +# ```c++ +# // labeling of the boundary parts +# Physical Line(1) = {4}; // Inflow. Label in Abaqus .inp file: PhysicalLine1 +# Physical Line(2) = {2}; // Outflow. Label in Abaqus .inp file: PhysicalLine2 +# Physical Line(3) = {1, 3}; // Airfoil. Label in Abaqus .inp file: PhysicalLine3 +# Physical Line(4) = {5, 6}; //Upper and lower wall/farfield/... Label in Abaqus .inp file: PhysicalLine4 +# ``` +# which are crucial for the correct assignment of boundary conditions in `Trixi.jl`. +# In particular, it is the responsibility of a user to keep track on the physical boundary names between the mesh generation and assignment of boundary condition functions in an elixir. +# +# After opening this file in `gmsh`, meshing the geometry and exporting to Abaqus `.inp` format, +# we can have a look at the input file: +# ``` +# *Heading +# +# *NODE +# 1, -1.25, -0.5, 0 +# 2, 1.25, -0.5, 0 +# 3, 1.25, 0.5, 0 +# 4, -1.25, 0.5, 0 +# ... +# ******* E L E M E N T S ************* +# *ELEMENT, type=T3D2, ELSET=Line1 +# 1, 1, 7 +# ... +# *ELEMENT, type=CPS4, ELSET=Surface1 +# 191, 272, 46, 263, 807 +# ... +# *NSET,NSET=PhysicalLine1 +# 1, 4, 52, 53, 54, 55, 56, 57, 58, +# *NSET,NSET=PhysicalLine2 +# 2, 3, 26, 27, 28, 29, 30, 31, 32, +# *NSET,NSET=PhysicalLine3 +# 1, 2, 3, 4, 7, 8, 9, 10, 11, 12, +# 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, +# 23, 24, 25, 33, 34, 35, 36, 37, 38, 39, +# 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, +# 50, 51, +# *NSET,NSET=PhysicalLine4 +# 5, 6, 59, 60, 61, 62, 63, 64, 65, 66, +# 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, +# 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, +# 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, +# 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, +# 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, +# 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, +# 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, +# 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, +# 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, +# 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, +# 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, +# 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, +# 187, 188, 189, 190, +# ``` +# +# First, the coordinates of the nodes are listed, followed by the elements. +# Note that `gmsh` exports also line elements of type `T3D2` which are ignored by `p4est`. +# The relevant elements in 2D which form the gridcells are of type `CPS4` which are defined by their four corner nodes. +# This is followed by the nodesets encoded via `*NSET` which are used to assign boundary conditions in Trixi.jl. +# Trixi.jl parses the `.inp` file and assigns the edges (in 2D, surfaces in 3D) of elements to the corresponding boundary condition based on +# the supplied `boundary_symbols` that have to be supplied to the `P4estMesh` constructor: +# ```julia +# # boundary symbols +# boundary_symbols = [:PhysicalLine1, :PhysicalLine2, :PhysicalLine3, :PhysicalLine4] +# mesh = P4estMesh{2}(mesh_file, polydeg = polydeg, boundary_symbols = boundary_symbols) +# ``` +# The same boundary symbols have then also be supplied to the semidiscretization alongside the +# corresponding physical boundary conditions: +# ```julia +# # Supersonic inflow boundary condition. +# # Calculate the boundary flux entirely from the external solution state, i.e., set +# # external solution state values for everything entering the domain. +# @inline function boundary_condition_supersonic_inflow(u_inner, +# normal_direction::AbstractVector, +# x, t, surface_flux_function, +# equations::CompressibleEulerEquations2D) +# u_boundary = initial_condition_mach2_flow(x, t, equations) +# flux = Trixi.flux(u_boundary, normal_direction, equations) +# +# return flux +# end +# +# # Supersonic outflow boundary condition. +# # Calculate the boundary flux entirely from the internal solution state. Analogous to supersonic inflow +# # except all the solution state values are set from the internal solution as everything leaves the domain +# @inline function boundary_condition_supersonic_outflow(u_inner, +# normal_direction::AbstractVector, x, +# t, +# surface_flux_function, +# equations::CompressibleEulerEquations2D) +# flux = Trixi.flux(u_inner, normal_direction, equations) +# +# boundary_conditions = Dict(:PhysicalLine1 => boundary_condition_supersonic_inflow, # Left boundary +# :PhysicalLine2 => boundary_condition_supersonic_outflow, # Right boundary +# :PhysicalLine3 => boundary_condition_slip_wall, # Airfoil +# :PhysicalLine4 => boundary_condition_supersonic_outflow) # Top and bottom boundary +# +# semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, +# boundary_conditions = boundary_conditions) +# ``` +# Note that you **have to** supply the `boundary_symbols` keyword to the `P4estMesh` constructor +# to select the boundaries from the available nodesets in the `.inp` file. +# If the `boundary_symbols` keyword is not supplied, all boundaries will be assigned to the default set `:all`. + +# ## Package versions + +# These results were obtained using the following versions. + +using InteractiveUtils +versioninfo() + +using Pkg +Pkg.status(["Trixi", "OrdinaryDiffEq", "Plots", "Download"], + mode=PKGMODE_MANIFEST) diff --git a/docs/make.jl b/docs/make.jl index df8ac04be12..dee87371bd1 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -65,6 +65,7 @@ files = [ "Adaptive mesh refinement" => "adaptive_mesh_refinement.jl", "Structured mesh with curvilinear mapping" => "structured_mesh_mapping.jl", "Unstructured meshes with HOHQMesh.jl" => "hohqmesh_tutorial.jl", + "P4est mesh from gmsh" => "p4est_from_gmsh.jl", # Topic: other stuff "Explicit time stepping" => "time_stepping.jl", "Differentiable programming" => "differentiable_programming.jl", diff --git a/docs/src/meshes/p4est_mesh.md b/docs/src/meshes/p4est_mesh.md index 1e5d782ebb6..db75346cab3 100644 --- a/docs/src/meshes/p4est_mesh.md +++ b/docs/src/meshes/p4est_mesh.md @@ -55,7 +55,7 @@ This heading is used to indicate to the mesh constructor which of the above mapp create a curvilinear mesh. If the Abaqus file header is **not** present then the `P4estMesh` is created with the first strategy above. -#### List of corner nodes +#### List of corner nodes Next, prefaced with `*NODE`, comes a list of the physical `(x,y,z)` coordinates of all the corners. The first integer in the list of the corners provides its id number. @@ -71,7 +71,7 @@ Thus, for the two-dimensional example mesh this block of corner information is 7, 3.0, -1.0, 0.0 ``` -#### List of elements +#### List of elements The element connectivity is given after the list of corners. The header for this information block is ``` @@ -98,7 +98,9 @@ The construction of the element neighbor ids and identifying physical boundary s directly from the [`p4est`](https://github.com/cburstedde/p4est) library. For example, the neighbor connectivity is created in the mesh constructor using the wrapper `read_inp_p4est` function. -#### HOHQMesh boundary information +#### Encoding of boundaries + +##### HOHQMesh boundary information If present, any additional information in the mesh file that was created by `HOHQMesh` is prefaced with `** ` to make it an Abaqus comment. @@ -230,8 +232,38 @@ For completeness, we provide the entire Abaqus mesh file for the example mesh in ** Bottom --- Right --- ``` +##### Standard Abaqus format boundary information + +As an alternative to an Abaqus mesh generated by `HOHQMesh`, `.inp` files with boundary information encoded as nodesets `*NSET,NSET=` can be used to construct a `p4est` mesh. +This is especially useful for usage of existing meshes (consisting of bilinear elements) which could stem from the popular [`gmsh`](https://gmsh.info/) meshing software. + +In addition to the list of [nodes](#nodes) and [elements](#elements) given above, there are nodesets of the form +``` +*NSET,NSET=PhysicalLine1 +1, 4, 52, 53, 54, 55, 56, 57, 58, +``` +present which are used to associate the edges defined through their corner nodes with a label. In this case it is called `PhysicalLine1`. +By looping over every element and its associated edges, consisting of two nodes, we query the read in `NSET`s if the current node pair is present. + +To prevent that every nodeset following `*NSET,NSET=` is treated as a boundary, the user must supply a `boundary_symbols` keyword to the [`P4estMesh`](@ref) constructor: + +```julia +boundary_symbols = [:PhysicalLine1] + +mesh = P4estMesh{2}(mesh_file, polydeg = polydeg, boundary_symbols = boundary_symbols) +``` +By doing so, only nodesets with a label present in `boundary_symbols` are treated as physical boundaries. +Other nodesets that could be used for diagnostics are not treated as external boundaries. +Note that there is a leading colon `:` compared to the label in the `.inp` mesh file. +This is required to turn the label into a [`Symbol`](https://docs.julialang.org/en/v1/manual/metaprogramming/#Symbols). + +A 2D example for this mesh, which is read-in for an unstructured mesh file created with `gmsh`, is presented in +`examples/p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl`. + ### Mesh in three spatial dimensions +#### `HOHQMesh`-Extended Abaqus format + The 3D Abaqus file format with high-order boundary information from `HOHQMesh` is very similar to the 2D version discussed above. There are only three changes: @@ -346,4 +378,222 @@ transfinite map of the straight sided hexahedral element to find \mathbf{X}(\boldsymbol{\xi}) = \boldsymbol\Sigma(\boldsymbol{\xi}) - \mathcal{C}_{\texttt{edge}}(\boldsymbol{\xi}) + \mathbf{X}_{linear}(\boldsymbol{\xi}). +``` + +#### Construction from standard Abaqus + +Also for a mesh in standard Abaqus format there are no qualitative changes when going from 2D to 3D. +The most notable difference is that boundaries are formed in 3D by faces defined by four nodes while in 2D boundaries are edges consisting of two elements. +A simple mesh file, which is used also in `examples/p4est_3d_dgsem/elixir_euler_free_stream_boundaries.jl`, is given below: +``` +*Heading + +*NODE +1, -2, 0, 0 +2, -1, 0, 0 +3, -1, 1, 0 +4, -2, 1, 0 +5, -2, 0, 1 +6, -1, 0, 1 +7, -1, 1, 1 +8, -2, 1, 1 +9, -1.75, 1, 0 +10, -1.5, 1, 0 +11, -1.25, 1, 0 +12, -1, 0.75000000000035, 0 +13, -1, 0.50000000000206, 0 +14, -1, 0.25000000000104, 0 +15, -1.25, 0, 0 +16, -1.5, 0, 0 +17, -1.75, 0, 0 +18, -2, 0.24999999999941, 0 +19, -2, 0.49999999999869, 0 +20, -2, 0.74999999999934, 0 +21, -1.75, 0, 1 +22, -1.5, 0, 1 +23, -1.25, 0, 1 +24, -1, 0.24999999999941, 1 +25, -1, 0.49999999999869, 1 +26, -1, 0.74999999999934, 1 +27, -1.25, 1, 1 +28, -1.5, 1, 1 +29, -1.75, 1, 1 +30, -2, 0.75000000000035, 1 +31, -2, 0.50000000000206, 1 +32, -2, 0.25000000000104, 1 +33, -2, 0, 0.24999999999941 +34, -2, 0, 0.49999999999869 +35, -2, 0, 0.74999999999934 +36, -2, 1, 0.24999999999941 +37, -2, 1, 0.49999999999869 +38, -2, 1, 0.74999999999934 +39, -1, 0, 0.24999999999941 +40, -1, 0, 0.49999999999869 +41, -1, 0, 0.74999999999934 +42, -1, 1, 0.24999999999941 +43, -1, 1, 0.49999999999869 +44, -1, 1, 0.74999999999934 +45, -1.25, 0.25000000000063, 0 +46, -1.25, 0.50000000000122, 0 +47, -1.25, 0.7500000000001, 0 +48, -1.5, 0.25000000000023, 0 +49, -1.5, 0.50000000000038, 0 +50, -1.5, 0.74999999999984, 0 +51, -1.75, 0.24999999999982, 0 +52, -1.75, 0.49999999999953, 0 +53, -1.75, 0.74999999999959, 0 +54, -1.75, 0.25000000000063, 1 +55, -1.75, 0.50000000000122, 1 +56, -1.75, 0.7500000000001, 1 +57, -1.5, 0.25000000000023, 1 +58, -1.5, 0.50000000000038, 1 +59, -1.5, 0.74999999999984, 1 +60, -1.25, 0.24999999999982, 1 +61, -1.25, 0.49999999999953, 1 +62, -1.25, 0.74999999999959, 1 +63, -2, 0.24999999999982, 0.24999999999941 +64, -2, 0.49999999999953, 0.24999999999941 +65, -2, 0.74999999999959, 0.24999999999941 +66, -2, 0.25000000000023, 0.49999999999869 +67, -2, 0.50000000000038, 0.49999999999869 +68, -2, 0.74999999999984, 0.49999999999869 +69, -2, 0.25000000000063, 0.74999999999934 +70, -2, 0.50000000000122, 0.74999999999934 +71, -2, 0.7500000000001, 0.74999999999934 +72, -1.25, 1, 0.74999999999934 +73, -1.25, 1, 0.49999999999869 +74, -1.25, 1, 0.24999999999941 +75, -1.5, 1, 0.74999999999934 +76, -1.5, 1, 0.49999999999869 +77, -1.5, 1, 0.24999999999941 +78, -1.75, 1, 0.74999999999934 +79, -1.75, 1, 0.49999999999869 +80, -1.75, 1, 0.24999999999941 +81, -1, 0.25000000000063, 0.24999999999941 +82, -1, 0.50000000000122, 0.24999999999941 +83, -1, 0.7500000000001, 0.24999999999941 +84, -1, 0.25000000000023, 0.49999999999869 +85, -1, 0.50000000000038, 0.49999999999869 +86, -1, 0.74999999999984, 0.49999999999869 +87, -1, 0.24999999999982, 0.74999999999934 +88, -1, 0.49999999999953, 0.74999999999934 +89, -1, 0.74999999999959, 0.74999999999934 +90, -1.75, 0, 0.74999999999934 +91, -1.75, 0, 0.49999999999869 +92, -1.75, 0, 0.24999999999941 +93, -1.5, 0, 0.74999999999934 +94, -1.5, 0, 0.49999999999869 +95, -1.5, 0, 0.24999999999941 +96, -1.25, 0, 0.74999999999934 +97, -1.25, 0, 0.49999999999869 +98, -1.25, 0, 0.24999999999941 +99, -1.75, 0.25000000000043, 0.74999999999934 +100, -1.75, 0.25000000000023, 0.49999999999869 +101, -1.75, 0.25000000000002, 0.24999999999941 +102, -1.75, 0.5000000000008, 0.74999999999934 +103, -1.75, 0.50000000000038, 0.49999999999869 +104, -1.75, 0.49999999999995, 0.24999999999941 +105, -1.75, 0.74999999999997, 0.74999999999934 +106, -1.75, 0.74999999999984, 0.49999999999869 +107, -1.75, 0.74999999999972, 0.24999999999941 +108, -1.5, 0.25000000000023, 0.74999999999934 +109, -1.5, 0.25000000000023, 0.49999999999869 +110, -1.5, 0.25000000000023, 0.24999999999941 +111, -1.5, 0.50000000000038, 0.74999999999934 +112, -1.5, 0.50000000000038, 0.49999999999869 +113, -1.5, 0.50000000000038, 0.24999999999941 +114, -1.5, 0.74999999999984, 0.74999999999934 +115, -1.5, 0.74999999999984, 0.49999999999869 +116, -1.5, 0.74999999999984, 0.24999999999941 +117, -1.25, 0.25000000000002, 0.74999999999934 +118, -1.25, 0.25000000000023, 0.49999999999869 +119, -1.25, 0.25000000000043, 0.24999999999941 +120, -1.25, 0.49999999999995, 0.74999999999934 +121, -1.25, 0.50000000000038, 0.49999999999869 +122, -1.25, 0.5000000000008, 0.24999999999941 +123, -1.25, 0.74999999999972, 0.74999999999934 +124, -1.25, 0.74999999999984, 0.49999999999869 +125, -1.25, 0.74999999999997, 0.24999999999941 +******* E L E M E N T S ************* +*ELEMENT, type=C3D8, ELSET=Volume1 +153, 54, 21, 5, 32, 99, 90, 35, 69 +154, 99, 90, 35, 69, 100, 91, 34, 66 +155, 100, 91, 34, 66, 101, 92, 33, 63 +156, 101, 92, 33, 63, 51, 17, 1, 18 +157, 55, 54, 32, 31, 102, 99, 69, 70 +158, 102, 99, 69, 70, 103, 100, 66, 67 +159, 103, 100, 66, 67, 104, 101, 63, 64 +160, 104, 101, 63, 64, 52, 51, 18, 19 +161, 56, 55, 31, 30, 105, 102, 70, 71 +162, 105, 102, 70, 71, 106, 103, 67, 68 +163, 106, 103, 67, 68, 107, 104, 64, 65 +164, 107, 104, 64, 65, 53, 52, 19, 20 +165, 29, 56, 30, 8, 78, 105, 71, 38 +166, 78, 105, 71, 38, 79, 106, 68, 37 +167, 79, 106, 68, 37, 80, 107, 65, 36 +168, 80, 107, 65, 36, 9, 53, 20, 4 +169, 57, 22, 21, 54, 108, 93, 90, 99 +170, 108, 93, 90, 99, 109, 94, 91, 100 +171, 109, 94, 91, 100, 110, 95, 92, 101 +172, 110, 95, 92, 101, 48, 16, 17, 51 +173, 58, 57, 54, 55, 111, 108, 99, 102 +174, 111, 108, 99, 102, 112, 109, 100, 103 +175, 112, 109, 100, 103, 113, 110, 101, 104 +176, 113, 110, 101, 104, 49, 48, 51, 52 +177, 59, 58, 55, 56, 114, 111, 102, 105 +178, 114, 111, 102, 105, 115, 112, 103, 106 +179, 115, 112, 103, 106, 116, 113, 104, 107 +180, 116, 113, 104, 107, 50, 49, 52, 53 +181, 28, 59, 56, 29, 75, 114, 105, 78 +182, 75, 114, 105, 78, 76, 115, 106, 79 +183, 76, 115, 106, 79, 77, 116, 107, 80 +184, 77, 116, 107, 80, 10, 50, 53, 9 +185, 60, 23, 22, 57, 117, 96, 93, 108 +186, 117, 96, 93, 108, 118, 97, 94, 109 +187, 118, 97, 94, 109, 119, 98, 95, 110 +188, 119, 98, 95, 110, 45, 15, 16, 48 +189, 61, 60, 57, 58, 120, 117, 108, 111 +190, 120, 117, 108, 111, 121, 118, 109, 112 +191, 121, 118, 109, 112, 122, 119, 110, 113 +192, 122, 119, 110, 113, 46, 45, 48, 49 +193, 62, 61, 58, 59, 123, 120, 111, 114 +194, 123, 120, 111, 114, 124, 121, 112, 115 +195, 124, 121, 112, 115, 125, 122, 113, 116 +196, 125, 122, 113, 116, 47, 46, 49, 50 +197, 27, 62, 59, 28, 72, 123, 114, 75 +198, 72, 123, 114, 75, 73, 124, 115, 76 +199, 73, 124, 115, 76, 74, 125, 116, 77 +200, 74, 125, 116, 77, 11, 47, 50, 10 +201, 24, 6, 23, 60, 87, 41, 96, 117 +202, 87, 41, 96, 117, 84, 40, 97, 118 +203, 84, 40, 97, 118, 81, 39, 98, 119 +204, 81, 39, 98, 119, 14, 2, 15, 45 +205, 25, 24, 60, 61, 88, 87, 117, 120 +206, 88, 87, 117, 120, 85, 84, 118, 121 +207, 85, 84, 118, 121, 82, 81, 119, 122 +208, 82, 81, 119, 122, 13, 14, 45, 46 +209, 26, 25, 61, 62, 89, 88, 120, 123 +210, 89, 88, 120, 123, 86, 85, 121, 124 +211, 86, 85, 121, 124, 83, 82, 122, 125 +212, 83, 82, 122, 125, 12, 13, 46, 47 +213, 7, 26, 62, 27, 44, 89, 123, 72 +214, 44, 89, 123, 72, 43, 86, 124, 73 +215, 43, 86, 124, 73, 42, 83, 125, 74 +216, 42, 83, 125, 74, 3, 12, 47, 11 +*NSET,NSET=PhysicalSurface1 +1, 2, 3, 4, 5, 6, 7, 8, 9, 10, +11, 12, 13, 14, 15, 16, 17, 18, 19, 20, +21, 22, 23, 24, 25, 26, 27, 28, 29, 30, +31, 32, 33, 34, 35, 36, 37, 38, 45, 46, +47, 48, 49, 50, 51, 52, 53, 54, 55, 56, +57, 58, 59, 60, 61, 62, 63, 64, 65, 66, +67, 68, 69, 70, 71, +*NSET,NSET=PhysicalSurface2 +1, 2, 3, 4, 5, 6, 7, 8, 9, 10, +11, 12, 13, 14, 15, 16, 17, 21, 22, 23, +24, 25, 26, 27, 28, 29, 33, 34, 35, 36, +37, 38, 39, 40, 41, 42, 43, 44, 72, 73, +74, 75, 76, 77, 78, 79, 80, 81, 82, 83, +84, 85, 86, 87, 88, 89, 90, 91, 92, 93, +94, 95, 96, 97, 98, ``` \ No newline at end of file diff --git a/examples/p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl b/examples/p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl new file mode 100644 index 00000000000..6673053d88f --- /dev/null +++ b/examples/p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl @@ -0,0 +1,108 @@ + +using Trixi +using OrdinaryDiffEq +using Downloads: download + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations2D(1.4) + +@inline function initial_condition_mach2_flow(x, t, equations::CompressibleEulerEquations2D) + # set the freestream flow parameters + rho_freestream = 1.4 + v1 = 2.0 + v2 = 0.0 + p_freestream = 1.0 + + prim = SVector(rho_freestream, v1, v2, p_freestream) + return prim2cons(prim, equations) +end + +initial_condition = initial_condition_mach2_flow + +# Supersonic inflow boundary condition. +# Calculate the boundary flux entirely from the external solution state, i.e., set +# external solution state values for everything entering the domain. +@inline function boundary_condition_supersonic_inflow(u_inner, + normal_direction::AbstractVector, + x, t, surface_flux_function, + equations::CompressibleEulerEquations2D) + u_boundary = initial_condition_mach2_flow(x, t, equations) + flux = Trixi.flux(u_boundary, normal_direction, equations) + + return flux +end + +# Supersonic outflow boundary condition. +# Calculate the boundary flux entirely from the internal solution state. Analogous to supersonic inflow +# except all the solution state values are set from the internal solution as everything leaves the domain +@inline function boundary_condition_supersonic_outflow(u_inner, + normal_direction::AbstractVector, x, + t, + surface_flux_function, + equations::CompressibleEulerEquations2D) + flux = Trixi.flux(u_inner, normal_direction, equations) + + return flux +end + +polydeg = 3 + +surface_flux = flux_lax_friedrichs +volume_flux = flux_ranocha + +basis = LobattoLegendreBasis(polydeg) +shock_indicator = IndicatorHennemannGassner(equations, basis, + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = density_pressure) +volume_integral = VolumeIntegralShockCapturingHG(shock_indicator; + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) + +# DG Solver +solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, + volume_integral = volume_integral) + +# Mesh generated from the following gmsh geometry input file: +# 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) + +boundary_symbols = [:PhysicalLine1, :PhysicalLine2, :PhysicalLine3, :PhysicalLine4] + +mesh = P4estMesh{2}(mesh_file, polydeg = polydeg, boundary_symbols = boundary_symbols) + +boundary_conditions = Dict(:PhysicalLine1 => boundary_condition_supersonic_inflow, # Left boundary + :PhysicalLine2 => boundary_condition_supersonic_outflow, # Right boundary + :PhysicalLine3 => boundary_condition_slip_wall, # Airfoil + :PhysicalLine4 => boundary_condition_supersonic_outflow) # Top and bottom boundary + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) + +tspan = (0.0, 5.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +stepsize_callback = StepsizeCallback(cfl = 4.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + stepsize_callback) + +# Run the simulation +############################################################################### +sol = solve(ode, SSPRK104(; thread = OrdinaryDiffEq.True()); + dt = 1.0, # overwritten by the `stepsize_callback` + callback = callbacks); + +summary_callback() # print the timer summary diff --git a/examples/p4est_3d_dgsem/elixir_euler_free_stream_boundaries.jl b/examples/p4est_3d_dgsem/elixir_euler_free_stream_boundaries.jl new file mode 100644 index 00000000000..bdc4da26c1f --- /dev/null +++ b/examples/p4est_3d_dgsem/elixir_euler_free_stream_boundaries.jl @@ -0,0 +1,60 @@ + +using Downloads: download +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations3D(1.4) + +initial_condition = initial_condition_constant + +polydeg = 3 +solver = DGSEM(polydeg = polydeg, surface_flux = flux_lax_friedrichs) + +############################################################################### +# 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) || + 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) + +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.0, 1.0) +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.5) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_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/src/meshes/p4est_mesh.jl b/src/meshes/p4est_mesh.jl index 60db285e04f..c5d39ef00c0 100644 --- a/src/meshes/p4est_mesh.jl +++ b/src/meshes/p4est_mesh.jl @@ -289,7 +289,8 @@ end P4estMesh{NDIMS}(meshfile::String; mapping=nothing, polydeg=1, RealT=Float64, initial_refinement_level=0, unsaved_changes=true, - p4est_partition_allow_for_coarsening=true) + p4est_partition_allow_for_coarsening=true, + boundary_symbols = nothing) Main mesh constructor for the `P4estMesh` that imports an unstructured, conforming mesh from an Abaqus mesh file (`.inp`). Each element of the conforming mesh parsed @@ -310,8 +311,9 @@ To create a curved unstructured mesh `P4estMesh` two strategies are available: straight-sided from the information parsed from the `meshfile`. If a mapping function is specified then it computes the mapped tree coordinates via polynomial interpolants with degree `polydeg`. The mesh created by this function will only - have one boundary `:all`, as distinguishing different physical boundaries is - non-trivial. + have one boundary `:all` if `boundary_symbols` is not specified. + If `boundary_symbols` is specified the mesh file will be parsed for nodesets defining + the boundary nodes from which boundary edges (2D) and faces (3D) will be assigned. Note that the `mapping` and `polydeg` keyword arguments are only used by the `p4est_mesh_from_standard_abaqus` function. The `p4est_mesh_from_hohqmesh_abaqus` function obtains the mesh `polydeg` directly from the `meshfile` @@ -345,11 +347,14 @@ For example, if a two-dimensional base mesh contains 25 elements then setting - `p4est_partition_allow_for_coarsening::Bool`: Must be `true` when using AMR to make mesh adaptivity 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`. """ function P4estMesh{NDIMS}(meshfile::String; mapping = nothing, polydeg = 1, RealT = Float64, initial_refinement_level = 0, unsaved_changes = true, - p4est_partition_allow_for_coarsening = true) where {NDIMS} + p4est_partition_allow_for_coarsening = true, + boundary_symbols = nothing) where {NDIMS} # Prevent `p4est` from crashing Julia if the file doesn't exist @assert isfile(meshfile) @@ -373,7 +378,8 @@ function P4estMesh{NDIMS}(meshfile::String; polydeg, initial_refinement_level, NDIMS, - RealT) + RealT, + boundary_symbols) end return P4estMesh{NDIMS}(p4est, tree_node_coordinates, nodes, @@ -444,7 +450,8 @@ end # the `mapping` passed to this function using polynomial interpolants of degree `polydeg`. All boundary # names are given the name `:all`. function p4est_mesh_from_standard_abaqus(meshfile, mapping, polydeg, - initial_refinement_level, n_dimensions, RealT) + initial_refinement_level, n_dimensions, RealT, + boundary_symbols) # Create the mesh connectivity using `p4est` connectivity = read_inp_p4est(meshfile, Val(n_dimensions)) connectivity_pw = PointerWrapper(connectivity) @@ -469,12 +476,215 @@ function p4est_mesh_from_standard_abaqus(meshfile, mapping, polydeg, p4est = new_p4est(connectivity, initial_refinement_level) - # There's no simple and generic way to distinguish boundaries. Name all of them :all. - boundary_names = fill(:all, 2 * n_dimensions, n_trees) + if boundary_symbols === nothing + # There's no simple and generic way to distinguish boundaries without any information given. + # Name all of them :all. + boundary_names = fill(:all, 2 * n_dimensions, n_trees) + else # Boundary information given + # Read in nodes belonging to boundaries + node_set_dict = parse_node_sets(meshfile, boundary_symbols) + # Read in all elements with associated nodes to specify the boundaries + element_node_matrix = parse_elements(meshfile, n_trees, n_dimensions) + + # Initialize boundary information matrix with symbol for no boundary / internal connection + boundary_names = fill(Symbol("---"), 2 * n_dimensions, n_trees) + + # Fill `boundary_names` such that it can be processed by p4est + assign_boundaries_standard_abaqus!(boundary_names, n_trees, + element_node_matrix, node_set_dict, + Val(n_dimensions)) + end return p4est, tree_node_coordinates, nodes, boundary_names end +function parse_elements(meshfile, n_trees, n_dims) + @assert n_dims in (2, 3) "Only 2D and 3D meshes are supported" + # Valid element types (that can be processed by p4est) based on dimension + 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 + expected_content_length = n_dims == 2 ? 5 : 9 + + element_node_matrix = Matrix{Int64}(undef, n_trees, expected_content_length - 1) + el_list_follows = false + tree_id = 1 + + open(meshfile, "r") do file + for line in eachline(file) + if any(startswith(line, el_type) for el_type in element_types) + el_list_follows = true + elseif el_list_follows + content = split(line, ",") + if length(content) == expected_content_length # Check that we still read in connectivity data + content_int = parse.(Int64, content) + # Add constituent nodes to the element_node_matrix. + # Important: Do not use index from the Abaqus file, but the one from p4est. + element_node_matrix[tree_id, :] = content_int[2:end] # First entry is element id + tree_id += 1 + else # Processed all elements for this ELSET + el_list_follows = false + end + end + end + end + + return element_node_matrix +end + +function parse_node_sets(meshfile, boundary_symbols) + nodes_dict = Dict{Symbol, Vector{Int64}}() + current_symbol = nothing + current_nodes = Int64[] + + open(meshfile, "r") do file + for line in eachline(file) + # Check if the line contains nodes assembled in a special set, i.e., a physical boundary + if startswith(line, "*NSET,NSET=") + # Safe the previous nodeset + if current_symbol !== nothing + nodes_dict[current_symbol] = current_nodes + end + + current_symbol = Symbol(split(line, "=")[2]) + if current_symbol in boundary_symbols + # New nodeset + current_nodes = Int64[] + else # Read only boundary node sets + current_symbol = nothing + end + elseif current_symbol !== nothing # Read only if there was already a nodeset specified + try # Check if line contains nodes + # There is always a trailing comma, remove the corresponding empty string + append!(current_nodes, parse.(Int64, split(line, ",")[1:(end - 1)])) + catch # Something different, stop reading in nodes + # If parsing fails, set current_symbol to nothing + nodes_dict[current_symbol] = current_nodes + current_symbol = nothing + end + end + end + # Safe the previous nodeset + if current_symbol !== nothing + nodes_dict[current_symbol] = current_nodes + end + end + + for symbol in boundary_symbols + if !haskey(nodes_dict, symbol) + @warn "No nodes found for nodeset :" * "$symbol" * " !" + end + end + + return nodes_dict +end + +# This function assigns the edges of elements to boundaries by +# checking if the nodes that define the edges are part of nodesets which correspond to boundaries. +function assign_boundaries_standard_abaqus!(boundary_names, n_trees, + element_node_matrix, node_set_dict, + ::Val{2}) # 2D version + for tree in 1:n_trees + tree_nodes = element_node_matrix[tree, :] + # 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 + # Check bottom edge + if tree_nodes[1] in node_set_dict[boundary] && + tree_nodes[2] in node_set_dict[boundary] + # Bottom boundary is position 3 in p4est indexing + boundary_names[3, tree] = boundary + end + # Check right edge + if tree_nodes[2] in node_set_dict[boundary] && + tree_nodes[3] in node_set_dict[boundary] + # Right boundary is position 2 in p4est indexing + boundary_names[2, tree] = boundary + end + # Check top edge + if tree_nodes[3] in node_set_dict[boundary] && + tree_nodes[4] in node_set_dict[boundary] + # Top boundary is position 4 in p4est indexing + boundary_names[4, tree] = boundary + end + # Check left edge + if tree_nodes[4] in node_set_dict[boundary] && + tree_nodes[1] in node_set_dict[boundary] + # Left boundary is position 1 in p4est indexing + boundary_names[1, tree] = boundary + end + end + end + + return boundary_names +end + +# This function assigns the edges of elements to boundaries by +# checking if the nodes that define the faces are part of nodesets which correspond to boundaries. +function assign_boundaries_standard_abaqus!(boundary_names, n_trees, + element_node_matrix, node_set_dict, + ::Val{3}) # 3D version + for tree in 1:n_trees + tree_nodes = element_node_matrix[tree, :] + # 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) + if tree_nodes[1] in node_set_dict[boundary] && + tree_nodes[2] in node_set_dict[boundary] && + tree_nodes[5] in node_set_dict[boundary] && + tree_nodes[6] in node_set_dict[boundary] + # Front face is position 3 in p4est indexing + boundary_names[3, tree] = boundary + end + # Check "back face" (y_max) + if tree_nodes[3] in node_set_dict[boundary] && + tree_nodes[4] in node_set_dict[boundary] && + tree_nodes[7] in node_set_dict[boundary] && + tree_nodes[8] in node_set_dict[boundary] + # Front face is position 4 in p4est indexing + boundary_names[4, tree] = boundary + end + # Check "left face" (x_min) + if tree_nodes[1] in node_set_dict[boundary] && + tree_nodes[4] in node_set_dict[boundary] && + tree_nodes[5] in node_set_dict[boundary] && + tree_nodes[8] in node_set_dict[boundary] + # Left face is position 1 in p4est indexing + boundary_names[1, tree] = boundary + end + # Check "right face" (x_max) + if tree_nodes[2] in node_set_dict[boundary] && + tree_nodes[3] in node_set_dict[boundary] && + tree_nodes[6] in node_set_dict[boundary] && + tree_nodes[7] in node_set_dict[boundary] + # Right face is position 2 in p4est indexing + boundary_names[2, tree] = boundary + end + # Check "bottom face" (z_min) + if tree_nodes[1] in node_set_dict[boundary] && + tree_nodes[2] in node_set_dict[boundary] && + tree_nodes[3] in node_set_dict[boundary] && + tree_nodes[4] in node_set_dict[boundary] + # Bottom face is position 5 in p4est indexing + boundary_names[5, tree] = boundary + end + # Check "top face" (z_max) + if tree_nodes[5] in node_set_dict[boundary] && + tree_nodes[6] in node_set_dict[boundary] && + tree_nodes[7] in node_set_dict[boundary] && + tree_nodes[8] in node_set_dict[boundary] + # Top face is position 6 in p4est indexing + boundary_names[6, tree] = boundary + end + end + end + + return boundary_names +end + """ P4estMeshCubedSphere(trees_per_face_dimension, layers, inner_radius, thickness; polydeg, RealT=Float64, diff --git a/test/test_p4est_2d.jl b/test/test_p4est_2d.jl index cebc2917d52..b034091a175 100644 --- a/test/test_p4est_2d.jl +++ b/test/test_p4est_2d.jl @@ -391,6 +391,27 @@ end end end +@trixi_testset "elixir_euler_NACA6412airfoil_mach2.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_NACA6412airfoil_mach2.jl"), + l2=[ + 1.9752162683735258e-9, 3.150450205812513e-9, + 1.8885499402935914e-9, 7.273629602920966e-9, + ], + linf=[ + 6.007577890709825e-7, 1.005273289944597e-6, + 5.948514542597182e-7, 2.3111764217986774e-6, + ], + tspan=(0.0, 0.1)) + # 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_eulergravity_convergence.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_eulergravity_convergence.jl"), l2=[ diff --git a/test/test_p4est_3d.jl b/test/test_p4est_3d.jl index dc5d32b5a04..ea7d9193add 100644 --- a/test/test_p4est_3d.jl +++ b/test/test_p4est_3d.jl @@ -234,6 +234,29 @@ end end end +@trixi_testset "elixir_euler_free_stream_boundaries.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_free_stream_boundaries.jl"), + l2=[ + 6.530157034651212e-16, 1.6057829680004379e-15, + 3.31107455378537e-15, 3.908829498281281e-15, + 5.048390610424672e-15, + ], + linf=[ + 4.884981308350689e-15, 1.1921019726912618e-14, + 1.5432100042289676e-14, 2.298161660974074e-14, + 6.039613253960852e-14, + ]) + # 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=[ From c021c4816b8f0d8aa81c990439771f26684f93b0 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Thu, 25 Jan 2024 14:34:19 +0100 Subject: [PATCH 228/263] set version to v0.6.7 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index f246bdfdab4..8532e47f761 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.6.7-pre" +version = "0.6.7" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 246dc5be204c8937f077a1d12b5603bb70138357 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Thu, 25 Jan 2024 14:34:36 +0100 Subject: [PATCH 229/263] set development version to v0.6.8-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 8532e47f761..1a0aa0103dc 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.6.7" +version = "0.6.8-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 70d365f405c2494e314277f22e63dcc32d04f095 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Thu, 25 Jan 2024 16:09:57 +0100 Subject: [PATCH 230/263] Fix Docs rendering: Avoid Markdown hyperlink (#1814) * Avoid hyperlink in doc * Update docs/src/meshes/p4est_mesh.md Co-authored-by: Michael Schlottke-Lakemper * Apply suggestions from code review Co-authored-by: Michael Schlottke-Lakemper --------- Co-authored-by: Michael Schlottke-Lakemper --- docs/src/meshes/p4est_mesh.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/meshes/p4est_mesh.md b/docs/src/meshes/p4est_mesh.md index db75346cab3..3b35ffcad6f 100644 --- a/docs/src/meshes/p4est_mesh.md +++ b/docs/src/meshes/p4est_mesh.md @@ -55,7 +55,7 @@ This heading is used to indicate to the mesh constructor which of the above mapp create a curvilinear mesh. If the Abaqus file header is **not** present then the `P4estMesh` is created with the first strategy above. -#### List of corner nodes +#### [List of corner nodes](@id corner-node-list) Next, prefaced with `*NODE`, comes a list of the physical `(x,y,z)` coordinates of all the corners. The first integer in the list of the corners provides its id number. @@ -71,7 +71,7 @@ Thus, for the two-dimensional example mesh this block of corner information is 7, 3.0, -1.0, 0.0 ``` -#### List of elements +#### [List of elements](@id element-list) The element connectivity is given after the list of corners. The header for this information block is ``` @@ -237,7 +237,7 @@ For completeness, we provide the entire Abaqus mesh file for the example mesh in As an alternative to an Abaqus mesh generated by `HOHQMesh`, `.inp` files with boundary information encoded as nodesets `*NSET,NSET=` can be used to construct a `p4est` mesh. This is especially useful for usage of existing meshes (consisting of bilinear elements) which could stem from the popular [`gmsh`](https://gmsh.info/) meshing software. -In addition to the list of [nodes](#nodes) and [elements](#elements) given above, there are nodesets of the form +In addition to the list of [nodes](@ref corner-node-list) and [elements](@ref element-list) given above, there are nodesets of the form ``` *NSET,NSET=PhysicalLine1 1, 4, 52, 53, 54, 55, 56, 57, 58, From 367881bb713f8671acc1a42ae28a3d68f3000935 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Mon, 29 Jan 2024 09:29:02 +0100 Subject: [PATCH 231/263] Correct NACA6412 BC assignment (#1815) --- docs/literate/src/files/p4est_from_gmsh.jl | 8 ++++---- .../p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl | 4 ++-- test/test_p4est_2d.jl | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/literate/src/files/p4est_from_gmsh.jl b/docs/literate/src/files/p4est_from_gmsh.jl index 356339cdd47..abfe70eebc4 100644 --- a/docs/literate/src/files/p4est_from_gmsh.jl +++ b/docs/literate/src/files/p4est_from_gmsh.jl @@ -347,8 +347,8 @@ end #hide #md # // labeling of the boundary parts # Physical Line(1) = {4}; // Inflow. Label in Abaqus .inp file: PhysicalLine1 # Physical Line(2) = {2}; // Outflow. Label in Abaqus .inp file: PhysicalLine2 -# Physical Line(3) = {1, 3}; // Airfoil. Label in Abaqus .inp file: PhysicalLine3 -# Physical Line(4) = {5, 6}; //Upper and lower wall/farfield/... Label in Abaqus .inp file: PhysicalLine4 +# Physical Line(3) = {1, 3}; // Upper and lower wall/farfield/... Label in Abaqus .inp file: PhysicalLine3 +# Physical Line(4) = {5, 6}; // Airfoil. Label in Abaqus .inp file: PhysicalLine4 # ``` # which are crucial for the correct assignment of boundary conditions in `Trixi.jl`. # In particular, it is the responsibility of a user to keep track on the physical boundary names between the mesh generation and assignment of boundary condition functions in an elixir. @@ -437,8 +437,8 @@ end #hide #md # # boundary_conditions = Dict(:PhysicalLine1 => boundary_condition_supersonic_inflow, # Left boundary # :PhysicalLine2 => boundary_condition_supersonic_outflow, # Right boundary -# :PhysicalLine3 => boundary_condition_slip_wall, # Airfoil -# :PhysicalLine4 => 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, # boundary_conditions = boundary_conditions) diff --git a/examples/p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl b/examples/p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl index 6673053d88f..fcd2ca00e10 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl @@ -79,8 +79,8 @@ 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_slip_wall, # Airfoil - :PhysicalLine4 => 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, boundary_conditions = boundary_conditions) diff --git a/test/test_p4est_2d.jl b/test/test_p4est_2d.jl index b034091a175..121001b35ff 100644 --- a/test/test_p4est_2d.jl +++ b/test/test_p4est_2d.jl @@ -394,12 +394,12 @@ end @trixi_testset "elixir_euler_NACA6412airfoil_mach2.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_NACA6412airfoil_mach2.jl"), l2=[ - 1.9752162683735258e-9, 3.150450205812513e-9, - 1.8885499402935914e-9, 7.273629602920966e-9, + 0.19107654776276498, 0.3545913719444839, + 0.18492730895077583, 0.817927213517244, ], linf=[ - 6.007577890709825e-7, 1.005273289944597e-6, - 5.948514542597182e-7, 2.3111764217986774e-6, + 2.5397624311491946, 2.7075156425517917, 2.200980534211764, + 9.031153939238115, ], tspan=(0.0, 0.1)) # Ensure that we do not have excessive memory allocations From 38100d0a855b0a370c0fd65fbe9bfbe301f5d096 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 29 Jan 2024 09:44:45 +0100 Subject: [PATCH 232/263] set version to v0.6.8 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 1a0aa0103dc..29e36a46dc5 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.6.8-pre" +version = "0.6.8" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From fcf2652f8ce3f16ba640a66990134632c9f8d3d5 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 29 Jan 2024 09:44:57 +0100 Subject: [PATCH 233/263] set development version to v0.6.9-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 29e36a46dc5..0bbdec206d8 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.6.8" +version = "0.6.9-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From f4e6e494846784e513987a91d2248c04fd616029 Mon Sep 17 00:00:00 2001 From: Benjamin Bolm <74359358+bennibolm@users.noreply.github.com> Date: Tue, 30 Jan 2024 11:07:31 +0100 Subject: [PATCH 234/263] (Thread-)Parallelize bounds check routine for subcell IDP limiting (#1736) * Implement parallel bounds check for IDP limiting * Add missing warning as "experimental" from last PR * Updating `idp_bounds_delta_threaded` for all bounds at once * Revise parallel memory structure * Using maximum instead of reduce * Expand vector length to fix False Sharing problem * Generalize stride size in vector * Add suggested comment --- src/callbacks_stage/subcell_bounds_check.jl | 10 ++- .../subcell_bounds_check_2d.jl | 81 ++++++++++++------- .../dgsem_tree/dg_2d_subcell_limiters.jl | 3 + src/solvers/dgsem_tree/subcell_limiters_2d.jl | 23 ++++-- 4 files changed, 80 insertions(+), 37 deletions(-) diff --git a/src/callbacks_stage/subcell_bounds_check.jl b/src/callbacks_stage/subcell_bounds_check.jl index d7e30ab1621..9f34a6b3b4b 100644 --- a/src/callbacks_stage/subcell_bounds_check.jl +++ b/src/callbacks_stage/subcell_bounds_check.jl @@ -118,7 +118,7 @@ end @inline function finalize_callback(callback::BoundsCheckCallback, semi, limiter::SubcellLimiterIDP) (; local_minmax, positivity) = limiter - (; idp_bounds_delta) = limiter.cache + (; idp_bounds_delta_global) = limiter.cache variables = varnames(cons2cons, semi.equations) println("─"^100) @@ -128,8 +128,10 @@ end for v in limiter.local_minmax_variables_cons v_string = string(v) println("$(variables[v]):") - println("-lower bound: ", idp_bounds_delta[Symbol(v_string, "_min")][2]) - println("-upper bound: ", idp_bounds_delta[Symbol(v_string, "_max")][2]) + println("- lower bound: ", + idp_bounds_delta_global[Symbol(v_string, "_min")]) + println("- upper bound: ", + idp_bounds_delta_global[Symbol(v_string, "_max")]) end end if positivity @@ -138,7 +140,7 @@ end continue end println(string(variables[v]) * ":\n- positivity: ", - idp_bounds_delta[Symbol(string(v), "_min")][2]) + idp_bounds_delta_global[Symbol(string(v), "_min")]) end end println("─"^100 * "\n") diff --git a/src/callbacks_stage/subcell_bounds_check_2d.jl b/src/callbacks_stage/subcell_bounds_check_2d.jl index d52eb6edb9e..545d19b5136 100644 --- a/src/callbacks_stage/subcell_bounds_check_2d.jl +++ b/src/callbacks_stage/subcell_bounds_check_2d.jl @@ -10,26 +10,37 @@ time, iter, output_directory, save_errors) (; local_minmax, positivity) = solver.volume_integral.limiter (; variable_bounds) = limiter.cache.subcell_limiter_coefficients - (; idp_bounds_delta) = limiter.cache + (; idp_bounds_delta_local, idp_bounds_delta_global) = limiter.cache + + # Note: Accessing the threaded memory vector `idp_bounds_delta_local` with + # `deviation = idp_bounds_delta_local[key][Threads.threadid()]` causes critical performance + # issues due to False Sharing. + # Initializing a vector with n times the length and using every n-th entry fixes this + # problem and allows proper scaling: + # `deviation = idp_bounds_delta_local[key][n * Threads.threadid()]` + # Since there are no processors with caches over 128B, we use `n = 128B / size(uEltype)` + stride_size = div(128, sizeof(eltype(u))) # = n if local_minmax for v in limiter.local_minmax_variables_cons v_string = string(v) key_min = Symbol(v_string, "_min") key_max = Symbol(v_string, "_max") - deviation_min = idp_bounds_delta[key_min] - deviation_max = idp_bounds_delta[key_max] - for element in eachelement(solver, cache), j in eachnode(solver), - i in eachnode(solver) - - var = u[v, i, j, element] - deviation_min[1] = max(deviation_min[1], - variable_bounds[key_min][i, j, element] - var) - deviation_max[1] = max(deviation_max[1], - var - variable_bounds[key_max][i, j, element]) + deviation_min_threaded = idp_bounds_delta_local[key_min] + deviation_max_threaded = idp_bounds_delta_local[key_max] + @threaded for element in eachelement(solver, cache) + deviation_min = deviation_min_threaded[stride_size * Threads.threadid()] + deviation_max = deviation_max_threaded[stride_size * Threads.threadid()] + for j in eachnode(solver), i in eachnode(solver) + var = u[v, i, j, element] + deviation_min = max(deviation_min, + variable_bounds[key_min][i, j, element] - var) + deviation_max = max(deviation_max, + var - variable_bounds[key_max][i, j, element]) + end + deviation_min_threaded[stride_size * Threads.threadid()] = deviation_min + deviation_max_threaded[stride_size * Threads.threadid()] = deviation_max end - deviation_min[2] = max(deviation_min[2], deviation_min[1]) - deviation_max[2] = max(deviation_max[2], deviation_max[1]) end end if positivity @@ -38,17 +49,28 @@ continue end key = Symbol(string(v), "_min") - deviation = idp_bounds_delta[key] - for element in eachelement(solver, cache), j in eachnode(solver), - i in eachnode(solver) - - var = u[v, i, j, element] - deviation[1] = max(deviation[1], - variable_bounds[key][i, j, element] - var) + deviation_threaded = idp_bounds_delta_local[key] + @threaded for element in eachelement(solver, cache) + deviation = deviation_threaded[stride_size * Threads.threadid()] + for j in eachnode(solver), i in eachnode(solver) + var = u[v, i, j, element] + deviation = max(deviation, + variable_bounds[key][i, j, element] - var) + end + deviation_threaded[stride_size * Threads.threadid()] = deviation end - deviation[2] = max(deviation[2], deviation[1]) end end + + for (key, _) in idp_bounds_delta_local + # Calculate maximum deviations of all threads + idp_bounds_delta_local[key][stride_size] = maximum(idp_bounds_delta_local[key][stride_size * i] + for i in 1:Threads.nthreads()) + # Update global maximum deviations + idp_bounds_delta_global[key] = max(idp_bounds_delta_global[key], + idp_bounds_delta_local[key][stride_size]) + end + if save_errors # Print to output file open("$output_directory/deviations.txt", "a") do f @@ -56,8 +78,10 @@ if local_minmax for v in limiter.local_minmax_variables_cons v_string = string(v) - print(f, ", ", idp_bounds_delta[Symbol(v_string, "_min")][1], ", ", - idp_bounds_delta[Symbol(v_string, "_max")][1]) + print(f, ", ", + idp_bounds_delta_local[Symbol(v_string, "_min")][stride_size], + ", ", + idp_bounds_delta_local[Symbol(v_string, "_max")][stride_size]) end end if positivity @@ -65,14 +89,17 @@ if v in limiter.local_minmax_variables_cons continue end - print(f, ", ", idp_bounds_delta[Symbol(string(v), "_min")][1]) + print(f, ", ", + idp_bounds_delta_local[Symbol(string(v), "_min")][stride_size]) end end println(f) end - # Reset first entries of idp_bounds_delta - for (key, _) in idp_bounds_delta - idp_bounds_delta[key][1] = zero(eltype(idp_bounds_delta[key][1])) + # Reset local maximum deviations + for (key, _) in idp_bounds_delta_local + for i in 1:Threads.nthreads() + idp_bounds_delta_local[key][stride_size * i] = zero(eltype(idp_bounds_delta_local[key][stride_size])) + end end end diff --git a/src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl b/src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl index 2fc62f548d2..9af8b65b4cd 100644 --- a/src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl +++ b/src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl @@ -470,6 +470,9 @@ end For subcell limiting, the calculation of local bounds for non-periodic domains require the boundary outer state. This function returns the boundary value at time `t` and for node with spatial indices `indices`. + +!!! warning "Experimental implementation" + This is an experimental feature and may change in future releases. """ @inline function get_boundary_outer_state(boundary_condition::BoundaryConditionDirichlet, cache, t, equations, dg, indices...) diff --git a/src/solvers/dgsem_tree/subcell_limiters_2d.jl b/src/solvers/dgsem_tree/subcell_limiters_2d.jl index 384f4178bc9..3d272359fe4 100644 --- a/src/solvers/dgsem_tree/subcell_limiters_2d.jl +++ b/src/solvers/dgsem_tree/subcell_limiters_2d.jl @@ -13,21 +13,32 @@ function create_cache(limiter::Type{SubcellLimiterIDP}, equations::AbstractEquat bound_keys) # Memory for bounds checking routine with `BoundsCheckCallback`. - # The first entry of each vector contains the maximum deviation since the last export. - # The second one contains the total maximum deviation. - idp_bounds_delta = Dict{Symbol, Vector{real(basis)}}() + # Local variable contains the maximum deviation since the last export. + # Using a threaded vector to parallelize bounds check. + idp_bounds_delta_local = Dict{Symbol, Vector{real(basis)}}() + # Global variable contains the total maximum deviation. + idp_bounds_delta_global = Dict{Symbol, real(basis)}() + # Note: False sharing causes critical performance issues on multiple threads when using a vector + # of length `Threads.nthreads()`. Initializing a vector of length `n * Threads.nthreads()` + # and then only using every n-th entry, fixes the problem and allows proper scaling. + # Since there are no processors with caches over 128B, we use `n = 128B / size(uEltype)` + stride_size = div(128, sizeof(eltype(basis.nodes))) # = n for key in bound_keys - idp_bounds_delta[key] = zeros(real(basis), 2) + idp_bounds_delta_local[key] = [zero(real(basis)) + for _ in 1:(stride_size * Threads.nthreads())] + idp_bounds_delta_global[key] = zero(real(basis)) end - return (; subcell_limiter_coefficients, idp_bounds_delta) + return (; subcell_limiter_coefficients, idp_bounds_delta_local, + idp_bounds_delta_global) end function (limiter::SubcellLimiterIDP)(u::AbstractArray{<:Any, 4}, semi, dg::DGSEM, t, dt; kwargs...) @unpack alpha = limiter.cache.subcell_limiter_coefficients - alpha .= zero(eltype(alpha)) + # TODO: Do not abuse `reset_du!` but maybe implement a generic `set_zero!` + @trixi_timeit timer() "reset alpha" reset_du!(alpha, dg, semi.cache) if limiter.local_minmax @trixi_timeit timer() "local min/max limiting" idp_local_minmax!(alpha, limiter, From 4b07706f01cc17c7ef6215c21da312e221cb0c00 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Tue, 30 Jan 2024 20:32:24 +0100 Subject: [PATCH 235/263] Do not safe sol (#1820) --- examples/p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl b/examples/p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl index fcd2ca00e10..7e55a259596 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl @@ -103,6 +103,7 @@ callbacks = CallbackSet(summary_callback, ############################################################################### sol = solve(ode, SSPRK104(; thread = OrdinaryDiffEq.True()); dt = 1.0, # overwritten by the `stepsize_callback` + save_everystep = false, callback = callbacks); summary_callback() # print the timer summary From 07990295b7ba155669ef4c2953809abe8e3c4880 Mon Sep 17 00:00:00 2001 From: Simon Candelaresi <10759273+SimonCan@users.noreply.github.com> Date: Wed, 31 Jan 2024 13:21:11 +0000 Subject: [PATCH 236/263] Sc/converters coupling (#1558) * Added coupling converters. * Added generic converter_function for structured 2d meshes. * Added example elixir for coupling converters. * Cleaned up converter coupling elixir. * Added equations in coupling converters. * Added converter functions. * Added identity converter function. * Autoformat for converter coupling implementation. * Added coupled converter elixir. * Corrected file name of coupled converters test. * Removed redundant doc string. * Added function signature in doc string. * Removed coverage_override in coupled tests. * Removed old commented code. * Update make.jl Added interface coupling docs to the main menu. * Update make.jl Moved converter coupling section. * Create coupling.md * Update coupling.md Added some documentation on coupling converters. * Removed troublesome AnalysisCallbackCoupled from test. * Chenged coupling converter function. * Changed coupling converter function and updated tests. * Sepcialized coupling function call. * Removed volume coupling from documentation to avoit confusion. * Update src/coupling_converters/coupling_converters.jl Co-authored-by: Hendrik Ranocha * Removed redundant converter function for coupling. * Removed redundant coupling converter file mentioned in some files. * Autoreformatted. * Removed old coupled elixir and replaced it with one using converter functions. * Updated errors for coupled tests. * Corrected test results for coupled equations. * Corrected comment. * Removed coupled test from special tests. * Removed coupled test from specials. * Chaned the coupling function to the identity. * Updated coupling tests. * Updated errors for coupled test. * Added advice about binary compatability for coupled equations in the documentation. * Typo. * Added numerical fluxes. * Corrected rs copy routine. Now loop over this semi's components. * Reformatted equations source file. * Removed problemating include of time_integration.jl. * Removed export of deleted methods. * Reverted to old version of compressible Euler multicomponent with no support for structured grid. * Renamed documentation file for multi-physics coupling. * Renamed doc reference. * Update src/semidiscretization/semidiscretization_coupled.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/src/multi-physics_coupling.md Co-authored-by: Michael Schlottke-Lakemper * Update docs/src/multi-physics_coupling.md Co-authored-by: Michael Schlottke-Lakemper * Update docs/src/multi-physics_coupling.md Co-authored-by: Michael Schlottke-Lakemper * Reinstated structured_2d_dgsem coupled in special tests. * Update examples/structured_2d_dgsem/elixir_advection_coupled.jl Co-authored-by: Michael Schlottke-Lakemper * Renamed CouplingFunction to CouplingConverter. * Update src/semidiscretization/semidiscretization_coupled.jl Co-authored-by: Michael Schlottke-Lakemper * Cleaned the copy of coupled boundary values. * Reduced time span for example coupling elixir. * Removed redundant loop. * Applied formatter. * Removed default coupling covnerter function. * Moved coupling converter function into elixir. * Apply suggestions from code review Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/make.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Removed coupling_converters.jl from the include. * Corrected introduced issue with coupling boundary copy. The latest change to clean up the boundary copying introduced a bug related to the determination of the wrong node indices. This is now corrected. * Corrected comment on final simulation time. * Updated errors for coupled test to reflect changed final simulation time. * Added miladd. * Corrected coordinate finding in semidiscretization_coupled. * Fixed issued related to memory allocation. * Corrected loop over semidiscretization. * Removed commented out code. * Fixed type instability with loops over semidiscretizations using lispy tuple programming. * Removed obsolete code. * Fixed another typa instability in coupled semidiscretization. * Cleaning up of the coupled semidiscretization. * Autoformatted coupled semidiscretization. * Fixed last type instability in coupling. * Autoformatter on semidiscretization. * Fixed bug in boundary values copy that arose when coupling multiple systems. * aplpied autoformatter on coupled semidiscretization. * Extended the structured 2d example elixir for the coupled advection to 4 semidiscretizations. This hase two purpuses: 1. Users are given an example fro 2d coupling avoiding common pitfalls. 2. This increases the code coverege for the test. * Updated test results for coupled advection in 2d to reflect the 4 semidiscretizations that are now used. * Added correct errors for tests for the coupled adveciton equations in structured 2d. * Update examples/structured_2d_dgsem/elixir_advection_coupled.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * Update examples/structured_2d_dgsem/elixir_advection_coupled.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * Update src/semidiscretization/semidiscretization_coupled.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * Update src/semidiscretization/semidiscretization_coupled.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * Update src/semidiscretization/semidiscretization_coupled.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * Update src/semidiscretization/semidiscretization_coupled.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * Update src/semidiscretization/semidiscretization_coupled.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * Update src/semidiscretization/semidiscretization_coupled.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * Update src/semidiscretization/semidiscretization_coupled.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * Corrected foreach_enumerate implementation. * Fix closing parens * Remove unused recursive rhs! * Pass equations to converter function * Apply formatting * Reverted copy_to_coupled_boundary to previou version to avoid type instability. * Corrected computation of coupled semidiscretizations and fixed memory issue. * Removed redundant nelements function, as it is no longer used. * Applied autoformatter. * Improvements in style and added info about passing equations to coupling functions, as suggested by Andrew and Daniel. * Restored timings in semidiscretization coupled. --------- Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Hendrik Ranocha Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> --- docs/make.jl | 1 + docs/src/multi-physics_coupling.md | 46 +++++ .../elixir_advection_coupled.jl | 191 +++++++++++++----- .../semidiscretization_coupled.jl | 191 ++++++++++++------ test/test_structured_2d.jl | 28 ++- 5 files changed, 340 insertions(+), 117 deletions(-) create mode 100644 docs/src/multi-physics_coupling.md diff --git a/docs/make.jl b/docs/make.jl index dee87371bd1..7fce3b31e24 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -108,6 +108,7 @@ makedocs( ], "Time integration" => "time_integration.md", "Callbacks" => "callbacks.md", + "Coupling" => "multi-physics_coupling.md" ], "Advanced topics & developers" => [ "Conventions" =>"conventions.md", diff --git a/docs/src/multi-physics_coupling.md b/docs/src/multi-physics_coupling.md new file mode 100644 index 00000000000..eec92bc21de --- /dev/null +++ b/docs/src/multi-physics_coupling.md @@ -0,0 +1,46 @@ +# [Multi-physics coupling](@id multi-physics-coupling) +A complex simulation can consist of different spatial domains in which +different equations are being solved, different numerical methods being used +or the grid structure is different. +One example would be a fluid in a tank and an extended hot plate attached to it. +We would then like to solve the Navier-Stokes equations in the fluid domain +and the heat conduction equations in the plate. +The coupling would happen at the interface through the exchange of thermal energy. + + +## Converter coupling +It may happen that the two systems to be coupled do not share any variables, but +share some of the physics. +In such a situation, the same physics is just represented in a different form and with +a different set of variables. +This is the case, for instance assuming two domains, if there is a fluid system in one domain +and a Vlasov system in the other domain. +In that case we would have variables representing distribution functions of +the Vlasov system on one side and variables representing the mechanical quantities, like density, +of the fluid system. +To translate the fields from one description to the other one needs to use +converter functions. +These functions need to be hand tailored by the user in the elixir file where each +pair of coupled systems requires two coupling functions, one for each direction. + +In the general case, we have a system $A$ with $m$ variables +$u_{A,i}, \: i = 1, \dots, m$ and another +system $B$ with $n$ variables $u_{B,j}, \: j = 1, \dots, n$. +We then define two coupling functions, one that transforms $u_A$ into $u_B$ +and one that goes the other way. + +In their minimal form they take the position vector $x$, state vector $u$ +and the equations of the two coupled systems +and return the transformed variables. +By passing the equations we can make use of their parameters, if they are required. +Examples can be seen in `examples/structured_2d_dgsem/elixir_advection_coupled.jl`. + + +## Warning about binary compatibility +Currently the coordinate values on the nodes can differ by machine precision when +simulating the mesh and when splitting the mesh in multiple domains. +This is an issue coming from the coordinate interpolation on the nodes. +As a result, running a simulation in a single system and in two coupled domains +may result in a difference of the order of the machine precision. +While this is not an issue for most practical problems, it is best to keep this in mind when comparing test runs. + diff --git a/examples/structured_2d_dgsem/elixir_advection_coupled.jl b/examples/structured_2d_dgsem/elixir_advection_coupled.jl index 2a56d23f4c0..43b68f21b03 100644 --- a/examples/structured_2d_dgsem/elixir_advection_coupled.jl +++ b/examples/structured_2d_dgsem/elixir_advection_coupled.jl @@ -2,31 +2,38 @@ using OrdinaryDiffEq using Trixi ############################################################################### -# Coupled semidiscretization of two linear advection systems, which are connected periodically +# Coupled semidiscretization of four linear advection systems using converter functions such that +# they are also coupled across the domain boundaries to generate a periodic system. # -# In this elixir, we have a square domain that is divided into a left half and a right half. On each -# half of the domain, a completely independent SemidiscretizationHyperbolic is created for the -# linear advection equations. The two systems are coupled in the x-direction and have periodic -# boundaries in the y-direction. For a high-level overview, see also the figure below: +# In this elixir, we have a square domain that is divided into a upper-left, lower-left, +# upper-right and lower-right quarter. On each quarter +# of the domain, a completely independent SemidiscretizationHyperbolic is created for the +# linear advection equations. The four systems are coupled in the x and y-direction. +# For a high-level overview, see also the figure below: # # (-1, 1) ( 1, 1) # ┌────────────────────┬────────────────────┐ -# │ ↑ periodic ↑ │ ↑ periodic ↑ │ -# │ │ │ +# │ ↑ coupled ↑ │ ↑ coupled ↑ │ # │ │ │ # │ ========= │ ========= │ # │ system #1 │ system #2 │ # │ ========= │ ========= │ # │ │ │ +# │<-- coupled │<-- coupled │ +# │ coupled -->│ coupled -->│ # │ │ │ +# │ ↓ coupled ↓ │ ↓ coupled ↓ │ +# ├────────────────────┼────────────────────┤ +# │ ↑ coupled ↑ │ ↑ coupled ↑ │ # │ │ │ +# │ ========= │ ========= │ +# │ system #3 │ system #4 │ +# │ ========= │ ========= │ # │ │ │ -# │ coupled -->│<-- coupled │ -# │ │ │ -# │<-- coupled │ coupled -->│ -# │ │ │ +# │<-- coupled │<-- coupled │ +# │ coupled -->│ coupled -->│ # │ │ │ -# │ ↓ periodic ↓ │ ↓ periodic ↓ │ +# │ ↓ coupled ↓ │ ↓ coupled ↓ │ # └────────────────────┴────────────────────┘ # (-1, -1) ( 1, -1) @@ -36,60 +43,135 @@ 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) -# First mesh is the left half of a [-1,1]^2 square -coordinates_min1 = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) +# This will be the number of elements for each quarter/semidiscretization. +cells_per_dimension = (8, 8) + +########### +# system #1 +########### + +coordinates_min1 = (-1.0, 0.0) # minimum coordinates (min(x), min(y)) coordinates_max1 = (0.0, 1.0) # maximum coordinates (max(x), max(y)) -# Define identical resolution as a variable such that it is easier to change from `trixi_include` -cells_per_dimension = (8, 16) +mesh1 = StructuredMesh(cells_per_dimension, coordinates_min1, coordinates_max1) -cells_per_dimension1 = cells_per_dimension +# Define the coupling functions +coupling_function12 = (x, u, equations_other, equations_own) -> u +coupling_function13 = (x, u, equations_other, equations_own) -> u -mesh1 = StructuredMesh(cells_per_dimension1, coordinates_min1, coordinates_max1) +# Define the coupling boundary conditions and the system it is coupled to. +boundary_conditions_x_neg1 = BoundaryConditionCoupled(2, (:end, :i_forward), Float64, + coupling_function12) +boundary_conditions_x_pos1 = BoundaryConditionCoupled(2, (:begin, :i_forward), Float64, + coupling_function12) +boundary_conditions_y_neg1 = BoundaryConditionCoupled(3, (:i_forward, :end), Float64, + coupling_function13) +boundary_conditions_y_pos1 = BoundaryConditionCoupled(3, (:i_forward, :begin), Float64, + coupling_function13) # A semidiscretization collects data structures and functions for the spatial discretization semi1 = SemidiscretizationHyperbolic(mesh1, equations, initial_condition_convergence_test, solver, - boundary_conditions = ( - # Connect left boundary with right boundary of right mesh - x_neg = BoundaryConditionCoupled(2, - (:end, - :i_forward), - Float64), - # Connect right boundary with left boundary of right mesh - x_pos = BoundaryConditionCoupled(2, - (:begin, - :i_forward), - Float64), - y_neg = boundary_condition_periodic, - y_pos = boundary_condition_periodic)) - -# Second mesh is the right half of a [-1,1]^2 square -coordinates_min2 = (0.0, -1.0) # minimum coordinates (min(x), min(y)) + boundary_conditions = (x_neg = boundary_conditions_x_neg1, + x_pos = boundary_conditions_x_pos1, + y_neg = boundary_conditions_y_neg1, + y_pos = boundary_conditions_y_pos1)) + +########### +# system #2 +########### + +coordinates_min2 = (0.0, 0.0) # minimum coordinates (min(x), min(y)) coordinates_max2 = (1.0, 1.0) # maximum coordinates (max(x), max(y)) -cells_per_dimension2 = cells_per_dimension +mesh2 = StructuredMesh(cells_per_dimension, coordinates_min2, coordinates_max2) -mesh2 = StructuredMesh(cells_per_dimension2, coordinates_min2, coordinates_max2) +# Define the coupling functions +coupling_function21 = (x, u, equations_other, equations_own) -> u +coupling_function24 = (x, u, equations_other, equations_own) -> u +# Define the coupling boundary conditions and the system it is coupled to. +boundary_conditions_x_neg2 = BoundaryConditionCoupled(1, (:end, :i_forward), Float64, + coupling_function21) +boundary_conditions_x_pos2 = BoundaryConditionCoupled(1, (:begin, :i_forward), Float64, + coupling_function21) +boundary_conditions_y_neg2 = BoundaryConditionCoupled(4, (:i_forward, :end), Float64, + coupling_function24) +boundary_conditions_y_pos2 = BoundaryConditionCoupled(4, (:i_forward, :begin), Float64, + coupling_function24) + +# A semidiscretization collects data structures and functions for the spatial discretization semi2 = SemidiscretizationHyperbolic(mesh2, equations, initial_condition_convergence_test, solver, - boundary_conditions = ( - # Connect left boundary with right boundary of left mesh - x_neg = BoundaryConditionCoupled(1, - (:end, - :i_forward), - Float64), - # Connect right boundary with left boundary of left mesh - x_pos = BoundaryConditionCoupled(1, - (:begin, - :i_forward), - Float64), - y_neg = boundary_condition_periodic, - y_pos = boundary_condition_periodic)) - -# Create a semidiscretization that bundles semi1 and semi2 -semi = SemidiscretizationCoupled(semi1, semi2) + boundary_conditions = (x_neg = boundary_conditions_x_neg2, + x_pos = boundary_conditions_x_pos2, + y_neg = boundary_conditions_y_neg2, + y_pos = boundary_conditions_y_pos2)) + +########### +# system #3 +########### + +coordinates_min3 = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) +coordinates_max3 = (0.0, 0.0) # maximum coordinates (max(x), max(y)) + +mesh3 = StructuredMesh(cells_per_dimension, coordinates_min3, coordinates_max3) + +# Define the coupling functions +coupling_function34 = (x, u, equations_other, equations_own) -> u +coupling_function31 = (x, u, equations_other, equations_own) -> u + +# Define the coupling boundary conditions and the system it is coupled to. +boundary_conditions_x_neg3 = BoundaryConditionCoupled(4, (:end, :i_forward), Float64, + coupling_function34) +boundary_conditions_x_pos3 = BoundaryConditionCoupled(4, (:begin, :i_forward), Float64, + coupling_function34) +boundary_conditions_y_neg3 = BoundaryConditionCoupled(1, (:i_forward, :end), Float64, + coupling_function31) +boundary_conditions_y_pos3 = BoundaryConditionCoupled(1, (:i_forward, :begin), Float64, + coupling_function31) + +# A semidiscretization collects data structures and functions for the spatial discretization +semi3 = SemidiscretizationHyperbolic(mesh3, equations, initial_condition_convergence_test, + solver, + boundary_conditions = (x_neg = boundary_conditions_x_neg3, + x_pos = boundary_conditions_x_pos3, + y_neg = boundary_conditions_y_neg3, + y_pos = boundary_conditions_y_pos3)) + +########### +# system #4 +########### + +coordinates_min4 = (0.0, -1.0) # minimum coordinates (min(x), min(y)) +coordinates_max4 = (1.0, 0.0) # maximum coordinates (max(x), max(y)) + +mesh4 = StructuredMesh(cells_per_dimension, coordinates_min4, coordinates_max4) + +# Define the coupling functions +coupling_function43 = (x, u, equations_other, equations_own) -> u +coupling_function42 = (x, u, equations_other, equations_own) -> u + +# Define the coupling boundary conditions and the system it is coupled to. +boundary_conditions_x_neg4 = BoundaryConditionCoupled(3, (:end, :i_forward), Float64, + coupling_function43) +boundary_conditions_x_pos4 = BoundaryConditionCoupled(3, (:begin, :i_forward), Float64, + coupling_function43) +boundary_conditions_y_neg4 = BoundaryConditionCoupled(2, (:i_forward, :end), Float64, + coupling_function42) +boundary_conditions_y_pos4 = BoundaryConditionCoupled(2, (:i_forward, :begin), Float64, + coupling_function42) + +# A semidiscretization collects data structures and functions for the spatial discretization +semi4 = SemidiscretizationHyperbolic(mesh4, equations, initial_condition_convergence_test, + solver, + boundary_conditions = (x_neg = boundary_conditions_x_neg4, + x_pos = boundary_conditions_x_pos4, + y_neg = boundary_conditions_y_neg4, + y_pos = boundary_conditions_y_pos4)) + +# Create a semidiscretization that bundles all the semidiscretizations. +semi = SemidiscretizationCoupled(semi1, semi2, semi3, semi4) ############################################################################### # ODE solvers, callbacks etc. @@ -104,7 +186,10 @@ summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results analysis_callback1 = AnalysisCallback(semi1, interval = 100) analysis_callback2 = AnalysisCallback(semi2, interval = 100) -analysis_callback = AnalysisCallbackCoupled(semi, analysis_callback1, analysis_callback2) +analysis_callback3 = AnalysisCallback(semi3, interval = 100) +analysis_callback4 = AnalysisCallback(semi4, interval = 100) +analysis_callback = AnalysisCallbackCoupled(semi, analysis_callback1, analysis_callback2, + analysis_callback3, analysis_callback4) # The SaveSolutionCallback allows to save the solution to a file in regular intervals save_solution = SaveSolutionCallback(interval = 100, diff --git a/src/semidiscretization/semidiscretization_coupled.jl b/src/semidiscretization/semidiscretization_coupled.jl index 0941ae6a8ca..dc21dbe9a1e 100644 --- a/src/semidiscretization/semidiscretization_coupled.jl +++ b/src/semidiscretization/semidiscretization_coupled.jl @@ -1,3 +1,10 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + """ SemidiscretizationCoupled @@ -65,11 +72,13 @@ function Base.show(io::IO, ::MIME"text/plain", semi::SemidiscretizationCoupled) summary_line(io, "system", i) mesh, equations, solver, _ = mesh_equations_solver_cache(semi.semis[i]) summary_line(increment_indent(io), "mesh", mesh |> typeof |> nameof) - summary_line(increment_indent(io), "equations", equations |> typeof |> nameof) + summary_line(increment_indent(io), "equations", + equations |> typeof |> nameof) summary_line(increment_indent(io), "initial condition", semi.semis[i].initial_condition) # no boundary conditions since that could be too much - summary_line(increment_indent(io), "source terms", semi.semis[i].source_terms) + summary_line(increment_indent(io), "source terms", + semi.semis[i].source_terms) summary_line(increment_indent(io), "solver", solver |> typeof |> nameof) end summary_line(io, "total #DOFs per field", ndofs(semi)) @@ -106,20 +115,14 @@ end @inline Base.real(semi::SemidiscretizationCoupled) = promote_type(real.(semi.semis)...) -@inline Base.eltype(semi::SemidiscretizationCoupled) = promote_type(eltype.(semi.semis)...) +@inline function Base.eltype(semi::SemidiscretizationCoupled) + promote_type(eltype.(semi.semis)...) +end @inline function ndofs(semi::SemidiscretizationCoupled) sum(ndofs, semi.semis) end -@inline function nelements(semi::SemidiscretizationCoupled) - return sum(semi.semis) do semi_ - mesh, equations, solver, cache = mesh_equations_solver_cache(semi_) - - nelements(mesh, solver, cache) - end -end - function compute_coefficients(t, semi::SemidiscretizationCoupled) @unpack u_indices = semi @@ -137,23 +140,40 @@ end @view u_ode[semi.u_indices[index]] end +# Same as `foreach(enumerate(something))`, but without allocations. +# +# Note that compile times may increase if this is used with big tuples. +@inline foreach_enumerate(func, collection) = foreach_enumerate(func, collection, 1) +@inline foreach_enumerate(func, collection::Tuple{}, index) = nothing + +@inline function foreach_enumerate(func, collection, index) + element = first(collection) + remaining_collection = Base.tail(collection) + + func((index, element)) + + # Process remaining collection + foreach_enumerate(func, remaining_collection, index + 1) +end + function rhs!(du_ode, u_ode, semi::SemidiscretizationCoupled, t) @unpack u_indices = semi time_start = time_ns() @trixi_timeit timer() "copy to coupled boundaries" begin - for semi_ in semi.semis - copy_to_coupled_boundary!(semi_.boundary_conditions, u_ode, semi) + foreach(semi.semis) do semi_ + copy_to_coupled_boundary!(semi_.boundary_conditions, u_ode, semi, semi_) end end # Call rhs! for each semidiscretization - for i in eachsystem(semi) - u_loc = get_system_u_ode(u_ode, i, semi) - du_loc = get_system_u_ode(du_ode, i, semi) - - @trixi_timeit timer() "system #$i" rhs!(du_loc, u_loc, semi.semis[i], t) + @trixi_timeit timer() "copy to coupled boundaries" begin + foreach_enumerate(semi.semis) do (i, semi_) + u_loc = get_system_u_ode(u_ode, i, semi) + du_loc = get_system_u_ode(du_ode, i, semi) + rhs!(du_loc, u_loc, semi_, t) + end end runtime = time_ns() - time_start @@ -309,7 +329,8 @@ end for i in eachsystem(semi) u_ode_slice = get_system_u_ode(u_ode, i, semi) - save_solution_file(semis[i], u_ode_slice, solution_callback, integrator, system = i) + save_solution_file(semis[i], u_ode_slice, solution_callback, integrator, + system = i) end end @@ -332,7 +353,7 @@ end ################################################################################ """ - BoundaryConditionCoupled(other_semi_index, indices, uEltype) + BoundaryConditionCoupled(other_semi_index, indices, uEltype, coupling_converter) Boundary condition to glue two meshes together. Solution values at the boundary of another mesh will be used as boundary values. This requires the use @@ -348,32 +369,37 @@ This is currently only implemented for [`StructuredMesh`](@ref). - `indices::Tuple`: node/cell indices at the boundary of the mesh in the other semidiscretization. See examples below. - `uEltype::Type`: element type of solution +- `coupling_converter::CouplingConverter`: function to call for converting the solution + state of one system to the other system # Examples ```julia # Connect the left boundary of mesh 2 to our boundary such that our positive # boundary direction will match the positive y direction of the other boundary -BoundaryConditionCoupled(2, (:begin, :i), Float64) +BoundaryConditionCoupled(2, (:begin, :i), Float64, fun) # Connect the same two boundaries oppositely oriented -BoundaryConditionCoupled(2, (:begin, :i_backwards), Float64) +BoundaryConditionCoupled(2, (:begin, :i_backwards), Float64, fun) # Using this as y_neg boundary will connect `our_cells[i, 1, j]` to `other_cells[j, end-i, end]` -BoundaryConditionCoupled(2, (:j, :i_backwards, :end), Float64) +BoundaryConditionCoupled(2, (:j, :i_backwards, :end), Float64, fun) ``` !!! warning "Experimental code" This is an experimental feature and can change any time. """ -mutable struct BoundaryConditionCoupled{NDIMS, NDIMST2M1, uEltype <: Real, Indices} +mutable struct BoundaryConditionCoupled{NDIMS, NDIMST2M1, uEltype <: Real, Indices, + CouplingConverter} # NDIMST2M1 == NDIMS * 2 - 1 # Buffer for boundary values: [variable, nodes_i, nodes_j, cell_i, cell_j] - u_boundary :: Array{uEltype, NDIMST2M1} # NDIMS * 2 - 1 - other_semi_index :: Int - other_orientation :: Int - indices :: Indices - - function BoundaryConditionCoupled(other_semi_index, indices, uEltype) + u_boundary :: Array{uEltype, NDIMST2M1} # NDIMS * 2 - 1 + other_semi_index :: Int + other_orientation :: Int + indices :: Indices + coupling_converter :: CouplingConverter + + function BoundaryConditionCoupled(other_semi_index, indices, uEltype, + coupling_converter) NDIMS = length(indices) u_boundary = Array{uEltype, NDIMS * 2 - 1}(undef, ntuple(_ -> 0, NDIMS * 2 - 1)) @@ -385,8 +411,10 @@ mutable struct BoundaryConditionCoupled{NDIMS, NDIMST2M1, uEltype <: Real, Indic other_orientation = 3 end - new{NDIMS, NDIMS * 2 - 1, uEltype, typeof(indices)}(u_boundary, other_semi_index, - other_orientation, indices) + new{NDIMS, NDIMS * 2 - 1, uEltype, typeof(indices), + typeof(coupling_converter)}(u_boundary, + other_semi_index, other_orientation, + indices, coupling_converter) end end @@ -395,8 +423,10 @@ function Base.eltype(boundary_condition::BoundaryConditionCoupled) end function (boundary_condition::BoundaryConditionCoupled)(u_inner, orientation, direction, - cell_indices, surface_node_indices, - surface_flux_function, equations) + cell_indices, + surface_node_indices, + surface_flux_function, + equations) # get_node_vars(boundary_condition.u_boundary, equations, solver, surface_node_indices..., cell_indices...), # but we don't have a solver here u_boundary = SVector(ntuple(v -> boundary_condition.u_boundary[v, @@ -421,13 +451,15 @@ function allocate_coupled_boundary_conditions(semi::AbstractSemidiscretization) for direction in 1:n_boundaries boundary_condition = semi.boundary_conditions[direction] - allocate_coupled_boundary_condition(boundary_condition, direction, mesh, equations, + allocate_coupled_boundary_condition(boundary_condition, direction, mesh, + equations, solver) end end # Don't do anything for other BCs than BoundaryConditionCoupled -function allocate_coupled_boundary_condition(boundary_condition, direction, mesh, equations, +function allocate_coupled_boundary_condition(boundary_condition, direction, mesh, + equations, solver) return nothing end @@ -448,43 +480,69 @@ function allocate_coupled_boundary_condition(boundary_condition::BoundaryConditi end # Don't do anything for other BCs than BoundaryConditionCoupled -function copy_to_coupled_boundary!(boundary_condition, u_ode, semi) +function copy_to_coupled_boundary!(boundary_condition, u_ode, semi_coupled, semi) return nothing end +function copy_to_coupled_boundary!(u_ode, semi_coupled, semi, i, n_boundaries, + boundary_condition, boundary_conditions...) + copy_to_coupled_boundary!(boundary_condition, u_ode, semi_coupled, semi) + if i < n_boundaries + copy_to_coupled_boundary!(u_ode, semi_coupled, semi, i + 1, n_boundaries, + boundary_conditions...) + end +end + function copy_to_coupled_boundary!(boundary_conditions::Union{Tuple, NamedTuple}, u_ode, - semi) - for boundary_condition in boundary_conditions - copy_to_coupled_boundary!(boundary_condition, u_ode, semi) + semi_coupled, semi) + copy_to_coupled_boundary!(u_ode, semi_coupled, semi, 1, length(boundary_conditions), + boundary_conditions...) +end + +function mesh_equations_solver_cache(other_semi_index, i, semi_, semi_tuple...) + if i == other_semi_index + return mesh_equations_solver_cache(semi_) + else + # Walk through semidiscretizations until we find `i` + mesh_equations_solver_cache(other_semi_index, i + 1, semi_tuple...) end end # In 2D -function copy_to_coupled_boundary!(boundary_condition::BoundaryConditionCoupled{2}, u_ode, - semi) - @unpack u_indices = semi +function copy_to_coupled_boundary!(boundary_condition::BoundaryConditionCoupled{2}, + u_ode, + semi_coupled, semi) + @unpack u_indices = semi_coupled @unpack other_semi_index, other_orientation, indices = boundary_condition + @unpack coupling_converter, u_boundary = boundary_condition + + mesh_own, equations_own, solver_own, cache_own = mesh_equations_solver_cache(semi) + + mesh_other, equations_other, solver_other, cache_other = mesh_equations_solver_cache(other_semi_index, + 1, + semi_coupled.semis...) - mesh, equations, solver, cache = mesh_equations_solver_cache(semi.semis[other_semi_index]) - u = wrap_array(get_system_u_ode(u_ode, other_semi_index, semi), mesh, equations, solver, - cache) + node_coordinates_other = cache_other.elements.node_coordinates + u_ode_other = get_system_u_ode(u_ode, other_semi_index, semi_coupled) + u_other = wrap_array(u_ode_other, mesh_other, equations_other, solver_other, + cache_other) - linear_indices = LinearIndices(size(mesh)) + linear_indices = LinearIndices(size(mesh_other)) if other_orientation == 1 - cells = axes(mesh, 2) + cells = axes(mesh_other, 2) else # other_orientation == 2 - cells = axes(mesh, 1) + cells = axes(mesh_other, 1) end # Copy solution data to the coupled boundary using "delayed indexing" with # a start value and a step size to get the correct face and orientation. - node_index_range = eachnode(solver) + node_index_range = eachnode(solver_other) i_node_start, i_node_step = index_to_start_step_2d(indices[1], node_index_range) j_node_start, j_node_step = index_to_start_step_2d(indices[2], node_index_range) - i_cell_start, i_cell_step = index_to_start_step_2d(indices[1], axes(mesh, 1)) - j_cell_start, j_cell_step = index_to_start_step_2d(indices[2], axes(mesh, 2)) + i_cell_start, i_cell_step = index_to_start_step_2d(indices[1], axes(mesh_other, 1)) + j_cell_start, j_cell_step = index_to_start_step_2d(indices[2], axes(mesh_other, 2)) i_cell = i_cell_start j_cell = j_cell_start @@ -492,16 +550,26 @@ function copy_to_coupled_boundary!(boundary_condition::BoundaryConditionCoupled{ for cell in cells i_node = i_node_start j_node = j_node_start - - for i in eachnode(solver) - for v in 1:size(u, 1) - boundary_condition.u_boundary[v, i, cell] = u[v, i_node, j_node, - linear_indices[i_cell, - j_cell]] + element_id = linear_indices[i_cell, j_cell] + + for element_id in eachnode(solver_other) + x_other = get_node_coords(node_coordinates_other, equations_other, + solver_other, + i_node, j_node, linear_indices[i_cell, j_cell]) + u_node_other = get_node_vars(u_other, equations_other, solver_other, i_node, + j_node, linear_indices[i_cell, j_cell]) + u_node_converted = coupling_converter(x_other, u_node_other, + equations_other, + equations_own) + + for i in eachindex(u_node_converted) + u_boundary[i, element_id, cell] = u_node_converted[i] end + i_node += i_node_step j_node += j_node_step end + i_cell += i_cell_step j_cell += j_cell_step end @@ -511,7 +579,8 @@ end ### DGSEM/structured ################################################################################ -@inline function calc_boundary_flux_by_direction!(surface_flux_values, u, t, orientation, +@inline function calc_boundary_flux_by_direction!(surface_flux_values, u, t, + orientation, boundary_condition::BoundaryConditionCoupled, mesh::StructuredMesh, equations, surface_integral, dg::DG, cache, @@ -531,7 +600,8 @@ end sign_jacobian = sign(inverse_jacobian[node_indices..., element]) # Contravariant vector Ja^i is the normal vector - normal = sign_jacobian * get_contravariant_vector(orientation, contravariant_vectors, + normal = sign_jacobian * + get_contravariant_vector(orientation, contravariant_vectors, node_indices..., element) # If the mapping is orientation-reversing, the normal vector will be reversed (see above). @@ -608,3 +678,4 @@ function analyze_convergence(errors_coupled, iterations, return eoc_mean_values end +end # @muladd diff --git a/test/test_structured_2d.jl b/test/test_structured_2d.jl index e5d45ebcc07..522510a42e3 100644 --- a/test/test_structured_2d.jl +++ b/test/test_structured_2d.jl @@ -33,14 +33,34 @@ end @trixi_testset "elixir_advection_coupled.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_coupled.jl"), - l2=[7.816742843181738e-6, 7.816742843196112e-6], - linf=[6.314906965543265e-5, 6.314906965410039e-5], + l2=[ + 7.816742843336293e-6, + 7.816742843340186e-6, + 7.816742843025513e-6, + 7.816742843061526e-6, + ], + linf=[ + 6.314906965276812e-5, + 6.314906965187994e-5, + 6.31490696496595e-5, + 6.314906965032563e-5, + ], coverage_override=(maxiters = 10^5,)) @testset "analysis_callback(sol) for AnalysisCallbackCoupled" begin errors = analysis_callback(sol) - @test errors.l2≈[7.816742843181738e-6, 7.816742843196112e-6] rtol=1.0e-4 - @test errors.linf≈[6.314906965543265e-5, 6.314906965410039e-5] rtol=1.0e-4 + @test errors.l2≈[ + 7.816742843336293e-6, + 7.816742843340186e-6, + 7.816742843025513e-6, + 7.816742843061526e-6, + ] rtol=1.0e-4 + @test errors.linf≈[ + 6.314906965276812e-5, + 6.314906965187994e-5, + 6.31490696496595e-5, + 6.314906965032563e-5, + ] rtol=1.0e-4 # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let From d53fdb59fe71c1ba956fc758b5874c3914304ddf Mon Sep 17 00:00:00 2001 From: Johannes Markert <10619309+jmark@users.noreply.github.com> Date: Wed, 31 Jan 2024 16:49:35 +0100 Subject: [PATCH 237/263] Feature: T8codeMesh backend with MPI support (#1803) * Initial commit for the new feature using t8code as meshing backend. * Delete t8code_2d_dgsem * Added new examples and tests. Testing updates for T8code.jl. * Worked in the comments. * Fixed spelling. * Update src/auxiliary/auxiliary.jl Co-authored-by: Hendrik Ranocha * Added whitespace in Unions. * Adapted commented out code block reporting the no. of elements per level. * Added dummy save mesh support for . * Added test . * Added to method signature. * Deleted unnecessary comments. * Removed commented out tests. * Fixed Morton ordering bug in 2D at mortar interfaces. * Disabled `save_solution` callbacks and added more tests. * Added more tests. * Updated code according to the review. * Update src/auxiliary/t8code.jl Co-authored-by: Hendrik Ranocha * Update src/auxiliary/t8code.jl Co-authored-by: Hendrik Ranocha * Update src/auxiliary/t8code.jl Co-authored-by: Hendrik Ranocha * Update src/auxiliary/t8code.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/solvers/dgsem_t8code/containers_2d.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Code cleanup. * Updated to T8code@0.3.0 * Fixing minor issues. * Fixed typo. * Code cleanup. * Enabled `set_ghost` in examples. * Generalized type info in function signature. * Added namespace qualifier. * Updated comments. * Refactored code and deleted lots of it. * Removed a copy operation. * Initial commit. * Fxinig minor bugs. * Fixed minor typo. * Added first 3d example and fixed segfault. * Added many 3D examples and tests. * Backup. * Fixed merging issues. * Adding more tests. * Fixed some merging issues and formatting. * Fixed spelling. * Fixed spelling and changed assert macro. * Applied automatic formatting. * Applied automatic formatting. * Backup. * Removed superfluous outer constructor for T8codeMesh. * Added return statement for consistency. * Fixed wrong indentation by autoformatter. * Added comments. * Made sure an exception is thrown. * Changed flags for sc_init for t8code initialization. * Updated formatting. * Workaround for error about calling MPI routines after MPI has been finalized. * Upped to T8code v0.4.1. * Added mpi_finailize_hook for proper memory cleanup. * Added t8code to test_threaded.jl * Added a `save_mesh_file` call in order to satisfy code coverage. * Improved finalizer logic for T8coeMesh. * Refined code. * Restructured to do blocks. * Moved save_mesh_file call to test file. * Fixed spelling error. * Made sc_finalize optional. * Fixed spelling. * Cleaned up examples. * Updated and cleaned t8code solver codes. * Updated tests for t8code 3D code. * Fixed spelling. * Update elixir_euler_source_terms_nonconforming_unstructured_curved.jl * Update elixir_euler_source_terms_nonconforming_unstructured_curved.jl * Fixed indentation. * Update src/solvers/dgsem_structured/dg_3d.jl Co-authored-by: Hendrik Ranocha * Update src/solvers/dgsem_t8code/containers_3d.jl Co-authored-by: Andrew Winters * Update src/callbacks_step/amr_dg3d.jl Co-authored-by: Andrew Winters * Update examples/t8code_3d_dgsem/elixir_euler_ec.jl Co-authored-by: Andrew Winters * Update examples/t8code_3d_dgsem/elixir_advection_unstructured_curved.jl Co-authored-by: Andrew Winters * Update examples/t8code_3d_dgsem/elixir_advection_amr_unstructured_curved.jl Co-authored-by: Andrew Winters * Update src/solvers/dgsem_structured/dg_3d.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/callbacks_step/analysis_dg3d.jl Co-authored-by: Hendrik Ranocha * Update examples/t8code_3d_dgsem/elixir_euler_free_stream.jl Co-authored-by: Andrew Winters * Removed NDIMS from T8codeMesh construction in case of p4est/p8est connectivity input. * Aligned T8codeMesh constructur with other mesh constructors. * Update examples/t8code_3d_dgsem/elixir_euler_sedov.jl Co-authored-by: Andrew Winters * Update examples/t8code_3d_dgsem/elixir_euler_sedov.jl Co-authored-by: Andrew Winters * Cleanup up. * Added @allocated test. * Fixed formatting. * Applied formatter. * Added ParallelT8codeMesh to constructor. * Code cleanup. * Extended T8codeMesh backend to support MPI interfaces datastructures. * Update NEWS.md (#1780) * set version to v0.6.5 * set development version to v0.6.6-pre * hotfix: restrict DiffEqBase.jl to let CI pass (#1788) * hotfix: restrict DiffEqBase.jl to let CI pass * restrict DiffEqBase.jl in main Project.toml * Update Project.toml * Parabolic Mortar for AMR `P4estMesh{3}` (#1765) * Clean branch * Un-Comment * un-comment * test coarsen * remove redundancy * Remove support for passive terms * expand resize * comments * format * Avoid code duplication * Update src/callbacks_step/amr_dg1d.jl Co-authored-by: Michael Schlottke-Lakemper * comment * comment & format * Try to increase coverage * Slightly more expressive names * Apply suggestions from code review * add specifier for 1d * Structs for resizing parabolic helpers * check if mortars are present * reuse `reinitialize_containers!` * resize calls for parabolic helpers * update analysis callbacks * Velocities for compr euler * Init container * correct copy-paste error * resize each dim * add dispatch * Add AMR for shear layer * USe only amr shear layer * first steps towards p4est parabolic amr * Add tests * remove plots * Format * remove redundant line * platform independent tests * No need for different flux_viscous comps after adding container_viscous to p4est * Laplace 3d * Longer times to allow converage to hit coarsen! * Increase testing of Laplace 3D * Add tests for velocities * remove comment * add elixir for amr testing * adding commented out mortar routines in 2D * Adding Mortar to 2d dg parabolic term * remove testing snippet * fix comments * add more arguments for dispatch * add some temporary todo notes * some updates for AP and KS * specialize mortar_fluxes_to_elements * BUGFIX: apply_jacobian_parabolic! was incorrect for P4estMesh * fixed rhs_parabolic! for mortars * more changes to elixir * indexing bug * comments * Adding the example for nonperiodic BCs with amr * hopefully this fixes AMR boundaries for parabolic terms * add elixir * Example with non periodic bopundary conditions * remove cruft * 3D parabolic amr * TGV elixir * Creating test for AMR 3D parabolic * Formatting * test formatting * Update src/Trixi.jl * Update src/equations/compressible_euler_1d.jl * Update src/equations/compressible_euler_2d.jl * Update src/equations/compressible_euler_3d.jl * Update src/solvers/dgsem_tree/container_viscous_2d.jl * Update src/solvers/dgsem_tree/container_viscous_2d.jl * Update src/solvers/dgsem_tree/container_viscous_2d.jl * Update src/solvers/dgsem_tree/container_viscous_3d.jl * Update src/solvers/dgsem_tree/container_viscous_3d.jl * Update src/solvers/dgsem_tree/container_viscous_3d.jl * Update src/solvers/dgsem_p4est/dg_2d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_2d_parabolic.jl * Update src/solvers/dgsem_tree/dg_2d_parabolic.jl * Update src/solvers/dgsem_tree/dg_2d_parabolic.jl * Update src/solvers/dgsem_tree/dg_2d_parabolic.jl * Update src/solvers/dgsem_tree/dg_2d_parabolic.jl * Update src/solvers/dgsem_tree/dg_2d_parabolic.jl * Update src/solvers/dgsem_tree/dg_2d_parabolic.jl * Update src/solvers/dgsem_tree/dg_2d_parabolic.jl * Update src/solvers/dgsem_tree/dg_2d_parabolic.jl * Update src/solvers/dgsem_tree/dg_2d_parabolic.jl * Update test/test_parabolic_3d.jl * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl * Update src/solvers/dgsem_tree/dg_3d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_3d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_3d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_3d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_3d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_2d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_2d.jl * Update src/solvers/dgsem_p4est/dg_2d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_2d_parabolic.jl * Update test/test_parabolic_3d.jl * Update test/test_parabolic_3d.jl * Update test/test_parabolic_3d.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_3d_blast_wave_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_3d_blast_wave_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_3d_blast_wave_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_3d_blast_wave_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_3d_blast_wave_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_3d_blast_wave_amr.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_taylor_green_vortex_amr.jl * Update dg_3d_parabolic.jl * Update test_parabolic_3d.jl * Update elixir_navierstokes_3d_blast_wave_amr.jl * Update elixir_navierstokes_taylor_green_vortex_amr.jl * Update dg_3d_parabolic.jl * Update test_parabolic_3d.jl * Update test_parabolic_3d.jl * Update examples/p4est_3d_dgsem/elixir_navierstokes_3d_blast_wave_amr.jl * Update elixir_navierstokes_3d_blast_wave_amr.jl * Update elixir_navierstokes_taylor_green_vortex_amr.jl * Update dg_3d_parabolic.jl * Update test_parabolic_3d.jl * Delete examples/p4est_3d_dgsem/elixir_navierstokes_3d_blast_wave_amr.jl * Create elixir_navierstokes_blast_wave_amr.jl * Update test_parabolic_3d.jl * Update NEWS.md * Update NEWS.md * Update src/solvers/dgsem_p4est/dg_3d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_3d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_3d_parabolic.jl * Update src/solvers/dgsem_p4est/dg_3d_parabolic.jl --------- Co-authored-by: Daniel_Doehring Co-authored-by: Daniel Doehring Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> Co-authored-by: Jesse Chan * reset the timer also on non-root MPI processes (#1787) Co-authored-by: Michael Schlottke-Lakemper * Add HLLC flux for non-cartesian meshes to CompressibleEulerEquations{2,3}D (#1790) * add HLLC flux for non-cartesian meshes * add tests for HLLC flux * Add 2D test with HLLC * Update test_p4est_3d.jl * Update test_p4est_2d.jl * Update test_p4est_3d.jl * Update src/equations/compressible_euler_3d.jl Co-authored-by: Hendrik Ranocha * Update src/equations/compressible_euler_2d.jl Co-authored-by: Hendrik Ranocha * Update compressible_euler_2d.jl * Update compressible_euler_3d.jl * Update test_p4est_2d.jl * Update test_p4est_3d.jl * Update compressible_euler_2d.jl * Update compressible_euler_2d.jl --------- Co-authored-by: Daniel Doehring Co-authored-by: Hendrik Ranocha * Bump crate-ci/typos from 1.16.23 to 1.16.26 (#1793) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.16.23 to 1.16.26. - [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.16.23...v1.16.26) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Extend `CompressibleEulerQuasi1D` and `ShallowWaterQuasi1D` to `DGMulti` (#1797) * adding DGMulti versions of fluxes * remove incorrect factor of 2 * add example and test * formatting * add comment * revert removing factor of 2 * formatting * add SWE quasi-1D test d * enable quasi1D SWE for DGMulti * add docstrings * formatting * Update src/equations/compressible_euler_quasi_1d.jl Co-authored-by: Hendrik Ranocha * adding comments explaining why `normal_direction` is included in 1D * Apply suggestions from code review Co-authored-by: Daniel Doehring --------- Co-authored-by: Hendrik Ranocha Co-authored-by: Daniel Doehring * Fix boundary_condition_slip_wall for SWE (#1798) * fix_wall_bc * add test * apply formatter * adjust some comments * update elixir and test; add topography * comments explaining usage of `ForwardDiff.jacobian` (#1800) * Bump actions/upload-artifact from 3 to 4 (#1795) * Bump actions/upload-artifact from 3 to 4 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * bump download-artifact to v4 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Hendrik Ranocha * Code cleanup. * Applied formatter. * Registered mpi t8code tests. * Added load-balancing feature to T8codeMesh. * Applied formatter. * Updated some test values. * Fixed typo. * Removed unused member variable. * Apply suggestions from code review Co-authored-by: Daniel Doehring * suggestions from review * fix format (strange?) * Added comments to help interpreting the source code. * Update src/callbacks_step/amr_dg3d.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Adhered to unified mesh constructor calling scheme. * Applied formatter. * Switched to Float64 instead of Cdouble. * Update src/meshes/t8code_mesh.jl Co-authored-by: Daniel Doehring * Refactored negative volume check. * Applied formatter. * Fixed typo resp. bug. * Apply suggestions from code review Co-authored-by: Hendrik Ranocha * add missing allocation checks * Some refactoring. * Deleted msh file. * Fixed a bug. * Code cleanup. * Ignore gmsh files. * Removed adapt! from global namespace. * Added documentation. * Added @test_warn to test. * Applied formatter. * Apply suggestions from code review Co-authored-by: Hendrik Ranocha Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Turned @warn to @info. * Code cleanup and added @deprecated routines in order to avoid breaking release. * Applied formatter. * Added formatter pragmas to avoid ugly formatting. * Applied formatter. * Code cleanup. Documenting. * Applied formatter. * Removed remnants of development. * Removed dubious commented out line. * minors in comments skip ci * Added `retrieve` function which downloads missing mesh file without race conditions in case of MPI environment. * Added Downloads as dependency. * Added missing namespace qualifier. * add compat bound * Apply suggestions from code review Co-authored-by: Daniel Doehring Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * use retrieve everywhere for downloading * try to improve formatting * and what julia formatter makes out of it * try to consolidate max_dt computation * format * add default allocation tests * remove left over vtk_write * Revert "try to consolidate max_dt computation" This reverts commit d0e9a2cb2882f426a3966aac03e6ce497e1b720f. * fix variable name * less consolidation * remove unused variables * Update src/auxiliary/auxiliary.jl Co-authored-by: Hendrik Ranocha * Update src/Trixi.jl Co-authored-by: Hendrik Ranocha * revert b068d1183 (manually) * use Trixi.download * Revert "use retrieve everywhere for downloading" This reverts commit a438547e23bc489f12beea625dcc0905a50d18ce. * change to new Trixi.download signature * format * remove merge leftover * format * Code refactor. Applied review comments. * Fixed bug. * Fixed typo. * Update src/auxiliary/auxiliary.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Update src/meshes/t8code_mesh.jl Co-authored-by: Hendrik Ranocha * Applying review comments. * Added return early if there is nothing to do in adapt routines. --------- Signed-off-by: dependabot[bot] Co-authored-by: Johannes Markert Co-authored-by: Hendrik Ranocha Co-authored-by: Andrew Winters Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> Co-authored-by: Hendrik Ranocha Co-authored-by: Ahmad Peyvan <115842305+apey236@users.noreply.github.com> Co-authored-by: Daniel_Doehring Co-authored-by: Daniel Doehring Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Jesse Chan Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Patrick Ersing <114223904+patrickersing@users.noreply.github.com> Co-authored-by: Benedict Geihe Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> --- Project.toml | 2 + .../elixir_2d_euler_vortex_unstructured.jl | 9 +- examples/dgmulti_2d/elixir_euler_hohqmesh.jl | 9 +- .../elixir_advection_amr_unstructured_flag.jl | 7 +- .../elixir_advection_unstructured_flag.jl | 7 +- .../elixir_euler_blast_wave_amr.jl | 7 +- .../elixir_euler_double_mach_amr.jl | 8 +- .../elixir_euler_forward_step_amr.jl | 8 +- .../elixir_euler_free_stream.jl | 7 +- ...e_terms_nonconforming_unstructured_flag.jl | 7 +- .../elixir_euler_supersonic_cylinder.jl | 8 +- .../elixir_euler_wall_bc_amr.jl | 8 +- examples/p4est_2d_dgsem/elixir_mhd_rotor.jl | 7 +- ...lixir_advection_amr_unstructured_curved.jl | 7 +- .../elixir_advection_unstructured_curved.jl | 7 +- examples/p4est_3d_dgsem/elixir_euler_ec.jl | 7 +- .../elixir_euler_free_stream.jl | 7 +- .../elixir_euler_free_stream_extruded.jl | 7 +- ...terms_nonconforming_unstructured_curved.jl | 7 +- ...euler_source_terms_nonperiodic_hohqmesh.jl | 8 +- .../elixir_shallowwater_well_balanced.jl | 1 - .../elixir_advection_amr_unstructured_flag.jl | 7 +- .../elixir_advection_unstructured_flag.jl | 7 +- .../elixir_euler_free_stream.jl | 7 +- ...e_terms_nonconforming_unstructured_flag.jl | 7 +- examples/t8code_2d_dgsem/elixir_mhd_rotor.jl | 7 +- ...lixir_advection_amr_unstructured_curved.jl | 9 +- .../elixir_advection_unstructured_curved.jl | 7 +- examples/t8code_3d_dgsem/elixir_euler_ec.jl | 7 +- .../elixir_euler_free_stream.jl | 7 +- .../elixir_euler_free_stream_extruded.jl | 7 +- ...terms_nonconforming_unstructured_curved.jl | 7 +- .../elixir_acoustics_gauss_wall.jl | 8 +- .../elixir_advection_basic.jl | 9 +- .../elixir_euler_basic.jl | 9 +- .../unstructured_2d_dgsem/elixir_euler_ec.jl | 9 +- .../elixir_euler_free_stream.jl | 9 +- .../elixir_euler_periodic.jl | 9 +- .../elixir_euler_sedov.jl | 7 +- .../elixir_euler_wall_bc.jl | 9 +- .../elixir_mhd_alfven_wave.jl | 8 +- .../unstructured_2d_dgsem/elixir_mhd_ec.jl | 8 +- .../elixir_shallowwater_dirichlet.jl | 8 +- .../elixir_shallowwater_ec.jl | 8 +- .../elixir_shallowwater_ec_shockcapturing.jl | 8 +- .../elixir_shallowwater_source_terms.jl | 8 +- ...ixir_shallowwater_three_mound_dam_break.jl | 13 +- ...lixir_shallowwater_twolayer_convergence.jl | 8 +- .../elixir_shallowwater_twolayer_dam_break.jl | 8 +- ...xir_shallowwater_twolayer_well_balanced.jl | 8 +- ...xir_shallowwater_wall_bc_shockcapturing.jl | 9 +- .../elixir_shallowwater_well_balanced.jl | 9 +- .../elixir_advection_basic.jl | 9 +- .../elixir_euler_free_stream.jl | 9 +- .../elixir_euler_source_terms.jl | 9 +- src/Trixi.jl | 1 + src/auxiliary/auxiliary.jl | 23 + src/auxiliary/t8code.jl | 235 +------ src/callbacks_step/amr.jl | 40 +- src/callbacks_step/amr_dg.jl | 11 +- src/callbacks_step/amr_dg2d.jl | 7 +- src/callbacks_step/amr_dg3d.jl | 7 +- src/callbacks_step/analysis_dg2d_parallel.jl | 6 +- src/callbacks_step/analysis_dg3d_parallel.jl | 6 +- src/callbacks_step/stepsize_dg2d.jl | 32 + src/callbacks_step/stepsize_dg3d.jl | 32 + src/meshes/p4est_mesh.jl | 4 + src/meshes/t8code_mesh.jl | 577 +++++++++++++++++- .../dgsem_p4est/containers_parallel.jl | 6 +- src/solvers/dgsem_p4est/dg_2d_parallel.jl | 21 +- src/solvers/dgsem_p4est/dg_3d_parallel.jl | 23 +- src/solvers/dgsem_p4est/dg_parallel.jl | 9 +- src/solvers/dgsem_t8code/containers.jl | 13 +- src/solvers/dgsem_t8code/containers_2d.jl | 3 +- src/solvers/dgsem_t8code/containers_3d.jl | 3 +- .../dgsem_t8code/containers_parallel.jl | 65 ++ src/solvers/dgsem_t8code/dg.jl | 7 +- src/solvers/dgsem_t8code/dg_parallel.jl | 135 ++++ src/solvers/dgsem_tree/dg_2d_parallel.jl | 3 +- test/test_mpi.jl | 4 +- test/test_mpi_p4est_2d.jl | 63 ++ test/test_mpi_p4est_3d.jl | 81 +++ test/test_mpi_t8code_2d.jl | 142 +++++ test/test_mpi_t8code_3d.jl | 180 ++++++ test/test_t8code_2d.jl | 7 +- 85 files changed, 1529 insertions(+), 640 deletions(-) create mode 100644 src/solvers/dgsem_t8code/containers_parallel.jl create mode 100644 src/solvers/dgsem_t8code/dg_parallel.jl create mode 100644 test/test_mpi_t8code_2d.jl create mode 100644 test/test_mpi_t8code_3d.jl diff --git a/Project.toml b/Project.toml index 0bbdec206d8..e99b08e0e81 100644 --- a/Project.toml +++ b/Project.toml @@ -9,6 +9,7 @@ ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" DiffEqCallbacks = "459566f4-90b8-5000-8ac3-15dfb0a30def" +Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" EllipsisNotation = "da5c29d0-fa7d-589e-88eb-ea29b0a81949" FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" @@ -57,6 +58,7 @@ ConstructionBase = "1.3" DataStructures = "0.18.15" DiffEqBase = "6 - 6.143" DiffEqCallbacks = "2.25" +Downloads = "1.6" EllipsisNotation = "1.0" FillArrays = "0.13.2, 1" ForwardDiff = "0.10.18" diff --git a/benchmark/elixir_2d_euler_vortex_unstructured.jl b/benchmark/elixir_2d_euler_vortex_unstructured.jl index 082b6648abf..43e4b6559de 100644 --- a/benchmark/elixir_2d_euler_vortex_unstructured.jl +++ b/benchmark/elixir_2d_euler_vortex_unstructured.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -49,11 +48,9 @@ end initial_condition = initial_condition_isentropic_vortex solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) -default_mesh_file = joinpath(@__DIR__, "mesh_uniform_cartesian.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/ranocha/f4ea19ba3b62348968c971db43d7798b/raw/a506abb9479c020920cf6068c142670fc1a9aadc/mesh_uniform_cartesian.mesh", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/ranocha/f4ea19ba3b62348968c971db43d7798b/raw/a506abb9479c020920cf6068c142670fc1a9aadc/mesh_uniform_cartesian.mesh", + joinpath(@__DIR__, "mesh_uniform_cartesian.mesh")) + mesh = UnstructuredMesh2D(mesh_file, periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) diff --git a/examples/dgmulti_2d/elixir_euler_hohqmesh.jl b/examples/dgmulti_2d/elixir_euler_hohqmesh.jl index f534b5bc8ad..9b14a5c6827 100644 --- a/examples/dgmulti_2d/elixir_euler_hohqmesh.jl +++ b/examples/dgmulti_2d/elixir_euler_hohqmesh.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -30,12 +29,8 @@ dg = DGMulti(polydeg = 8, element_type = Quad(), approximation_type = SBP(), ############################################################################### # Get the curved quad mesh from a file (downloads the file if not available locally) - -default_mesh_file = joinpath(@__DIR__, "mesh_trixi_unstructured_mesh_docs.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/52056f1487853fab63b7f4ed7f171c80/raw/9d573387dfdbb8bce2a55db7246f4207663ac07f/mesh_trixi_unstructured_mesh_docs.mesh", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/52056f1487853fab63b7f4ed7f171c80/raw/9d573387dfdbb8bce2a55db7246f4207663ac07f/mesh_trixi_unstructured_mesh_docs.mesh", + joinpath(@__DIR__, "mesh_trixi_unstructured_mesh_docs.mesh")) mesh = DGMultiMesh(dg, mesh_file) diff --git a/examples/p4est_2d_dgsem/elixir_advection_amr_unstructured_flag.jl b/examples/p4est_2d_dgsem/elixir_advection_amr_unstructured_flag.jl index 0a50b3644f0..4bfb2d3e375 100644 --- a/examples/p4est_2d_dgsem/elixir_advection_amr_unstructured_flag.jl +++ b/examples/p4est_2d_dgsem/elixir_advection_amr_unstructured_flag.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -31,10 +30,8 @@ Trixi.validate_faces(faces) mapping_flag = Trixi.transfinite_mapping(faces) # Unstructured mesh with 24 cells of the square domain [-1, 1]^n -mesh_file = joinpath(@__DIR__, "square_unstructured_2.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", + joinpath(@__DIR__, "square_unstructured_2.inp")) mesh = P4estMesh{2}(mesh_file, polydeg = 3, mapping = mapping_flag, diff --git a/examples/p4est_2d_dgsem/elixir_advection_unstructured_flag.jl b/examples/p4est_2d_dgsem/elixir_advection_unstructured_flag.jl index 37fcc547f60..1ab96925fe6 100644 --- a/examples/p4est_2d_dgsem/elixir_advection_unstructured_flag.jl +++ b/examples/p4est_2d_dgsem/elixir_advection_unstructured_flag.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -29,10 +28,8 @@ Trixi.validate_faces(faces) mapping_flag = Trixi.transfinite_mapping(faces) # Unstructured mesh with 24 cells of the square domain [-1, 1]^n -mesh_file = joinpath(@__DIR__, "square_unstructured_2.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", + joinpath(@__DIR__, "square_unstructured_2.inp")) mesh = P4estMesh{2}(mesh_file, polydeg = 3, mapping = mapping_flag, diff --git a/examples/p4est_2d_dgsem/elixir_euler_blast_wave_amr.jl b/examples/p4est_2d_dgsem/elixir_euler_blast_wave_amr.jl index 0ca4fdc2eb7..5db5f74a686 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_blast_wave_amr.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_blast_wave_amr.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -50,10 +49,8 @@ volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; solver = DGSEM(basis, surface_flux, volume_integral) # Unstructured mesh with 48 cells of the square domain [-1, 1]^n -mesh_file = joinpath(@__DIR__, "square_unstructured_1.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/a075f8ec39a67fa9fad8f6f84342cbca/raw/a7206a02ed3a5d3cadacd8d9694ac154f9151db7/square_unstructured_1.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/a075f8ec39a67fa9fad8f6f84342cbca/raw/a7206a02ed3a5d3cadacd8d9694ac154f9151db7/square_unstructured_1.inp", + joinpath(@__DIR__, "square_unstructured_1.inp")) mesh = P4estMesh{2}(mesh_file, polydeg = 3, initial_refinement_level = 1) diff --git a/examples/p4est_2d_dgsem/elixir_euler_double_mach_amr.jl b/examples/p4est_2d_dgsem/elixir_euler_double_mach_amr.jl index 92928146d7b..fbc11e89185 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_double_mach_amr.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_double_mach_amr.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -99,11 +98,8 @@ solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, volume_integral = volume_integral) # Get the unstructured quad mesh from a file (downloads the file if not available locally) -default_mesh_file = joinpath(@__DIR__, "abaqus_double_mach.inp") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/a0806ef0d03cf5ea221af523167b6e32/raw/61ed0eb017eb432d996ed119a52fb041fe363e8c/abaqus_double_mach.inp", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/a0806ef0d03cf5ea221af523167b6e32/raw/61ed0eb017eb432d996ed119a52fb041fe363e8c/abaqus_double_mach.inp", + joinpath(@__DIR__, "abaqus_double_mach.inp")) mesh = P4estMesh{2}(mesh_file) diff --git a/examples/p4est_2d_dgsem/elixir_euler_forward_step_amr.jl b/examples/p4est_2d_dgsem/elixir_euler_forward_step_amr.jl index 0ec9fc222f2..654efd5e209 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_forward_step_amr.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_forward_step_amr.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -104,11 +103,8 @@ solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, volume_integral = volume_integral) # Get the unstructured quad mesh from a file (downloads the file if not available locally) -default_mesh_file = joinpath(@__DIR__, "abaqus_forward_step.inp") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/b346ee6aa5446687f128eab8b37d52a7/raw/cd1e1d43bebd8d2631a07caec45585ec8456ca4c/abaqus_forward_step.inp", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/b346ee6aa5446687f128eab8b37d52a7/raw/cd1e1d43bebd8d2631a07caec45585ec8456ca4c/abaqus_forward_step.inp", + joinpath(@__DIR__, "abaqus_forward_step.inp")) mesh = P4estMesh{2}(mesh_file) diff --git a/examples/p4est_2d_dgsem/elixir_euler_free_stream.jl b/examples/p4est_2d_dgsem/elixir_euler_free_stream.jl index 38307a7d781..ab11dc11567 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_free_stream.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_free_stream.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -31,10 +30,8 @@ end # Get the uncurved mesh from a file (downloads the file if not available locally) # Unstructured mesh with 48 cells of the square domain [-1, 1]^n -mesh_file = joinpath(@__DIR__, "square_unstructured_1.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/a075f8ec39a67fa9fad8f6f84342cbca/raw/a7206a02ed3a5d3cadacd8d9694ac154f9151db7/square_unstructured_1.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/a075f8ec39a67fa9fad8f6f84342cbca/raw/a7206a02ed3a5d3cadacd8d9694ac154f9151db7/square_unstructured_1.inp", + joinpath(@__DIR__, "square_unstructured_1.inp")) # Map the unstructured mesh with the mapping above mesh = P4estMesh{2}(mesh_file, polydeg = 3, mapping = mapping, initial_refinement_level = 1) diff --git a/examples/p4est_2d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_flag.jl b/examples/p4est_2d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_flag.jl index 09d018309a6..084fd699b8e 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_flag.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_flag.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -31,10 +30,8 @@ mapping_flag = Trixi.transfinite_mapping(faces) # Get the uncurved mesh from a file (downloads the file if not available locally) # Unstructured mesh with 24 cells of the square domain [-1, 1]^n -mesh_file = joinpath(@__DIR__, "square_unstructured_2.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", + joinpath(@__DIR__, "square_unstructured_2.inp")) mesh = P4estMesh{2}(mesh_file, polydeg = 3, mapping = mapping_flag, diff --git a/examples/p4est_2d_dgsem/elixir_euler_supersonic_cylinder.jl b/examples/p4est_2d_dgsem/elixir_euler_supersonic_cylinder.jl index 36c5624ba97..76ee96d4766 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_supersonic_cylinder.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_supersonic_cylinder.jl @@ -13,7 +13,6 @@ # # Keywords: supersonic flow, shock capturing, AMR, unstructured curved mesh, positivity preservation, compressible Euler, 2D -using Downloads: download using OrdinaryDiffEq using Trixi @@ -82,11 +81,8 @@ solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, volume_integral = volume_integral) # Get the unstructured quad mesh from a file (downloads the file if not available locally) -default_mesh_file = joinpath(@__DIR__, "abaqus_cylinder_in_channel.inp") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/a08f78f6b185b63c3baeff911a63f628/raw/addac716ea0541f588b9d2bd3f92f643eb27b88f/abaqus_cylinder_in_channel.inp", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/a08f78f6b185b63c3baeff911a63f628/raw/addac716ea0541f588b9d2bd3f92f643eb27b88f/abaqus_cylinder_in_channel.inp", + joinpath(@__DIR__, "abaqus_cylinder_in_channel.inp")) mesh = P4estMesh{2}(mesh_file) diff --git a/examples/p4est_2d_dgsem/elixir_euler_wall_bc_amr.jl b/examples/p4est_2d_dgsem/elixir_euler_wall_bc_amr.jl index 8b8d05bade8..75e60d0c78b 100644 --- a/examples/p4est_2d_dgsem/elixir_euler_wall_bc_amr.jl +++ b/examples/p4est_2d_dgsem/elixir_euler_wall_bc_amr.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -39,11 +38,8 @@ solver = DGSEM(polydeg = 5, surface_flux = flux_lax_friedrichs, volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) # Get the unstructured quad mesh from a file (downloads the file if not available locally) -default_mesh_file = joinpath(@__DIR__, "abaqus_gingerbread_man.inp") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/0e9e990a04b5105d1d2e3096a6e41272/raw/0d924b1d7e7d3cc1070a6cc22fe1d501687aa6dd/abaqus_gingerbread_man.inp", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/0e9e990a04b5105d1d2e3096a6e41272/raw/0d924b1d7e7d3cc1070a6cc22fe1d501687aa6dd/abaqus_gingerbread_man.inp", + joinpath(@__DIR__, "abaqus_gingerbread_man.inp")) mesh = P4estMesh{2}(mesh_file) diff --git a/examples/p4est_2d_dgsem/elixir_mhd_rotor.jl b/examples/p4est_2d_dgsem/elixir_mhd_rotor.jl index 380db487356..089e82580c9 100644 --- a/examples/p4est_2d_dgsem/elixir_mhd_rotor.jl +++ b/examples/p4est_2d_dgsem/elixir_mhd_rotor.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -69,10 +68,8 @@ function mapping_twist(xi, eta) return SVector(x, y) end -mesh_file = joinpath(@__DIR__, "square_unstructured_2.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", + joinpath(@__DIR__, "square_unstructured_2.inp")) mesh = P4estMesh{2}(mesh_file, polydeg = 4, diff --git a/examples/p4est_3d_dgsem/elixir_advection_amr_unstructured_curved.jl b/examples/p4est_3d_dgsem/elixir_advection_amr_unstructured_curved.jl index cd280cf5bf6..33afd2e030e 100644 --- a/examples/p4est_3d_dgsem/elixir_advection_amr_unstructured_curved.jl +++ b/examples/p4est_3d_dgsem/elixir_advection_amr_unstructured_curved.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -49,10 +48,8 @@ function mapping(xi, eta, zeta) end # Unstructured mesh with 48 cells of the cube domain [-1, 1]^3 -mesh_file = joinpath(@__DIR__, "cube_unstructured_2.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", + joinpath(@__DIR__, "cube_unstructured_2.inp")) # Mesh polydeg of 2 (half the solver polydeg) to ensure FSP (see above). mesh = P4estMesh{3}(mesh_file, polydeg = 2, diff --git a/examples/p4est_3d_dgsem/elixir_advection_unstructured_curved.jl b/examples/p4est_3d_dgsem/elixir_advection_unstructured_curved.jl index 6df9ac0b16a..83adcbf6a63 100644 --- a/examples/p4est_3d_dgsem/elixir_advection_unstructured_curved.jl +++ b/examples/p4est_3d_dgsem/elixir_advection_unstructured_curved.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -46,10 +45,8 @@ function mapping(xi, eta, zeta) end # Unstructured mesh with 68 cells of the cube domain [-1, 1]^3 -mesh_file = joinpath(@__DIR__, "cube_unstructured_1.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", + joinpath(@__DIR__, "cube_unstructured_1.inp")) mesh = P4estMesh{3}(mesh_file, polydeg = 3, mapping = mapping, diff --git a/examples/p4est_3d_dgsem/elixir_euler_ec.jl b/examples/p4est_3d_dgsem/elixir_euler_ec.jl index d9d774a7ffc..91698545052 100644 --- a/examples/p4est_3d_dgsem/elixir_euler_ec.jl +++ b/examples/p4est_3d_dgsem/elixir_euler_ec.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -46,10 +45,8 @@ function mapping(xi_, eta_, zeta_) end # Unstructured mesh with 48 cells of the cube domain [-1, 1]^3 -mesh_file = joinpath(@__DIR__, "cube_unstructured_2.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", + joinpath(@__DIR__, "cube_unstructured_2.inp")) mesh = P4estMesh{3}(mesh_file, polydeg = 5, mapping = mapping, diff --git a/examples/p4est_3d_dgsem/elixir_euler_free_stream.jl b/examples/p4est_3d_dgsem/elixir_euler_free_stream.jl index 24a781ca59e..6406a38186b 100644 --- a/examples/p4est_3d_dgsem/elixir_euler_free_stream.jl +++ b/examples/p4est_3d_dgsem/elixir_euler_free_stream.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -47,10 +46,8 @@ function mapping(xi_, eta_, zeta_) end # Unstructured mesh with 68 cells of the cube domain [-1, 1]^3 -mesh_file = joinpath(@__DIR__, "cube_unstructured_1.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", + joinpath(@__DIR__, "cube_unstructured_1.inp")) # Mesh polydeg of 2 (half the solver polydeg) to ensure FSP (see above). mesh = P4estMesh{3}(mesh_file, polydeg = 2, diff --git a/examples/p4est_3d_dgsem/elixir_euler_free_stream_extruded.jl b/examples/p4est_3d_dgsem/elixir_euler_free_stream_extruded.jl index f56fe3a429d..08307a449a7 100644 --- a/examples/p4est_3d_dgsem/elixir_euler_free_stream_extruded.jl +++ b/examples/p4est_3d_dgsem/elixir_euler_free_stream_extruded.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -36,10 +35,8 @@ function mapping(xi, eta_, zeta_) end # Unstructured mesh with 48 cells of the cube domain [-1, 1]^3 -mesh_file = joinpath(@__DIR__, "cube_unstructured_2.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", + joinpath(@__DIR__, "cube_unstructured_2.inp")) mesh = P4estMesh{3}(mesh_file, polydeg = 3, mapping = mapping, diff --git a/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_curved.jl b/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_curved.jl index 0de22eaea40..e7ca0cad4ba 100644 --- a/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_curved.jl +++ b/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonconforming_unstructured_curved.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -49,10 +48,8 @@ function mapping(xi, eta, zeta) end # Unstructured mesh with 68 cells of the cube domain [-1, 1]^3 -mesh_file = joinpath(@__DIR__, "cube_unstructured_1.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", + joinpath(@__DIR__, "cube_unstructured_1.inp")) # Mesh polydeg of 2 (half the solver polydeg) to ensure FSP (see above). mesh = P4estMesh{3}(mesh_file, polydeg = 2, diff --git a/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonperiodic_hohqmesh.jl b/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonperiodic_hohqmesh.jl index 0fa3a28fe8b..7d81d6739bf 100644 --- a/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonperiodic_hohqmesh.jl +++ b/examples/p4est_3d_dgsem/elixir_euler_source_terms_nonperiodic_hohqmesh.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -19,11 +18,8 @@ boundary_conditions = Dict(:Bottom => boundary_condition, solver = DGSEM(polydeg = 4, surface_flux = flux_lax_friedrichs) # Unstructured 3D half circle mesh from HOHQMesh -default_mesh_file = joinpath(@__DIR__, "abaqus_half_circle_3d.inp") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/11461efbfb02c42e06aca338b3d0b645/raw/81deeb1ebc4945952c30af5bb75fe222a18d975c/abaqus_half_circle_3d.inp", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/11461efbfb02c42e06aca338b3d0b645/raw/81deeb1ebc4945952c30af5bb75fe222a18d975c/abaqus_half_circle_3d.inp", + joinpath(@__DIR__, "abaqus_half_circle_3d.inp")) mesh = P4estMesh{3}(mesh_file, initial_refinement_level = 0) diff --git a/examples/structured_2d_dgsem/elixir_shallowwater_well_balanced.jl b/examples/structured_2d_dgsem/elixir_shallowwater_well_balanced.jl index 61dd252fd83..a6a56aa807c 100644 --- a/examples/structured_2d_dgsem/elixir_shallowwater_well_balanced.jl +++ b/examples/structured_2d_dgsem/elixir_shallowwater_well_balanced.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi 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 f285d24fc6c..0923e328487 100644 --- a/examples/t8code_2d_dgsem/elixir_advection_amr_unstructured_flag.jl +++ b/examples/t8code_2d_dgsem/elixir_advection_amr_unstructured_flag.jl @@ -1,4 +1,3 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -31,10 +30,8 @@ Trixi.validate_faces(faces) mapping_flag = Trixi.transfinite_mapping(faces) # Unstructured mesh with 24 cells of the square domain [-1, 1]^n -mesh_file = joinpath(@__DIR__, "square_unstructured_2.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", + joinpath(@__DIR__, "square_unstructured_2.inp")) # INP mesh files are only support by p4est. Hence, we # create a p4est connecvity object first from which diff --git a/examples/t8code_2d_dgsem/elixir_advection_unstructured_flag.jl b/examples/t8code_2d_dgsem/elixir_advection_unstructured_flag.jl index 5ba1ab15489..ba8f1b59b80 100644 --- a/examples/t8code_2d_dgsem/elixir_advection_unstructured_flag.jl +++ b/examples/t8code_2d_dgsem/elixir_advection_unstructured_flag.jl @@ -1,4 +1,3 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -28,10 +27,8 @@ Trixi.validate_faces(faces) mapping_flag = Trixi.transfinite_mapping(faces) # Unstructured mesh with 24 cells of the square domain [-1, 1]^n. -mesh_file = joinpath(@__DIR__, "square_unstructured_2.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", + joinpath(@__DIR__, "square_unstructured_2.inp")) # INP mesh files are only support by p4est. Hence, we # create a p4est connecvity object first from which diff --git a/examples/t8code_2d_dgsem/elixir_euler_free_stream.jl b/examples/t8code_2d_dgsem/elixir_euler_free_stream.jl index 37d15f38566..5e6c4193c50 100644 --- a/examples/t8code_2d_dgsem/elixir_euler_free_stream.jl +++ b/examples/t8code_2d_dgsem/elixir_euler_free_stream.jl @@ -1,4 +1,3 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -30,10 +29,8 @@ end # Get the uncurved mesh from a file (downloads the file if not available locally) # Unstructured mesh with 48 cells of the square domain [-1, 1]^n -mesh_file = joinpath(@__DIR__, "square_unstructured_1.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/a075f8ec39a67fa9fad8f6f84342cbca/raw/a7206a02ed3a5d3cadacd8d9694ac154f9151db7/square_unstructured_1.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/a075f8ec39a67fa9fad8f6f84342cbca/raw/a7206a02ed3a5d3cadacd8d9694ac154f9151db7/square_unstructured_1.inp", + joinpath(@__DIR__, "square_unstructured_1.inp")) # INP mesh files are only support by p4est. Hence, we # create a p4est connecvity object first from which 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 bcc1abc560e..e496eb76729 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 @@ -1,4 +1,3 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -30,10 +29,8 @@ mapping_flag = Trixi.transfinite_mapping(faces) # Get the uncurved mesh from a file (downloads the file if not available locally) # Unstructured mesh with 24 cells of the square domain [-1, 1]^n -mesh_file = joinpath(@__DIR__, "square_unstructured_2.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", + joinpath(@__DIR__, "square_unstructured_2.inp")) # INP mesh files are only support by p4est. Hence, we # create a p4est connecvity object first from which diff --git a/examples/t8code_2d_dgsem/elixir_mhd_rotor.jl b/examples/t8code_2d_dgsem/elixir_mhd_rotor.jl index adb154948fb..ff2e40ae607 100644 --- a/examples/t8code_2d_dgsem/elixir_mhd_rotor.jl +++ b/examples/t8code_2d_dgsem/elixir_mhd_rotor.jl @@ -1,4 +1,3 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -68,10 +67,8 @@ function mapping_twist(xi, eta) return SVector(x, y) end -mesh_file = joinpath(@__DIR__, "square_unstructured_2.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/63ff2ea224409e55ee8423b3a33e316a/raw/7db58af7446d1479753ae718930741c47a3b79b7/square_unstructured_2.inp", + joinpath(@__DIR__, "square_unstructured_2.inp")) # INP mesh files are only support by p4est. Hence, we # create a p4est connecvity object first from which 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 617736afbdd..e7c0f4b7318 100644 --- a/examples/t8code_3d_dgsem/elixir_advection_amr_unstructured_curved.jl +++ b/examples/t8code_3d_dgsem/elixir_advection_amr_unstructured_curved.jl @@ -1,4 +1,3 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -47,11 +46,9 @@ function mapping(xi, eta, zeta) return SVector(5 * x, 5 * y, 5 * z) end -# Unstructured mesh with 48 cells of the cube domain [-1, 1]^3 -mesh_file = joinpath(@__DIR__, "cube_unstructured_2.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", - mesh_file) +# Unstructured mesh with 48 cells of the cube domain [-1, 1]^3. +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", + joinpath(@__DIR__, "cube_unstructured_2.inp")) # INP mesh files are only support by p4est. Hence, we # create a p4est connectivity object first from which diff --git a/examples/t8code_3d_dgsem/elixir_advection_unstructured_curved.jl b/examples/t8code_3d_dgsem/elixir_advection_unstructured_curved.jl index df358435c9a..ee27ee117fe 100644 --- a/examples/t8code_3d_dgsem/elixir_advection_unstructured_curved.jl +++ b/examples/t8code_3d_dgsem/elixir_advection_unstructured_curved.jl @@ -1,4 +1,3 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -45,10 +44,8 @@ function mapping(xi, eta, zeta) end # Unstructured mesh with 68 cells of the cube domain [-1, 1]^3 -mesh_file = joinpath(@__DIR__, "cube_unstructured_1.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", + joinpath(@__DIR__, "cube_unstructured_1.inp")) # INP mesh files are only support by p4est. Hence, we # create a p4est connectivity object first from which diff --git a/examples/t8code_3d_dgsem/elixir_euler_ec.jl b/examples/t8code_3d_dgsem/elixir_euler_ec.jl index 07745c3ac56..b720bfcd375 100644 --- a/examples/t8code_3d_dgsem/elixir_euler_ec.jl +++ b/examples/t8code_3d_dgsem/elixir_euler_ec.jl @@ -1,4 +1,3 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -45,10 +44,8 @@ function mapping(xi_, eta_, zeta_) end # Unstructured mesh with 48 cells of the cube domain [-1, 1]^3 -mesh_file = joinpath(@__DIR__, "cube_unstructured_2.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", + joinpath(@__DIR__, "cube_unstructured_2.inp")) # INP mesh files are only support by p4est. Hence, we # create a p4est connectivity object first from which diff --git a/examples/t8code_3d_dgsem/elixir_euler_free_stream.jl b/examples/t8code_3d_dgsem/elixir_euler_free_stream.jl index e135d464810..b70a6091adf 100644 --- a/examples/t8code_3d_dgsem/elixir_euler_free_stream.jl +++ b/examples/t8code_3d_dgsem/elixir_euler_free_stream.jl @@ -1,4 +1,3 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -46,10 +45,8 @@ function mapping(xi_, eta_, zeta_) end # Unstructured mesh with 68 cells of the cube domain [-1, 1]^3 -mesh_file = joinpath(@__DIR__, "cube_unstructured_1.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", + joinpath(@__DIR__, "cube_unstructured_1.inp")) # INP mesh files are only support by p4est. Hence, we # create a p4est connectivity object first from which 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 d129b59826e..6ae38d20b5a 100644 --- a/examples/t8code_3d_dgsem/elixir_euler_free_stream_extruded.jl +++ b/examples/t8code_3d_dgsem/elixir_euler_free_stream_extruded.jl @@ -1,4 +1,3 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -35,10 +34,8 @@ function mapping(xi, eta_, zeta_) end # Unstructured mesh with 48 cells of the cube domain [-1, 1]^3 -mesh_file = joinpath(@__DIR__, "cube_unstructured_2.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/b8df0033798e4926dec515fc045e8c2c/raw/b9254cde1d1fb64b6acc8416bc5ccdd77a240227/cube_unstructured_2.inp", + joinpath(@__DIR__, "cube_unstructured_2.inp")) # INP mesh files are only support by p4est. Hence, we # create a p4est connecvity object first from which 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 d4664522bea..6856be36ea1 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 @@ -1,4 +1,3 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -48,10 +47,8 @@ function mapping(xi, eta, zeta) end # Unstructured mesh with 68 cells of the cube domain [-1, 1]^3 -mesh_file = joinpath(@__DIR__, "cube_unstructured_1.inp") -isfile(mesh_file) || - download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", - mesh_file) +mesh_file = Trixi.download("https://gist.githubusercontent.com/efaulhaber/d45c8ac1e248618885fa7cc31a50ab40/raw/37fba24890ab37cfa49c39eae98b44faf4502882/cube_unstructured_1.inp", + joinpath(@__DIR__, "cube_unstructured_1.inp")) # INP mesh files are only support by p4est. Hence, we # create a p4est connecvity object first from which diff --git a/examples/unstructured_2d_dgsem/elixir_acoustics_gauss_wall.jl b/examples/unstructured_2d_dgsem/elixir_acoustics_gauss_wall.jl index 8f8e867dca8..9741430d11c 100644 --- a/examples/unstructured_2d_dgsem/elixir_acoustics_gauss_wall.jl +++ b/examples/unstructured_2d_dgsem/elixir_acoustics_gauss_wall.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -14,11 +13,8 @@ equations = AcousticPerturbationEquations2D(v_mean_global = (0.0, -0.5), solver = DGSEM(polydeg = 4, surface_flux = flux_lax_friedrichs) # Create unstructured quadrilateral mesh from a file -default_mesh_file = joinpath(@__DIR__, "mesh_five_circles_in_circle.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/3c79baad6b4d73bb26ec6420b5d16f45/raw/22aefc4ec2107cf0bffc40e81dfbc52240c625b1/mesh_five_circles_in_circle.mesh", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/3c79baad6b4d73bb26ec6420b5d16f45/raw/22aefc4ec2107cf0bffc40e81dfbc52240c625b1/mesh_five_circles_in_circle.mesh", + joinpath(@__DIR__, "mesh_five_circles_in_circle.mesh")) mesh = UnstructuredMesh2D(mesh_file) diff --git a/examples/unstructured_2d_dgsem/elixir_advection_basic.jl b/examples/unstructured_2d_dgsem/elixir_advection_basic.jl index afef6c2c38f..c0ee453344d 100644 --- a/examples/unstructured_2d_dgsem/elixir_advection_basic.jl +++ b/examples/unstructured_2d_dgsem/elixir_advection_basic.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -16,12 +15,8 @@ solver = DGSEM(polydeg = 6, surface_flux = flux_lax_friedrichs) ############################################################################### # Get the curved quad mesh from a file (downloads the file if not available locally) - -default_mesh_file = joinpath(@__DIR__, "mesh_periodic_square_with_twist.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", + joinpath(@__DIR__, "mesh_periodic_square_with_twist.mesh")) mesh = UnstructuredMesh2D(mesh_file, periodicity = true) diff --git a/examples/unstructured_2d_dgsem/elixir_euler_basic.jl b/examples/unstructured_2d_dgsem/elixir_euler_basic.jl index cd6a1995757..f8976120d53 100644 --- a/examples/unstructured_2d_dgsem/elixir_euler_basic.jl +++ b/examples/unstructured_2d_dgsem/elixir_euler_basic.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -25,12 +24,8 @@ solver = DGSEM(polydeg = 8, surface_flux = flux_lax_friedrichs) ############################################################################### # Get the curved quad mesh from a file (downloads the file if not available locally) - -default_mesh_file = joinpath(@__DIR__, "mesh_trixi_unstructured_mesh_docs.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/52056f1487853fab63b7f4ed7f171c80/raw/9d573387dfdbb8bce2a55db7246f4207663ac07f/mesh_trixi_unstructured_mesh_docs.mesh", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/52056f1487853fab63b7f4ed7f171c80/raw/9d573387dfdbb8bce2a55db7246f4207663ac07f/mesh_trixi_unstructured_mesh_docs.mesh", + joinpath(@__DIR__, "mesh_trixi_unstructured_mesh_docs.mesh")) mesh = UnstructuredMesh2D(mesh_file) diff --git a/examples/unstructured_2d_dgsem/elixir_euler_ec.jl b/examples/unstructured_2d_dgsem/elixir_euler_ec.jl index 0f53aa62a18..58b4d9a1dd2 100644 --- a/examples/unstructured_2d_dgsem/elixir_euler_ec.jl +++ b/examples/unstructured_2d_dgsem/elixir_euler_ec.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -19,12 +18,8 @@ solver = DGSEM(polydeg = 6, surface_flux = flux_ranocha, ############################################################################### # Get the curved quad mesh from a file - -default_mesh_file = joinpath(@__DIR__, "mesh_periodic_square_with_twist.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", + joinpath(@__DIR__, "mesh_periodic_square_with_twist.mesh")) mesh = UnstructuredMesh2D(mesh_file, periodicity = true) diff --git a/examples/unstructured_2d_dgsem/elixir_euler_free_stream.jl b/examples/unstructured_2d_dgsem/elixir_euler_free_stream.jl index a2fec1a320a..f266a3de0b2 100644 --- a/examples/unstructured_2d_dgsem/elixir_euler_free_stream.jl +++ b/examples/unstructured_2d_dgsem/elixir_euler_free_stream.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -26,12 +25,8 @@ solver = DGSEM(polydeg = 6, surface_flux = flux_hll) ############################################################################### # Get the curved quad mesh from a file (downloads the file if not available locally) - -default_mesh_file = joinpath(@__DIR__, "mesh_gingerbread_man.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/2c6440b5f8a57db131061ad7aa78ee2b/raw/1f89fdf2c874ff678c78afb6fe8dc784bdfd421f/mesh_gingerbread_man.mesh", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/2c6440b5f8a57db131061ad7aa78ee2b/raw/1f89fdf2c874ff678c78afb6fe8dc784bdfd421f/mesh_gingerbread_man.mesh", + joinpath(@__DIR__, "mesh_gingerbread_man.mesh")) mesh = UnstructuredMesh2D(mesh_file) diff --git a/examples/unstructured_2d_dgsem/elixir_euler_periodic.jl b/examples/unstructured_2d_dgsem/elixir_euler_periodic.jl index afd177f0740..e640001ad7f 100644 --- a/examples/unstructured_2d_dgsem/elixir_euler_periodic.jl +++ b/examples/unstructured_2d_dgsem/elixir_euler_periodic.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -19,12 +18,8 @@ solver = DGSEM(polydeg = 6, surface_flux = FluxRotated(flux_hll)) ############################################################################### # Get the curved quad mesh from a file (downloads the file if not available locally) - -default_mesh_file = joinpath(@__DIR__, "mesh_periodic_square_with_twist.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", + joinpath(@__DIR__, "mesh_periodic_square_with_twist.mesh")) mesh = UnstructuredMesh2D(mesh_file, periodicity = true) diff --git a/examples/unstructured_2d_dgsem/elixir_euler_sedov.jl b/examples/unstructured_2d_dgsem/elixir_euler_sedov.jl index e1cc0932969..06053273b74 100644 --- a/examples/unstructured_2d_dgsem/elixir_euler_sedov.jl +++ b/examples/unstructured_2d_dgsem/elixir_euler_sedov.jl @@ -55,11 +55,8 @@ solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, volume_integral = volume_integral) # Get the curved quad mesh from a file -default_mesh_file = joinpath(@__DIR__, "mesh_periodic_square_with_twist.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", + joinpath(@__DIR__, "mesh_periodic_square_with_twist.mesh")) mesh = UnstructuredMesh2D(mesh_file, periodicity = true) diff --git a/examples/unstructured_2d_dgsem/elixir_euler_wall_bc.jl b/examples/unstructured_2d_dgsem/elixir_euler_wall_bc.jl index b2abefe7eeb..65e5eb51ce6 100644 --- a/examples/unstructured_2d_dgsem/elixir_euler_wall_bc.jl +++ b/examples/unstructured_2d_dgsem/elixir_euler_wall_bc.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -40,12 +39,8 @@ solver = DGSEM(polydeg = 4, surface_flux = flux_hll) ############################################################################### # Get the curved quad mesh from a file - -default_mesh_file = joinpath(@__DIR__, "mesh_box_around_circle.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/8b9b11a1eedfa54b215c122c3d17b271/raw/0d2b5d98c87e67a6f384693a8b8e54b4c9fcbf3d/mesh_box_around_circle.mesh", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/8b9b11a1eedfa54b215c122c3d17b271/raw/0d2b5d98c87e67a6f384693a8b8e54b4c9fcbf3d/mesh_box_around_circle.mesh", + joinpath(@__DIR__, "mesh_box_around_circle.mesh")) mesh = UnstructuredMesh2D(mesh_file) diff --git a/examples/unstructured_2d_dgsem/elixir_mhd_alfven_wave.jl b/examples/unstructured_2d_dgsem/elixir_mhd_alfven_wave.jl index 3ed3e828ca8..0c7152a6ea0 100644 --- a/examples/unstructured_2d_dgsem/elixir_mhd_alfven_wave.jl +++ b/examples/unstructured_2d_dgsem/elixir_mhd_alfven_wave.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -17,12 +16,9 @@ solver = DGSEM(polydeg = 7, volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) # Get the unstructured quad mesh from a file (downloads the file if not available locally) -default_mesh_file = joinpath(@__DIR__, "mesh_alfven_wave_with_twist_and_flip.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", - default_mesh_file) +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_file = default_mesh_file mesh = UnstructuredMesh2D(mesh_file, periodicity = true) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) diff --git a/examples/unstructured_2d_dgsem/elixir_mhd_ec.jl b/examples/unstructured_2d_dgsem/elixir_mhd_ec.jl index a40f92cac02..805934e305d 100644 --- a/examples/unstructured_2d_dgsem/elixir_mhd_ec.jl +++ b/examples/unstructured_2d_dgsem/elixir_mhd_ec.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -35,11 +34,8 @@ solver = DGSEM(polydeg = 6, volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) # Get the unstructured quad mesh from a file (downloads the file if not available locally) -default_mesh_file = joinpath(@__DIR__, "mesh_alfven_wave_with_twist_and_flip.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", - default_mesh_file) -mesh_file = default_mesh_file +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) diff --git a/examples/unstructured_2d_dgsem/elixir_shallowwater_dirichlet.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_dirichlet.jl index 1148f25fae3..df1a69192ce 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_dirichlet.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_dirichlet.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -38,11 +37,8 @@ solver = DGSEM(polydeg = 4, surface_flux = (flux_hll, flux_nonconservative_fjord # This setup is for the curved, split form well-balancedness testing # Get the unstructured quad mesh from a file (downloads the file if not available locally) -default_mesh_file = joinpath(@__DIR__, "mesh_outer_circle.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/9beddd9cd00e2a0a15865129eeb24928/raw/be71e67fa48bc4e1e97f5f6cd77c3ed34c6ba9be/mesh_outer_circle.mesh", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/9beddd9cd00e2a0a15865129eeb24928/raw/be71e67fa48bc4e1e97f5f6cd77c3ed34c6ba9be/mesh_outer_circle.mesh", + joinpath(@__DIR__, "mesh_outer_circle.mesh")) mesh = UnstructuredMesh2D(mesh_file) diff --git a/examples/unstructured_2d_dgsem/elixir_shallowwater_ec.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_ec.jl index 8e9d396d826..9122fb8287d 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_ec.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_ec.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -25,11 +24,8 @@ solver = DGSEM(polydeg = 6, # 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) -default_mesh_file = joinpath(@__DIR__, "mesh_alfven_wave_with_twist_and_flip.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", - default_mesh_file) -mesh_file = default_mesh_file +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) diff --git a/examples/unstructured_2d_dgsem/elixir_shallowwater_ec_shockcapturing.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_ec_shockcapturing.jl index 94202b81df0..98408db5a78 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_ec_shockcapturing.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_ec_shockcapturing.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -34,11 +33,8 @@ solver = DGSEM(basis, surface_flux, volume_integral) # 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) -default_mesh_file = joinpath(@__DIR__, "mesh_alfven_wave_with_twist_and_flip.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", - default_mesh_file) -mesh_file = default_mesh_file +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) diff --git a/examples/unstructured_2d_dgsem/elixir_shallowwater_source_terms.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_source_terms.jl index 07668688406..a7aa5808955 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_source_terms.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_source_terms.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -23,11 +22,8 @@ solver = DGSEM(polydeg = 6, surface_flux = surface_flux, # This setup is for the curved, split form convergence test on a periodic domain # Get the unstructured quad mesh from a file (downloads the file if not available locally) -default_mesh_file = joinpath(@__DIR__, "mesh_alfven_wave_with_twist_and_flip.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", - default_mesh_file) -mesh_file = default_mesh_file +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) diff --git a/examples/unstructured_2d_dgsem/elixir_shallowwater_three_mound_dam_break.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_three_mound_dam_break.jl index 6164f9d4a55..df321aad267 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_three_mound_dam_break.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_three_mound_dam_break.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -93,16 +92,10 @@ solver = DGSEM(basis, surface_flux, volume_integral) ############################################################################### # Get the unstructured quad mesh from a file (downloads the file if not available locally) +mesh_file = Trixi.download("https://gist.githubusercontent.com/svengoldberg/c3c87fecb3fc6e46be7f0d1c7cb35f83/raw/e817ecd9e6c4686581d63c46128f9b6468d396d3/mesh_three_mound.mesh", + joinpath(@__DIR__, "mesh_three_mound.mesh")) -default_meshfile = joinpath(@__DIR__, "mesh_three_mound.mesh") - -isfile(default_meshfile) || - download("https://gist.githubusercontent.com/svengoldberg/c3c87fecb3fc6e46be7f0d1c7cb35f83/raw/e817ecd9e6c4686581d63c46128f9b6468d396d3/mesh_three_mound.mesh", - default_meshfile) - -meshfile = default_meshfile - -mesh = UnstructuredMesh2D(meshfile) +mesh = UnstructuredMesh2D(mesh_file) # Create the semi discretization object semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver; diff --git a/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl index 0b86095663a..fcc08b6f991 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_convergence.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -24,11 +23,8 @@ solver = DGSEM(polydeg = 6, surface_flux = surface_flux, # This setup is for the curved, split form convergence test on a periodic domain # Get the unstructured quad mesh from a file (downloads the file if not available locally) -default_mesh_file = joinpath(@__DIR__, "mesh_alfven_wave_with_twist_and_flip.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", - default_mesh_file) -mesh_file = default_mesh_file +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) diff --git a/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_dam_break.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_dam_break.jl index 4ad5f7e3201..821f31c52ac 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_dam_break.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_dam_break.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -48,11 +47,8 @@ solver = DGSEM(polydeg = 6, surface_flux = surface_flux, ############################################################################### # Get the unstructured quad mesh from a file (downloads the file if not available locally) -default_mesh_file = joinpath(@__DIR__, "mesh_alfven_wave_with_twist_and_flip.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", - default_mesh_file) -mesh_file = default_mesh_file +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 = false) diff --git a/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl index 6a727df2502..ca1f54595bb 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_twolayer_well_balanced.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -42,11 +41,8 @@ solver = DGSEM(polydeg = 6, surface_flux = surface_flux, # This setup is for the curved, split form well-balancedness testing # Get the unstructured quad mesh from a file (downloads the file if not available locally) -default_mesh_file = joinpath(@__DIR__, "mesh_alfven_wave_with_twist_and_flip.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", - default_mesh_file) -mesh_file = default_mesh_file +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) diff --git a/examples/unstructured_2d_dgsem/elixir_shallowwater_wall_bc_shockcapturing.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_wall_bc_shockcapturing.jl index 76b9642d595..f115113ed27 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_wall_bc_shockcapturing.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_wall_bc_shockcapturing.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -55,12 +54,8 @@ solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux, ############################################################################### # Get the unstructured quad mesh from a file (downloads the file if not available locally) - -default_mesh_file = joinpath(@__DIR__, "mesh_outer_circle.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/9beddd9cd00e2a0a15865129eeb24928/raw/be71e67fa48bc4e1e97f5f6cd77c3ed34c6ba9be/mesh_outer_circle.mesh", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/9beddd9cd00e2a0a15865129eeb24928/raw/be71e67fa48bc4e1e97f5f6cd77c3ed34c6ba9be/mesh_outer_circle.mesh", + joinpath(@__DIR__, "mesh_outer_circle.mesh")) mesh = UnstructuredMesh2D(mesh_file) diff --git a/examples/unstructured_2d_dgsem/elixir_shallowwater_well_balanced.jl b/examples/unstructured_2d_dgsem/elixir_shallowwater_well_balanced.jl index bf4d0be682a..6bad3a77f03 100644 --- a/examples/unstructured_2d_dgsem/elixir_shallowwater_well_balanced.jl +++ b/examples/unstructured_2d_dgsem/elixir_shallowwater_well_balanced.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -36,13 +35,9 @@ solver = DGSEM(polydeg = 6, surface_flux = surface_flux, ############################################################################### # This setup is for the curved, split form well-balancedness testing - # Get the unstructured quad mesh from a file (downloads the file if not available locally) -default_mesh_file = joinpath(@__DIR__, "mesh_alfven_wave_with_twist_and_flip.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/8f8cd23df27fcd494553f2a89f3c1ba4/raw/85e3c8d976bbe57ca3d559d653087b0889535295/mesh_alfven_wave_with_twist_and_flip.mesh", - default_mesh_file) -mesh_file = default_mesh_file +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) diff --git a/examples/unstructured_2d_fdsbp/elixir_advection_basic.jl b/examples/unstructured_2d_fdsbp/elixir_advection_basic.jl index c181203e7a4..fe7e708f3b3 100644 --- a/examples/unstructured_2d_fdsbp/elixir_advection_basic.jl +++ b/examples/unstructured_2d_fdsbp/elixir_advection_basic.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -21,12 +20,8 @@ solver = FDSBP(D_SBP, ############################################################################### # Get the curved quad mesh from a file (downloads the file if not available locally) - -default_mesh_file = joinpath(@__DIR__, "mesh_periodic_square_with_twist.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", + joinpath(@__DIR__, "mesh_periodic_square_with_twist.mesh")) mesh = UnstructuredMesh2D(mesh_file, periodicity = true) diff --git a/examples/unstructured_2d_fdsbp/elixir_euler_free_stream.jl b/examples/unstructured_2d_fdsbp/elixir_euler_free_stream.jl index 7ada50c0c65..25a81c16bf9 100644 --- a/examples/unstructured_2d_fdsbp/elixir_euler_free_stream.jl +++ b/examples/unstructured_2d_fdsbp/elixir_euler_free_stream.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -33,12 +32,8 @@ solver = FDSBP(D_SBP, ############################################################################### # Get the curved quad mesh from a file (downloads the file if not available locally) - -default_mesh_file = joinpath(@__DIR__, "mesh_gingerbread_man.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/2c6440b5f8a57db131061ad7aa78ee2b/raw/1f89fdf2c874ff678c78afb6fe8dc784bdfd421f/mesh_gingerbread_man.mesh", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/2c6440b5f8a57db131061ad7aa78ee2b/raw/1f89fdf2c874ff678c78afb6fe8dc784bdfd421f/mesh_gingerbread_man.mesh", + joinpath(@__DIR__, "mesh_gingerbread_man.mesh")) mesh = UnstructuredMesh2D(mesh_file) diff --git a/examples/unstructured_2d_fdsbp/elixir_euler_source_terms.jl b/examples/unstructured_2d_fdsbp/elixir_euler_source_terms.jl index edcd221bf59..5f11d41ad5c 100644 --- a/examples/unstructured_2d_fdsbp/elixir_euler_source_terms.jl +++ b/examples/unstructured_2d_fdsbp/elixir_euler_source_terms.jl @@ -1,5 +1,4 @@ -using Downloads: download using OrdinaryDiffEq using Trixi @@ -22,12 +21,8 @@ solver = FDSBP(D_SBP, ############################################################################### # Get the curved quad mesh from a file (downloads the file if not available locally) - -default_mesh_file = joinpath(@__DIR__, "mesh_periodic_square_with_twist.mesh") -isfile(default_mesh_file) || - download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", - default_mesh_file) -mesh_file = default_mesh_file +mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/12ce661d7c354c3d94c74b964b0f1c96/raw/8275b9a60c6e7ebbdea5fc4b4f091c47af3d5273/mesh_periodic_square_with_twist.mesh", + joinpath(@__DIR__, "mesh_periodic_square_with_twist.mesh")) mesh = UnstructuredMesh2D(mesh_file, periodicity = true) diff --git a/src/Trixi.jl b/src/Trixi.jl index e18b2f6415c..8d74fbc9736 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -39,6 +39,7 @@ import SciMLBase: get_du, get_tmp_cache, u_modified!, get_proposed_dt, set_proposed_dt!, terminate!, remake, add_tstop!, has_tstop, first_tstop +using Downloads: Downloads using CodeTracking: CodeTracking using ConstructionBase: ConstructionBase using DiffEqCallbacks: PeriodicCallback, PeriodicCallbackAffect diff --git a/src/auxiliary/auxiliary.jl b/src/auxiliary/auxiliary.jl index 1f7d30d6aa8..92da9a5ba8b 100644 --- a/src/auxiliary/auxiliary.jl +++ b/src/auxiliary/auxiliary.jl @@ -345,4 +345,27 @@ function register_error_hints() return nothing end + +""" + Trixi.download(src_url, file_path) + +Download a file from given `src_url` to given `file_path` if +`file_path` is not already a file. This function just returns +`file_path`. +This is a small wrapper of `Downloads.download(src_url, file_path)` +that avoids race conditions when multiple MPI ranks are used. +""" +function download(src_url, file_path) + # Note that `mpi_isroot()` is also `true` if running + # in serial (without MPI). + if mpi_isroot() + isfile(file_path) || Downloads.download(src_url, file_path) + end + + if mpi_isparallel() + MPI.Barrier(mpi_comm()) + end + + return file_path +end end # @muladd diff --git a/src/auxiliary/t8code.jl b/src/auxiliary/t8code.jl index db01476bb86..7c1399fc803 100644 --- a/src/auxiliary/t8code.jl +++ b/src/auxiliary/t8code.jl @@ -46,230 +46,6 @@ function init_t8code() return nothing end -function trixi_t8_unref_forest(forest) - t8_forest_unref(Ref(forest)) -end - -function t8_free(ptr) - T8code.Libt8.sc_free(t8_get_package_id(), ptr) -end - -function trixi_t8_count_interfaces(forest) - # Check that forest is a committed, that is valid and usable, forest. - @assert t8_forest_is_committed(forest) != 0 - - # Get the number of local elements of forest. - num_local_elements = t8_forest_get_local_num_elements(forest) - # Get the number of ghost elements of forest. - num_ghost_elements = t8_forest_get_num_ghosts(forest) - # Get the number of trees that have elements of this process. - num_local_trees = t8_forest_get_num_local_trees(forest) - - current_index = t8_locidx_t(0) - - local_num_conform = 0 - local_num_mortars = 0 - local_num_boundary = 0 - - for itree in 0:(num_local_trees - 1) - tree_class = t8_forest_get_tree_class(forest, itree) - eclass_scheme = t8_forest_get_eclass_scheme(forest, tree_class) - - # Get the number of elements of this tree. - num_elements_in_tree = t8_forest_get_tree_num_elements(forest, itree) - - for ielement in 0:(num_elements_in_tree - 1) - element = t8_forest_get_element_in_tree(forest, itree, ielement) - - level = t8_element_level(eclass_scheme, element) - - num_faces = t8_element_num_faces(eclass_scheme, element) - - for iface in 0:(num_faces - 1) - pelement_indices_ref = Ref{Ptr{t8_locidx_t}}() - pneighbor_leafs_ref = Ref{Ptr{Ptr{t8_element}}}() - pneigh_scheme_ref = Ref{Ptr{t8_eclass_scheme}}() - - dual_faces_ref = Ref{Ptr{Cint}}() - num_neighbors_ref = Ref{Cint}() - - forest_is_balanced = Cint(1) - - t8_forest_leaf_face_neighbors(forest, itree, element, - pneighbor_leafs_ref, iface, dual_faces_ref, - num_neighbors_ref, - pelement_indices_ref, pneigh_scheme_ref, - forest_is_balanced) - - num_neighbors = num_neighbors_ref[] - neighbor_ielements = unsafe_wrap(Array, pelement_indices_ref[], - num_neighbors) - neighbor_leafs = unsafe_wrap(Array, pneighbor_leafs_ref[], num_neighbors) - neighbor_scheme = pneigh_scheme_ref[] - - if num_neighbors > 0 - neighbor_level = t8_element_level(neighbor_scheme, neighbor_leafs[1]) - - # Conforming interface: The second condition ensures we only visit the interface once. - if level == neighbor_level && current_index <= neighbor_ielements[1] - local_num_conform += 1 - elseif level < neighbor_level - local_num_mortars += 1 - end - else - local_num_boundary += 1 - end - - t8_free(dual_faces_ref[]) - t8_free(pneighbor_leafs_ref[]) - t8_free(pelement_indices_ref[]) - end # for - - current_index += 1 - end # for - end # for - - return (interfaces = local_num_conform, - mortars = local_num_mortars, - boundaries = local_num_boundary) -end - -function trixi_t8_fill_mesh_info(forest, elements, interfaces, mortars, boundaries, - boundary_names) - # Check that forest is a committed, that is valid and usable, forest. - @assert t8_forest_is_committed(forest) != 0 - - # Get the number of local elements of forest. - num_local_elements = t8_forest_get_local_num_elements(forest) - # Get the number of ghost elements of forest. - num_ghost_elements = t8_forest_get_num_ghosts(forest) - # Get the number of trees that have elements of this process. - num_local_trees = t8_forest_get_num_local_trees(forest) - - current_index = t8_locidx_t(0) - - local_num_conform = 0 - local_num_mortars = 0 - local_num_boundary = 0 - - for itree in 0:(num_local_trees - 1) - tree_class = t8_forest_get_tree_class(forest, itree) - eclass_scheme = t8_forest_get_eclass_scheme(forest, tree_class) - - # Get the number of elements of this tree. - num_elements_in_tree = t8_forest_get_tree_num_elements(forest, itree) - - for ielement in 0:(num_elements_in_tree - 1) - element = t8_forest_get_element_in_tree(forest, itree, ielement) - - level = t8_element_level(eclass_scheme, element) - - num_faces = t8_element_num_faces(eclass_scheme, element) - - for iface in 0:(num_faces - 1) - - # Compute the `orientation` of the touching faces. - if t8_element_is_root_boundary(eclass_scheme, element, iface) == 1 - cmesh = t8_forest_get_cmesh(forest) - itree_in_cmesh = t8_forest_ltreeid_to_cmesh_ltreeid(forest, itree) - iface_in_tree = t8_element_tree_face(eclass_scheme, element, iface) - orientation_ref = Ref{Cint}() - - t8_cmesh_get_face_neighbor(cmesh, itree_in_cmesh, iface_in_tree, C_NULL, - orientation_ref) - orientation = orientation_ref[] - else - orientation = zero(Cint) - end - - pelement_indices_ref = Ref{Ptr{t8_locidx_t}}() - pneighbor_leafs_ref = Ref{Ptr{Ptr{t8_element}}}() - pneigh_scheme_ref = Ref{Ptr{t8_eclass_scheme}}() - - dual_faces_ref = Ref{Ptr{Cint}}() - num_neighbors_ref = Ref{Cint}() - - forest_is_balanced = Cint(1) - - t8_forest_leaf_face_neighbors(forest, itree, element, - pneighbor_leafs_ref, iface, dual_faces_ref, - num_neighbors_ref, - pelement_indices_ref, pneigh_scheme_ref, - forest_is_balanced) - - num_neighbors = num_neighbors_ref[] - dual_faces = unsafe_wrap(Array, dual_faces_ref[], num_neighbors) - neighbor_ielements = unsafe_wrap(Array, pelement_indices_ref[], - num_neighbors) - neighbor_leafs = unsafe_wrap(Array, pneighbor_leafs_ref[], num_neighbors) - neighbor_scheme = pneigh_scheme_ref[] - - if num_neighbors > 0 - neighbor_level = t8_element_level(neighbor_scheme, neighbor_leafs[1]) - - # Conforming interface: The second condition ensures we only visit the interface once. - if level == neighbor_level && current_index <= neighbor_ielements[1] - local_num_conform += 1 - - faces = (iface, dual_faces[1]) - interface_id = local_num_conform - - # Write data to interfaces container. - interfaces.neighbor_ids[1, interface_id] = current_index + 1 - interfaces.neighbor_ids[2, interface_id] = neighbor_ielements[1] + 1 - - # Save interfaces.node_indices dimension specific in containers_3d.jl. - init_interface_node_indices!(interfaces, faces, orientation, - interface_id) - # Non-conforming interface. - elseif level < neighbor_level - local_num_mortars += 1 - - faces = (dual_faces[1], iface) - - mortar_id = local_num_mortars - - # Last entry is the large element. - mortars.neighbor_ids[end, mortar_id] = current_index + 1 - - # Fill in the `mortars.neighbor_ids` array and reorder if necessary. - init_mortar_neighbor_ids!(mortars, faces[2], faces[1], - orientation, neighbor_ielements, - mortar_id) - - # Fill in the `mortars.node_indices` array. - init_mortar_node_indices!(mortars, faces, orientation, mortar_id) - - # else: "level > neighbor_level" is skipped since we visit the mortar interface only once. - end - - # Domain boundary. - else - local_num_boundary += 1 - boundary_id = local_num_boundary - - boundaries.neighbor_ids[boundary_id] = current_index + 1 - - init_boundary_node_indices!(boundaries, iface, boundary_id) - - # One-based indexing. - boundaries.name[boundary_id] = boundary_names[iface + 1, itree + 1] - end - - t8_free(dual_faces_ref[]) - t8_free(pneighbor_leafs_ref[]) - t8_free(pelement_indices_ref[]) - end # for iface = ... - - current_index += 1 - end # for - end # for - - return (interfaces = local_num_conform, - mortars = local_num_mortars, - boundaries = local_num_boundary) -end - function trixi_t8_get_local_element_levels(forest) # Check that forest is a committed, that is valid and usable, forest. @assert t8_forest_is_committed(forest) != 0 @@ -341,23 +117,16 @@ function adapt_callback(forest, end function trixi_t8_adapt_new(old_forest, indicators) - # Check that forest is a committed, that is valid and usable, forest. - @assert t8_forest_is_committed(old_forest) != 0 - - # Init new forest. new_forest_ref = Ref{t8_forest_t}() t8_forest_init(new_forest_ref) new_forest = new_forest_ref[] - let set_from = C_NULL, recursive = 0, set_for_coarsening = 0, no_repartition = 0, - do_ghost = 1 - + let set_from = C_NULL, recursive = 0, no_repartition = 1, do_ghost = 1 t8_forest_set_user_data(new_forest, pointer(indicators)) t8_forest_set_adapt(new_forest, old_forest, @t8_adapt_callback(adapt_callback), recursive) t8_forest_set_balance(new_forest, set_from, no_repartition) - t8_forest_set_partition(new_forest, set_from, set_for_coarsening) - t8_forest_set_ghost(new_forest, do_ghost, T8_GHOST_FACES) # Note: MPI support not available yet so it is a dummy call. + t8_forest_set_ghost(new_forest, do_ghost, T8_GHOST_FACES) t8_forest_commit(new_forest) end diff --git a/src/callbacks_step/amr.jl b/src/callbacks_step/amr.jl index 5854c8617c3..6f57d6647fc 100644 --- a/src/callbacks_step/amr.jl +++ b/src/callbacks_step/amr.jl @@ -726,7 +726,7 @@ function (amr_callback::AMRCallback)(u_ode::AbstractVector, mesh::P4estMesh, return has_changed end -function (amr_callback::AMRCallback)(u_ode::AbstractVector, mesh::SerialT8codeMesh, +function (amr_callback::AMRCallback)(u_ode::AbstractVector, mesh::T8codeMesh, equations, dg::DG, cache, semi, t, iter; only_refine = false, only_coarsen = false, @@ -754,29 +754,29 @@ function (amr_callback::AMRCallback)(u_ode::AbstractVector, mesh::SerialT8codeMe @trixi_timeit timer() "adapt" begin difference = @trixi_timeit timer() "mesh" trixi_t8_adapt!(mesh, indicators) - @trixi_timeit timer() "solver" adapt!(u_ode, adaptor, mesh, equations, dg, - cache, difference) - end + # Store whether there were any cells coarsened or refined and perform load balancing. + has_changed = any(difference .!= 0) - # Store whether there were any cells coarsened or refined and perform load balancing. - has_changed = any(difference .!= 0) + # Check if mesh changed on other processes + if mpi_isparallel() + has_changed = MPI.Allreduce!(Ref(has_changed), |, mpi_comm())[] + end - # TODO: T8codeMesh for MPI not implemented yet. - # Check if mesh changed on other processes - # if mpi_isparallel() - # has_changed = MPI.Allreduce!(Ref(has_changed), |, mpi_comm())[] - # end + if has_changed + @trixi_timeit timer() "solver" adapt!(u_ode, adaptor, mesh, equations, dg, + cache, difference) + end + end if has_changed - # TODO: T8codeMesh for MPI not implemented yet. - # if mpi_isparallel() && amr_callback.dynamic_load_balancing - # @trixi_timeit timer() "dynamic load balancing" begin - # global_first_quadrant = unsafe_wrap(Array, mesh.p4est.global_first_quadrant, mpi_nranks() + 1) - # old_global_first_quadrant = copy(global_first_quadrant) - # partition!(mesh) - # rebalance_solver!(u_ode, mesh, equations, dg, cache, old_global_first_quadrant) - # end - # end + if mpi_isparallel() && amr_callback.dynamic_load_balancing + @trixi_timeit timer() "dynamic load balancing" begin + old_global_first_element_ids = get_global_first_element_ids(mesh) + partition!(mesh) + rebalance_solver!(u_ode, mesh, equations, dg, cache, + old_global_first_element_ids) + end + end reinitialize_boundaries!(semi.boundary_conditions, cache) end diff --git a/src/callbacks_step/amr_dg.jl b/src/callbacks_step/amr_dg.jl index 1dcfdccdea8..0a7055af409 100644 --- a/src/callbacks_step/amr_dg.jl +++ b/src/callbacks_step/amr_dg.jl @@ -6,11 +6,14 @@ #! format: noindent # Redistribute data for load balancing after partitioning the mesh -function rebalance_solver!(u_ode::AbstractVector, mesh::ParallelP4estMesh, equations, +function rebalance_solver!(u_ode::AbstractVector, + mesh::Union{ParallelP4estMesh, ParallelT8codeMesh}, + equations, dg::DGSEM, cache, old_global_first_quadrant) - # mpi ranks are 0-based, this array uses 1-based indices - global_first_quadrant = unsafe_wrap(Array, mesh.p4est.global_first_quadrant, - mpi_nranks() + 1) + + # MPI ranks are 0-based. This array uses 1-based indices. + global_first_quadrant = get_global_first_element_ids(mesh) + if global_first_quadrant[mpi_rank() + 1] == old_global_first_quadrant[mpi_rank() + 1] && global_first_quadrant[mpi_rank() + 2] == diff --git a/src/callbacks_step/amr_dg2d.jl b/src/callbacks_step/amr_dg2d.jl index b816bc06e65..94524b23a3a 100644 --- a/src/callbacks_step/amr_dg2d.jl +++ b/src/callbacks_step/amr_dg2d.jl @@ -385,7 +385,12 @@ function adapt!(u_ode::AbstractVector, adaptor, mesh::T8codeMesh{2}, equations, # Return early if there is nothing to do. if !any(difference .!= 0) - return nothing + if mpi_isparallel() + # MPICache init uses all-to-all communication -> reinitialize even if there is nothing to do + # locally (there still might be other MPI ranks that have refined elements) + reinitialize_containers!(mesh, equations, dg, cache) + end + return end # Number of (local) cells/elements. diff --git a/src/callbacks_step/amr_dg3d.jl b/src/callbacks_step/amr_dg3d.jl index 392cbba9e28..3f67951bafe 100644 --- a/src/callbacks_step/amr_dg3d.jl +++ b/src/callbacks_step/amr_dg3d.jl @@ -316,7 +316,12 @@ function adapt!(u_ode::AbstractVector, adaptor, mesh::T8codeMesh{3}, equations, # Return early if there is nothing to do. if !any(difference .!= 0) - return nothing + if mpi_isparallel() + # MPICache init uses all-to-all communication -> reinitialize even if there is nothing to do + # locally (there still might be other MPI ranks that have refined elements) + reinitialize_containers!(mesh, equations, dg, cache) + end + return end # Number of (local) cells/elements. diff --git a/src/callbacks_step/analysis_dg2d_parallel.jl b/src/callbacks_step/analysis_dg2d_parallel.jl index a04bf732604..000daa015dc 100644 --- a/src/callbacks_step/analysis_dg2d_parallel.jl +++ b/src/callbacks_step/analysis_dg2d_parallel.jl @@ -91,7 +91,8 @@ function calc_error_norms_per_element(func, u, t, analyzer, end function calc_error_norms(func, u, t, analyzer, - mesh::ParallelP4estMesh{2}, equations, + mesh::Union{ParallelP4estMesh{2}, ParallelT8codeMesh{2}}, + equations, initial_condition, dg::DGSEM, cache, cache_analysis) @unpack vandermonde, weights = analyzer @unpack node_coordinates, inverse_jacobian = cache.elements @@ -171,7 +172,8 @@ function integrate_via_indices(func::Func, u, end function integrate_via_indices(func::Func, u, - mesh::ParallelP4estMesh{2}, equations, + mesh::Union{ParallelP4estMesh{2}, ParallelT8codeMesh{2}}, + equations, dg::DGSEM, cache, args...; normalize = true) where {Func} @unpack weights = dg.basis diff --git a/src/callbacks_step/analysis_dg3d_parallel.jl b/src/callbacks_step/analysis_dg3d_parallel.jl index d8756d91c9d..de777be406d 100644 --- a/src/callbacks_step/analysis_dg3d_parallel.jl +++ b/src/callbacks_step/analysis_dg3d_parallel.jl @@ -6,7 +6,8 @@ #! format: noindent function calc_error_norms(func, u, t, analyzer, - mesh::ParallelP4estMesh{3}, equations, + mesh::Union{ParallelP4estMesh{3}, ParallelT8codeMesh{3}}, + equations, initial_condition, dg::DGSEM, cache, cache_analysis) @unpack vandermonde, weights = analyzer @unpack node_coordinates, inverse_jacobian = cache.elements @@ -64,7 +65,8 @@ function calc_error_norms(func, u, t, analyzer, end function integrate_via_indices(func::Func, u, - mesh::ParallelP4estMesh{3}, equations, + mesh::Union{ParallelP4estMesh{3}, ParallelT8codeMesh{3}}, + equations, dg::DGSEM, cache, args...; normalize = true) where {Func} @unpack weights = dg.basis diff --git a/src/callbacks_step/stepsize_dg2d.jl b/src/callbacks_step/stepsize_dg2d.jl index 673c3ba6aa6..c6d32c0f6dc 100644 --- a/src/callbacks_step/stepsize_dg2d.jl +++ b/src/callbacks_step/stepsize_dg2d.jl @@ -174,4 +174,36 @@ function max_dt(u, t, mesh::ParallelP4estMesh{2}, return dt end + +function max_dt(u, t, mesh::ParallelT8codeMesh{2}, + constant_speed::False, equations, dg::DG, cache) + # call the method accepting a general `mesh::T8codeMesh{2}` + # TODO: MPI, we should improve this; maybe we should dispatch on `u` + # and create some MPI array type, overloading broadcasting and mapreduce etc. + # Then, this specific array type should also work well with DiffEq etc. + dt = invoke(max_dt, + Tuple{typeof(u), typeof(t), T8codeMesh{2}, + typeof(constant_speed), typeof(equations), typeof(dg), + typeof(cache)}, + u, t, mesh, constant_speed, equations, dg, cache) + dt = MPI.Allreduce!(Ref(dt), min, mpi_comm())[] + + return dt +end + +function max_dt(u, t, mesh::ParallelT8codeMesh{2}, + constant_speed::True, equations, dg::DG, cache) + # call the method accepting a general `mesh::T8codeMesh{2}` + # TODO: MPI, we should improve this; maybe we should dispatch on `u` + # and create some MPI array type, overloading broadcasting and mapreduce etc. + # Then, this specific array type should also work well with DiffEq etc. + dt = invoke(max_dt, + Tuple{typeof(u), typeof(t), T8codeMesh{2}, + typeof(constant_speed), typeof(equations), typeof(dg), + typeof(cache)}, + u, t, mesh, constant_speed, equations, dg, cache) + dt = MPI.Allreduce!(Ref(dt), min, mpi_comm())[] + + return dt +end end # @muladd diff --git a/src/callbacks_step/stepsize_dg3d.jl b/src/callbacks_step/stepsize_dg3d.jl index 822ab2f87ec..664596f989e 100644 --- a/src/callbacks_step/stepsize_dg3d.jl +++ b/src/callbacks_step/stepsize_dg3d.jl @@ -150,4 +150,36 @@ function max_dt(u, t, mesh::ParallelP4estMesh{3}, return dt end + +function max_dt(u, t, mesh::ParallelT8codeMesh{3}, + constant_speed::False, equations, dg::DG, cache) + # call the method accepting a general `mesh::T8codeMesh{3}` + # TODO: MPI, we should improve this; maybe we should dispatch on `u` + # and create some MPI array type, overloading broadcasting and mapreduce etc. + # Then, this specific array type should also work well with DiffEq etc. + dt = invoke(max_dt, + Tuple{typeof(u), typeof(t), T8codeMesh{3}, + typeof(constant_speed), typeof(equations), typeof(dg), + typeof(cache)}, + u, t, mesh, constant_speed, equations, dg, cache) + dt = MPI.Allreduce!(Ref(dt), min, mpi_comm())[] + + return dt +end + +function max_dt(u, t, mesh::ParallelT8codeMesh{3}, + constant_speed::True, equations, dg::DG, cache) + # call the method accepting a general `mesh::T8codeMesh{3}` + # TODO: MPI, we should improve this; maybe we should dispatch on `u` + # and create some MPI array type, overloading broadcasting and mapreduce etc. + # Then, this specific array type should also work well with DiffEq etc. + dt = invoke(max_dt, + Tuple{typeof(u), typeof(t), T8codeMesh{3}, + typeof(constant_speed), typeof(equations), typeof(dg), + typeof(cache)}, + u, t, mesh, constant_speed, equations, dg, cache) + dt = MPI.Allreduce!(Ref(dt), min, mpi_comm())[] + + return dt +end end # @muladd diff --git a/src/meshes/p4est_mesh.jl b/src/meshes/p4est_mesh.jl index c5d39ef00c0..abe9d9345b5 100644 --- a/src/meshes/p4est_mesh.jl +++ b/src/meshes/p4est_mesh.jl @@ -1700,6 +1700,10 @@ function bilinear_interpolation!(coordinate, face_vertices, u, v) end end +function get_global_first_element_ids(mesh::P4estMesh) + return unsafe_wrap(Array, mesh.p4est.global_first_quadrant, mpi_nranks() + 1) +end + function balance!(mesh::P4estMesh{2}, init_fn = C_NULL) p4est_balance(mesh.p4est, P4EST_CONNECT_FACE, init_fn) # Due to a bug in `p4est`, the forest needs to be rebalanced twice sometimes diff --git a/src/meshes/t8code_mesh.jl b/src/meshes/t8code_mesh.jl index c9665a22af9..6fb4d861d10 100644 --- a/src/meshes/t8code_mesh.jl +++ b/src/meshes/t8code_mesh.jl @@ -7,8 +7,6 @@ to manage trees and mesh refinement. """ mutable struct T8codeMesh{NDIMS, RealT <: Real, IsParallel, NDIMSP2, NNODES} <: AbstractMesh{NDIMS} - cmesh :: Ptr{t8_cmesh} # cpointer to coarse mesh - scheme :: Ptr{t8_eclass_scheme} # cpointer to element scheme forest :: Ptr{t8_forest} # cpointer to forest is_parallel :: IsParallel @@ -25,14 +23,15 @@ mutable struct T8codeMesh{NDIMS, RealT <: Real, IsParallel, NDIMSP2, NNODES} <: nmortars :: Int nboundaries :: Int - function T8codeMesh{NDIMS}(cmesh, scheme, forest, tree_node_coordinates, nodes, + nmpiinterfaces :: Int + nmpimortars :: Int + + function T8codeMesh{NDIMS}(forest, tree_node_coordinates, nodes, boundary_names, current_filename) where {NDIMS} - is_parallel = False() + is_parallel = mpi_isparallel() ? True() : False() - mesh = new{NDIMS, Float64, typeof(is_parallel), NDIMS + 2, length(nodes)}(cmesh, - scheme, - forest, + mesh = new{NDIMS, Float64, typeof(is_parallel), NDIMS + 2, length(nodes)}(forest, is_parallel) mesh.nodes = nodes @@ -52,7 +51,7 @@ mutable struct T8codeMesh{NDIMS, RealT <: Real, IsParallel, NDIMSP2, NNODES} <: # further down. However, this might cause a pile-up of `mesh` # objects during long-running sessions. if !MPI.Finalized() - trixi_t8_unref_forest(mesh.forest) + t8_forest_unref(Ref(mesh.forest)) end end @@ -63,7 +62,7 @@ mutable struct T8codeMesh{NDIMS, RealT <: Real, IsParallel, NDIMSP2, NNODES} <: # more information. if haskey(ENV, "TRIXI_T8CODE_SC_FINALIZE") MPI.add_finalize_hook!() do - trixi_t8_unref_forest(mesh.forest) + t8_forest_unref(Ref(mesh.forest)) end end @@ -72,16 +71,15 @@ mutable struct T8codeMesh{NDIMS, RealT <: Real, IsParallel, NDIMSP2, NNODES} <: end const SerialT8codeMesh{NDIMS} = T8codeMesh{NDIMS, <:Real, <:False} +const ParallelT8codeMesh{NDIMS} = T8codeMesh{NDIMS, <:Real, <:True} @inline mpi_parallel(mesh::SerialT8codeMesh) = False() +@inline mpi_parallel(mesh::ParallelT8codeMesh) = True() @inline Base.ndims(::T8codeMesh{NDIMS}) where {NDIMS} = NDIMS @inline Base.real(::T8codeMesh{NDIMS, RealT}) where {NDIMS, RealT} = RealT -@inline ntrees(mesh::T8codeMesh) = Int(t8_forest_get_num_local_trees(mesh.forest)) +@inline ntrees(mesh::T8codeMesh) = size(mesh.tree_node_coordinates)[end] @inline ncells(mesh::T8codeMesh) = Int(t8_forest_get_local_num_elements(mesh.forest)) -@inline ninterfaces(mesh::T8codeMesh) = mesh.ninterfaces -@inline nmortars(mesh::T8codeMesh) = mesh.nmortars -@inline nboundaries(mesh::T8codeMesh) = mesh.nboundaries function Base.show(io::IO, mesh::T8codeMesh) print(io, "T8codeMesh{", ndims(mesh), ", ", real(mesh), "}") @@ -184,21 +182,23 @@ function T8codeMesh(trees_per_dimension; polydeg = 1, T8code.Libt8.p8est_connectivity_destroy(conn) end + do_face_ghost = mpi_isparallel() scheme = t8_scheme_new_default_cxx() - forest = t8_forest_new_uniform(cmesh, scheme, initial_refinement_level, 0, mpi_comm()) + forest = t8_forest_new_uniform(cmesh, scheme, initial_refinement_level, do_face_ghost, + mpi_comm()) basis = LobattoLegendreBasis(RealT, polydeg) nodes = basis.nodes + num_trees = t8_cmesh_get_num_trees(cmesh) + tree_node_coordinates = Array{RealT, NDIMS + 2}(undef, NDIMS, ntuple(_ -> length(nodes), NDIMS)..., - prod(trees_per_dimension)) + num_trees) # Get cell length in reference mesh: Omega_ref = [-1,1]^NDIMS. dx = [2 / n for n in trees_per_dimension] - num_local_trees = t8_cmesh_get_num_local_trees(cmesh) - # Non-periodic boundaries. boundary_names = fill(Symbol("---"), 2 * NDIMS, prod(trees_per_dimension)) @@ -208,7 +208,7 @@ function T8codeMesh(trees_per_dimension; polydeg = 1, mapping_ = mapping end - for itree in 1:num_local_trees + for itree in 1:num_trees veptr = t8_cmesh_get_tree_vertices(cmesh, itree - 1) verts = unsafe_wrap(Array, veptr, (3, 1 << NDIMS)) @@ -256,7 +256,7 @@ function T8codeMesh(trees_per_dimension; polydeg = 1, end end - return T8codeMesh{NDIMS}(cmesh, scheme, forest, tree_node_coordinates, nodes, + return T8codeMesh{NDIMS}(forest, tree_node_coordinates, nodes, boundary_names, "") end @@ -290,21 +290,25 @@ function T8codeMesh(cmesh::Ptr{t8_cmesh}; @assert (NDIMS == 2||NDIMS == 3) "NDIMS should be 2 or 3." + do_face_ghost = mpi_isparallel() scheme = t8_scheme_new_default_cxx() - forest = t8_forest_new_uniform(cmesh, scheme, initial_refinement_level, 0, mpi_comm()) + forest = t8_forest_new_uniform(cmesh, scheme, initial_refinement_level, do_face_ghost, + mpi_comm()) basis = LobattoLegendreBasis(RealT, polydeg) nodes = basis.nodes - num_local_trees = t8_cmesh_get_num_local_trees(cmesh) + num_trees = t8_cmesh_get_num_trees(cmesh) tree_node_coordinates = Array{RealT, NDIMS + 2}(undef, NDIMS, ntuple(_ -> length(nodes), NDIMS)..., - num_local_trees) + num_trees) nodes_in = [-1.0, 1.0] matrix = polynomial_interpolation_matrix(nodes_in, nodes) + num_local_trees = t8_cmesh_get_num_local_trees(cmesh) + if NDIMS == 2 data_in = Array{RealT, 3}(undef, 2, 2, 2) tmp1 = zeros(RealT, 2, length(nodes), length(nodes_in)) @@ -353,7 +357,7 @@ function T8codeMesh(cmesh::Ptr{t8_cmesh}; tmp1 = zeros(RealT, 3, length(nodes), length(nodes_in), length(nodes_in)) verts = zeros(3, 8) - for itree in 0:(num_local_trees - 1) + for itree in 0:(num_trees - 1) veptr = t8_cmesh_get_tree_vertices(cmesh, itree) # Note, `verts = unsafe_wrap(Array, veptr, (3, 1 << NDIMS))` @@ -387,9 +391,9 @@ function T8codeMesh(cmesh::Ptr{t8_cmesh}; map_node_coordinates!(tree_node_coordinates, mapping) # There's no simple and generic way to distinguish boundaries. Name all of them :all. - boundary_names = fill(:all, 2 * NDIMS, num_local_trees) + boundary_names = fill(:all, 2 * NDIMS, num_trees) - return T8codeMesh{NDIMS}(cmesh, scheme, forest, tree_node_coordinates, nodes, + return T8codeMesh{NDIMS}(forest, tree_node_coordinates, nodes, boundary_names, "") end @@ -442,7 +446,7 @@ function T8codeMesh(conn::Ptr{p8est_connectivity}; kwargs...) end """ - T8codeMesh{NDIMS}(meshfile::String; kwargs...) + T8codeMesh(meshfile::String, ndims; kwargs...) Main mesh constructor for the `T8codeMesh` that imports an unstructured, conforming mesh from a Gmsh mesh file (`.msh`). @@ -461,7 +465,6 @@ mesh from a Gmsh mesh file (`.msh`). - `initial_refinement_level::Integer`: refine the mesh uniformly to this level before the simulation starts. """ function T8codeMesh(meshfile::String, ndims; kwargs...) - # Prevent `t8code` from crashing Julia if the file doesn't exist. @assert isfile(meshfile) @@ -586,13 +589,525 @@ function adapt!(mesh::T8codeMesh, adapt_callback; recursive = true, balance = tr return nothing end -# TODO: Just a placeholder. Will be implemented later when MPI is supported. -function balance!(mesh::T8codeMesh, init_fn = C_NULL) +""" + Trixi.balance!(mesh::T8codeMesh) + +Balance a `T8codeMesh` to ensure 2^(NDIMS-1):1 face neighbors. +""" +function balance!(mesh::T8codeMesh) + new_forest_ref = Ref{t8_forest_t}() + t8_forest_init(new_forest_ref) + new_forest = new_forest_ref[] + + let set_from = mesh.forest, no_repartition = 1, do_ghost = 1 + t8_forest_set_balance(new_forest, set_from, no_repartition) + t8_forest_set_ghost(new_forest, do_ghost, T8_GHOST_FACES) + t8_forest_commit(new_forest) + end + + mesh.forest = new_forest + + return nothing +end + +""" + Trixi.partition!(mesh::T8codeMesh) + +Partition a `T8codeMesh` in order to redistribute elements evenly among MPI ranks. + +# Arguments +- `mesh::T8codeMesh`: Initialized mesh object. +""" +function partition!(mesh::T8codeMesh) + new_forest_ref = Ref{t8_forest_t}() + t8_forest_init(new_forest_ref) + new_forest = new_forest_ref[] + + let set_from = mesh.forest, do_ghost = 1, allow_for_coarsening = 1 + t8_forest_set_partition(new_forest, set_from, allow_for_coarsening) + t8_forest_set_ghost(new_forest, do_ghost, T8_GHOST_FACES) + t8_forest_commit(new_forest) + end + + mesh.forest = new_forest + return nothing end -# TODO: Just a placeholder. Will be implemented later when MPI is supported. -function partition!(mesh::T8codeMesh; allow_coarsening = true, weight_fn = C_NULL) +# Compute the global ids (zero-indexed) of first element in each MPI rank. +function get_global_first_element_ids(mesh::T8codeMesh) + n_elements_local = Int(t8_forest_get_local_num_elements(mesh.forest)) + n_elements_by_rank = Vector{Int}(undef, mpi_nranks()) + n_elements_by_rank[mpi_rank() + 1] = n_elements_local + MPI.Allgather!(MPI.UBuffer(n_elements_by_rank, 1), mpi_comm()) + return [sum(n_elements_by_rank[1:(rank - 1)]) for rank in 1:(mpi_nranks() + 1)] +end + +function count_interfaces(mesh::T8codeMesh) + @assert t8_forest_is_committed(mesh.forest) != 0 + + num_local_elements = t8_forest_get_local_num_elements(mesh.forest) + num_local_trees = t8_forest_get_num_local_trees(mesh.forest) + + current_index = t8_locidx_t(0) + + local_num_conform = 0 + local_num_mortars = 0 + local_num_boundary = 0 + + local_num_mpi_conform = 0 + local_num_mpi_mortars = 0 + + visited_global_mortar_ids = Set{UInt64}([]) + + max_level = t8_forest_get_maxlevel(mesh.forest) #UInt64 + max_tree_num_elements = UInt64(2^ndims(mesh))^max_level + + if mpi_isparallel() + ghost_num_trees = t8_forest_ghost_num_trees(mesh.forest) + + ghost_tree_element_offsets = [num_local_elements + + t8_forest_ghost_get_tree_element_offset(mesh.forest, + itree) + for itree in 0:(ghost_num_trees - 1)] + ghost_global_treeids = [t8_forest_ghost_get_global_treeid(mesh.forest, itree) + for itree in 0:(ghost_num_trees - 1)] + end + + for itree in 0:(num_local_trees - 1) + tree_class = t8_forest_get_tree_class(mesh.forest, itree) + eclass_scheme = t8_forest_get_eclass_scheme(mesh.forest, tree_class) + + num_elements_in_tree = t8_forest_get_tree_num_elements(mesh.forest, itree) + + global_itree = t8_forest_global_tree_id(mesh.forest, itree) + + for ielement in 0:(num_elements_in_tree - 1) + element = t8_forest_get_element_in_tree(mesh.forest, itree, ielement) + + level = t8_element_level(eclass_scheme, element) + + num_faces = t8_element_num_faces(eclass_scheme, element) + + # Note: This works only for forests of one element class. + current_linear_id = global_itree * max_tree_num_elements + + t8_element_get_linear_id(eclass_scheme, element, max_level) + + for iface in 0:(num_faces - 1) + pelement_indices_ref = Ref{Ptr{t8_locidx_t}}() + pneighbor_leafs_ref = Ref{Ptr{Ptr{t8_element}}}() + pneigh_scheme_ref = Ref{Ptr{t8_eclass_scheme}}() + + dual_faces_ref = Ref{Ptr{Cint}}() + num_neighbors_ref = Ref{Cint}() + + forest_is_balanced = Cint(1) + + t8_forest_leaf_face_neighbors(mesh.forest, itree, element, + pneighbor_leafs_ref, iface, dual_faces_ref, + num_neighbors_ref, + pelement_indices_ref, pneigh_scheme_ref, + forest_is_balanced) + + num_neighbors = num_neighbors_ref[] + dual_faces = unsafe_wrap(Array, dual_faces_ref[], num_neighbors) + neighbor_ielements = unsafe_wrap(Array, pelement_indices_ref[], + num_neighbors) + neighbor_leafs = unsafe_wrap(Array, pneighbor_leafs_ref[], num_neighbors) + neighbor_scheme = pneigh_scheme_ref[] + + if num_neighbors == 0 + local_num_boundary += 1 + else + neighbor_level = t8_element_level(neighbor_scheme, neighbor_leafs[1]) + + if all(neighbor_ielements .< num_local_elements) + # Conforming interface: The second condition ensures we + # only visit the interface once. + if level == neighbor_level && current_index <= neighbor_ielements[1] + local_num_conform += 1 + elseif level < neighbor_level + local_num_mortars += 1 + # `else level > neighbor_level` is ignored since we + # only want to count the mortar interface once. + end + else + if level == neighbor_level + local_num_mpi_conform += 1 + elseif level < neighbor_level + local_num_mpi_mortars += 1 + + global_mortar_id = 2 * ndims(mesh) * current_linear_id + iface + + else # level > neighbor_level + neighbor_global_ghost_itree = ghost_global_treeids[findlast(ghost_tree_element_offsets .<= + neighbor_ielements[1])] + neighbor_linear_id = neighbor_global_ghost_itree * + max_tree_num_elements + + t8_element_get_linear_id(neighbor_scheme, + neighbor_leafs[1], + max_level) + global_mortar_id = 2 * ndims(mesh) * neighbor_linear_id + + dual_faces[1] + + if !(global_mortar_id in visited_global_mortar_ids) + push!(visited_global_mortar_ids, global_mortar_id) + local_num_mpi_mortars += 1 + end + end + end + end + + t8_free(dual_faces_ref[]) + t8_free(pneighbor_leafs_ref[]) + t8_free(pelement_indices_ref[]) + end # for + + current_index += 1 + end # for + end # for + + return (interfaces = local_num_conform, + mortars = local_num_mortars, + boundaries = local_num_boundary, + mpi_interfaces = local_num_mpi_conform, + mpi_mortars = local_num_mpi_mortars) +end + +# I know this routine is an unmaintainable behemoth. However, I see no real +# and elegant way to refactor this into, for example, smaller parts. The +# `t8_forest_leaf_face_neighbors` routine is as of now rather costly and it +# makes sense to query it only once per face per element and extract all the +# information needed at once in order to fill the connectivity information. +# Instead, I opted for good documentation. +function fill_mesh_info!(mesh::T8codeMesh, interfaces, mortars, boundaries, + boundary_names; mpi_mesh_info = nothing) + @assert t8_forest_is_committed(mesh.forest) != 0 + + num_local_elements = t8_forest_get_local_num_elements(mesh.forest) + num_local_trees = t8_forest_get_num_local_trees(mesh.forest) + + if !isnothing(mpi_mesh_info) + #! format: off + remotes = t8_forest_ghost_get_remotes(mesh.forest) + ghost_num_trees = t8_forest_ghost_num_trees(mesh.forest) + + ghost_remote_first_elem = [num_local_elements + + t8_forest_ghost_remote_first_elem(mesh.forest, remote) + for remote in remotes] + + ghost_tree_element_offsets = [num_local_elements + + t8_forest_ghost_get_tree_element_offset(mesh.forest, itree) + for itree in 0:(ghost_num_trees - 1)] + + ghost_global_treeids = [t8_forest_ghost_get_global_treeid(mesh.forest, itree) + for itree in 0:(ghost_num_trees - 1)] + #! format: on + end + + # Process-local index of the current element in the space-filling curve. + current_index = t8_locidx_t(0) + + # Increment counters for the different interface/mortar/boundary types. + local_num_conform = 0 + local_num_mortars = 0 + local_num_boundary = 0 + + local_num_mpi_conform = 0 + local_num_mpi_mortars = 0 + + # Works for quads and hexs only. This mapping is needed in the MPI mortar + # sections below. + map_iface_to_ichild_to_position = [ + # 0 1 2 3 4 5 6 7 ichild/iface + [1, 0, 2, 0, 3, 0, 4, 0], # 0 + [0, 1, 0, 2, 0, 3, 0, 4], # 1 + [1, 2, 0, 0, 3, 4, 0, 0], # 2 + [0, 0, 1, 2, 0, 0, 3, 4], # 3 + [1, 2, 3, 4, 0, 0, 0, 0], # 4 + [0, 0, 0, 0, 1, 2, 3, 4], # 5 + ] + + # Helper variables to compute unique global MPI interface/mortar ids. + max_level = t8_forest_get_maxlevel(mesh.forest) #UInt64 + max_tree_num_elements = UInt64(2^ndims(mesh))^max_level + + # These two variables help to ensure that we count MPI mortars from smaller + # elements point of view only once. + visited_global_mortar_ids = Set{UInt64}([]) + global_mortar_id_to_local = Dict{UInt64, Int}([]) + + # Loop over all local trees. + for itree in 0:(num_local_trees - 1) + tree_class = t8_forest_get_tree_class(mesh.forest, itree) + eclass_scheme = t8_forest_get_eclass_scheme(mesh.forest, tree_class) + + num_elements_in_tree = t8_forest_get_tree_num_elements(mesh.forest, itree) + + global_itree = t8_forest_global_tree_id(mesh.forest, itree) + + # Loop over all local elements of the current local tree. + for ielement in 0:(num_elements_in_tree - 1) + element = t8_forest_get_element_in_tree(mesh.forest, itree, ielement) + + level = t8_element_level(eclass_scheme, element) + + num_faces = t8_element_num_faces(eclass_scheme, element) + + # Note: This works only for forests of one element class. + current_linear_id = global_itree * max_tree_num_elements + + t8_element_get_linear_id(eclass_scheme, element, max_level) + + # Loop over all faces of the current local element. + for iface in 0:(num_faces - 1) + # Compute the `orientation` of the touching faces. + if t8_element_is_root_boundary(eclass_scheme, element, iface) == 1 + cmesh = t8_forest_get_cmesh(mesh.forest) + itree_in_cmesh = t8_forest_ltreeid_to_cmesh_ltreeid(mesh.forest, itree) + iface_in_tree = t8_element_tree_face(eclass_scheme, element, iface) + orientation_ref = Ref{Cint}() + + t8_cmesh_get_face_neighbor(cmesh, itree_in_cmesh, iface_in_tree, C_NULL, + orientation_ref) + orientation = orientation_ref[] + else + orientation = zero(Cint) + end + + pelement_indices_ref = Ref{Ptr{t8_locidx_t}}() + pneighbor_leafs_ref = Ref{Ptr{Ptr{t8_element}}}() + pneigh_scheme_ref = Ref{Ptr{t8_eclass_scheme}}() + + dual_faces_ref = Ref{Ptr{Cint}}() + num_neighbors_ref = Ref{Cint}() + + forest_is_balanced = Cint(1) + + # Query neighbor information from t8code. + t8_forest_leaf_face_neighbors(mesh.forest, itree, element, + pneighbor_leafs_ref, iface, dual_faces_ref, + num_neighbors_ref, + pelement_indices_ref, pneigh_scheme_ref, + forest_is_balanced) + + num_neighbors = num_neighbors_ref[] + dual_faces = unsafe_wrap(Array, dual_faces_ref[], num_neighbors) + neighbor_ielements = unsafe_wrap(Array, pelement_indices_ref[], + num_neighbors) + neighbor_leafs = unsafe_wrap(Array, pneighbor_leafs_ref[], num_neighbors) + neighbor_scheme = pneigh_scheme_ref[] + + # Now we check for the different cases. The nested if-structure is as follows: + # + # if `boundary`: + # + # + # else: // It must be an interface or mortar. + # + # if `all neighbors are local elements`: + # + # if `local interface`: + # + # elseif `local mortar from larger element point of view`: + # + # else: // `local mortar from smaller elements point of view` + # // We only count local mortars once. + # + # else: // It must be either a MPI interface or a MPI mortar. + # + # if `MPI interface`: + # + # elseif `MPI mortar from larger element point of view`: + # + # else: // `MPI mortar from smaller elements point of view` + # + # + # // end + + # Domain boundary. + if num_neighbors == 0 + local_num_boundary += 1 + boundary_id = local_num_boundary + + boundaries.neighbor_ids[boundary_id] = current_index + 1 + + init_boundary_node_indices!(boundaries, iface, boundary_id) + + # One-based indexing. + boundaries.name[boundary_id] = boundary_names[iface + 1, itree + 1] + + # Interface or mortar. + else + neighbor_level = t8_element_level(neighbor_scheme, neighbor_leafs[1]) + + # Local interface or mortar. + if all(neighbor_ielements .< num_local_elements) + + # Local interface: The second condition ensures we only visit the interface once. + if level == neighbor_level && current_index <= neighbor_ielements[1] + local_num_conform += 1 + + interfaces.neighbor_ids[1, local_num_conform] = current_index + + 1 + interfaces.neighbor_ids[2, local_num_conform] = neighbor_ielements[1] + + 1 + + init_interface_node_indices!(interfaces, (iface, dual_faces[1]), + orientation, + local_num_conform) + # Local mortar. + elseif level < neighbor_level + local_num_mortars += 1 + + # Last entry is the large element. + mortars.neighbor_ids[end, local_num_mortars] = current_index + 1 + + init_mortar_neighbor_ids!(mortars, iface, dual_faces[1], + orientation, neighbor_ielements, + local_num_mortars) + + init_mortar_node_indices!(mortars, (dual_faces[1], iface), + orientation, local_num_mortars) + + # else: `level > neighbor_level` is skipped since we visit the mortar interface only once. + end + + # MPI interface or MPI mortar. + else + + # MPI interface. + if level == neighbor_level + local_num_mpi_conform += 1 + + neighbor_global_ghost_itree = ghost_global_treeids[findlast(ghost_tree_element_offsets .<= + neighbor_ielements[1])] + + neighbor_linear_id = neighbor_global_ghost_itree * + max_tree_num_elements + + t8_element_get_linear_id(neighbor_scheme, + neighbor_leafs[1], + max_level) + + if current_linear_id < neighbor_linear_id + local_side = 1 + smaller_iface = iface + smaller_linear_id = current_linear_id + faces = (iface, dual_faces[1]) + else + local_side = 2 + smaller_iface = dual_faces[1] + smaller_linear_id = neighbor_linear_id + faces = (dual_faces[1], iface) + end + + global_interface_id = 2 * ndims(mesh) * smaller_linear_id + + smaller_iface + + mpi_mesh_info.mpi_interfaces.local_neighbor_ids[local_num_mpi_conform] = current_index + + 1 + mpi_mesh_info.mpi_interfaces.local_sides[local_num_mpi_conform] = local_side + + init_mpi_interface_node_indices!(mpi_mesh_info.mpi_interfaces, + faces, local_side, orientation, + local_num_mpi_conform) + + neighbor_rank = remotes[findlast(ghost_remote_first_elem .<= + neighbor_ielements[1])] + mpi_mesh_info.neighbor_ranks_interface[local_num_mpi_conform] = neighbor_rank + + mpi_mesh_info.global_interface_ids[local_num_mpi_conform] = global_interface_id + + # MPI Mortar: from larger element point of view + elseif level < neighbor_level + local_num_mpi_mortars += 1 + + global_mortar_id = 2 * ndims(mesh) * current_linear_id + iface + + neighbor_ids = neighbor_ielements .+ 1 + + local_neighbor_positions = findall(neighbor_ids .<= + num_local_elements) + local_neighbor_ids = [neighbor_ids[i] + for i in local_neighbor_positions] + local_neighbor_positions = [map_iface_to_ichild_to_position[dual_faces[1] + 1][t8_element_child_id(neighbor_scheme, neighbor_leafs[i]) + 1] + for i in local_neighbor_positions] + + # Last entry is the large element. + push!(local_neighbor_ids, current_index + 1) + push!(local_neighbor_positions, 2^(ndims(mesh) - 1) + 1) + + mpi_mesh_info.mpi_mortars.local_neighbor_ids[local_num_mpi_mortars] = local_neighbor_ids + mpi_mesh_info.mpi_mortars.local_neighbor_positions[local_num_mpi_mortars] = local_neighbor_positions + + init_mortar_node_indices!(mpi_mesh_info.mpi_mortars, + (dual_faces[1], iface), orientation, + local_num_mpi_mortars) + + neighbor_ranks = [remotes[findlast(ghost_remote_first_elem .<= + ineighbor_ghost)] + for ineighbor_ghost in filter(x -> x >= + num_local_elements, + neighbor_ielements)] + mpi_mesh_info.neighbor_ranks_mortar[local_num_mpi_mortars] = neighbor_ranks + + mpi_mesh_info.global_mortar_ids[local_num_mpi_mortars] = global_mortar_id + + # MPI Mortar: from smaller elements point of view + else + neighbor_global_ghost_itree = ghost_global_treeids[findlast(ghost_tree_element_offsets .<= + neighbor_ielements[1])] + neighbor_linear_id = neighbor_global_ghost_itree * + max_tree_num_elements + + t8_element_get_linear_id(neighbor_scheme, + neighbor_leafs[1], + max_level) + global_mortar_id = 2 * ndims(mesh) * neighbor_linear_id + + dual_faces[1] + + if global_mortar_id in visited_global_mortar_ids + local_mpi_mortar_id = global_mortar_id_to_local[global_mortar_id] + + push!(mpi_mesh_info.mpi_mortars.local_neighbor_ids[local_mpi_mortar_id], + current_index + 1) + push!(mpi_mesh_info.mpi_mortars.local_neighbor_positions[local_mpi_mortar_id], + map_iface_to_ichild_to_position[iface + 1][t8_element_child_id(eclass_scheme, element) + 1]) + else + local_num_mpi_mortars += 1 + local_mpi_mortar_id = local_num_mpi_mortars + push!(visited_global_mortar_ids, global_mortar_id) + global_mortar_id_to_local[global_mortar_id] = local_mpi_mortar_id + + mpi_mesh_info.mpi_mortars.local_neighbor_ids[local_mpi_mortar_id] = [ + current_index + 1, + ] + mpi_mesh_info.mpi_mortars.local_neighbor_positions[local_mpi_mortar_id] = [ + map_iface_to_ichild_to_position[iface + 1][t8_element_child_id(eclass_scheme, element) + 1], + ] + init_mortar_node_indices!(mpi_mesh_info.mpi_mortars, + (iface, dual_faces[1]), + orientation, local_mpi_mortar_id) + + neighbor_ranks = [ + remotes[findlast(ghost_remote_first_elem .<= + neighbor_ielements[1])], + ] + mpi_mesh_info.neighbor_ranks_mortar[local_mpi_mortar_id] = neighbor_ranks + + mpi_mesh_info.global_mortar_ids[local_mpi_mortar_id] = global_mortar_id + end + end + end + end + + t8_free(dual_faces_ref[]) + t8_free(pneighbor_leafs_ref[]) + t8_free(pelement_indices_ref[]) + end # for iface + + current_index += 1 + end # for ielement + end # for itree + return nothing end diff --git a/src/solvers/dgsem_p4est/containers_parallel.jl b/src/solvers/dgsem_p4est/containers_parallel.jl index 7c7bd868457..fd2749155bb 100644 --- a/src/solvers/dgsem_p4est/containers_parallel.jl +++ b/src/solvers/dgsem_p4est/containers_parallel.jl @@ -43,7 +43,8 @@ function Base.resize!(mpi_interfaces::P4estMPIInterfaceContainer, capacity) end # Create MPI interface container and initialize interface data -function init_mpi_interfaces(mesh::ParallelP4estMesh, equations, basis, elements) +function init_mpi_interfaces(mesh::Union{ParallelP4estMesh, ParallelT8codeMesh}, + equations, basis, elements) NDIMS = ndims(elements) uEltype = eltype(elements) @@ -133,7 +134,8 @@ function Base.resize!(mpi_mortars::P4estMPIMortarContainer, capacity) end # Create MPI mortar container and initialize MPI mortar data -function init_mpi_mortars(mesh::ParallelP4estMesh, equations, basis, elements) +function init_mpi_mortars(mesh::Union{ParallelP4estMesh, ParallelT8codeMesh}, equations, + basis, elements) NDIMS = ndims(mesh) RealT = real(mesh) uEltype = eltype(elements) diff --git a/src/solvers/dgsem_p4est/dg_2d_parallel.jl b/src/solvers/dgsem_p4est/dg_2d_parallel.jl index a8887351c46..3bf0cd0cab5 100644 --- a/src/solvers/dgsem_p4est/dg_2d_parallel.jl +++ b/src/solvers/dgsem_p4est/dg_2d_parallel.jl @@ -6,7 +6,8 @@ #! format: noindent function prolong2mpiinterfaces!(cache, u, - mesh::ParallelP4estMesh{2}, + mesh::Union{ParallelP4estMesh{2}, + ParallelT8codeMesh{2}}, equations, surface_integral, dg::DG) @unpack mpi_interfaces = cache index_range = eachnode(dg) @@ -43,7 +44,8 @@ function prolong2mpiinterfaces!(cache, u, end function calc_mpi_interface_flux!(surface_flux_values, - mesh::ParallelP4estMesh{2}, + mesh::Union{ParallelP4estMesh{2}, + ParallelT8codeMesh{2}}, nonconservative_terms, equations, surface_integral, dg::DG, cache) @unpack local_neighbor_ids, node_indices, local_sides = cache.mpi_interfaces @@ -106,7 +108,8 @@ end # Inlined version of the interface flux computation for conservation laws @inline function calc_mpi_interface_flux!(surface_flux_values, - mesh::P4estMesh{2}, + mesh::Union{ParallelP4estMesh{2}, + ParallelT8codeMesh{2}}, nonconservative_terms::False, equations, surface_integral, dg::DG, cache, interface_index, normal_direction, @@ -131,7 +134,8 @@ end end function prolong2mpimortars!(cache, u, - mesh::ParallelP4estMesh{2}, equations, + mesh::Union{ParallelP4estMesh{2}, ParallelT8codeMesh{2}}, + equations, mortar_l2::LobattoLegendreMortarL2, surface_integral, dg::DGSEM) @unpack node_indices = cache.mpi_mortars @@ -199,7 +203,7 @@ function prolong2mpimortars!(cache, u, end function calc_mpi_mortar_flux!(surface_flux_values, - mesh::ParallelP4estMesh{2}, + mesh::Union{ParallelP4estMesh{2}, ParallelT8codeMesh{2}}, nonconservative_terms, equations, mortar_l2::LobattoLegendreMortarL2, surface_integral, dg::DG, cache) @@ -253,7 +257,8 @@ end # Inlined version of the mortar flux computation on small elements for conservation laws @inline function calc_mpi_mortar_flux!(fstar, - mesh::ParallelP4estMesh{2}, + mesh::Union{ParallelP4estMesh{2}, + ParallelT8codeMesh{2}}, nonconservative_terms::False, equations, surface_integral, dg::DG, cache, mortar_index, position_index, normal_direction, @@ -271,7 +276,9 @@ end end @inline function mpi_mortar_fluxes_to_elements!(surface_flux_values, - mesh::ParallelP4estMesh{2}, equations, + mesh::Union{ParallelP4estMesh{2}, + ParallelT8codeMesh{2}}, + equations, mortar_l2::LobattoLegendreMortarL2, dg::DGSEM, cache, mortar, fstar, u_buffer) diff --git a/src/solvers/dgsem_p4est/dg_3d_parallel.jl b/src/solvers/dgsem_p4est/dg_3d_parallel.jl index 13bf2a1a2eb..e504e06d2c4 100644 --- a/src/solvers/dgsem_p4est/dg_3d_parallel.jl +++ b/src/solvers/dgsem_p4est/dg_3d_parallel.jl @@ -6,7 +6,7 @@ #! format: noindent function rhs!(du, u, t, - mesh::ParallelP4estMesh{3}, equations, + mesh::Union{ParallelP4estMesh{3}, ParallelT8codeMesh{3}}, equations, initial_condition, boundary_conditions, source_terms::Source, dg::DG, cache) where {Source} # Start to receive MPI data @@ -113,7 +113,8 @@ function rhs!(du, u, t, end function prolong2mpiinterfaces!(cache, u, - mesh::ParallelP4estMesh{3}, + mesh::Union{ParallelP4estMesh{3}, + ParallelT8codeMesh{3}}, equations, surface_integral, dg::DG) @unpack mpi_interfaces = cache index_range = eachnode(dg) @@ -160,7 +161,8 @@ function prolong2mpiinterfaces!(cache, u, end function calc_mpi_interface_flux!(surface_flux_values, - mesh::ParallelP4estMesh{3}, + mesh::Union{ParallelP4estMesh{3}, + ParallelT8codeMesh{3}}, nonconservative_terms, equations, surface_integral, dg::DG, cache) @unpack local_neighbor_ids, node_indices, local_sides = cache.mpi_interfaces @@ -237,7 +239,8 @@ end # Inlined version of the interface flux computation for conservation laws @inline function calc_mpi_interface_flux!(surface_flux_values, - mesh::P4estMesh{3}, + mesh::Union{ParallelP4estMesh{3}, + ParallelT8codeMesh{3}}, nonconservative_terms::False, equations, surface_integral, dg::DG, cache, interface_index, normal_direction, @@ -265,7 +268,8 @@ end end function prolong2mpimortars!(cache, u, - mesh::ParallelP4estMesh{3}, equations, + mesh::Union{ParallelP4estMesh{3}, ParallelT8codeMesh{3}}, + equations, mortar_l2::LobattoLegendreMortarL2, surface_integral, dg::DGSEM) @unpack node_indices = cache.mpi_mortars @@ -374,7 +378,7 @@ function prolong2mpimortars!(cache, u, end function calc_mpi_mortar_flux!(surface_flux_values, - mesh::ParallelP4estMesh{3}, + mesh::Union{ParallelP4estMesh{3}, ParallelT8codeMesh{3}}, nonconservative_terms, equations, mortar_l2::LobattoLegendreMortarL2, surface_integral, dg::DG, cache) @@ -437,7 +441,8 @@ end # Inlined version of the mortar flux computation on small elements for conservation laws @inline function calc_mpi_mortar_flux!(fstar, - mesh::ParallelP4estMesh{3}, + mesh::Union{ParallelP4estMesh{3}, + ParallelT8codeMesh{3}}, nonconservative_terms::False, equations, surface_integral, dg::DG, cache, mortar_index, position_index, normal_direction, @@ -456,7 +461,9 @@ end end @inline function mpi_mortar_fluxes_to_elements!(surface_flux_values, - mesh::ParallelP4estMesh{3}, equations, + mesh::Union{ParallelP4estMesh{3}, + ParallelT8codeMesh{3}}, + equations, mortar_l2::LobattoLegendreMortarL2, dg::DGSEM, cache, mortar, fstar, u_buffer, fstar_tmp) diff --git a/src/solvers/dgsem_p4est/dg_parallel.jl b/src/solvers/dgsem_p4est/dg_parallel.jl index 712ede2bfce..eaa6ab5cee2 100644 --- a/src/solvers/dgsem_p4est/dg_parallel.jl +++ b/src/solvers/dgsem_p4est/dg_parallel.jl @@ -166,7 +166,8 @@ end # at `index_base`+1 in the MPI buffer. `data_size` is the data size associated with each small # position (i.e. position 1 or 2). The data corresponding to the large side (i.e. position 3) has # size `2 * data_size`. -@inline function buffer_mortar_indices(mesh::ParallelP4estMesh{2}, index_base, +@inline function buffer_mortar_indices(mesh::Union{ParallelP4estMesh{2}, + ParallelT8codeMesh{2}}, index_base, data_size) return ( # first, last for local element in position 1 (small element) @@ -185,7 +186,8 @@ end # at `index_base`+1 in the MPI buffer. `data_size` is the data size associated with each small # position (i.e. position 1 to 4). The data corresponding to the large side (i.e. position 5) has # size `4 * data_size`. -@inline function buffer_mortar_indices(mesh::ParallelP4estMesh{3}, index_base, +@inline function buffer_mortar_indices(mesh::Union{ParallelP4estMesh{3}, + ParallelT8codeMesh{3}}, index_base, data_size) return ( # first, last for local element in position 1 (small element) @@ -491,7 +493,8 @@ end # Exchange normal directions of small elements of the MPI mortars. They are needed on all involved # MPI ranks to calculate the mortar fluxes. -function exchange_normal_directions!(mpi_mortars, mpi_cache, mesh::ParallelP4estMesh, +function exchange_normal_directions!(mpi_mortars, mpi_cache, + mesh::Union{ParallelP4estMesh, ParallelT8codeMesh}, n_nodes) RealT = real(mesh) n_dims = ndims(mesh) diff --git a/src/solvers/dgsem_t8code/containers.jl b/src/solvers/dgsem_t8code/containers.jl index 093feb2985a..d7ff79fbf2f 100644 --- a/src/solvers/dgsem_t8code/containers.jl +++ b/src/solvers/dgsem_t8code/containers.jl @@ -18,19 +18,22 @@ function reinitialize_containers!(mesh::T8codeMesh, equations, dg::DGSEM, cache) @unpack boundaries = cache resize!(boundaries, mesh.nboundaries) - trixi_t8_fill_mesh_info(mesh.forest, elements, interfaces, mortars, boundaries, - mesh.boundary_names) + fill_mesh_info!(mesh, interfaces, mortars, boundaries, + mesh.boundary_names) return nothing end function count_required_surfaces!(mesh::T8codeMesh) - counts = trixi_t8_count_interfaces(mesh.forest) + counts = count_interfaces(mesh) mesh.nmortars = counts.mortars mesh.ninterfaces = counts.interfaces mesh.nboundaries = counts.boundaries + mesh.nmpimortars = counts.mpi_mortars + mesh.nmpiinterfaces = counts.mpi_interfaces + return counts end @@ -38,7 +41,9 @@ end function count_required_surfaces(mesh::T8codeMesh) return (interfaces = mesh.ninterfaces, mortars = mesh.nmortars, - boundaries = mesh.nboundaries) + boundaries = mesh.nboundaries, + mpi_interfaces = mesh.nmpiinterfaces, + mpi_mortars = mesh.nmpimortars) end # Compatibility to `dgsem_p4est/containers.jl`. diff --git a/src/solvers/dgsem_t8code/containers_2d.jl b/src/solvers/dgsem_t8code/containers_2d.jl index bf77826a34b..ce525bfdf65 100644 --- a/src/solvers/dgsem_t8code/containers_2d.jl +++ b/src/solvers/dgsem_t8code/containers_2d.jl @@ -26,6 +26,7 @@ function calc_node_coordinates!(node_coordinates, tree_class = t8_forest_get_tree_class(mesh.forest, itree) eclass_scheme = t8_forest_get_eclass_scheme(mesh.forest, tree_class) num_elements_in_tree = t8_forest_get_tree_num_elements(mesh.forest, itree) + global_itree = t8_forest_global_tree_id(mesh.forest, itree) for ielement in 0:(num_elements_in_tree - 1) element = t8_forest_get_element_in_tree(mesh.forest, itree, ielement) @@ -55,7 +56,7 @@ function calc_node_coordinates!(node_coordinates, multiply_dimensionwise!(view(node_coordinates, :, :, :, current_index += 1), matrix1, matrix2, view(mesh.tree_node_coordinates, :, :, :, - itree + 1), + global_itree + 1), tmp1) end end diff --git a/src/solvers/dgsem_t8code/containers_3d.jl b/src/solvers/dgsem_t8code/containers_3d.jl index f2d54ff07da..4d56bc734aa 100644 --- a/src/solvers/dgsem_t8code/containers_3d.jl +++ b/src/solvers/dgsem_t8code/containers_3d.jl @@ -28,6 +28,7 @@ function calc_node_coordinates!(node_coordinates, tree_class = t8_forest_get_tree_class(mesh.forest, itree) eclass_scheme = t8_forest_get_eclass_scheme(mesh.forest, tree_class) num_elements_in_tree = t8_forest_get_tree_num_elements(mesh.forest, itree) + global_itree = t8_forest_global_tree_id(mesh.forest, itree) for ielement in 0:(num_elements_in_tree - 1) element = t8_forest_get_element_in_tree(mesh.forest, itree, ielement) @@ -63,7 +64,7 @@ function calc_node_coordinates!(node_coordinates, current_index += 1), matrix1, matrix2, matrix3, view(mesh.tree_node_coordinates, :, :, :, :, - itree + 1), + global_itree + 1), tmp1) end end diff --git a/src/solvers/dgsem_t8code/containers_parallel.jl b/src/solvers/dgsem_t8code/containers_parallel.jl new file mode 100644 index 00000000000..0cb3f5887a0 --- /dev/null +++ b/src/solvers/dgsem_t8code/containers_parallel.jl @@ -0,0 +1,65 @@ +function reinitialize_containers!(mesh::ParallelT8codeMesh, equations, dg::DGSEM, cache) + @unpack elements, interfaces, boundaries, mortars, mpi_interfaces, mpi_mortars, + mpi_cache = cache + resize!(elements, ncells(mesh)) + init_elements!(elements, mesh, dg.basis) + + count_required_surfaces!(mesh) + required = count_required_surfaces(mesh) + + resize!(interfaces, required.interfaces) + + resize!(boundaries, required.boundaries) + + resize!(mortars, required.mortars) + + resize!(mpi_interfaces, required.mpi_interfaces) + + resize!(mpi_mortars, required.mpi_mortars) + + mpi_mesh_info = (mpi_mortars = mpi_mortars, + mpi_interfaces = mpi_interfaces, + + # Temporary arrays for updating `mpi_cache`. + global_mortar_ids = fill(UInt64(0), nmpimortars(mpi_mortars)), + global_interface_ids = fill(UInt64(0), nmpiinterfaces(mpi_interfaces)), + neighbor_ranks_mortar = Vector{Vector{Int}}(undef, + nmpimortars(mpi_mortars)), + neighbor_ranks_interface = fill(-1, nmpiinterfaces(mpi_interfaces))) + + fill_mesh_info!(mesh, interfaces, mortars, boundaries, + mesh.boundary_names; mpi_mesh_info = mpi_mesh_info) + + init_mpi_cache!(mpi_cache, mesh, mpi_mesh_info, nvariables(equations), nnodes(dg), + eltype(elements)) + + empty!(mpi_mesh_info.global_mortar_ids) + empty!(mpi_mesh_info.global_interface_ids) + empty!(mpi_mesh_info.neighbor_ranks_mortar) + empty!(mpi_mesh_info.neighbor_ranks_interface) + + # Re-initialize and distribute normal directions of MPI mortars; requires + # MPI communication, so the MPI cache must be re-initialized beforehand. + init_normal_directions!(mpi_mortars, dg.basis, elements) + exchange_normal_directions!(mpi_mortars, mpi_cache, mesh, nnodes(dg)) + + return nothing +end + +# Compatibility to `dgsem_p4est/containers.jl`. +function init_mpi_interfaces!(interfaces, mesh::ParallelT8codeMesh) + # Do nothing. + return nothing +end + +# Compatibility to `dgsem_p4est/containers.jl`. +function init_mpi_mortars!(mortars, mesh::ParallelT8codeMesh) + # Do nothing. + return nothing +end + +# Compatibility to `dgsem_p4est/containers_parallel.jl`. +function init_mpi_mortars!(mpi_mortars, mesh::ParallelT8codeMesh, basis, elements) + # Do nothing. + return nothing +end diff --git a/src/solvers/dgsem_t8code/dg.jl b/src/solvers/dgsem_t8code/dg.jl index 6e9660c917d..e01b12e0f80 100644 --- a/src/solvers/dgsem_t8code/dg.jl +++ b/src/solvers/dgsem_t8code/dg.jl @@ -13,8 +13,8 @@ function create_cache(mesh::T8codeMesh, equations::AbstractEquations, dg::DG, :: boundaries = init_boundaries(mesh, equations, dg.basis, elements) mortars = init_mortars(mesh, equations, dg.basis, elements) - trixi_t8_fill_mesh_info(mesh.forest, elements, interfaces, mortars, boundaries, - mesh.boundary_names) + fill_mesh_info!(mesh, interfaces, mortars, boundaries, + mesh.boundary_names) cache = (; elements, interfaces, boundaries, mortars) @@ -29,4 +29,7 @@ end include("containers.jl") include("containers_2d.jl") include("containers_3d.jl") + +include("containers_parallel.jl") +include("dg_parallel.jl") end # @muladd diff --git a/src/solvers/dgsem_t8code/dg_parallel.jl b/src/solvers/dgsem_t8code/dg_parallel.jl new file mode 100644 index 00000000000..ece614b7d75 --- /dev/null +++ b/src/solvers/dgsem_t8code/dg_parallel.jl @@ -0,0 +1,135 @@ +@muladd begin +#! format: noindent + +# This method is called when a `SemidiscretizationHyperbolic` is constructed. +# It constructs the basic `cache` used throughout the simulation to compute +# the RHS etc. +function create_cache(mesh::ParallelT8codeMesh, equations::AbstractEquations, dg::DG, + ::Any, + ::Type{uEltype}) where {uEltype <: Real} + # Make sure to balance and partition the forest before creating any + # containers in case someone has tampered with forest after creating the + # mesh. + balance!(mesh) + partition!(mesh) + + count_required_surfaces!(mesh) + + elements = init_elements(mesh, equations, dg.basis, uEltype) + mortars = init_mortars(mesh, equations, dg.basis, elements) + interfaces = init_interfaces(mesh, equations, dg.basis, elements) + boundaries = init_boundaries(mesh, equations, dg.basis, elements) + + mpi_mortars = init_mpi_mortars(mesh, equations, dg.basis, elements) + mpi_interfaces = init_mpi_interfaces(mesh, equations, dg.basis, elements) + + mpi_mesh_info = (mpi_mortars = mpi_mortars, + mpi_interfaces = mpi_interfaces, + global_mortar_ids = fill(UInt64(0), nmpimortars(mpi_mortars)), + global_interface_ids = fill(UInt64(0), + nmpiinterfaces(mpi_interfaces)), + neighbor_ranks_mortar = Vector{Vector{Int}}(undef, + nmpimortars(mpi_mortars)), + neighbor_ranks_interface = fill(-1, + nmpiinterfaces(mpi_interfaces))) + + fill_mesh_info!(mesh, interfaces, mortars, boundaries, + mesh.boundary_names; mpi_mesh_info = mpi_mesh_info) + + mpi_cache = init_mpi_cache(mesh, mpi_mesh_info, nvariables(equations), nnodes(dg), + uEltype) + + empty!(mpi_mesh_info.global_mortar_ids) + empty!(mpi_mesh_info.global_interface_ids) + empty!(mpi_mesh_info.neighbor_ranks_mortar) + empty!(mpi_mesh_info.neighbor_ranks_interface) + + init_normal_directions!(mpi_mortars, dg.basis, elements) + exchange_normal_directions!(mpi_mortars, mpi_cache, mesh, nnodes(dg)) + + cache = (; elements, interfaces, mpi_interfaces, boundaries, mortars, mpi_mortars, + mpi_cache) + + # Add specialized parts of the cache required to compute the volume integral etc. + cache = (; cache..., + create_cache(mesh, equations, dg.volume_integral, dg, uEltype)...) + cache = (; cache..., create_cache(mesh, equations, dg.mortar, uEltype)...) + + return cache +end + +function init_mpi_cache(mesh::ParallelT8codeMesh, mpi_mesh_info, nvars, nnodes, uEltype) + mpi_cache = P4estMPICache(uEltype) + init_mpi_cache!(mpi_cache, mesh, mpi_mesh_info, nvars, nnodes, uEltype) + return mpi_cache +end + +function init_mpi_cache!(mpi_cache::P4estMPICache, mesh::ParallelT8codeMesh, + mpi_mesh_info, nvars, nnodes, uEltype) + mpi_neighbor_ranks, mpi_neighbor_interfaces, mpi_neighbor_mortars = init_mpi_neighbor_connectivity(mpi_mesh_info, + mesh) + + mpi_send_buffers, mpi_recv_buffers, mpi_send_requests, mpi_recv_requests = init_mpi_data_structures(mpi_neighbor_interfaces, + mpi_neighbor_mortars, + ndims(mesh), + nvars, + nnodes, + uEltype) + + n_elements_global = Int(t8_forest_get_global_num_elements(mesh.forest)) + n_elements_local = Int(t8_forest_get_local_num_elements(mesh.forest)) + + n_elements_by_rank = Vector{Int}(undef, mpi_nranks()) + n_elements_by_rank[mpi_rank() + 1] = n_elements_local + + MPI.Allgather!(MPI.UBuffer(n_elements_by_rank, 1), mpi_comm()) + + n_elements_by_rank = OffsetArray(n_elements_by_rank, 0:(mpi_nranks() - 1)) + + # Account for 1-based indexing in Julia. + first_element_global_id = sum(n_elements_by_rank[0:(mpi_rank() - 1)]) + 1 + + @assert n_elements_global==sum(n_elements_by_rank) "error in total number of elements" + + @pack! mpi_cache = mpi_neighbor_ranks, mpi_neighbor_interfaces, + mpi_neighbor_mortars, + mpi_send_buffers, mpi_recv_buffers, + mpi_send_requests, mpi_recv_requests, + n_elements_by_rank, n_elements_global, + first_element_global_id + + return mpi_cache +end + +function init_mpi_neighbor_connectivity(mpi_mesh_info, mesh::ParallelT8codeMesh) + @unpack mpi_interfaces, mpi_mortars, global_interface_ids, neighbor_ranks_interface, global_mortar_ids, neighbor_ranks_mortar = mpi_mesh_info + + mpi_neighbor_ranks = vcat(neighbor_ranks_interface, neighbor_ranks_mortar...) |> + sort |> unique + + p = sortperm(global_interface_ids) + + neighbor_ranks_interface .= neighbor_ranks_interface[p] + interface_ids = collect(1:nmpiinterfaces(mpi_interfaces))[p] + + p = sortperm(global_mortar_ids) + neighbor_ranks_mortar .= neighbor_ranks_mortar[p] + mortar_ids = collect(1:nmpimortars(mpi_mortars))[p] + + # For each neighbor rank, init connectivity data structures + mpi_neighbor_interfaces = Vector{Vector{Int}}(undef, length(mpi_neighbor_ranks)) + mpi_neighbor_mortars = Vector{Vector{Int}}(undef, length(mpi_neighbor_ranks)) + for (index, d) in enumerate(mpi_neighbor_ranks) + mpi_neighbor_interfaces[index] = interface_ids[findall(==(d), + neighbor_ranks_interface)] + mpi_neighbor_mortars[index] = mortar_ids[findall(x -> (d in x), + neighbor_ranks_mortar)] + end + + # Check that all interfaces were counted exactly once + @assert mapreduce(length, +, mpi_neighbor_interfaces; init = 0) == + nmpiinterfaces(mpi_interfaces) + + return mpi_neighbor_ranks, mpi_neighbor_interfaces, mpi_neighbor_mortars +end +end # @muladd diff --git a/src/solvers/dgsem_tree/dg_2d_parallel.jl b/src/solvers/dgsem_tree/dg_2d_parallel.jl index 8095dae123a..157d462aa2f 100644 --- a/src/solvers/dgsem_tree/dg_2d_parallel.jl +++ b/src/solvers/dgsem_tree/dg_2d_parallel.jl @@ -446,7 +446,8 @@ function init_mpi_neighbor_connectivity(elements, mpi_interfaces, mpi_mortars, end function rhs!(du, u, t, - mesh::Union{ParallelTreeMesh{2}, ParallelP4estMesh{2}}, equations, + mesh::Union{ParallelTreeMesh{2}, ParallelP4estMesh{2}, + ParallelT8codeMesh{2}}, equations, initial_condition, boundary_conditions, source_terms::Source, dg::DG, cache) where {Source} # Start to receive MPI data diff --git a/test/test_mpi.jl b/test/test_mpi.jl index ad1ba4e835d..1ab1282b891 100644 --- a/test/test_mpi.jl +++ b/test/test_mpi.jl @@ -19,10 +19,12 @@ CI_ON_WINDOWS = (get(ENV, "GITHUB_ACTIONS", false) == "true") && Sys.iswindows() # TreeMesh tests include("test_mpi_tree.jl") - # P4estMesh tests + # P4estMesh and T8codeMesh tests include("test_mpi_p4est_2d.jl") + include("test_mpi_t8code_2d.jl") if !CI_ON_WINDOWS # see comment on `CI_ON_WINDOWS` above include("test_mpi_p4est_3d.jl") + include("test_mpi_t8code_3d.jl") end end # MPI diff --git a/test/test_mpi_p4est_2d.jl b/test/test_mpi_p4est_2d.jl index da90537fcfd..6d66bc68a26 100644 --- a/test/test_mpi_p4est_2d.jl +++ b/test/test_mpi_p4est_2d.jl @@ -33,6 +33,15 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_2d_dgsem") @test errors.linf≈[0.00011787417954578494] rtol=1.0e-4 end end + + # 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_nonconforming_flag.jl" begin @@ -40,6 +49,15 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_2d_dgsem") "elixir_advection_nonconforming_flag.jl"), l2=[3.198940059144588e-5], linf=[0.00030636069494005547]) + + # 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_unstructured_flag.jl" begin @@ -47,6 +65,15 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_2d_dgsem") "elixir_advection_unstructured_flag.jl"), l2=[0.0005379687442422346], linf=[0.007438525029884735]) + + # 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_amr_solution_independent.jl" begin @@ -56,6 +83,15 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_2d_dgsem") l2=[4.949660644033807e-5], linf=[0.0004867846262313763], 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 end @trixi_testset "elixir_advection_amr_unstructured_flag.jl" begin @@ -64,6 +100,15 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_2d_dgsem") l2=[0.0012766060609964525], linf=[0.01750280631586159], 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 end @trixi_testset "elixir_advection_restart.jl" begin @@ -73,6 +118,15 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_2d_dgsem") # With the default `maxiters = 1` in coverage tests, # there would be no time steps after the restart. coverage_override=(maxiters = 100_000,)) + + # 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_source_terms_nonconforming_unstructured_flag.jl" begin @@ -90,6 +144,15 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_2d_dgsem") 0.03759938693042297, 0.08039824959535657, ]) + + # 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 end # P4estMesh MPI diff --git a/test/test_mpi_p4est_3d.jl b/test/test_mpi_p4est_3d.jl index 75f43650082..cca9093ec51 100644 --- a/test/test_mpi_p4est_3d.jl +++ b/test/test_mpi_p4est_3d.jl @@ -33,6 +33,15 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_3d_dgsem") @test errors.linf≈[0.0014548839020096516] rtol=1.0e-4 end end + + # 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_amr.jl" begin @@ -46,6 +55,15 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_3d_dgsem") initial_refinement_level = 2, base_level = 2, med_level = 3, max_level = 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 @trixi_testset "elixir_advection_amr_unstructured_curved.jl" begin @@ -58,6 +76,15 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_3d_dgsem") initial_refinement_level = 0, base_level = 0, med_level = 1, max_level = 2)) + + # 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_restart.jl" begin @@ -67,12 +94,30 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_3d_dgsem") # With the default `maxiters = 1` in coverage tests, # there would be no time steps after the restart. coverage_override=(maxiters = 100_000,)) + + # 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_cubed_sphere.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_cubed_sphere.jl"), l2=[0.002006918015656413], linf=[0.027655117058380085]) + + # 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 # Compressible Euler @@ -94,6 +139,15 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_3d_dgsem") 0.008526972236273522, ], tspan=(0.0, 0.01)) + + # 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_source_terms_nonperiodic.jl" begin @@ -114,6 +168,15 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_3d_dgsem") 0.01562861968368434, ], tspan=(0.0, 1.0)) + + # 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_ec.jl" begin @@ -134,6 +197,15 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_3d_dgsem") ], tspan=(0.0, 0.2), coverage_override=(polydeg = 3,)) # Prevent long compile time in CI + + # 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_source_terms_nonperiodic_hohqmesh.jl" begin @@ -153,6 +225,15 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_3d_dgsem") 0.048396544302230504, 0.1154589758186293, ]) + + # 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 end # P4estMesh MPI diff --git a/test/test_mpi_t8code_2d.jl b/test/test_mpi_t8code_2d.jl new file mode 100644 index 00000000000..7c7fc03898c --- /dev/null +++ b/test/test_mpi_t8code_2d.jl @@ -0,0 +1,142 @@ +module TestExamplesMPIT8codeMesh2D + +using Test +using Trixi + +include("test_trixi.jl") + +const EXAMPLES_DIR = pkgdir(Trixi, "examples", "t8code_2d_dgsem") + +@testset "T8codeMesh MPI 2D" begin +#! format: noindent + +# Run basic tests +@testset "Examples 2D" begin + # Linear scalar advection + @trixi_testset "elixir_advection_basic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), + # Expected errors are exactly the same as with TreeMesh! + l2=[8.311947673061856e-6], + linf=[6.627000273229378e-5]) + + @testset "error-based step size control" begin + Trixi.mpi_isroot() && println("-"^100) + Trixi.mpi_isroot() && + println("elixir_advection_basic.jl with error-based step size control") + + sol = solve(ode, RDPK3SpFSAL35(); abstol = 1.0e-4, reltol = 1.0e-4, + ode_default_options()..., callback = callbacks) + summary_callback() + errors = analysis_callback(sol) + if Trixi.mpi_isroot() + @test errors.l2≈[3.3022040342579066e-5] rtol=1.0e-4 + @test errors.linf≈[0.00011787417954578494] rtol=1.0e-4 + end + end + + # 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_nonconforming_flag.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_nonconforming_flag.jl"), + l2=[3.198940059144588e-5], + linf=[0.00030636069494005547]) + + # 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_unstructured_flag.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_unstructured_flag.jl"), + l2=[0.0005379687442422346], + linf=[0.007438525029884735]) + + # 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_amr_solution_independent.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_advection_amr_solution_independent.jl"), + # Expected errors are exactly the same as with TreeMesh! + l2=[4.933027431215839e-5], + linf=[0.00048678461161243136], + 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 + end + + @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], + 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 + end + + @trixi_testset "elixir_euler_source_terms_nonconforming_unstructured_flag.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonconforming_unstructured_flag.jl"), + l2=[ + 0.0034516244508588046, + 0.0023420334036925493, + 0.0024261923964557187, + 0.004731710454271893, + ], + linf=[ + 0.04155789011775046, + 0.024772109862748914, + 0.03759938693042297, + 0.08039824959535657, + ]) + + # 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 +end # T8codeMesh MPI + +end # module diff --git a/test/test_mpi_t8code_3d.jl b/test/test_mpi_t8code_3d.jl new file mode 100644 index 00000000000..a15690a7629 --- /dev/null +++ b/test/test_mpi_t8code_3d.jl @@ -0,0 +1,180 @@ +module TestExamplesMPIT8codeMesh3D + +using Test +using Trixi + +include("test_trixi.jl") + +const EXAMPLES_DIR = pkgdir(Trixi, "examples", "t8code_3d_dgsem") + +@testset "T8codeMesh MPI 3D" begin +#! format: noindent + +# Run basic tests +@testset "Examples 3D" begin + # Linear scalar advection + @trixi_testset "elixir_advection_basic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"), + # Expected errors are exactly the same as with TreeMesh! + l2=[0.00016263963870641478], + linf=[0.0014537194925779984]) + + @testset "error-based step size control" begin + Trixi.mpi_isroot() && println("-"^100) + Trixi.mpi_isroot() && + println("elixir_advection_basic.jl with error-based step size control") + + sol = solve(ode, RDPK3SpFSAL35(); abstol = 1.0e-4, reltol = 1.0e-4, + ode_default_options()..., callback = callbacks) + summary_callback() + errors = analysis_callback(sol) + if Trixi.mpi_isroot() + @test errors.l2≈[0.00016800412839949264] rtol=1.0e-4 + @test errors.linf≈[0.0014548839020096516] rtol=1.0e-4 + end + end + + # 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_amr.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr.jl"), + # Expected errors are exactly the same as with TreeMesh! + l2=[1.1302812803902801e-5], + linf=[0.0007889950196294793], + # override values are different from the serial tests to ensure each process holds at least + # one element, otherwise OrdinaryDiffEq fails during initialization + coverage_override=(maxiters = 6, + initial_refinement_level = 2, + base_level = 2, med_level = 3, + max_level = 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 + + @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], + 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 + # (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 + + # Compressible Euler + @trixi_testset "elixir_euler_source_terms_nonconforming_unstructured_curved.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonconforming_unstructured_curved.jl"), + l2=[ + 4.070355207909268e-5, + 4.4993257426833716e-5, + 5.10588457841744e-5, + 5.102840924036687e-5, + 0.00019986264001630542, + ], + linf=[ + 0.0016987332417202072, + 0.003622956808262634, + 0.002029576258317789, + 0.0024206977281964193, + 0.008526972236273522, + ], + tspan=(0.0, 0.01)) + + # 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_source_terms_nonperiodic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_source_terms_nonperiodic.jl"), + l2=[ + 0.0015106060984283647, + 0.0014733349038567685, + 0.00147333490385685, + 0.001473334903856929, + 0.0028149479453087093, + ], + linf=[ + 0.008070806335238156, + 0.009007245083113125, + 0.009007245083121784, + 0.009007245083102688, + 0.01562861968368434, + ], + tspan=(0.0, 1.0)) + + # 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_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"), + l2=[ + 0.010380390326164493, + 0.006192950051354618, + 0.005970674274073704, + 0.005965831290564327, + 0.02628875593094754, + ], + linf=[ + 0.3326911600075694, + 0.2824952141320467, + 0.41401037398065543, + 0.45574161423218573, + 0.8099577682187109, + ], + tspan=(0.0, 0.2), + coverage_override=(polydeg = 3,)) # Prevent long compile time in CI + + # 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 +end # T8codeMesh MPI + +end # module diff --git a/test/test_t8code_2d.jl b/test/test_t8code_2d.jl index ab95e068d02..d536a6dd73a 100644 --- a/test/test_t8code_2d.jl +++ b/test/test_t8code_2d.jl @@ -33,10 +33,9 @@ end @trixi_testset "test check_for_negative_volumes" begin @test_warn "Discovered negative volumes" begin # Unstructured mesh with six cells which have left-handed node ordering. - mesh_file = joinpath(EXAMPLES_DIR, "rectangle_with_negative_volumes.msh") - isfile(mesh_file) || - download("https://gist.githubusercontent.com/jmark/bfe0d45f8e369298d6cc637733819013/raw/cecf86edecc736e8b3e06e354c494b2052d41f7a/rectangle_with_negative_volumes.msh", - mesh_file) + mesh_file = Trixi.download("https://gist.githubusercontent.com/jmark/bfe0d45f8e369298d6cc637733819013/raw/cecf86edecc736e8b3e06e354c494b2052d41f7a/rectangle_with_negative_volumes.msh", + joinpath(EXAMPLES_DIR, + "rectangle_with_negative_volumes.msh")) # This call should throw a warning about negative volumes detected. mesh = T8codeMesh(mesh_file, 2) From c7cee980f56835e9c396424e742efe85da465042 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Wed, 31 Jan 2024 19:09:15 +0100 Subject: [PATCH 238/263] Remove race condition in mpi testing (#1821) * remove race condition in mpi testing * add additional barriers --- test/test_mpi.jl | 2 ++ test/test_mpi_tree.jl | 3 ++- test/test_threaded.jl | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/test/test_mpi.jl b/test/test_mpi.jl index 1ab1282b891..001d9bff86e 100644 --- a/test/test_mpi.jl +++ b/test/test_mpi.jl @@ -8,6 +8,7 @@ include("test_trixi.jl") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive = true) +Trixi.MPI.Barrier(Trixi.mpi_comm()) # CI with MPI and some tests fails often on Windows. Thus, we check whether this # is the case here. We use GitHub Actions, so we can check whether we run CI @@ -45,5 +46,6 @@ end # MPI supporting functionality # Clean up afterwards: delete Trixi.jl output directory Trixi.mpi_isroot() && @test_nowarn rm(outdir, recursive = true) +Trixi.MPI.Barrier(Trixi.mpi_comm()) end # module diff --git a/test/test_mpi_tree.jl b/test/test_mpi_tree.jl index 0831f6a1313..6351a405b5d 100644 --- a/test/test_mpi_tree.jl +++ b/test/test_mpi_tree.jl @@ -76,7 +76,8 @@ CI_ON_WINDOWS = (get(ENV, "GITHUB_ACTIONS", false) == "true") && Sys.iswindows() # Here, we also test that SaveSolutionCallback prints multiple mesh files with AMR # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" - isdir(outdir) && rm(outdir, recursive = true) + Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive = true) + Trixi.MPI.Barrier(Trixi.mpi_comm()) @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_refine_twice.jl"), l2=[0.00020547512522578292], diff --git a/test/test_threaded.jl b/test/test_threaded.jl index dbbcbf4c7ce..a8a1b1b425a 100644 --- a/test/test_threaded.jl +++ b/test/test_threaded.jl @@ -8,6 +8,7 @@ include("test_trixi.jl") # Start with a clean environment: remove Trixi.jl output directory if it exists outdir = "out" Trixi.mpi_isroot() && isdir(outdir) && rm(outdir, recursive = true) +Trixi.MPI.Barrier(Trixi.mpi_comm()) @testset "Threaded tests" begin #! format: noindent @@ -471,5 +472,6 @@ end # Clean up afterwards: delete Trixi.jl output directory Trixi.mpi_isroot() && isdir(outdir) && @test_nowarn rm(outdir, recursive = true) +Trixi.MPI.Barrier(Trixi.mpi_comm()) end # module From dfd632e69631ff4dbb42215966d4f7a546b92816 Mon Sep 17 00:00:00 2001 From: Benjamin Bolm <74359358+bennibolm@users.noreply.github.com> Date: Wed, 31 Jan 2024 21:50:27 +0100 Subject: [PATCH 239/263] Add subcell positivity limiting of non-linear variables (#1738) * Add positivity limiting of non-linear variables * Revise derivative function call; Add default derivative version * Adapt test to actually test pos limiter for nonlinear variables * Add unit test to test default implementation of variable_derivative * Clean up comments and code * Rename Newton-bisection variables * Implement suggestions * Relocate functions * Implement suggestions * Change error message for negative value with low-order method * Add changes from main to new limiter * Update NEWS.md * Rename is_valid_state and gradient_u --------- Co-authored-by: Michael Schlottke-Lakemper --- NEWS.md | 1 + ...kelvin_helmholtz_instability_sc_subcell.jl | 91 ++++++++ .../elixir_mhd_shockcapturing_subcell.jl | 7 +- src/callbacks_stage/subcell_bounds_check.jl | 8 + .../subcell_bounds_check_2d.jl | 18 ++ src/equations/compressible_euler_2d.jl | 21 ++ src/equations/equations.jl | 6 + src/equations/ideal_glm_mhd_2d.jl | 23 ++ src/solvers/dgsem_tree/subcell_limiters.jl | 60 +++-- src/solvers/dgsem_tree/subcell_limiters_2d.jl | 215 +++++++++++++++++- test/test_tree_2d_euler.jl | 26 +++ test/test_tree_2d_mhd.jl | 32 +-- test/test_unit.jl | 23 +- 13 files changed, 496 insertions(+), 35 deletions(-) create mode 100644 examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_sc_subcell.jl diff --git a/NEWS.md b/NEWS.md index 3a3a504a911..02a723fca45 100644 --- a/NEWS.md +++ b/NEWS.md @@ -11,6 +11,7 @@ for human readability. - `flux_hllc` on non-cartesian meshes for `CompressibleEulerEquations{2,3}D` - Different boundary conditions for quad/hex meshes in Abaqus format, even if not generated by HOHQMesh, can now be digested by Trixi in 2D and 3D. +- Subcell (positivity) limiting support for nonlinear variables in 2D for `TreeMesh` ## Changes when updating to v0.6 from v0.5.x diff --git a/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_sc_subcell.jl b/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_sc_subcell.jl new file mode 100644 index 00000000000..1817672778a --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_sc_subcell.jl @@ -0,0 +1,91 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations +gamma = 1.4 +equations = CompressibleEulerEquations2D(gamma) + +""" + initial_condition_kelvin_helmholtz_instability(x, t, equations::CompressibleEulerEquations2D) + +A version of the classical Kelvin-Helmholtz instability based on +- Andrés M. Rueda-Ramírez, Gregor J. Gassner (2021) + A Subcell Finite Volume Positivity-Preserving Limiter for DGSEM Discretizations + of the Euler Equations + [arXiv: 2102.06017](https://arxiv.org/abs/2102.06017) +""" +function initial_condition_kelvin_helmholtz_instability(x, t, + equations::CompressibleEulerEquations2D) + # change discontinuity to tanh + # typical resolution 128^2, 256^2 + # domain size is [-1,+1]^2 + slope = 15 + amplitude = 0.02 + B = tanh(slope * x[2] + 7.5) - tanh(slope * x[2] - 7.5) + rho = 0.5 + 0.75 * B + v1 = 0.5 * (B - 1) + v2 = 0.1 * sin(2 * pi * x[1]) + p = 1.0 + return prim2cons(SVector(rho, v1, v2, p), equations) +end +initial_condition = initial_condition_kelvin_helmholtz_instability + +surface_flux = flux_lax_friedrichs +volume_flux = flux_ranocha +polydeg = 3 +basis = LobattoLegendreBasis(polydeg) + +limiter_idp = SubcellLimiterIDP(equations, basis; + positivity_variables_cons = ["rho"], + positivity_variables_nonlinear = [pressure]) +volume_integral = VolumeIntegralSubcellLimiting(limiter_idp; + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) +solver = DGSEM(basis, surface_flux, volume_integral) + +coordinates_min = (-1.0, -1.0) +coordinates_max = (1.0, 1.0) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 5, + n_cells_max = 100_000) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 3.7) +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 = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +save_restart = SaveRestartCallback(interval = 1000, + save_final_restart = true) + +stepsize_callback = StepsizeCallback(cfl = 0.7) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + stepsize_callback, + save_restart, save_solution) + +############################################################################### +# run the simulation + +stage_callbacks = (SubcellLimiterIDPCorrection(), BoundsCheckCallback(save_errors = false)) + +sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks = stage_callbacks); + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + callback = callbacks); +summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl b/examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl index fe9ad92467f..74d0370647a 100644 --- a/examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl +++ b/examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl @@ -22,7 +22,7 @@ function initial_condition_blast_wave(x, t, equations::IdealGlmMhdEquations2D) r = sqrt(x[1]^2 + x[2]^2) pmax = 10.0 - pmin = 1.0 + pmin = 0.01 rhomax = 1.0 rhomin = 0.01 if r <= 0.09 @@ -52,7 +52,8 @@ basis = LobattoLegendreBasis(3) limiter_idp = SubcellLimiterIDP(equations, basis; positivity_variables_cons = ["rho"], - positivity_correction_factor = 0.5) + positivity_variables_nonlinear = [pressure], + positivity_correction_factor = 0.1) volume_integral = VolumeIntegralSubcellLimiting(limiter_idp; volume_flux_dg = volume_flux, volume_flux_fv = surface_flux) @@ -84,7 +85,7 @@ save_solution = SaveSolutionCallback(interval = 100, save_final_solution = true, solution_variables = cons2prim) -cfl = 0.5 +cfl = 0.4 stepsize_callback = StepsizeCallback(cfl = cfl) glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) diff --git a/src/callbacks_stage/subcell_bounds_check.jl b/src/callbacks_stage/subcell_bounds_check.jl index 9f34a6b3b4b..4dbf44d29c4 100644 --- a/src/callbacks_stage/subcell_bounds_check.jl +++ b/src/callbacks_stage/subcell_bounds_check.jl @@ -97,6 +97,9 @@ function init_callback(callback::BoundsCheckCallback, semi, limiter::SubcellLimi end print(f, ", " * string(variables[v]) * "_min") end + for variable in limiter.positivity_variables_nonlinear + print(f, ", " * string(variable) * "_min") + end end println(f) end @@ -142,6 +145,11 @@ end println(string(variables[v]) * ":\n- positivity: ", idp_bounds_delta_global[Symbol(string(v), "_min")]) end + for variable in limiter.positivity_variables_nonlinear + variable_string = string(variable) + println(variable_string * ":\n- positivity: ", + idp_bounds_delta_global[Symbol(variable_string, "_min")]) + end end println("─"^100 * "\n") diff --git a/src/callbacks_stage/subcell_bounds_check_2d.jl b/src/callbacks_stage/subcell_bounds_check_2d.jl index 545d19b5136..19d73968c9a 100644 --- a/src/callbacks_stage/subcell_bounds_check_2d.jl +++ b/src/callbacks_stage/subcell_bounds_check_2d.jl @@ -60,6 +60,20 @@ deviation_threaded[stride_size * Threads.threadid()] = deviation end end + for variable in limiter.positivity_variables_nonlinear + key = Symbol(string(variable), "_min") + deviation_threaded = idp_bounds_delta_local[key] + @threaded for element in eachelement(solver, cache) + deviation = deviation_threaded[stride_size * Threads.threadid()] + for j in eachnode(solver), i in eachnode(solver) + var = variable(get_node_vars(u, equations, solver, i, j, element), + equations) + deviation = max(deviation, + variable_bounds[key][i, j, element] - var) + end + deviation_threaded[stride_size * Threads.threadid()] = deviation + end + end end for (key, _) in idp_bounds_delta_local @@ -92,6 +106,10 @@ print(f, ", ", idp_bounds_delta_local[Symbol(string(v), "_min")][stride_size]) end + for variable in limiter.positivity_variables_nonlinear + print(f, ", ", + idp_bounds_delta_local[Symbol(string(variable), "_min")][stride_size]) + end end println(f) end diff --git a/src/equations/compressible_euler_2d.jl b/src/equations/compressible_euler_2d.jl index 3c6f759db2b..f5a632723cf 100644 --- a/src/equations/compressible_euler_2d.jl +++ b/src/equations/compressible_euler_2d.jl @@ -1632,6 +1632,18 @@ end return p end +# Transformation from conservative variables u to d(p)/d(u) +@inline function gradient_conservative(::typeof(pressure), + u, equations::CompressibleEulerEquations2D) + rho, rho_v1, rho_v2, rho_e = u + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v_square = v1^2 + v2^2 + + return (equations.gamma - 1.0) * SVector(0.5 * v_square, -v1, -v2, 1.0) +end + @inline function density_pressure(u, equations::CompressibleEulerEquations2D) rho, rho_v1, rho_v2, rho_e = u rho_times_p = (equations.gamma - 1) * (rho * rho_e - 0.5 * (rho_v1^2 + rho_v2^2)) @@ -1699,4 +1711,13 @@ end @inline function energy_internal(cons, equations::CompressibleEulerEquations2D) return energy_total(cons, equations) - energy_kinetic(cons, equations) end + +# State validation for Newton-bisection method of subcell IDP limiting +@inline function Base.isvalid(u, equations::CompressibleEulerEquations2D) + p = pressure(u, equations) + if u[1] <= 0.0 || p <= 0.0 + return false + end + return true +end end # @muladd diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 7a3c326984d..c041bf117ba 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -376,6 +376,12 @@ of the correct length `nvariables(equations)`. """ function energy_internal end +# Default implementation of gradient for `variable`. Used for subcell limiting. +# Implementing a gradient function for a specific variable improves the performance. +@inline function gradient_conservative(variable, u, equations) + return ForwardDiff.gradient(x -> variable(x, equations), u) +end + #################################################################################################### # Include files with actual implementations for different systems of equations. diff --git a/src/equations/ideal_glm_mhd_2d.jl b/src/equations/ideal_glm_mhd_2d.jl index 43d1991e34b..4366cd32f08 100644 --- a/src/equations/ideal_glm_mhd_2d.jl +++ b/src/equations/ideal_glm_mhd_2d.jl @@ -1118,6 +1118,20 @@ end return p end +# Transformation from conservative variables u to d(p)/d(u) +@inline function gradient_conservative(::typeof(pressure), + u, equations::IdealGlmMhdEquations2D) + rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3, psi = u + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v_square = v1^2 + v2^2 + v3^2 + + return (equations.gamma - 1.0) * + SVector(0.5 * v_square, -v1, -v2, -v3, 1.0, -B1, -B2, -B3, -psi) +end + @inline function density_pressure(u, equations::IdealGlmMhdEquations2D) rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3, psi = u p = (equations.gamma - 1) * (rho_e - 0.5 * (rho_v1^2 + rho_v2^2 + rho_v3^2) / rho @@ -1384,6 +1398,15 @@ end cons[9]^2 / 2) end +# State validation for Newton-bisection method of subcell IDP limiting +@inline function Base.isvalid(u, equations::IdealGlmMhdEquations2D) + p = pressure(u, equations) + if u[1] <= 0.0 || p <= 0.0 + return false + end + return true +end + # Calculate the cross helicity (\vec{v}⋅\vec{B}) for a conservative state `cons' @inline function cross_helicity(cons, ::IdealGlmMhdEquations2D) return (cons[2] * cons[6] + cons[3] * cons[7] + cons[4] * cons[8]) / cons[1] diff --git a/src/solvers/dgsem_tree/subcell_limiters.jl b/src/solvers/dgsem_tree/subcell_limiters.jl index 055e7ce24a4..e433c953779 100644 --- a/src/solvers/dgsem_tree/subcell_limiters.jl +++ b/src/solvers/dgsem_tree/subcell_limiters.jl @@ -16,18 +16,28 @@ end SubcellLimiterIDP(equations::AbstractEquations, basis; local_minmax_variables_cons = String[], positivity_variables_cons = String[], - positivity_correction_factor = 0.1) + positivity_variables_nonlinear = [], + positivity_correction_factor = 0.1, + max_iterations_newton = 10, + newton_tolerances = (1.0e-12, 1.0e-14), + gamma_constant_newton = 2 * ndims(equations)) Subcell invariant domain preserving (IDP) limiting used with [`VolumeIntegralSubcellLimiting`](@ref) including: - Local maximum/minimum Zalesak-type limiting for conservative variables (`local_minmax_variables_cons`) -- Positivity limiting for conservative variables (`positivity_variables_cons`) +- Positivity limiting for conservative variables (`positivity_variables_cons`) and nonlinear variables +(`positivity_variables_nonlinear`) Conservative variables to be limited are passed as a vector of strings, e.g. `local_minmax_variables_cons = ["rho"]` -and `positivity_variables_cons = ["rho"]`. +and `positivity_variables_cons = ["rho"]`. For nonlinear variables the specific functions are +passed in a vector, e.g. `positivity_variables_nonlinear = [pressure]`. The bounds are calculated using the low-order FV solution. The positivity limiter uses `positivity_correction_factor` such that `u^new >= positivity_correction_factor * u^FV`. +The limiting of nonlinear variables uses a Newton-bisection method with a maximum of +`max_iterations_newton` iterations, relative and absolute tolerances of `newton_tolerances` +and a provisional update constant `gamma_constant_newton` (`gamma_constant_newton>=2*d`, +where `d = #dimensions`). See equation (20) of Pazner (2020) and equation (30) of Rueda-Ramírez et al. (2022). !!! note This limiter and the correction callback [`SubcellLimiterIDPCorrection`](@ref) only work together. @@ -45,22 +55,32 @@ The bounds are calculated using the low-order FV solution. The positivity limite !!! warning "Experimental implementation" This is an experimental feature and may change in future releases. """ -struct SubcellLimiterIDP{RealT <: Real, Cache} <: AbstractSubcellLimiter +struct SubcellLimiterIDP{RealT <: Real, LimitingVariablesNonlinear, Cache} <: + AbstractSubcellLimiter local_minmax::Bool local_minmax_variables_cons::Vector{Int} # Local mininum/maximum principles for conservative variables positivity::Bool positivity_variables_cons::Vector{Int} # Positivity for conservative variables + positivity_variables_nonlinear::LimitingVariablesNonlinear # Positivity for nonlinear variables positivity_correction_factor::RealT cache::Cache + max_iterations_newton::Int + newton_tolerances::Tuple{RealT, RealT} # Relative and absolute tolerances for Newton's method + gamma_constant_newton::RealT # Constant for the subcell limiting of convex (nonlinear) constraints end # this method is used when the limiter is constructed as for shock-capturing volume integrals function SubcellLimiterIDP(equations::AbstractEquations, basis; local_minmax_variables_cons = String[], positivity_variables_cons = String[], - positivity_correction_factor = 0.1) + positivity_variables_nonlinear = [], + positivity_correction_factor = 0.1, + max_iterations_newton = 10, + newton_tolerances = (1.0e-12, 1.0e-14), + gamma_constant_newton = 2 * ndims(equations)) local_minmax = (length(local_minmax_variables_cons) > 0) - positivity = (length(positivity_variables_cons) > 0) + positivity = (length(positivity_variables_cons) + + length(positivity_variables_nonlinear) > 0) local_minmax_variables_cons_ = get_variable_index.(local_minmax_variables_cons, equations) @@ -80,13 +100,20 @@ function SubcellLimiterIDP(equations::AbstractEquations, basis; bound_keys = (bound_keys..., Symbol(string(v), "_min")) end end + for variable in positivity_variables_nonlinear + bound_keys = (bound_keys..., Symbol(string(variable), "_min")) + end cache = create_cache(SubcellLimiterIDP, equations, basis, bound_keys) SubcellLimiterIDP{typeof(positivity_correction_factor), + typeof(positivity_variables_nonlinear), typeof(cache)}(local_minmax, local_minmax_variables_cons_, positivity, positivity_variables_cons_, - positivity_correction_factor, cache) + positivity_variables_nonlinear, + positivity_correction_factor, cache, + max_iterations_newton, newton_tolerances, + gamma_constant_newton) end function Base.show(io::IO, limiter::SubcellLimiterIDP) @@ -97,10 +124,15 @@ function Base.show(io::IO, limiter::SubcellLimiterIDP) if !(local_minmax || positivity) print(io, "No limiter selected => pure DG method") else - print(io, "limiter=(") - local_minmax && print(io, "min/max limiting, ") - positivity && print(io, "positivity") - print(io, "), ") + features = String[] + if local_minmax + push!(features, "local min/max") + end + if positivity + push!(features, "positivity") + end + join(io, features, ", ") + print(io, "Limiter=($features), ") end print(io, "Local bounds with FV solution") print(io, ")") @@ -120,15 +152,15 @@ function Base.show(io::IO, ::MIME"text/plain", limiter::SubcellLimiterIDP) if local_minmax setup = [ setup..., - "" => "local maximum/minimum bounds for conservative variables $(limiter.local_minmax_variables_cons)", + "" => "Local maximum/minimum limiting for conservative variables $(limiter.local_minmax_variables_cons)", ] end if positivity - string = "positivity for conservative variables $(limiter.positivity_variables_cons)" + string = "Positivity limiting for conservative variables $(limiter.positivity_variables_cons) and $(limiter.positivity_variables_nonlinear)" setup = [setup..., "" => string] setup = [ setup..., - "" => " positivity correction factor = $(limiter.positivity_correction_factor)", + "" => "- with positivity correction factor = $(limiter.positivity_correction_factor)", ] end setup = [ diff --git a/src/solvers/dgsem_tree/subcell_limiters_2d.jl b/src/solvers/dgsem_tree/subcell_limiters_2d.jl index 3d272359fe4..3f7954c8958 100644 --- a/src/solvers/dgsem_tree/subcell_limiters_2d.jl +++ b/src/solvers/dgsem_tree/subcell_limiters_2d.jl @@ -5,6 +5,10 @@ @muladd begin #! format: noindent +############################################################################### +# IDP Limiting +############################################################################### + # this method is used when the limiter is constructed as for shock-capturing volume integrals function create_cache(limiter::Type{SubcellLimiterIDP}, equations::AbstractEquations{2}, basis::LobattoLegendreBasis, bound_keys) @@ -66,6 +70,9 @@ function (limiter::SubcellLimiterIDP)(u::AbstractArray{<:Any, 4}, semi, dg::DGSE return nothing end +############################################################################### +# Calculation of local bounds using low-order FV solution + @inline function calc_bounds_twosided!(var_min, var_max, variable, u, t, semi) mesh, equations, dg, cache = mesh_equations_solver_cache(semi) # Calc bounds inside elements @@ -164,6 +171,9 @@ end return nothing end +############################################################################### +# Local minimum/maximum limiting + @inline function idp_local_minmax!(alpha, limiter, u, t, dt, semi) for variable in limiter.local_minmax_variables_cons idp_local_minmax!(alpha, limiter, u, t, dt, semi, variable) @@ -233,16 +243,36 @@ end return nothing end +############################################################################### +# Global positivity limiting + @inline function idp_positivity!(alpha, limiter, u, dt, semi) # Conservative variables for variable in limiter.positivity_variables_cons - idp_positivity!(alpha, limiter, u, dt, semi, variable) + @trixi_timeit timer() "conservative variables" idp_positivity_conservative!(alpha, + limiter, + u, + dt, + semi, + variable) + end + + # Nonlinear variables + for variable in limiter.positivity_variables_nonlinear + @trixi_timeit timer() "nonlinear variables" idp_positivity_nonlinear!(alpha, + limiter, + u, dt, + semi, + variable) end return nothing end -@inline function idp_positivity!(alpha, limiter, u, dt, semi, variable) +############################################################################### +# Global positivity limiting of conservative variables + +@inline function idp_positivity_conservative!(alpha, limiter, u, dt, semi, variable) mesh, equations, dg, cache = mesh_equations_solver_cache(semi) (; antidiffusive_flux1_L, antidiffusive_flux2_L, antidiffusive_flux1_R, antidiffusive_flux2_R) = cache.antidiffusive_fluxes (; inverse_weights) = dg.basis @@ -256,7 +286,7 @@ end for j in eachnode(dg), i in eachnode(dg) var = u[variable, i, j, element] if var < 0 - error("Safe $variable is not safe. element=$element, node: $i $j, value=$var") + error("Safe low-order method produces negative value for conservative variable $variable. Try a smaller time step.") end # Compute bound @@ -302,4 +332,183 @@ end return nothing end + +@inline function idp_positivity_nonlinear!(alpha, limiter, u, dt, semi, variable) + _, equations, dg, cache = mesh_equations_solver_cache(semi) + (; positivity_correction_factor) = limiter + + (; variable_bounds) = limiter.cache.subcell_limiter_coefficients + var_min = variable_bounds[Symbol(string(variable), "_min")] + + @threaded for element in eachelement(dg, semi.cache) + inverse_jacobian = cache.elements.inverse_jacobian[element] + for j in eachnode(dg), i in eachnode(dg) + # Compute bound + u_local = get_node_vars(u, equations, dg, i, j, element) + var = variable(u_local, equations) + if var < 0 + error("Safe low-order method produces negative value for variable $variable. Try a smaller time step.") + end + var_min[i, j, element] = positivity_correction_factor * var + + # Perform Newton's bisection method to find new alpha + newton_loops_alpha!(alpha, var_min[i, j, element], u_local, i, j, element, + variable, initial_check_nonnegative_newton_idp, + final_check_nonnegative_newton_idp, inverse_jacobian, + dt, equations, dg, cache, limiter) + end + end + + return nothing +end + +@inline function newton_loops_alpha!(alpha, bound, u, i, j, element, variable, + initial_check, final_check, inverse_jacobian, dt, + equations, dg, cache, limiter) + (; inverse_weights) = dg.basis + (; antidiffusive_flux1_L, antidiffusive_flux2_L, antidiffusive_flux1_R, antidiffusive_flux2_R) = cache.antidiffusive_fluxes + + (; gamma_constant_newton) = limiter + + # negative xi direction + antidiffusive_flux = gamma_constant_newton * inverse_jacobian * inverse_weights[i] * + get_node_vars(antidiffusive_flux1_R, equations, dg, i, j, + element) + newton_loop!(alpha, bound, u, i, j, element, variable, initial_check, final_check, + equations, dt, limiter, antidiffusive_flux) + + # positive xi direction + antidiffusive_flux = -gamma_constant_newton * inverse_jacobian * + inverse_weights[i] * + get_node_vars(antidiffusive_flux1_L, equations, dg, i + 1, j, + element) + newton_loop!(alpha, bound, u, i, j, element, variable, initial_check, final_check, + equations, dt, limiter, antidiffusive_flux) + + # negative eta direction + antidiffusive_flux = gamma_constant_newton * inverse_jacobian * inverse_weights[j] * + get_node_vars(antidiffusive_flux2_R, equations, dg, i, j, + element) + newton_loop!(alpha, bound, u, i, j, element, variable, initial_check, final_check, + equations, dt, limiter, antidiffusive_flux) + + # positive eta direction + antidiffusive_flux = -gamma_constant_newton * inverse_jacobian * + inverse_weights[j] * + get_node_vars(antidiffusive_flux2_L, equations, dg, i, j + 1, + element) + newton_loop!(alpha, bound, u, i, j, element, variable, initial_check, final_check, + equations, dt, limiter, antidiffusive_flux) + + return nothing +end + +@inline function newton_loop!(alpha, bound, u, i, j, element, variable, initial_check, + final_check, equations, dt, limiter, antidiffusive_flux) + newton_reltol, newton_abstol = limiter.newton_tolerances + + beta = 1 - alpha[i, j, element] + + beta_L = 0 # alpha = 1 + beta_R = beta # No higher beta (lower alpha) than the current one + + u_curr = u + beta * dt * antidiffusive_flux + + # If state is valid, perform initial check and return if correction is not needed + if isvalid(u_curr, equations) + goal = goal_function_newton_idp(variable, bound, u_curr, equations) + + initial_check(bound, goal, newton_abstol) && return nothing + end + + # Newton iterations + for iter in 1:(limiter.max_iterations_newton) + beta_old = beta + + # If the state is valid, evaluate d(goal)/d(beta) + if isvalid(u_curr, equations) + dgoal_dbeta = dgoal_function_newton_idp(variable, u_curr, dt, + antidiffusive_flux, equations) + else # Otherwise, perform a bisection step + dgoal_dbeta = 0 + end + + if dgoal_dbeta != 0 + # Update beta with Newton's method + beta = beta - goal / dgoal_dbeta + 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) + # Get new u + u_curr = u + beta * dt * antidiffusive_flux + + # If the state is invalid, finish bisection step without checking tolerance and iterate further + if !isvalid(u_curr, equations) + beta_R = beta + continue + end + + # Check new beta for condition and update bounds + goal = goal_function_newton_idp(variable, bound, u_curr, equations) + if initial_check(bound, goal, newton_abstol) + # New beta fulfills condition + beta_L = beta + else + # New beta does not fulfill condition + beta_R = beta + end + else + # Get new u + u_curr = u + beta * dt * antidiffusive_flux + + # If the state is invalid, redefine right bound without checking tolerance and iterate further + if !isvalid(u_curr, equations) + beta_R = beta + continue + end + + # Evaluate goal function + goal = goal_function_newton_idp(variable, bound, u_curr, equations) + end + + # Check relative tolerance + if abs(beta_old - beta) <= newton_reltol + break + end + + # Check absolute tolerance + if final_check(bound, goal, newton_abstol) + break + end + end + + new_alpha = 1 - beta + if alpha[i, j, element] > new_alpha + newton_abstol + error("Alpha is getting smaller. old: $(alpha[i, j, element]), new: $new_alpha") + else + alpha[i, j, element] = new_alpha + end + + return nothing +end + +### Auxiliary routines for Newton's bisection method ### +# Initial checks +@inline initial_check_nonnegative_newton_idp(bound, goal, newton_abstol) = goal <= 0 + +# Goal and d(Goal)d(u) function +@inline goal_function_newton_idp(variable, bound, u, equations) = bound - + variable(u, equations) +@inline function dgoal_function_newton_idp(variable, u, dt, antidiffusive_flux, + equations) + -dot(gradient_conservative(variable, u, equations), dt * antidiffusive_flux) +end + +# Final checks +@inline function final_check_nonnegative_newton_idp(bound, goal, newton_abstol) + (goal <= eps()) && (goal > -max(newton_abstol, abs(bound) * newton_abstol)) +end end # @muladd diff --git a/test/test_tree_2d_euler.jl b/test/test_tree_2d_euler.jl index 61b5c54b5e9..b937abe92c0 100644 --- a/test/test_tree_2d_euler.jl +++ b/test/test_tree_2d_euler.jl @@ -581,6 +581,32 @@ end end end +@trixi_testset "elixir_euler_kelvin_helmholtz_instability_sc_subcell.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_euler_kelvin_helmholtz_instability_sc_subcell.jl"), + l2=[ + 0.42185634563805724, + 0.1686471269704017, + 0.18240674916968103, + 0.17858250604280654, + ], + linf=[ + 1.7012978064377158, + 0.7149714986746726, + 0.5822547982757897, + 0.7300051017382696, + ], + tspan=(0.0, 2.0)) + # 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)) < 15000 + end +end + @trixi_testset "elixir_euler_colliding_flow.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_colliding_flow.jl"), l2=[ diff --git a/test/test_tree_2d_mhd.jl b/test/test_tree_2d_mhd.jl index 953c077c0a3..1f8458075aa 100644 --- a/test/test_tree_2d_mhd.jl +++ b/test/test_tree_2d_mhd.jl @@ -332,24 +332,28 @@ end @trixi_testset "elixir_mhd_shockcapturing_subcell.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_shockcapturing_subcell.jl"), - l2=[2.9974425783503109e-02, - 7.2849646345685956e-02, - 7.2488477174662239e-02, + l2=[ + 3.2064026219236076e-02, + 7.2461094392606618e-02, + 7.2380202888062711e-02, 0.0000000000000000e+00, - 1.2507971380965512e+00, - 1.8929505145499678e-02, - 1.2218606317164420e-02, + 8.6293936673145932e-01, + 8.4091669534557805e-03, + 5.2156364913231732e-03, 0.0000000000000000e+00, - 3.0154796910479838e-03], - linf=[3.2147382412340830e-01, - 1.3709471664007811e+00, - 1.3465154685288383e+00, + 2.0786952301129021e-04, + ], + linf=[ + 3.8778760255775635e-01, + 9.4666683953698927e-01, + 9.4618924645661928e-01, 0.0000000000000000e+00, - 1.6051257523415284e+01, - 3.0564266749926644e-01, - 2.3908016329805595e-01, + 1.0980297261521951e+01, + 1.0264404591009069e-01, + 1.0655686942176350e-01, 0.0000000000000000e+00, - 1.3711262178549158e-01], + 6.1013422157115546e-03, + ], tspan=(0.0, 0.003)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) diff --git a/test/test_unit.jl b/test/test_unit.jl index e8a8effbe29..7943d952f71 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -416,7 +416,8 @@ end indicator_hg = IndicatorHennemannGassner(1.0, 0.0, true, "variable", "cache") @test_nowarn show(stdout, indicator_hg) - limiter_idp = SubcellLimiterIDP(true, [1], true, [1], 0.1, "cache") + limiter_idp = SubcellLimiterIDP(true, [1], true, [1], ["variable"], 0.1, "cache", 1, + (1.0, 1.0), 1.0) @test_nowarn show(stdout, limiter_idp) # TODO: TrixiShallowWater: move unit test @@ -1220,6 +1221,26 @@ end end end +@testset "Consistency check for `gradient_conservative` routine" begin + # Set up conservative variables, equations + u = [ + 0.5011914484393387, + 0.8829127712445113, + 0.43024132987932817, + 0.7560616633050348, + ] + + equations = CompressibleEulerEquations2D(1.4) + + # Define wrapper function for pressure in order to call default implementation + function pressure_test(u, equations) + return pressure(u, equations) + end + + @test Trixi.gradient_conservative(pressure_test, u, equations) ≈ + Trixi.gradient_conservative(pressure, u, equations) +end + @testset "Equivalent Fluxes" begin # Set up equations and dummy conservative variables state # Burgers' Equation From e2c92f32457e22d6f8b766bf1ecd7a25d413cc6e Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Thu, 1 Feb 2024 09:35:16 +0100 Subject: [PATCH 240/263] Move Jacobian for para P4est to respective files, add muladd (#1807) * Move Jacobian for para P4est to respective files, add muladd * fmt * compare checks without muladd * update test val for muladd * test vals --------- Co-authored-by: Jesse Chan <1156048+jlchan@users.noreply.github.com> --- src/solvers/dgsem_p4est/dg_2d_parabolic.jl | 176 +++++++++++++++------ src/solvers/dgsem_p4est/dg_3d_parabolic.jl | 137 +++++++++++----- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 18 --- src/solvers/dgsem_tree/dg_3d_parabolic.jl | 18 --- test/test_parabolic_2d.jl | 4 +- 5 files changed, 228 insertions(+), 125 deletions(-) diff --git a/src/solvers/dgsem_p4est/dg_2d_parabolic.jl b/src/solvers/dgsem_p4est/dg_2d_parabolic.jl index 299f2f6140a..ed21f371449 100644 --- a/src/solvers/dgsem_p4est/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_p4est/dg_2d_parabolic.jl @@ -1,7 +1,15 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + # This method is called when a SemidiscretizationHyperbolicParabolic is constructed. # It constructs the basic `cache` used throughout the simulation to compute # the RHS etc. -function create_cache_parabolic(mesh::P4estMesh{2}, equations_hyperbolic::AbstractEquations, +function create_cache_parabolic(mesh::P4estMesh{2}, + equations_hyperbolic::AbstractEquations, equations_parabolic::AbstractEquationsParabolic, dg::DG, parabolic_scheme, RealT, uEltype) balance!(mesh) @@ -167,12 +175,14 @@ function calc_gradient!(gradients, u_transformed, t, element) for ii in eachnode(dg) - multiply_add_to_node_vars!(gradients_x, derivative_dhat[ii, i], u_node, + multiply_add_to_node_vars!(gradients_x, derivative_dhat[ii, i], + u_node, equations_parabolic, dg, ii, j, element) end for jj in eachnode(dg) - multiply_add_to_node_vars!(gradients_y, derivative_dhat[jj, j], u_node, + multiply_add_to_node_vars!(gradients_y, derivative_dhat[jj, j], + u_node, equations_parabolic, dg, i, jj, element) end end @@ -185,9 +195,11 @@ function calc_gradient!(gradients, u_transformed, t, Ja21, Ja22 = get_contravariant_vector(2, contravariant_vectors, i, j, element) - gradients_reference_1 = get_node_vars(gradients_x, equations_parabolic, dg, + gradients_reference_1 = get_node_vars(gradients_x, equations_parabolic, + dg, i, j, element) - gradients_reference_2 = get_node_vars(gradients_y, equations_parabolic, dg, + gradients_reference_2 = get_node_vars(gradients_y, equations_parabolic, + dg, i, j, element) # note that the contravariant vectors are transposed compared with computations of flux @@ -199,9 +211,11 @@ function calc_gradient!(gradients, u_transformed, t, gradient_y_node = Ja12 * gradients_reference_1 + Ja22 * gradients_reference_2 - set_node_vars!(gradients_x, gradient_x_node, equations_parabolic, dg, i, j, + set_node_vars!(gradients_x, gradient_x_node, equations_parabolic, dg, i, + j, element) - set_node_vars!(gradients_y, gradient_y_node, equations_parabolic, dg, i, j, + set_node_vars!(gradients_y, gradient_y_node, equations_parabolic, dg, i, + j, element) end end @@ -219,7 +233,8 @@ function calc_gradient!(gradients, u_transformed, t, @trixi_timeit timer() "interface flux" begin calc_interface_flux!(cache_parabolic.elements.surface_flux_values, mesh, False(), # False() = no nonconservative terms - equations_parabolic, dg.surface_integral, dg, cache_parabolic) + equations_parabolic, dg.surface_integral, dg, + cache_parabolic) end # Prolong solution to boundaries @@ -231,7 +246,8 @@ function calc_gradient!(gradients, u_transformed, t, # Calculate boundary fluxes @trixi_timeit timer() "boundary flux" begin calc_boundary_flux_gradients!(cache_parabolic, t, boundary_conditions_parabolic, - mesh, equations_parabolic, dg.surface_integral, dg) + mesh, equations_parabolic, dg.surface_integral, + dg) end # Prolong solution to mortars. This resues the hyperbolic version of `prolong2mortars` @@ -268,70 +284,94 @@ function calc_gradient!(gradients, u_transformed, t, # Compute x-component of gradients # surface at -x - normal_direction_x, _ = get_normal_direction(1, contravariant_vectors, + normal_direction_x, _ = get_normal_direction(1, + contravariant_vectors, 1, l, element) gradients_x[v, 1, l, element] = (gradients_x[v, 1, l, element] + - surface_flux_values[v, l, 1, element] * + surface_flux_values[v, l, 1, + element] * factor_1 * normal_direction_x) # surface at +x - normal_direction_x, _ = get_normal_direction(2, contravariant_vectors, + normal_direction_x, _ = get_normal_direction(2, + contravariant_vectors, nnodes(dg), l, element) - gradients_x[v, nnodes(dg), l, element] = (gradients_x[v, nnodes(dg), l, + gradients_x[v, nnodes(dg), l, element] = (gradients_x[v, nnodes(dg), + l, element] + - surface_flux_values[v, l, 2, + surface_flux_values[v, l, + 2, element] * - factor_2 * normal_direction_x) + factor_2 * + normal_direction_x) # surface at -y - normal_direction_x, _ = get_normal_direction(3, contravariant_vectors, + normal_direction_x, _ = get_normal_direction(3, + contravariant_vectors, l, 1, element) gradients_x[v, l, 1, element] = (gradients_x[v, l, 1, element] + - surface_flux_values[v, l, 3, element] * + surface_flux_values[v, l, 3, + element] * factor_1 * normal_direction_x) # surface at +y - normal_direction_x, _ = get_normal_direction(4, contravariant_vectors, + normal_direction_x, _ = get_normal_direction(4, + contravariant_vectors, l, nnodes(dg), element) - gradients_x[v, l, nnodes(dg), element] = (gradients_x[v, l, nnodes(dg), + gradients_x[v, l, nnodes(dg), element] = (gradients_x[v, l, + nnodes(dg), element] + - surface_flux_values[v, l, 4, + surface_flux_values[v, l, + 4, element] * - factor_2 * normal_direction_x) + factor_2 * + normal_direction_x) # Compute y-component of gradients # surface at -x - _, normal_direction_y = get_normal_direction(1, contravariant_vectors, + _, normal_direction_y = get_normal_direction(1, + contravariant_vectors, 1, l, element) gradients_y[v, 1, l, element] = (gradients_y[v, 1, l, element] + - surface_flux_values[v, l, 1, element] * + surface_flux_values[v, l, 1, + element] * factor_1 * normal_direction_y) # surface at +x - _, normal_direction_y = get_normal_direction(2, contravariant_vectors, + _, normal_direction_y = get_normal_direction(2, + contravariant_vectors, nnodes(dg), l, element) - gradients_y[v, nnodes(dg), l, element] = (gradients_y[v, nnodes(dg), l, + gradients_y[v, nnodes(dg), l, element] = (gradients_y[v, nnodes(dg), + l, element] + - surface_flux_values[v, l, 2, + surface_flux_values[v, l, + 2, element] * - factor_2 * normal_direction_y) + factor_2 * + normal_direction_y) # surface at -y - _, normal_direction_y = get_normal_direction(3, contravariant_vectors, + _, normal_direction_y = get_normal_direction(3, + contravariant_vectors, l, 1, element) gradients_y[v, l, 1, element] = (gradients_y[v, l, 1, element] + - surface_flux_values[v, l, 3, element] * + surface_flux_values[v, l, 3, + element] * factor_1 * normal_direction_y) # surface at +y - _, normal_direction_y = get_normal_direction(4, contravariant_vectors, + _, normal_direction_y = get_normal_direction(4, + contravariant_vectors, l, nnodes(dg), element) - gradients_y[v, l, nnodes(dg), element] = (gradients_y[v, l, nnodes(dg), + gradients_y[v, l, nnodes(dg), element] = (gradients_y[v, l, + nnodes(dg), element] + - surface_flux_values[v, l, 4, + surface_flux_values[v, l, + 4, element] * - factor_2 * normal_direction_y) + factor_2 * + normal_direction_y) end end end @@ -444,24 +484,30 @@ function calc_volume_integral!(du, flux_viscous, @threaded for element in eachelement(dg, cache) # Calculate volume terms in one element for j in eachnode(dg), i in eachnode(dg) - flux1 = get_node_vars(flux_viscous_x, equations_parabolic, dg, i, j, element) - flux2 = get_node_vars(flux_viscous_y, equations_parabolic, dg, i, j, element) + flux1 = get_node_vars(flux_viscous_x, equations_parabolic, dg, i, j, + element) + flux2 = get_node_vars(flux_viscous_y, equations_parabolic, dg, i, j, + element) # Compute the contravariant flux by taking the scalar product of the # first contravariant vector Ja^1 and the flux vector - Ja11, Ja12 = get_contravariant_vector(1, contravariant_vectors, i, j, element) + Ja11, Ja12 = get_contravariant_vector(1, contravariant_vectors, i, j, + element) contravariant_flux1 = Ja11 * flux1 + Ja12 * flux2 for ii in eachnode(dg) - multiply_add_to_node_vars!(du, derivative_dhat[ii, i], contravariant_flux1, + multiply_add_to_node_vars!(du, derivative_dhat[ii, i], + contravariant_flux1, equations_parabolic, dg, ii, j, element) end # Compute the contravariant flux by taking the scalar product of the # second contravariant vector Ja^2 and the flux vector - Ja21, Ja22 = get_contravariant_vector(2, contravariant_vectors, i, j, element) + Ja21, Ja22 = get_contravariant_vector(2, contravariant_vectors, i, j, + element) contravariant_flux2 = Ja21 * flux1 + Ja22 * flux2 for jj in eachnode(dg) - multiply_add_to_node_vars!(du, derivative_dhat[jj, j], contravariant_flux2, + multiply_add_to_node_vars!(du, derivative_dhat[jj, j], + contravariant_flux2, equations_parabolic, dg, i, jj, element) end end @@ -503,7 +549,8 @@ function prolong2interfaces!(cache_parabolic, flux_viscous, # this is the outward normal direction on the primary element normal_direction = get_normal_direction(primary_direction, contravariant_vectors, - i_primary, j_primary, primary_element) + i_primary, j_primary, + primary_element) for v in eachvariable(equations_parabolic) # OBS! `interfaces.u` stores the interpolated *fluxes* and *not the solution*! @@ -602,7 +649,8 @@ function calc_interface_flux!(surface_flux_values, # 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, - dg, node, + dg, + node, interface) flux = 0.5 * (viscous_flux_normal_ll + viscous_flux_normal_rr) @@ -624,9 +672,11 @@ function calc_interface_flux!(surface_flux_values, end function prolong2mortars_divergence!(cache, flux_viscous::Vector{Array{uEltype, 4}}, - mesh::Union{P4estMesh{2}, T8codeMesh{2}}, equations, + mesh::Union{P4estMesh{2}, T8codeMesh{2}}, + equations, mortar_l2::LobattoLegendreMortarL2, - surface_integral, dg::DGSEM) where {uEltype <: Real} + surface_integral, + dg::DGSEM) where {uEltype <: Real} @unpack neighbor_ids, node_indices = cache.mortars @unpack contravariant_vectors = cache.elements index_range = eachnode(dg) @@ -683,7 +733,8 @@ function prolong2mortars_divergence!(cache, flux_viscous::Vector{Array{uEltype, j_large = j_large_start element = neighbor_ids[3, mortar] for i in eachnode(dg) - normal_direction = get_normal_direction(direction_index, contravariant_vectors, + normal_direction = get_normal_direction(direction_index, + contravariant_vectors, i_large, j_large, element) for v in eachvariable(equations) @@ -732,8 +783,10 @@ function calc_mortar_flux_divergence!(surface_flux_values, for position in 1:2 for node in eachnode(dg) for v in eachvariable(equations) - viscous_flux_normal_ll = cache.mortars.u[1, v, position, node, mortar] - viscous_flux_normal_rr = cache.mortars.u[2, v, position, node, mortar] + viscous_flux_normal_ll = cache.mortars.u[1, v, position, node, + mortar] + viscous_flux_normal_rr = cache.mortars.u[2, v, position, node, + mortar] # TODO: parabolic; only BR1 at the moment fstar[position][v, node] = 0.5 * (viscous_flux_normal_ll + @@ -824,7 +877,8 @@ end function calc_boundary_flux_gradients!(cache, t, boundary_condition::Union{BoundaryConditionPeriodic, BoundaryConditionDoNothing}, - mesh::P4estMesh, equations, surface_integral, dg::DG) + mesh::P4estMesh, equations, surface_integral, + dg::DG) @assert isempty(eachboundary(dg, cache)) end @@ -913,7 +967,8 @@ function calc_boundary_flux!(cache, t, boundary_index) # Outward-pointing normal direction (not normalized) - normal_direction = get_normal_direction(direction_index, contravariant_vectors, + normal_direction = get_normal_direction(direction_index, + contravariant_vectors, i_node, j_node, element) # TODO: revisit if we want more general boundary treatments. @@ -922,11 +977,13 @@ function calc_boundary_flux!(cache, t, flux_inner = u_inner # Coordinates at boundary node - x = get_node_coords(node_coordinates, equations_parabolic, dg, i_node, j_node, + x = get_node_coords(node_coordinates, equations_parabolic, dg, i_node, + j_node, element) flux_ = boundary_condition_parabolic(flux_inner, u_inner, normal_direction, - x, t, operator_type, equations_parabolic) + x, t, operator_type, + equations_parabolic) # Copy flux to element storage in the correct orientation for v in eachvariable(equations_parabolic) @@ -938,3 +995,22 @@ function calc_boundary_flux!(cache, t, end end end + +function apply_jacobian_parabolic!(du, mesh::P4estMesh{2}, + equations::AbstractEquationsParabolic, + dg::DG, cache) + @unpack inverse_jacobian = cache.elements + + @threaded for element in eachelement(dg, cache) + for j in eachnode(dg), i in eachnode(dg) + factor = inverse_jacobian[i, j, element] + + for v in eachvariable(equations) + du[v, i, j, element] *= factor + end + end + end + + return nothing +end +end # @muladd diff --git a/src/solvers/dgsem_p4est/dg_3d_parabolic.jl b/src/solvers/dgsem_p4est/dg_3d_parabolic.jl index 83d663809a7..63d431d35d5 100644 --- a/src/solvers/dgsem_p4est/dg_3d_parabolic.jl +++ b/src/solvers/dgsem_p4est/dg_3d_parabolic.jl @@ -1,7 +1,15 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + # This method is called when a SemidiscretizationHyperbolicParabolic is constructed. # It constructs the basic `cache` used throughout the simulation to compute # the RHS etc. -function create_cache_parabolic(mesh::P4estMesh{3}, equations_hyperbolic::AbstractEquations, +function create_cache_parabolic(mesh::P4estMesh{3}, + equations_hyperbolic::AbstractEquations, equations_parabolic::AbstractEquationsParabolic, dg::DG, parabolic_scheme, RealT, uEltype) balance!(mesh) @@ -73,11 +81,14 @@ function calc_gradient!(gradients, u_transformed, t, Ja31, Ja32, Ja33 = get_contravariant_vector(3, contravariant_vectors, i, j, k, element) - gradients_reference_1 = get_node_vars(gradients_x, equations_parabolic, dg, + gradients_reference_1 = get_node_vars(gradients_x, equations_parabolic, + dg, i, j, k, element) - gradients_reference_2 = get_node_vars(gradients_y, equations_parabolic, dg, + gradients_reference_2 = get_node_vars(gradients_y, equations_parabolic, + dg, i, j, k, element) - gradients_reference_3 = get_node_vars(gradients_z, equations_parabolic, dg, + gradients_reference_3 = get_node_vars(gradients_z, equations_parabolic, + dg, i, j, k, element) # note that the contravariant vectors are transposed compared with computations of flux @@ -115,7 +126,8 @@ function calc_gradient!(gradients, u_transformed, t, @trixi_timeit timer() "interface flux" begin calc_interface_flux!(cache_parabolic.elements.surface_flux_values, mesh, False(), # False() = no nonconservative terms - equations_parabolic, dg.surface_integral, dg, cache_parabolic) + equations_parabolic, dg.surface_integral, dg, + cache_parabolic) end # Prolong solution to boundaries @@ -127,7 +139,8 @@ function calc_gradient!(gradients, u_transformed, t, # Calculate boundary fluxes @trixi_timeit timer() "boundary flux" begin calc_boundary_flux_gradients!(cache_parabolic, t, boundary_conditions_parabolic, - mesh, equations_parabolic, dg.surface_integral, dg) + mesh, equations_parabolic, dg.surface_integral, + dg) end # Prolong solution to mortars. These should reuse the hyperbolic version of `prolong2mortars` @@ -165,7 +178,8 @@ function calc_gradient!(gradients, u_transformed, t, for dim in 1:3 grad = gradients[dim] # surface at -x - normal_direction = get_normal_direction(1, contravariant_vectors, + normal_direction = get_normal_direction(1, + contravariant_vectors, 1, l, m, element) grad[v, 1, l, m, element] = (grad[v, 1, l, m, element] + surface_flux_values[v, l, m, 1, @@ -173,18 +187,22 @@ function calc_gradient!(gradients, u_transformed, t, factor_1 * normal_direction[dim]) # surface at +x - normal_direction = get_normal_direction(2, contravariant_vectors, - nnodes(dg), l, m, element) + normal_direction = get_normal_direction(2, + contravariant_vectors, + nnodes(dg), l, m, + element) grad[v, nnodes(dg), l, m, element] = (grad[v, nnodes(dg), l, m, element] + - surface_flux_values[v, l, m, + surface_flux_values[v, l, + m, 2, element] * factor_2 * normal_direction[dim]) # surface at -y - normal_direction = get_normal_direction(3, contravariant_vectors, + normal_direction = get_normal_direction(3, + contravariant_vectors, l, m, 1, element) grad[v, l, 1, m, element] = (grad[v, l, 1, m, element] + surface_flux_values[v, l, m, 3, @@ -192,18 +210,22 @@ function calc_gradient!(gradients, u_transformed, t, factor_1 * normal_direction[dim]) # surface at +y - normal_direction = get_normal_direction(4, contravariant_vectors, - l, nnodes(dg), m, element) + normal_direction = get_normal_direction(4, + contravariant_vectors, + l, nnodes(dg), m, + element) grad[v, l, nnodes(dg), m, element] = (grad[v, l, nnodes(dg), m, element] + - surface_flux_values[v, l, m, + surface_flux_values[v, l, + m, 4, element] * factor_2 * normal_direction[dim]) # surface at -z - normal_direction = get_normal_direction(5, contravariant_vectors, + normal_direction = get_normal_direction(5, + contravariant_vectors, l, m, 1, element) grad[v, l, m, 1, element] = (grad[v, l, m, 1, element] + surface_flux_values[v, l, m, 5, @@ -211,11 +233,14 @@ function calc_gradient!(gradients, u_transformed, t, factor_1 * normal_direction[dim]) # surface at +z - normal_direction = get_normal_direction(6, contravariant_vectors, - l, m, nnodes(dg), element) + normal_direction = get_normal_direction(6, + contravariant_vectors, + l, m, nnodes(dg), + element) grad[v, l, m, nnodes(dg), element] = (grad[v, l, m, nnodes(dg), element] + - surface_flux_values[v, l, m, + surface_flux_values[v, l, + m, 6, element] * factor_2 * @@ -366,37 +391,46 @@ function calc_volume_integral!(du, flux_viscous, @threaded for element in eachelement(dg, cache) # Calculate volume terms in one element for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg) - flux1 = get_node_vars(flux_viscous_x, equations_parabolic, dg, i, j, k, element) - flux2 = get_node_vars(flux_viscous_y, equations_parabolic, dg, i, j, k, element) - flux3 = get_node_vars(flux_viscous_z, equations_parabolic, dg, i, j, k, element) + flux1 = get_node_vars(flux_viscous_x, equations_parabolic, dg, i, j, k, + element) + flux2 = get_node_vars(flux_viscous_y, equations_parabolic, dg, i, j, k, + element) + flux3 = get_node_vars(flux_viscous_z, equations_parabolic, dg, i, j, k, + element) # Compute the contravariant flux by taking the scalar product of the # first contravariant vector Ja^1 and the flux vector - Ja11, Ja12, Ja13 = get_contravariant_vector(1, contravariant_vectors, i, j, k, + Ja11, Ja12, Ja13 = get_contravariant_vector(1, contravariant_vectors, i, j, + k, element) contravariant_flux1 = Ja11 * flux1 + Ja12 * flux2 + Ja13 * flux3 for ii in eachnode(dg) - multiply_add_to_node_vars!(du, derivative_dhat[ii, i], contravariant_flux1, + multiply_add_to_node_vars!(du, derivative_dhat[ii, i], + contravariant_flux1, equations_parabolic, dg, ii, j, k, element) end # Compute the contravariant flux by taking the scalar product of the # second contravariant vector Ja^2 and the flux vector - Ja21, Ja22, Ja23 = get_contravariant_vector(2, contravariant_vectors, i, j, k, + Ja21, Ja22, Ja23 = get_contravariant_vector(2, contravariant_vectors, i, j, + k, element) contravariant_flux2 = Ja21 * flux1 + Ja22 * flux2 + Ja23 * flux3 for jj in eachnode(dg) - multiply_add_to_node_vars!(du, derivative_dhat[jj, j], contravariant_flux2, + multiply_add_to_node_vars!(du, derivative_dhat[jj, j], + contravariant_flux2, equations_parabolic, dg, i, jj, k, element) end # Compute the contravariant flux by taking the scalar product of the # second contravariant vector Ja^2 and the flux vector - Ja31, Ja32, Ja33 = get_contravariant_vector(3, contravariant_vectors, i, j, k, + Ja31, Ja32, Ja33 = get_contravariant_vector(3, contravariant_vectors, i, j, + k, element) contravariant_flux3 = Ja31 * flux1 + Ja32 * flux2 + Ja33 * flux3 for kk in eachnode(dg) - multiply_add_to_node_vars!(du, derivative_dhat[kk, k], contravariant_flux3, + multiply_add_to_node_vars!(du, derivative_dhat[kk, k], + contravariant_flux3, equations_parabolic, dg, i, j, kk, element) end end @@ -574,7 +608,8 @@ function calc_interface_flux!(surface_flux_values, viscous_flux_normal_ll, viscous_flux_normal_rr = get_surface_node_vars(cache_parabolic.interfaces.u, equations_parabolic, dg, - i, j, + i, + j, interface) flux = 0.5 * (viscous_flux_normal_ll + viscous_flux_normal_rr) @@ -606,7 +641,8 @@ function calc_interface_flux!(surface_flux_values, end function prolong2mortars_divergence!(cache, flux_viscous, - mesh::Union{P4estMesh{3}, T8codeMesh{3}}, equations, + mesh::Union{P4estMesh{3}, T8codeMesh{3}}, + equations, mortar_l2::LobattoLegendreMortarL2, surface_integral, dg::DGSEM) @unpack neighbor_ids, node_indices = cache.mortars @@ -642,11 +678,14 @@ function prolong2mortars_divergence!(cache, flux_viscous, element) for v in eachvariable(equations) - flux_viscous = SVector(flux_viscous_x[v, i_small, j_small, k_small, + flux_viscous = SVector(flux_viscous_x[v, i_small, j_small, + k_small, element], - flux_viscous_y[v, i_small, j_small, k_small, + flux_viscous_y[v, i_small, j_small, + k_small, element], - flux_viscous_z[v, i_small, j_small, k_small, + flux_viscous_z[v, i_small, j_small, + k_small, element]) cache.mortars.u[1, v, position, i, j, mortar] = dot(flux_viscous, @@ -688,7 +727,8 @@ function prolong2mortars_divergence!(cache, flux_viscous, for i in eachnode(dg) normal_direction = get_normal_direction(direction_index, contravariant_vectors, - i_large, j_large, k_large, element) + i_large, j_large, k_large, + element) for v in eachvariable(equations) flux_viscous = SVector(flux_viscous_x[v, i_large, j_large, k_large, @@ -827,7 +867,8 @@ end # TODO: parabolic; only BR1 at the moment flux_ = 0.5 * (u_ll + u_rr) # Copy flux to buffer - set_node_vars!(fstar, flux_, equations, dg, i_node_index, j_node_index, position_index) + set_node_vars!(fstar, flux_, equations, dg, i_node_index, j_node_index, + position_index) end # TODO: parabolic, finish implementing `calc_boundary_flux_gradients!` and `calc_boundary_flux_divergence!` @@ -862,7 +903,8 @@ function prolong2boundaries!(cache_parabolic, flux_viscous, for j in eachnode(dg) for i in eachnode(dg) # this is the outward normal direction on the primary element - normal_direction = get_normal_direction(direction, contravariant_vectors, + normal_direction = get_normal_direction(direction, + contravariant_vectors, i_node, j_node, k_node, element) for v in eachvariable(equations_parabolic) @@ -873,7 +915,8 @@ function prolong2boundaries!(cache_parabolic, flux_viscous, flux_viscous_z[v, i_node, j_node, k_node, element]) - boundaries.u[v, i, j, boundary] = dot(flux_viscous, normal_direction) + boundaries.u[v, i, j, boundary] = dot(flux_viscous, + normal_direction) end i_node += i_node_step_i j_node += j_node_step_i @@ -940,7 +983,8 @@ function calc_boundary_flux!(cache, t, j_node, k_node, element) - flux_ = boundary_condition_parabolic(flux_inner, u_inner, normal_direction, + flux_ = boundary_condition_parabolic(flux_inner, u_inner, + normal_direction, x, t, operator_type, equations_parabolic) @@ -959,3 +1003,22 @@ function calc_boundary_flux!(cache, t, end end end + +function apply_jacobian_parabolic!(du, mesh::P4estMesh{3}, + equations::AbstractEquationsParabolic, + dg::DG, cache) + @unpack inverse_jacobian = cache.elements + + @threaded for element in eachelement(dg, cache) + for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg) + factor = inverse_jacobian[i, j, k, element] + + for v in eachvariable(equations) + du[v, i, j, k, element] *= factor + end + end + end + + return nothing +end +end # @muladd diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index b1c27343999..a6c962e03cd 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -951,22 +951,4 @@ function apply_jacobian_parabolic!(du, mesh::TreeMesh{2}, return nothing end - -function apply_jacobian_parabolic!(du, mesh::P4estMesh{2}, - equations::AbstractEquationsParabolic, - dg::DG, cache) - @unpack inverse_jacobian = cache.elements - - @threaded for element in eachelement(dg, cache) - for j in eachnode(dg), i in eachnode(dg) - factor = inverse_jacobian[i, j, element] - - for v in eachvariable(equations) - du[v, i, j, element] *= factor - end - end - end - - return nothing -end end # @muladd diff --git a/src/solvers/dgsem_tree/dg_3d_parabolic.jl b/src/solvers/dgsem_tree/dg_3d_parabolic.jl index ee0e7c6b069..d5504744742 100644 --- a/src/solvers/dgsem_tree/dg_3d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_3d_parabolic.jl @@ -1033,22 +1033,4 @@ function apply_jacobian_parabolic!(du, mesh::TreeMesh{3}, return nothing end - -function apply_jacobian_parabolic!(du, mesh::P4estMesh{3}, - equations::AbstractEquationsParabolic, - dg::DG, cache) - @unpack inverse_jacobian = cache.elements - - @threaded for element in eachelement(dg, cache) - for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg) - factor = inverse_jacobian[i, j, k, element] - - for v in eachvariable(equations) - du[v, i, j, k, element] *= factor - end - end - end - - return nothing -end end # @muladd diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 6632cd0bb27..f7185a1a904 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -561,8 +561,8 @@ end @test_trixi_include(joinpath(examples_dir(), "p4est_2d_dgsem", "elixir_advection_diffusion_nonperiodic_amr.jl"), tspan=(0.0, 0.01), - l2=[0.00793438523666649], - linf=[0.11030633127144573]) + l2=[0.007933791324450538], + linf=[0.11029480573492567]) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let From 3ed62fb4e3bbd034b49fa452e4034c909b3a549b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Feb 2024 18:01:29 +0100 Subject: [PATCH 241/263] Bump actions/cache from 3 to 4 (#1828) Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/benchmark.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 6aa4809c1c2..4531c3aee0a 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -26,7 +26,7 @@ jobs: version: ${{ matrix.version }} arch: ${{ matrix.arch }} show-versioninfo: true - - uses: actions/cache@v3 + - uses: actions/cache@v4 env: cache-name: cache-artifacts with: From db1d7054b7832cb56dddda1076921dfd0476a2b2 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 2 Feb 2024 08:46:49 +0100 Subject: [PATCH 242/263] fix typo leafs -> leaves --- src/meshes/t8code_mesh.jl | 38 +++++++++++++++++++------------------- test/test_parabolic_2d.jl | 12 ++++++------ test/test_parabolic_3d.jl | 28 ++++++++++++++-------------- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/meshes/t8code_mesh.jl b/src/meshes/t8code_mesh.jl index 6fb4d861d10..cb2ac787e14 100644 --- a/src/meshes/t8code_mesh.jl +++ b/src/meshes/t8code_mesh.jl @@ -1,7 +1,7 @@ """ T8codeMesh{NDIMS} <: AbstractMesh{NDIMS} -An unstructured curved mesh based on trees that uses the C library +An unstructured curved mesh based on trees that uses the C library ['t8code'](https://github.com/DLR-AMR/t8code) to manage trees and mesh refinement. """ @@ -485,7 +485,7 @@ end # form a family and we decide whether this family should be coarsened # or only the first element should be refined. # Otherwise `is_family` must equal zero and we consider the first entry -# of the element array for refinement. +# of the element array for refinement. # Entries of the element array beyond the first `num_elements` are undefined. # \param [in] forest the forest to which the new elements belong # \param [in] forest_from the forest that is adapted. @@ -542,8 +542,8 @@ Adapt a `T8codeMesh` according to a user-defined `adapt_callback`. 0 : Stay unchanged. 1 : Refine element. -- `kwargs`: - - `recursive = true`: Adapt the forest recursively. If true the caller must ensure that the callback +- `kwargs`: + - `recursive = true`: Adapt the forest recursively. If true the caller must ensure that the callback returns 0 for every analyzed element at some point to stop the recursion. - `balance = true`: Make sure the adapted forest is 2^(NDIMS-1):1 balanced. - `partition = true`: Partition the forest to redistribute elements evenly among MPI ranks. @@ -695,7 +695,7 @@ function count_interfaces(mesh::T8codeMesh) for iface in 0:(num_faces - 1) pelement_indices_ref = Ref{Ptr{t8_locidx_t}}() - pneighbor_leafs_ref = Ref{Ptr{Ptr{t8_element}}}() + pneighbor_leaves_ref = Ref{Ptr{Ptr{t8_element}}}() pneigh_scheme_ref = Ref{Ptr{t8_eclass_scheme}}() dual_faces_ref = Ref{Ptr{Cint}}() @@ -704,7 +704,7 @@ function count_interfaces(mesh::T8codeMesh) forest_is_balanced = Cint(1) t8_forest_leaf_face_neighbors(mesh.forest, itree, element, - pneighbor_leafs_ref, iface, dual_faces_ref, + pneighbor_leaves_ref, iface, dual_faces_ref, num_neighbors_ref, pelement_indices_ref, pneigh_scheme_ref, forest_is_balanced) @@ -713,13 +713,13 @@ function count_interfaces(mesh::T8codeMesh) dual_faces = unsafe_wrap(Array, dual_faces_ref[], num_neighbors) neighbor_ielements = unsafe_wrap(Array, pelement_indices_ref[], num_neighbors) - neighbor_leafs = unsafe_wrap(Array, pneighbor_leafs_ref[], num_neighbors) + neighbor_leaves = unsafe_wrap(Array, pneighbor_leaves_ref[], num_neighbors) neighbor_scheme = pneigh_scheme_ref[] if num_neighbors == 0 local_num_boundary += 1 else - neighbor_level = t8_element_level(neighbor_scheme, neighbor_leafs[1]) + neighbor_level = t8_element_level(neighbor_scheme, neighbor_leaves[1]) if all(neighbor_ielements .< num_local_elements) # Conforming interface: The second condition ensures we @@ -745,7 +745,7 @@ function count_interfaces(mesh::T8codeMesh) neighbor_linear_id = neighbor_global_ghost_itree * max_tree_num_elements + t8_element_get_linear_id(neighbor_scheme, - neighbor_leafs[1], + neighbor_leaves[1], max_level) global_mortar_id = 2 * ndims(mesh) * neighbor_linear_id + dual_faces[1] @@ -759,7 +759,7 @@ function count_interfaces(mesh::T8codeMesh) end t8_free(dual_faces_ref[]) - t8_free(pneighbor_leafs_ref[]) + t8_free(pneighbor_leaves_ref[]) t8_free(pelement_indices_ref[]) end # for @@ -875,7 +875,7 @@ function fill_mesh_info!(mesh::T8codeMesh, interfaces, mortars, boundaries, end pelement_indices_ref = Ref{Ptr{t8_locidx_t}}() - pneighbor_leafs_ref = Ref{Ptr{Ptr{t8_element}}}() + pneighbor_leaves_ref = Ref{Ptr{Ptr{t8_element}}}() pneigh_scheme_ref = Ref{Ptr{t8_eclass_scheme}}() dual_faces_ref = Ref{Ptr{Cint}}() @@ -885,7 +885,7 @@ function fill_mesh_info!(mesh::T8codeMesh, interfaces, mortars, boundaries, # Query neighbor information from t8code. t8_forest_leaf_face_neighbors(mesh.forest, itree, element, - pneighbor_leafs_ref, iface, dual_faces_ref, + pneighbor_leaves_ref, iface, dual_faces_ref, num_neighbors_ref, pelement_indices_ref, pneigh_scheme_ref, forest_is_balanced) @@ -894,7 +894,7 @@ function fill_mesh_info!(mesh::T8codeMesh, interfaces, mortars, boundaries, dual_faces = unsafe_wrap(Array, dual_faces_ref[], num_neighbors) neighbor_ielements = unsafe_wrap(Array, pelement_indices_ref[], num_neighbors) - neighbor_leafs = unsafe_wrap(Array, pneighbor_leafs_ref[], num_neighbors) + neighbor_leaves = unsafe_wrap(Array, pneighbor_leaves_ref[], num_neighbors) neighbor_scheme = pneigh_scheme_ref[] # Now we check for the different cases. The nested if-structure is as follows: @@ -913,7 +913,7 @@ function fill_mesh_info!(mesh::T8codeMesh, interfaces, mortars, boundaries, # else: // `local mortar from smaller elements point of view` # // We only count local mortars once. # - # else: // It must be either a MPI interface or a MPI mortar. + # else: // It must be either a MPI interface or a MPI mortar. # # if `MPI interface`: # @@ -938,7 +938,7 @@ function fill_mesh_info!(mesh::T8codeMesh, interfaces, mortars, boundaries, # Interface or mortar. else - neighbor_level = t8_element_level(neighbor_scheme, neighbor_leafs[1]) + neighbor_level = t8_element_level(neighbor_scheme, neighbor_leaves[1]) # Local interface or mortar. if all(neighbor_ielements .< num_local_elements) @@ -985,7 +985,7 @@ function fill_mesh_info!(mesh::T8codeMesh, interfaces, mortars, boundaries, neighbor_linear_id = neighbor_global_ghost_itree * max_tree_num_elements + t8_element_get_linear_id(neighbor_scheme, - neighbor_leafs[1], + neighbor_leaves[1], max_level) if current_linear_id < neighbor_linear_id @@ -1029,7 +1029,7 @@ function fill_mesh_info!(mesh::T8codeMesh, interfaces, mortars, boundaries, num_local_elements) local_neighbor_ids = [neighbor_ids[i] for i in local_neighbor_positions] - local_neighbor_positions = [map_iface_to_ichild_to_position[dual_faces[1] + 1][t8_element_child_id(neighbor_scheme, neighbor_leafs[i]) + 1] + local_neighbor_positions = [map_iface_to_ichild_to_position[dual_faces[1] + 1][t8_element_child_id(neighbor_scheme, neighbor_leaves[i]) + 1] for i in local_neighbor_positions] # Last entry is the large element. @@ -1059,7 +1059,7 @@ function fill_mesh_info!(mesh::T8codeMesh, interfaces, mortars, boundaries, neighbor_linear_id = neighbor_global_ghost_itree * max_tree_num_elements + t8_element_get_linear_id(neighbor_scheme, - neighbor_leafs[1], + neighbor_leaves[1], max_level) global_mortar_id = 2 * ndims(mesh) * neighbor_linear_id + dual_faces[1] @@ -1100,7 +1100,7 @@ function fill_mesh_info!(mesh::T8codeMesh, interfaces, mortars, boundaries, end t8_free(dual_faces_ref[]) - t8_free(pneighbor_leafs_ref[]) + t8_free(pneighbor_leaves_ref[]) t8_free(pelement_indices_ref[]) end # for iface diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index f7185a1a904..9f1382caa62 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -218,9 +218,9 @@ end "elixir_advection_diffusion.jl"), tspan=(0.0, 0.0)) LLID = Trixi.local_leaf_cells(mesh.tree) - num_leafs = length(LLID) - @assert num_leafs % 8 == 0 - Trixi.refine!(mesh.tree, LLID[1:Int(num_leafs / 8)]) + num_leaves = length(LLID) + @assert num_leaves % 8 == 0 + Trixi.refine!(mesh.tree, LLID[1:Int(num_leaves / 8)]) tspan = (0.0, 1.5) semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), @@ -414,9 +414,9 @@ end "elixir_navierstokes_convergence.jl"), tspan=(0.0, 0.0), initial_refinement_level=3) LLID = Trixi.local_leaf_cells(mesh.tree) - num_leafs = length(LLID) - @assert num_leafs % 4 == 0 - Trixi.refine!(mesh.tree, LLID[1:Int(num_leafs / 4)]) + num_leaves = length(LLID) + @assert num_leaves % 4 == 0 + Trixi.refine!(mesh.tree, LLID[1:Int(num_leaves / 4)]) tspan = (0.0, 0.5) semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; diff --git a/test/test_parabolic_3d.jl b/test/test_parabolic_3d.jl index 6fbfb8259d4..1eaa9f51a56 100644 --- a/test/test_parabolic_3d.jl +++ b/test/test_parabolic_3d.jl @@ -252,9 +252,9 @@ end "elixir_navierstokes_convergence.jl"), tspan=(0.0, 0.0)) LLID = Trixi.local_leaf_cells(mesh.tree) - num_leafs = length(LLID) - @assert num_leafs % 16 == 0 - Trixi.refine!(mesh.tree, LLID[1:Int(num_leafs / 16)]) + num_leaves = length(LLID) + @assert num_leaves % 16 == 0 + Trixi.refine!(mesh.tree, LLID[1:Int(num_leaves / 16)]) tspan = (0.0, 0.25) semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; @@ -325,9 +325,9 @@ end "elixir_navierstokes_taylor_green_vortex.jl"), tspan=(0.0, 0.0)) LLID = Trixi.local_leaf_cells(mesh.tree) - num_leafs = length(LLID) - @assert num_leafs % 32 == 0 - Trixi.refine!(mesh.tree, LLID[1:Int(num_leafs / 32)]) + num_leaves = length(LLID) + @assert num_leaves % 32 == 0 + Trixi.refine!(mesh.tree, LLID[1:Int(num_leaves / 32)]) tspan = (0.0, 0.1) semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver) @@ -429,8 +429,8 @@ end "elixir_advection_diffusion_amr.jl"), l2=[0.000355780485397024], linf=[0.0010810770271614256]) - # Ensure that we do not have excessive memory allocations - # (e.g., from type instabilities) + # Ensure that we do not have excessive memory allocations + # (e.g., from type instabilities) let t = sol.t[end] u_ode = sol.u[end] @@ -444,8 +444,8 @@ end "elixir_advection_diffusion_nonperiodic.jl"), l2=[0.0009808996243280868], linf=[0.01732621559135459]) - # Ensure that we do not have excessive memory allocations - # (e.g., from type instabilities) + # Ensure that we do not have excessive memory allocations + # (e.g., from type instabilities) let t = sol.t[end] u_ode = sol.u[end] @@ -472,8 +472,8 @@ end 0.12129218723807476, 0.8433893297612087, ]) - # Ensure that we do not have excessive memory allocations - # (e.g., from type instabilities) + # Ensure that we do not have excessive memory allocations + # (e.g., from type instabilities) let t = sol.t[end] u_ode = sol.u[end] @@ -495,8 +495,8 @@ end 0.6782397526873181, 0.17663702154066238, 0.17663702154066266, 0.17663702154066238, 1.7327849844825238, ]) - # Ensure that we do not have excessive memory allocations - # (e.g., from type instabilities) + # Ensure that we do not have excessive memory allocations + # (e.g., from type instabilities) let t = sol.t[end] u_ode = sol.u[end] From 7f7f058d0721bc1634e9fee69a8d136b9ea57bc7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Feb 2024 08:47:41 +0100 Subject: [PATCH 243/263] Bump crate-ci/typos from 1.16.26 to 1.18.0 (#1826) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.16.26 to 1.18.0. - [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.16.26...v1.18.0) --- 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> Co-authored-by: Hendrik Ranocha --- .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 a780e975155..b242b6e811e 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.16.26 + uses: crate-ci/typos@v1.18.0 From fa129aa3be558df6246b7339ce2bc966d76bcc6a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Feb 2024 14:47:13 +0100 Subject: [PATCH 244/263] Bump codecov/codecov-action from 3 to 4 (#1827) Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 3 to 4. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v3...v4) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f287cc5feb2..2e388366fc8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -129,7 +129,7 @@ jobs: - uses: julia-actions/julia-processcoverage@v1 with: directories: src,examples,ext - - uses: codecov/codecov-action@v3 + - uses: codecov/codecov-action@v4 with: file: ./lcov.info flags: unittests From ea61e26ff330e720b011a85a2f4b9040e54da870 Mon Sep 17 00:00:00 2001 From: Benjamin Bolm <74359358+bennibolm@users.noreply.github.com> Date: Mon, 5 Feb 2024 11:50:25 +0100 Subject: [PATCH 245/263] Add section about false sharing problems to documentation (#1819) * Add section to docs about false sharing * Fix typos * Fix typo * Implement suggestions --- docs/src/performance.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/src/performance.md b/docs/src/performance.md index df66f451b79..82d7f501f63 100644 --- a/docs/src/performance.md +++ b/docs/src/performance.md @@ -267,3 +267,14 @@ requires. It can thus be seen as a proxy for "energy used" and, as an extension, timing result, you need to set the analysis interval such that the `AnalysisCallback` is invoked at least once during the course of the simulation and discard the first PID value. + +## Performance issues with multi-threaded reductions +[False sharing](https://en.wikipedia.org/wiki/False_sharing) is a known performance issue +for systems with distributed caches. It also occurred for the implementation of a thread +parallel bounds checking routine for the subcell IDP limiting +in [PR #1736](https://github.com/trixi-framework/Trixi.jl/pull/1736). +After some [testing and discussion](https://github.com/trixi-framework/Trixi.jl/pull/1736#discussion_r1423881895), +it turned out that initializing a vector of length `n * Threads.nthreads()` and only using every +n-th entry instead of a vector of length `Threads.nthreads()` fixes the problem. +Since there are no processors with caches over 128B, we use `n = 128B / size(uEltype)`. +Now, the bounds checking routine of the IDP limiting scales as hoped. From 14151e636ef654cb5421b3a7e498a9d76ed46a64 Mon Sep 17 00:00:00 2001 From: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Date: Mon, 5 Feb 2024 12:49:51 +0100 Subject: [PATCH 246/263] Add entry for gmsh tutorial in introduction (#1829) * add entry for gmsh tutorial in introduction * Update docs/literate/src/files/index.jl --------- Co-authored-by: Daniel Doehring Co-authored-by: Daniel Doehring --- docs/literate/src/files/index.jl | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/literate/src/files/index.jl b/docs/literate/src/files/index.jl index e259d25fb2f..26637e5b24b 100644 --- a/docs/literate/src/files/index.jl +++ b/docs/literate/src/files/index.jl @@ -108,20 +108,26 @@ # software in the Trixi.jl ecosystem, and then run a simulation using Trixi.jl on said mesh. # In the end, the tutorial briefly explains how to simulate an example using AMR via `P4estMesh`. -# ### [15 Explicit time stepping](@ref time_stepping) +# ### [15 P4est mesh from gmsh](@ref p4est_from_gmsh) +#- +# This tutorial describes how to obtain a [`P4estMesh`](@ref) from an existing mesh generated +# by [`gmsh`](https://gmsh.info/) or any other meshing software that can export to the Abaqus +# input `.inp` format. The tutorial demonstrates how edges/faces can be associated with boundary conditions based on the physical nodesets. + +# ### [16 Explicit time stepping](@ref time_stepping) #- # This tutorial is about time integration using [OrdinaryDiffEq.jl](https://github.com/SciML/OrdinaryDiffEq.jl). # It explains how to use their algorithms and presents two types of time step choices - with error-based # and CFL-based adaptive step size control. -# ### [16 Differentiable programming](@ref differentiable_programming) +# ### [17 Differentiable programming](@ref differentiable_programming) #- # This part deals with some basic differentiable programming topics. For example, a Jacobian, its # eigenvalues and a curve of total energy (through the simulation) are calculated and plotted for # a few semidiscretizations. Moreover, we calculate an example for propagating errors with Measurement.jl # at the end. -# ### [17 Custom semidiscretization](@ref custom_semidiscretization) +# ### [18 Custom semidiscretization](@ref custom_semidiscretization) #- # This tutorial describes the [semidiscretiations](@ref overview-semidiscretizations) of Trixi.jl # and explains how to extend them for custom tasks. From 5fec7f42121be7d01d8645fc91fe0da8567f3946 Mon Sep 17 00:00:00 2001 From: ArseniyKholod <119304909+ArseniyKholod@users.noreply.github.com> Date: Tue, 6 Feb 2024 20:52:50 +0100 Subject: [PATCH 247/263] Getting started with trixi (#1343) * 0th tutorial v1 * 0th tutorial v2 * 0th tutorial v3 (topic for developers) * 0th tutorial v4 * 0th tutorial v5 * 0th tutorial v6 * 0th tutorial v6.1 * 0th tutorial v6.2 * 0th tutorial v7 (new example) * 0th tutorial v8 * 0th tutorial v8.1 * 0th tutorial v9 New structure + new usage example * 0th tutorial v9.1 * 0th tutorial v9.2 * Revert "0th tutorial v9.2" This reverts commit e2da5c24c71ec5ebb86ead4da9e6dc33f8b2cf7f. * 0th tutorial v9.3 (test) * Revert "0th tutorial v9.3 (test)" This reverts commit 05d3d1c22729fc65f6a85bc224e0376bf7cc79ac. * 0th tutorial v9.3 (test) * 0th tutorial v9.3 (test checks without diff. prog.) * 0th tutorial v9.3 (test new diff. prog.) * 0th tutorial v9.3 (test new diff. prog. v2) * 0th tutorial v9.3 (test update of packages) * 0th tutorial v9.3 (test update of packages v2) * 0th tutorial v9.3 (downgrade Measurements.jl) * 0th tutorial v9.4 * 0th tutorial v9.5 * 0th tutorial review * 0th tutorial review 2 * 0th tutorial v9.6 * delete test files * Revert "rename into getting_started.jl" This reverts commit 6605ece69240d8bc850c6ef0b14b94beaac5eee6. * Update docs/make.jl Co-authored-by: Michael Schlottke-Lakemper * Update Project.toml Co-authored-by: Michael Schlottke-Lakemper * Update Project.toml Co-authored-by: Michael Schlottke-Lakemper * Update docs/make.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * rename into getting_started.jl * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started_with_Trixi.jl Co-authored-by: Michael Schlottke-Lakemper * correction of spelling errors * cleaning out directory * Correction according to the comments above * Trixi installation for Linux * Update getting_started.jl * cross-referencing correction * spelling * Update .gitignore Co-authored-by: Michael Schlottke-Lakemper * Update docs/make.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update .gitignore * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * new plot in Modifying an existing setup * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * julia/shell-formatting * Update getting_started.jl * Update getting_started.jl * Correction of Modifying part * Usage update * Update getting_started.jl * add Visualize the solution * spell check * correction * correction * add picture paraview * divide in two parts & correction * divide in 3 parts * Update docs/literate/src/files/getting_started.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update create_first_setup.jl * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update getting_started.jl * Update getting_started.jl * Update create_first_setup.jl * Update changing_trixi.jl * Update changing_trixi.jl * Update docs/literate/src/files/getting_started.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/getting_started.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/getting_started.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/getting_started.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/getting_started.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/getting_started.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/getting_started.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/getting_started.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/getting_started.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/getting_started.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * move files to subfolder * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update create_first_setup.jl * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/create_first_setup.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/changing_trixi.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/changing_trixi.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/changing_trixi.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/changing_trixi.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * Update docs/literate/src/files/changing_trixi.jl Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> * add transition between 2nd and 3rd parts * Update docs/make.jl Co-authored-by: Michael Schlottke-Lakemper * clear out folder * Update docs/literate/src/files/first_steps/getting_started.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/getting_started.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/getting_started.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update getting_started.jl * Update docs/literate/src/files/first_steps/getting_started.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/getting_started.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/getting_started.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/getting_started.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/getting_started.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/getting_started.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update getting_started.jl * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update create_first_setup.jl * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update create_first_setup.jl * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/changing_trixi.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/changing_trixi.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/changing_trixi.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/changing_trixi.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/changing_trixi.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/first_steps/changing_trixi.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * spelling * delete julia, tabs * add juliaup * add intro * rm * Apply suggestions from code review Co-authored-by: Daniel Doehring * Apply suggestions from code review Co-authored-by: Daniel Doehring * Update docs/literate/src/files/first_steps/getting_started.jl * Update docs/literate/src/files/first_steps/changing_trixi.jl Co-authored-by: Andrew Winters * Update docs/literate/src/files/first_steps/changing_trixi.jl Co-authored-by: Andrew Winters * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Andrew Winters * Update docs/literate/src/files/first_steps/create_first_setup.jl Co-authored-by: Andrew Winters * add save solution dt --------- Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Simon Candelaresi <10759273+SimonCan@users.noreply.github.com> Co-authored-by: Benedict <135045760+bgeihe@users.noreply.github.com> Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Co-authored-by: Daniel Doehring Co-authored-by: Andrew Winters --- .../src/files/first_steps/changing_trixi.jl | 77 +++++ .../files/first_steps/create_first_setup.jl | 268 ++++++++++++++++++ .../src/files/first_steps/getting_started.jl | 242 ++++++++++++++++ docs/literate/src/files/index.jl | 43 +-- docs/make.jl | 6 + 5 files changed, 618 insertions(+), 18 deletions(-) create mode 100644 docs/literate/src/files/first_steps/changing_trixi.jl create mode 100644 docs/literate/src/files/first_steps/create_first_setup.jl create mode 100644 docs/literate/src/files/first_steps/getting_started.jl diff --git a/docs/literate/src/files/first_steps/changing_trixi.jl b/docs/literate/src/files/first_steps/changing_trixi.jl new file mode 100644 index 00000000000..551377a6a71 --- /dev/null +++ b/docs/literate/src/files/first_steps/changing_trixi.jl @@ -0,0 +1,77 @@ +#src # Changing Trixi.jl itself + +# If you plan on editing Trixi.jl itself, you can download Trixi.jl locally and run it from +# the cloned directory. + + +# ## Cloning Trixi.jl + + +# ### Windows + +# If you are using Windows, you can clone Trixi.jl by using the GitHub Desktop tool: +# - If you do not have a GitHub account yet, create it on +# the [GitHub website](https://github.com/join). +# - Download and install [GitHub Desktop](https://desktop.github.com/) and then log in to +# your account. +# - Open GitHub Desktop, press `Ctrl+Shift+O`. +# - In the opened window, paste `trixi-framework/Trixi.jl` and choose the path to the folder where +# you want to save Trixi.jl. Then click `Clone` and Trixi.jl will be cloned to your computer. + +# Now you cloned Trixi.jl and only need to tell Julia to use the local clone as the package sources: +# - Open a terminal using `Win+r` and `cmd`. Navigate to the folder with the cloned Trixi.jl using `cd`. +# - Create a new directory `run`, enter it, and start Julia with the `--project=.` flag: +# ```shell +# mkdir run +# cd run +# julia --project=. +# ``` +# - Now run the following commands to install all relevant packages: +# ```julia +# using Pkg; Pkg.develop(PackageSpec(path="..")) # Tell Julia to use the local Trixi.jl clone +# Pkg.add(["OrdinaryDiffEq", "Plots"]) # Install additional packages +# ``` + +# Now you already installed Trixi.jl from your local clone. Note that if you installed Trixi.jl +# this way, you always have to start Julia with the `--project` flag set to your `run` directory, +# e.g., +# ```shell +# julia --project=. +# ``` +# if already inside the `run` directory. + + +# ### Linux + +# You can clone Trixi.jl to your computer by executing the following commands: +# ```shell +# git clone git@github.com:trixi-framework/Trixi.jl.git +# # If an error occurs, try the following: +# # git clone https://github.com/trixi-framework/Trixi.jl +# cd Trixi.jl +# mkdir run +# cd run +# julia --project=. -e 'using Pkg; Pkg.develop(PackageSpec(path=".."))' # Tell Julia to use the local Trixi.jl clone +# julia --project=. -e 'using Pkg; Pkg.add(["OrdinaryDiffEq", "Plots"])' # Install additional packages +# ``` +# Note that if you installed Trixi.jl this way, +# you always have to start Julia with the `--project` flag set to your `run` directory, e.g., +# ```shell +# julia --project=. +# ``` +# if already inside the `run` directory. + + +# ## Additional reading + +# To further delve into Trixi.jl, you may have a look at the following introductory tutorials. +# - [Introduction to DG methods](@ref scalar_linear_advection_1d) will teach you how to set up a +# simple way to approximate the solution of a hyperbolic partial differential equation. It will +# be especially useful to learn about the +# [Discontinuous Galerkin method](https://en.wikipedia.org/wiki/Discontinuous_Galerkin_method) +# and the way it is implemented in Trixi.jl. +# - [Adding a new scalar conservation law](@ref adding_new_scalar_equations) and +# [Adding a non-conservative equation](@ref adding_nonconservative_equation) +# describe how to add new physics models that are not yet included in Trixi.jl. +# - [Callbacks](@ref callbacks-id) gives an overview of how to regularly execute specific actions +# during a simulation, e.g., to store the solution or adapt the mesh. diff --git a/docs/literate/src/files/first_steps/create_first_setup.jl b/docs/literate/src/files/first_steps/create_first_setup.jl new file mode 100644 index 00000000000..906a6f93461 --- /dev/null +++ b/docs/literate/src/files/first_steps/create_first_setup.jl @@ -0,0 +1,268 @@ +#src # Create first setup + +# In this part of the introductory guide, we will create a first Trixi.jl setup as an extension of +# [`elixir_advection_basic.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_advection_basic.jl). +# Since Trixi.jl has a common basic structure for the setups, you can create your own by extending +# and modifying the following example. + +# Let's consider the linear advection equation for a state ``u = u(x, y, t)`` on the two-dimensional spatial domain +# ``[-1, 1] \times [-1, 1]`` with a source term +# ```math +# \frac{\partial}{\partial t}u + \frac{\partial}{\partial x} (0.2 u) - \frac{\partial}{\partial y} (0.7 u) = - 2 e^{-t} +# \sin\bigl(2 \pi (x - t) \bigr) \sin\bigl(2 \pi (y - t) \bigr), +# ``` +# with the initial condition +# ```math +# u(x, y, 0) = \sin\bigl(\pi x \bigr) \sin\bigl(\pi y \bigr), +# ``` +# and periodic boundary conditions. + +# The first step is to create and open a file with the .jl extension. You can do this with your +# favorite text editor (if you do not have one, we recommend [VS Code](https://code.visualstudio.com/)). +# In this file you will create your setup. + +# To be able to use functionalities of Trixi.jl, you always need to load Trixi.jl itself +# and the [OrdinaryDiffEq.jl](https://github.com/SciML/OrdinaryDiffEq.jl) package. + +using Trixi +using OrdinaryDiffEq + +# The next thing to do is to choose an equation that is suitable for your problem. To see all the +# currently implemented equations, take a look at +# [`src/equations`](https://github.com/trixi-framework/Trixi.jl/tree/main/src/equations). +# If you are interested in adding a new physics model that has not yet been implemented in +# Trixi.jl, take a look at the tutorials +# [Adding a new scalar conservation law](@ref adding_new_scalar_equations) or +# [Adding a non-conservative equation](@ref adding_nonconservative_equation). + +# The linear scalar advection equation in two spatial dimensions +# ```math +# \frac{\partial}{\partial t}u + \frac{\partial}{\partial x} (a_1 u) + \frac{\partial}{\partial y} (a_2 u) = 0 +# ``` +# is already implemented in Trixi.jl as +# [`LinearScalarAdvectionEquation2D`](@ref), for which we need to define a two-dimensional parameter +# `advection_velocity` describing the parameters ``a_1`` and ``a_2``. Appropriate for our problem is `(0.2, -0.7)`. + +advection_velocity = (0.2, -0.7) +equations = LinearScalarAdvectionEquation2D(advection_velocity) + +# To solve our problem numerically using Trixi.jl, we have to discretize the spatial +# domain, for which we set up a mesh. One of the most used meshes in Trixi.jl is the +# [`TreeMesh`](@ref). The spatial domain used is ``[-1, 1] \times [-1, 1]``. We set an initial number +# of elements in the mesh using `initial_refinement_level`, which describes the initial number of +# hierarchical refinements. In this simple case, the total number of elements is `2^initial_refinement_level` +# throughout the simulation. The variable `n_cells_max` is used to limit the number of elements in the mesh, +# which cannot be exceeded when using [adaptive mesh refinement](@ref Adaptive-mesh-refinement). + +# All minimum and all maximum coordinates must be combined into `Tuples`. + +coordinates_min = (-1.0, -1.0) +coordinates_max = ( 1.0, 1.0) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 4, + n_cells_max = 30_000) + +# To approximate the solution of the defined model, we create a [`DGSEM`](@ref) solver. +# The solution in each of the recently defined mesh elements will be approximated by a polynomial +# of degree `polydeg`. For more information about discontinuous Galerkin methods, +# check out the [Introduction to DG methods](@ref scalar_linear_advection_1d) tutorial. + +solver = DGSEM(polydeg=3) + +# Now we need to define an initial condition for our problem. All the already implemented +# initial conditions for [`LinearScalarAdvectionEquation2D`](@ref) can be found in +# [`src/equations/linear_scalar_advection_2d.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/src/equations/linear_scalar_advection_2d.jl). +# If you want to use, for example, a Gaussian pulse, it can be used as follows: +# ```julia +# initial_conditions = initial_condition_gauss +# ``` +# But to show you how an arbitrary initial condition can be implemented in a way suitable for +# Trixi.jl, we define our own initial conditions. +# ```math +# u(x, y, 0) = \sin\bigl(\pi x \bigr) \sin\bigl(\pi y \bigr). +# ``` +# The initial conditions function must take spatial coordinates, time and equation as arguments +# and returns an initial condition as a statically sized vector `SVector`. Following the same structure, you +# can define your own initial conditions. The time variable `t` can be unused in the initial +# condition, but might also be used to describe an analytical solution if known. If you use the +# initial condition as analytical solution, you can analyze your numerical solution by computing +# the error, see also the +# [section about analyzing the solution](https://trixi-framework.github.io/Trixi.jl/stable/callbacks/#Analyzing-the-numerical-solution). + +function initial_condition_sinpi(x, t, equations::LinearScalarAdvectionEquation2D) + scalar = sinpi(x[1]) * sinpi(x[2]) + return SVector(scalar) +end +initial_condition = initial_condition_sinpi + +# The next step is to define a function of the source term corresponding to our problem. +# ```math +# f(u, x, y, t) = - 2 e^{-t} \sin\bigl(2 \pi (x - t) \bigr) \sin\bigl(2 \pi (y - t) \bigr) +# ``` +# This function must take the state variable, the spatial coordinates, the time and the +# equation itself as arguments and returns the source term as a static vector `SVector`. + +function source_term_exp_sinpi(u, x, t, equations::LinearScalarAdvectionEquation2D) + scalar = - 2 * exp(-t) * sinpi(2*(x[1] - t)) * sinpi(2*(x[2] - t)) + return SVector(scalar) +end + +# Now we collect all the information that is necessary to define a spatial discretization, +# which leaves us with an ODE problem in time with a span from 0.0 to 1.0. +# This approach is commonly referred to as the method of lines. + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver; + source_terms = source_term_exp_sinpi) +tspan = (0.0, 1.0) +ode = semidiscretize(semi, tspan); + +# At this point, our problem is defined. We will use the `solve` function defined in +# [OrdinaryDiffEq.jl](https://github.com/SciML/OrdinaryDiffEq.jl) to get the solution. +# OrdinaryDiffEq.jl gives us the ability to customize the solver +# using callbacks without actually modifying it. Trixi.jl already has some implemented +# [Callbacks](@ref callbacks-id). The most widely used callbacks in Trixi.jl are +# [step control callbacks](https://docs.sciml.ai/DiffEqCallbacks/stable/step_control/) that are +# activated at the end of each time step to perform some actions, e.g. to print statistics. +# We will show you how to use some of the common callbacks. + +# To print a summary of the simulation setup at the beginning +# and to reset timers we use the [`SummaryCallback`](@ref). +# When the returned callback is executed directly, the current timer values are shown. + +summary_callback = SummaryCallback() + +# We also want to analyze the current state of the solution in regular intervals. +# The [`AnalysisCallback`](@ref) outputs some useful statistical information during the solving process +# every `interval` time steps. + +analysis_callback = AnalysisCallback(semi, interval = 5) + +# It is also possible to control the time step size using the [`StepsizeCallback`](@ref) if the time +# integration method isn't adaptive itself. To get more details, look at +# [CFL based step size control](@ref CFL-based-step-size-control). + +stepsize_callback = StepsizeCallback(cfl = 1.6) + +# To save the current solution in regular intervals we use the [`SaveSolutionCallback`](@ref). +# We would like to save the initial and final solutions as well. The data +# will be saved as HDF5 files located in the `out` folder. Afterwards it is possible to visualize +# a solution from saved files using Trixi2Vtk.jl and ParaView, which is described below in the +# section [Visualize the solution](@ref Visualize-the-solution). + +save_solution = SaveSolutionCallback(interval = 5, + save_initial_solution = true, + save_final_solution = true) + +# Alternatively, we have the option to print solution files at fixed time intervals. +# ```julua +# save_solution = SaveSolutionCallback(dt = 0.1, +# save_initial_solution = true, +# save_final_solution = true) +# ``` + +# Another useful callback is the [`SaveRestartCallback`](@ref). It saves information for restarting +# in regular intervals. We are interested in saving a restart file for the final solution as +# well. To perform a restart, you need to configure the restart setup in a special way, which is +# described in the section [Restart simulation](@ref restart). + +save_restart = SaveRestartCallback(interval = 100, save_final_restart = true) + +# Create a `CallbackSet` to collect all callbacks so that they can be passed to the `solve` +# function. + +callbacks = CallbackSet(summary_callback, analysis_callback, stepsize_callback, save_solution, + save_restart) + +# The last step is to choose the time integration method. OrdinaryDiffEq.jl defines a wide range of +# [ODE solvers](https://docs.sciml.ai/DiffEqDocs/latest/solvers/ode_solve/), e.g. +# `CarpenterKennedy2N54(williamson_condition = false)`. We will pass the ODE +# problem, the ODE solver and the callbacks to the `solve` function. Also, to use +# `StepsizeCallback`, we must explicitly specify the initial trial time step `dt`, the selected +# value is not important, because it will be overwritten by the `StepsizeCallback`. And there is no +# need to save every step of the solution, we are only interested in the final result. + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, + save_everystep = false, callback = callbacks); + +# Finally, we print the timer summary. + +summary_callback() + +# Now you can plot the solution as shown below, analyze it and improve the stability, accuracy or +# efficiency of your setup. + + +# ## Visualize the solution + +# In the previous part of the tutorial, we calculated the final solution of the given problem, now we want +# to visualize it. A more detailed explanation of visualization methods can be found in the section +# [Visualization](@ref visualization). + + +# ### Using Plots.jl + +# The first option is to use the [Plots.jl](https://github.com/JuliaPlots/Plots.jl) package +# directly after calculations, when the solution is saved in the `sol` variable. We load the +# package and use the `plot` function. + +using Plots +plot(sol) + +# To show the mesh on the plot, we need to extract the visualization data from the solution as +# a [`PlotData2D`](@ref) object. Mesh extraction is possible using the [`getmesh`](@ref) function. +# Plots.jl has the `plot!` function that allows you to modify an already built graph. + +pd = PlotData2D(sol) +plot!(getmesh(pd)) + + +# ### Using Trixi2Vtk.jl + +# Another way to visualize a solution is to extract it from a saved HDF5 file. After we used the +# `solve` function with [`SaveSolutionCallback`](@ref) there is a file with the final solution. +# It is located in the `out` folder and is named as follows: `solution_index.h5`. The `index` +# is the final time step of the solution that is padded to 6 digits with zeros from the beginning. +# With [Trixi2Vtk](@ref) you can convert the HDF5 output file generated by Trixi.jl into a VTK file. +# This can be used in visualization tools such as [ParaView](https://www.paraview.org) or +# [VisIt](https://visit.llnl.gov) to plot the solution. The important thing is that currently +# Trixi2Vtk.jl supports conversion only for solutions in 2D and 3D spatial domains. + +# If you haven't added Trixi2Vtk.jl to your project yet, you can add it as follows. +# ```julia +# import Pkg +# Pkg.add(["Trixi2Vtk"]) +# ``` +# Now we load the Trixi2Vtk.jl package and convert the file `out/solution_000018.h5` with +# the final solution using the [`trixi2vtk`](@ref) function saving the resulting file in the +# `out` folder. + +using Trixi2Vtk +trixi2vtk(joinpath("out", "solution_000018.h5"), output_directory="out") + +# Now two files `solution_000018.vtu` and `solution_000018_celldata.vtu` have been generated in the +# `out` folder. The first one contains all the information for visualizing the solution, the +# second one contains all the cell-based or discretization-based information. + +# Now let's visualize the solution from the generated files in ParaView. Follow this short +# instruction to get the visualization. +# - Download, install and open [ParaView](https://www.paraview.org/download/). +# - Press `Ctrl+O` and select the generated files `solution_000018.vtu` and +# `solution_000018_celldata.vtu` from the `out` folder. +# - In the upper-left corner in the Pipeline Browser window, left-click on the eye-icon near +# `solution_000018.vtu`. +# - In the lower-left corner in the Properties window, change the Coloring from Solid Color to +# scalar. This already generates the visualization of the final solution. +# - Now let's add the mesh to the visualization. In the upper-left corner in the +# Pipeline Browser window, left-click on the eye-icon near `solution_000018_celldata.vtu`. +# - In the lower-left corner in the Properties window, change the Representation from Surface +# to Wireframe. Then a white grid should appear on the visualization. +# Now, if you followed the instructions exactly, you should get a similar image as shown in the +# section [Using Plots.jl](@ref Using-Plots.jl): + +# ![paraview_trixi2vtk_example](https://github.com/trixi-framework/Trixi.jl/assets/119304909/0c29139b-6c5d-4d5c-86e1-f4ebc95aca7e) + +# After completing this tutorial you are able to set up your own simulations with +# Trixi.jl. If you have an interest in contributing to Trixi.jl as a developer, refer to the third +# part of the introduction titled [Changing Trixi.jl itself](@ref changing_trixi). + +Sys.rm("out"; recursive=true, force=true) #hide #md \ No newline at end of file diff --git a/docs/literate/src/files/first_steps/getting_started.jl b/docs/literate/src/files/first_steps/getting_started.jl new file mode 100644 index 00000000000..2bfaf33b5fc --- /dev/null +++ b/docs/literate/src/files/first_steps/getting_started.jl @@ -0,0 +1,242 @@ +#src # Getting started + +# Trixi.jl is a numerical simulation framework for conservation laws and +# is written in the [Julia programming language](https://julialang.org/). +# This tutorial is intended for beginners in Julia and Trixi.jl. +# After reading it, you will know how to install Julia and Trixi.jl on your computer, +# and you will be able to download setup files from our GitHub repository, modify them, +# and run simulations. + +# The contents of this tutorial: +# - [Julia installation](@ref Julia-installation) +# - [Trixi.jl installation](@ref Trixi.jl-installation) +# - [Running a simulation](@ref Running-a-simulation) +# - [Getting an existing setup file](@ref Getting-an-existing-setup-file) +# - [Modifying an existing setup](@ref Modifying-an-existing-setup) + + +# ## Julia installation + +# Trixi.jl is compatible with the latest stable release of Julia. Additional details regarding Julia +# support can be found in the [`README.md`](https://github.com/trixi-framework/Trixi.jl#installation) +# file. The current default Julia installation is managed through `juliaup`. You may follow our +# concise installation guidelines for Windows, Linux, and MacOS provided below. In the event of any +# issues during the installation process, please consult the official +# [Julia installation instruction](https://julialang.org/downloads/). + + +# ### Windows + +# - Open a terminal by pressing `Win+r` and entering `cmd` in the opened window. +# - To install Julia, execute the following command in the terminal: +# ```shell +# winget install julia -s msstore +# ``` +# - Verify the successful installation of Julia by executing the following command in the terminal: +# ```shell +# julia +# ``` +# To exit Julia, execute `exit()` or press `Ctrl+d`. + + +# ### Linux and MacOS + +# - To install Julia, run the following command in a terminal: +# ```shell +# curl -fsSL https://install.julialang.org | sh +# ``` +# Follow the instructions displayed in the terminal during the installation process. +# - If an error occurs during the execution of the previous command, you may need to install +# `curl`. On Ubuntu-type systems, you can use the following command: +# ```shell +# sudo apt install curl +# ``` +# After installing `curl`, repeat the first step once more to proceed with Julia installation. +# - Verify the successful installation of Julia by executing the following command in the terminal: +# ```shell +# julia +# ``` +# To exit Julia, execute `exit()` or press `Ctrl+d`. + + +# ## Trixi.jl installation + +# Trixi.jl and its related tools are registered Julia packages, thus their installation +# happens inside Julia. +# For a smooth workflow experience with Trixi.jl, you need to install +# [Trixi.jl](https://github.com/trixi-framework/Trixi.jl), +# [OrdinaryDiffEq.jl](https://github.com/SciML/OrdinaryDiffEq.jl), and +# [Plots.jl](https://github.com/JuliaPlots/Plots.jl). + +# - Open a terminal and start Julia. +# - Execute following commands: +# ```julia +# import Pkg +# Pkg.add(["OrdinaryDiffEq", "Plots", "Trixi"]) +# ``` + +# Now you have installed all these +# packages. [OrdinaryDiffEq.jl](https://github.com/SciML/OrdinaryDiffEq.jl) provides time +# integration schemes used by Trixi.jl and [Plots.jl](https://github.com/JuliaPlots/Plots.jl) +# can be used to directly visualize Trixi.jl results from the Julia REPL. + + +# ## Usage + + +# ### Running a simulation + +# To get you started, Trixi.jl has a large set +# of [example setups](https://github.com/trixi-framework/Trixi.jl/tree/main/examples), that can be +# taken as a basis for your future investigations. In Trixi.jl, we call these setup files +# "elixirs", since they contain Julia code that takes parts of Trixi.jl and combines them into +# something new. + +# Any of the examples can be executed using the [`trixi_include`](@ref) +# function. `trixi_include(...)` expects +# a single string argument with a path to a file containing Julia code. +# For convenience, the [`examples_dir`](@ref) function returns a path to the +# [`examples`](https://github.com/trixi-framework/Trixi.jl/tree/main/examples) +# folder, which has been locally downloaded while installing Trixi.jl. +# `joinpath(...)` can be used to join path components into a full path. + +# Let's execute a short two-dimensional problem setup. It approximates the solution of +# the compressible Euler equations in 2D for an ideal gas ([`CompressibleEulerEquations2D`](@ref)) +# with a weak blast wave as the initial condition. + +# Start Julia in a terminal and execute the following code: + +# ```julia +# using Trixi, OrdinaryDiffEq +# trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_euler_ec.jl")) +# ``` +using Trixi, OrdinaryDiffEq #hide #md +trixi_include(@__MODULE__,joinpath(examples_dir(), "tree_2d_dgsem", "elixir_euler_ec.jl")) #hide #md + +# To analyze the result of the computation, we can use the Plots.jl package and the function +# `plot(...)`, which creates a graphical representation of the solution. `sol` is a variable +# defined in the executed example and it contains the solution at the final moment of the simulation. + +using Plots +plot(sol) + +# To obtain a list of all Trixi.jl elixirs execute +# [`get_examples`](@ref). It returns the paths to all example setups. + +get_examples() + +# Editing an existing elixir is the best way to start your first own investigation using Trixi.jl. + + +# ### Getting an existing setup file + +# To edit an existing elixir, you first have to find a suitable one and then copy it to a local +# folder. Let's have a look at how to download the `elixir_euler_ec.jl` elixir used in the previous +# section from the [Trixi.jl GitHub repository](https://github.com/trixi-framework/Trixi.jl). + +# - All examples are located inside +# the [`examples`](https://github.com/trixi-framework/Trixi.jl/tree/main/examples) folder. +# - Navigate to the +# file [`elixir_euler_ec.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/tree_2d_dgsem/elixir_euler_ec.jl). +# - Right-click the `Raw` button on the right side of the webpage and choose `Save as...` +# (or `Save Link As...`). +# - Choose a folder and save the file. + + +# ### Modifying an existing setup + +# As an example, we will change the initial condition for calculations that occur in +# `elixir_euler_ec.jl`. In this example we consider the compressible Euler equations in two spatial +# dimensions, +# ```math +# \frac{\partial}{\partial t} +# \begin{pmatrix} +# \rho \\ \rho v_1 \\ \rho v_2 \\ \rho e +# \end{pmatrix} +# + +# \frac{\partial}{\partial x} +# \begin{pmatrix} +# \rho v_1 \\ \rho v_1^2 + p \\ \rho v_1 v_2 \\ (\rho e + p) v_1 +# \end{pmatrix} +# + +# \frac{\partial}{\partial y} +# \begin{pmatrix} +# \rho v_2 \\ \rho v_1 v_2 \\ \rho v_2^2 + p \\ (\rho e + p) v_2 +# \end{pmatrix} +# = +# \begin{pmatrix} +# 0 \\ 0 \\ 0 \\ 0 +# \end{pmatrix}, +# ``` +# for an ideal gas with the specific heat ratio ``\gamma``. +# Here, ``\rho`` is the density, ``v_1`` and ``v_2`` are the velocities, ``e`` is the specific +# total energy, and +# ```math +# p = (\gamma - 1) \left( \rho e - \frac{1}{2} \rho (v_1^2 + v_2^2) \right) +# ``` +# is the pressure. +# Initial conditions consist of initial values for ``\rho``, ``\rho v_1``, +# ``\rho v_2`` and ``\rho e``. +# One of the common initial conditions for the compressible Euler equations is a simple density +# wave. Let's implement it. + +# - Open the downloaded file `elixir_euler_ec.jl` with a text editor. +# - Go to the line with the following code: +# ```julia +# initial_condition = initial_condition_weak_blast_wave +# ``` +# Here, [`initial_condition_weak_blast_wave`](@ref) is used as the initial condition. +# - Comment out the line using the `#` symbol: +# ```julia +# # initial_condition = initial_condition_weak_blast_wave +# ``` +# - Now you can create your own initial conditions. Add the following code after the +# commented line: + +function initial_condition_density_waves(x, t, equations::CompressibleEulerEquations2D) + v1 = 0.1 # velocity along x-axis + v2 = 0.2 # velocity along y-axis + rho = 1.0 + 0.98 * sinpi(sum(x) - t * (v1 + v2)) # density wave profile + p = 20 # pressure + rho_e = p / (equations.gamma - 1) + 1/2 * rho * (v1^2 + v2^2) + return SVector(rho, rho*v1, rho*v2, rho_e) +end +initial_condition = initial_condition_density_waves + +# - Execute the following code one more time, but instead of `path/to/file` paste the path to the +# `elixir_euler_ec.jl` file that you just edited. +# ```julia +# using Trixi +# trixi_include(path/to/file) +# using Plots +# plot(sol) +# ``` +# Then you will obtain a new solution from running the simulation with a different initial +# condition. + +trixi_include(@__MODULE__,joinpath(examples_dir(), "tree_2d_dgsem", "elixir_euler_ec.jl"), #hide #md + initial_condition=initial_condition) #hide #md +pd = PlotData2D(sol) #hide #md +p1 = plot(pd["rho"]) #hide #md +p2 = plot(pd["v1"], clim=(0.05, 0.15)) #hide #md +p3 = plot(pd["v2"], clim=(0.15, 0.25)) #hide #md +p4 = plot(pd["p"], clim=(10, 30)) #hide #md +plot(p1, p2, p3, p4) #hide #md + +# To get exactly the same picture execute the following. +# ```julia +# pd = PlotData2D(sol) +# p1 = plot(pd["rho"]) +# p2 = plot(pd["v1"], clim=(0.05, 0.15)) +# p3 = plot(pd["v2"], clim=(0.15, 0.25)) +# p4 = plot(pd["p"], clim=(10, 30)) +# plot(p1, p2, p3, p4) +# ``` + +# Feel free to make further changes to the initial condition to observe different solutions. + +# Now you are able to download, modify and execute simulation setups for Trixi.jl. To explore +# further details on setting up a new simulation with Trixi.jl, refer to the second part of +# the introduction titled [Create first setup](@ref create_first_setup). + +Sys.rm("out"; recursive=true, force=true) #hide #md \ No newline at end of file diff --git a/docs/literate/src/files/index.jl b/docs/literate/src/files/index.jl index 26637e5b24b..1fc025d84da 100644 --- a/docs/literate/src/files/index.jl +++ b/docs/literate/src/files/index.jl @@ -14,20 +14,27 @@ # There are tutorials for the following topics: -# ### [1 Introduction to DG methods](@ref scalar_linear_advection_1d) +# ### [1 First steps in Trixi.jl](@ref getting_started) +#- +# This tutorial provides guidance for getting started with Trixi.jl, and Julia as well. It outlines +# the installation procedures for both Julia and Trixi.jl, the execution of Trixi.jl elixirs, the +# fundamental structure of a Trixi.jl setup, the visualization of results, and the development +# process for Trixi.jl. + +# ### [2 Introduction to DG methods](@ref scalar_linear_advection_1d) #- # This tutorial gives an introduction to discontinuous Galerkin (DG) methods with the example of the # scalar linear advection equation in 1D. Starting with some theoretical explanations, we first implement # a raw version of a discontinuous Galerkin spectral element method (DGSEM). Then, we will show how # to use features of Trixi.jl to achieve the same result. -# ### [2 DGSEM with flux differencing](@ref DGSEM_FluxDiff) +# ### [3 DGSEM with flux differencing](@ref DGSEM_FluxDiff) #- # To improve stability often the flux differencing formulation of the DGSEM (split form) is used. # We want to present the idea and formulation on a basic 1D level. Then, we show how this formulation # can be implemented in Trixi.jl and analyse entropy conservation for two different flux combinations. -# ### [3 Shock capturing with flux differencing and stage limiter](@ref shock_capturing) +# ### [4 Shock capturing with flux differencing and stage limiter](@ref shock_capturing) #- # Using the flux differencing formulation, a simple procedure to capture shocks is a hybrid blending # of a high-order DG method and a low-order subcell finite volume (FV) method. We present the idea on a @@ -35,20 +42,20 @@ # explained and added to an exemplary simulation of the Sedov blast wave with the 2D compressible Euler # equations. -# ### [4 Non-periodic boundary conditions](@ref non_periodic_boundaries) +# ### [5 Non-periodic boundary conditions](@ref non_periodic_boundaries) #- # Thus far, all examples used periodic boundaries. In Trixi.jl, you can also set up a simulation with # non-periodic boundaries. This tutorial presents the implementation of the classical Dirichlet # boundary condition with a following example. Then, other non-periodic boundaries are mentioned. -# ### [5 DG schemes via `DGMulti` solver](@ref DGMulti_1) +# ### [6 DG schemes via `DGMulti` solver](@ref DGMulti_1) #- # This tutorial is about the more general DG solver [`DGMulti`](@ref), introduced [here](@ref DGMulti). # We are showing some examples for this solver, for instance with discretization nodes by Gauss or # triangular elements. Moreover, we present a simple way to include pre-defined triangulate meshes for # non-Cartesian domains using the package [StartUpDG.jl](https://github.com/jlchan/StartUpDG.jl). -# ### [6 Other SBP schemes (FD, CGSEM) via `DGMulti` solver](@ref DGMulti_2) +# ### [7 Other SBP schemes (FD, CGSEM) via `DGMulti` solver](@ref DGMulti_2) #- # Supplementary to the previous tutorial about DG schemes via the `DGMulti` solver we now present # the possibility for `DGMulti` to use other SBP schemes via the package @@ -56,7 +63,7 @@ # For instance, we show how to set up a finite differences (FD) scheme and a continuous Galerkin # (CGSEM) method. -# ### [7 Upwind FD SBP schemes](@ref upwind_fdsbp) +# ### [8 Upwind FD SBP schemes](@ref upwind_fdsbp) #- # General SBP schemes can not only be used via the [`DGMulti`](@ref) solver but # also with a general `DG` solver. In particular, upwind finite difference SBP @@ -64,42 +71,42 @@ # schemes in the `DGMulti` framework, the interface is based on the package # [SummationByPartsOperators.jl](https://github.com/ranocha/SummationByPartsOperators.jl). -# ### [8 Adding a new scalar conservation law](@ref adding_new_scalar_equations) +# ### [9 Adding a new scalar conservation law](@ref adding_new_scalar_equations) #- # This tutorial explains how to add a new physics model using the example of the cubic conservation # law. First, we define the equation using a `struct` `CubicEquation` and the physical flux. Then, # the corresponding standard setup in Trixi.jl (`mesh`, `solver`, `semi` and `ode`) is implemented # and the ODE problem is solved by OrdinaryDiffEq's `solve` method. -# ### [9 Adding a non-conservative equation](@ref adding_nonconservative_equation) +# ### [10 Adding a non-conservative equation](@ref adding_nonconservative_equation) #- # In this part, another physics model is implemented, the nonconservative linear advection equation. # We run two different simulations with different levels of refinement and compare the resulting errors. -# ### [10 Parabolic terms](@ref parabolic_terms) +# ### [11 Parabolic terms](@ref parabolic_terms) #- # This tutorial describes how parabolic terms are implemented in Trixi.jl, e.g., # to solve the advection-diffusion equation. -# ### [11 Adding new parabolic terms](@ref adding_new_parabolic_terms) +# ### [12 Adding new parabolic terms](@ref adding_new_parabolic_terms) #- # This tutorial describes how new parabolic terms can be implemented using Trixi.jl. -# ### [12 Adaptive mesh refinement](@ref adaptive_mesh_refinement) +# ### [13 Adaptive mesh refinement](@ref adaptive_mesh_refinement) #- # Adaptive mesh refinement (AMR) helps to increase the accuracy in sensitive or turbolent regions while # not wasting resources for less interesting parts of the domain. This leads to much more efficient # simulations. This tutorial presents the implementation strategy of AMR in Trixi.jl, including the use of # different indicators and controllers. -# ### [13 Structured mesh with curvilinear mapping](@ref structured_mesh_mapping) +# ### [14 Structured mesh with curvilinear mapping](@ref structured_mesh_mapping) #- # In this tutorial, the use of Trixi.jl's structured curved mesh type [`StructuredMesh`](@ref) is explained. # We present the two basic option to initialize such a mesh. First, the curved domain boundaries # of a circular cylinder are set by explicit boundary functions. Then, a fully curved mesh is # defined by passing the transformation mapping. -# ### [14 Unstructured meshes with HOHQMesh.jl](@ref hohqmesh_tutorial) +# ### [15 Unstructured meshes with HOHQMesh.jl](@ref hohqmesh_tutorial) #- # The purpose of this tutorial is to demonstrate how to use the [`UnstructuredMesh2D`](@ref) # functionality of Trixi.jl. This begins by running and visualizing an available unstructured @@ -108,26 +115,26 @@ # software in the Trixi.jl ecosystem, and then run a simulation using Trixi.jl on said mesh. # In the end, the tutorial briefly explains how to simulate an example using AMR via `P4estMesh`. -# ### [15 P4est mesh from gmsh](@ref p4est_from_gmsh) +# ### [16 P4est mesh from gmsh](@ref p4est_from_gmsh) #- # This tutorial describes how to obtain a [`P4estMesh`](@ref) from an existing mesh generated # by [`gmsh`](https://gmsh.info/) or any other meshing software that can export to the Abaqus # input `.inp` format. The tutorial demonstrates how edges/faces can be associated with boundary conditions based on the physical nodesets. -# ### [16 Explicit time stepping](@ref time_stepping) +# ### [17 Explicit time stepping](@ref time_stepping) #- # This tutorial is about time integration using [OrdinaryDiffEq.jl](https://github.com/SciML/OrdinaryDiffEq.jl). # It explains how to use their algorithms and presents two types of time step choices - with error-based # and CFL-based adaptive step size control. -# ### [17 Differentiable programming](@ref differentiable_programming) +# ### [18 Differentiable programming](@ref differentiable_programming) #- # This part deals with some basic differentiable programming topics. For example, a Jacobian, its # eigenvalues and a curve of total energy (through the simulation) are calculated and plotted for # a few semidiscretizations. Moreover, we calculate an example for propagating errors with Measurement.jl # at the end. -# ### [18 Custom semidiscretization](@ref custom_semidiscretization) +# ### [19 Custom semidiscretization](@ref custom_semidiscretization) #- # This tutorial describes the [semidiscretiations](@ref overview-semidiscretizations) of Trixi.jl # and explains how to extend them for custom tasks. diff --git a/docs/make.jl b/docs/make.jl index 7fce3b31e24..584f151b5f3 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -48,6 +48,12 @@ end # "title" => ["subtitle 1" => ("folder 1", "filename 1.jl"), # "subtitle 2" => ("folder 2", "filename 2.jl")] files = [ + # Topic: introduction + "First steps in Trixi.jl" => [ + "Getting started" => ("first_steps", "getting_started.jl"), + "Create first setup" => ("first_steps", "create_first_setup.jl"), + "Changing Trixi.jl itself" => ("first_steps", "changing_trixi.jl"), + ], # Topic: DG semidiscretizations "Introduction to DG methods" => "scalar_linear_advection_1d.jl", "DGSEM with flux differencing" => "DGSEM_FluxDiff.jl", From fa18c8bab4c6855a989691ede7f8947c5e3ea945 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 7 Feb 2024 07:19:49 +0100 Subject: [PATCH 248/263] fix benchmarks configuration (#1837) --- benchmark/benchmarks.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/benchmarks.jl b/benchmark/benchmarks.jl index a3f7d1d2569..15d1d96c05f 100644 --- a/benchmark/benchmarks.jl +++ b/benchmark/benchmarks.jl @@ -55,5 +55,5 @@ let SUITE["latency"]["euler_2d"] = @benchmarkable run( `$(Base.julia_cmd()) -e 'using Trixi; trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_euler_kelvin_helmholtz_instability.jl"), tspan=(0.0, 1.0e-10), save_restart=TrivialCallback(), save_solution=TrivialCallback())'`) seconds=60 SUITE["latency"]["mhd_2d"] = @benchmarkable run( - `$(Base.julia_cmd()) -e 'using Trixi; trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_mhd_blast_wave.jl"), tspan=(0.0, 1.0e-10), save_restart=TrivialCallback(), save_solution=TrivialCallback())'`) seconds=60 + `$(Base.julia_cmd()) -e 'using Trixi; trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_mhd_blast_wave.jl"), tspan=(0.0, 1.0e-10), save_solution=TrivialCallback())'`) seconds=60 end From 8c6d9bc727219e470f56f3317997f17eb5615842 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 7 Feb 2024 07:27:40 +0100 Subject: [PATCH 249/263] Make CI fail if Codecov fails (#1834) --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2e388366fc8..86bd3f836e5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -134,7 +134,8 @@ jobs: file: ./lcov.info flags: unittests name: codecov-umbrella - fail_ci_if_error: false + fail_ci_if_error: true + verbose: true token: ${{ secrets.CODECOV_TOKEN }} # The standard setup of Coveralls is just annoying for parallel builds, see, e.g., # https://github.com/trixi-framework/Trixi.jl/issues/691 From 4fb8160c397df922e8fc4906a5c8f92225c21ecd Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Wed, 7 Feb 2024 08:43:50 +0100 Subject: [PATCH 250/263] Update compat bounds for Makie, CairoMakie (#1836) --- Project.toml | 2 +- docs/Project.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index e99b08e0e81..9b624c7733c 100644 --- a/Project.toml +++ b/Project.toml @@ -68,7 +68,7 @@ LinearAlgebra = "1" LinearMaps = "2.7, 3.0" LoopVectorization = "0.12.118" MPI = "0.20" -Makie = "0.19" +Makie = "0.19, 0.20" MuladdMacro = "0.2.2" Octavian = "0.3.5" OffsetArrays = "1.3" diff --git a/docs/Project.toml b/docs/Project.toml index 3a091f5b4f1..cc48aeb8ed9 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -12,7 +12,7 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Trixi2Vtk = "bc1476a1-1ca6-4cc3-950b-c312b255ff95" [compat] -CairoMakie = "0.6, 0.7, 0.8, 0.9, 0.10" +CairoMakie = "0.6, 0.7, 0.8, 0.9, 0.10, 0.11" Documenter = "1" ForwardDiff = "0.10" HOHQMesh = "0.1, 0.2" From 3e6872bd486a4cfcc94bd2c31b2fe8510670a7a2 Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Wed, 7 Feb 2024 09:06:07 +0100 Subject: [PATCH 251/263] Enable CI testing on Apple Silicon (#1830) * Enable CI testing on Apple Silicon * Use `threaded` instead of `threaded_legacy` --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86bd3f836e5..9d398f187b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -101,6 +101,10 @@ jobs: os: windows-latest arch: x64 trixi_test: threaded + - version: '1.9' + os: macos-14 + arch: arm64 + trixi_test: threaded steps: - uses: actions/checkout@v4 - uses: julia-actions/setup-julia@v1 From fe6a5276e1ea92a23d4897ca33a057288f277e8f Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 7 Feb 2024 10:37:22 +0100 Subject: [PATCH 252/263] coverallsapp at v2 (#1777) Co-authored-by: Michael Schlottke-Lakemper --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9d398f187b3..a7dfe033a90 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -200,7 +200,7 @@ jobs: coverage = merge_coverage_counts(coverage) @show covered_lines, total_lines = get_summary(coverage) LCOV.writefile("./lcov.info", coverage) - - uses: coverallsapp/github-action@master + - uses: coverallsapp/github-action@v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} path-to-lcov: ./lcov.info From 4369c1c00b3e44de43bba95adeedfb37fd09551c Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 14 Feb 2024 07:56:08 +0100 Subject: [PATCH 253/263] Fix formatter to older version (#1843) * Fix formatter to older version * fix JuliaFormatter version also in utils folder * Update utils/trixi-format-file.jl Co-authored-by: Arpit Babbar * Update utils/trixi-format.jl Co-authored-by: Arpit Babbar * Apply suggestions from code review Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * format --------- Co-authored-by: Arpit Babbar Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> --- .github/workflows/FormatCheck.yml | 2 +- utils/trixi-format-file.jl | 3 ++- utils/trixi-format.jl | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/FormatCheck.yml b/.github/workflows/FormatCheck.yml index a733cb7cc21..7297f1c3ff5 100644 --- a/.github/workflows/FormatCheck.yml +++ b/.github/workflows/FormatCheck.yml @@ -29,7 +29,7 @@ jobs: # TODO: Change the call below to # format(".") run: | - julia -e 'using Pkg; Pkg.add(PackageSpec(name = "JuliaFormatter"))' + julia -e 'using Pkg; Pkg.add(PackageSpec(name = "JuliaFormatter", version="1.0.45"))' julia -e 'using JuliaFormatter; format(["benchmark", "examples", "ext", "src", "test", "utils"])' - name: Format check run: | diff --git a/utils/trixi-format-file.jl b/utils/trixi-format-file.jl index c4d8e7c9032..9b9a0e4949c 100755 --- a/utils/trixi-format-file.jl +++ b/utils/trixi-format-file.jl @@ -2,7 +2,8 @@ using Pkg Pkg.activate(; temp = true, io = devnull) -Pkg.add("JuliaFormatter"; preserve = PRESERVE_ALL, io = devnull) +Pkg.add(PackageSpec(name = "JuliaFormatter", version = "1.0.45"); preserve = PRESERVE_ALL, + io = devnull) using JuliaFormatter: format_file diff --git a/utils/trixi-format.jl b/utils/trixi-format.jl index d1e7efa656a..63f14078807 100755 --- a/utils/trixi-format.jl +++ b/utils/trixi-format.jl @@ -2,7 +2,8 @@ using Pkg Pkg.activate(; temp = true, io = devnull) -Pkg.add("JuliaFormatter"; preserve = PRESERVE_ALL, io = devnull) +Pkg.add(PackageSpec(name = "JuliaFormatter", version = "1.0.45"); preserve = PRESERVE_ALL, + io = devnull) using JuliaFormatter: format From 4f33837e3c95b5af21057850c30ef603a9191d86 Mon Sep 17 00:00:00 2001 From: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> Date: Thu, 15 Feb 2024 08:50:30 +0100 Subject: [PATCH 254/263] Use `trixi_include` from TrixiBase.jl (#1832) * Use `trixi_include` from TrixiBase.jl * Add compat entry for TrixiBase.jl * Remove unused functions * Use `TrixiBase.walkexpr` * Fix docs * Add TrixiBase.jl API reference * Add TrixiBase to docs dependencies * Import `TrixiBase` * Remove `find_assignment` * Add TrixiBase to makedocs modules * 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> --- Project.toml | 2 + docs/Project.toml | 2 + docs/make.jl | 4 +- docs/src/conventions.md | 10 +- docs/src/reference-trixibase.md | 9 ++ src/Trixi.jl | 3 +- src/auxiliary/precompile.jl | 3 - src/auxiliary/special_elixirs.jl | 158 +------------------------------ src/callbacks_step/trivial.jl | 4 +- test/test_unit.jl | 97 ------------------- 10 files changed, 31 insertions(+), 261 deletions(-) create mode 100644 docs/src/reference-trixibase.md diff --git a/Project.toml b/Project.toml index 9b624c7733c..b4a06a70688 100644 --- a/Project.toml +++ b/Project.toml @@ -45,6 +45,7 @@ TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" Triangulate = "f7e6ffb2-c36d-4f8f-a77e-16e897189344" TriplotBase = "981d1d27-644d-49a2-9326-4793e63143c3" TriplotRecipes = "808ab39a-a642-4abf-81ff-4cb34ebbffa3" +TrixiBase = "9a0f1c46-06d5-4909-a5a3-ce25d3fa3284" [weakdeps] Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" @@ -95,6 +96,7 @@ TimerOutputs = "0.5.7" Triangulate = "2.0" TriplotBase = "0.1" TriplotRecipes = "0.1" +TrixiBase = "0.1.1" julia = "1.8" [extras] diff --git a/docs/Project.toml b/docs/Project.toml index cc48aeb8ed9..3b8d169fdb8 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -10,6 +10,7 @@ OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Trixi2Vtk = "bc1476a1-1ca6-4cc3-950b-c312b255ff95" +TrixiBase = "9a0f1c46-06d5-4909-a5a3-ce25d3fa3284" [compat] CairoMakie = "0.6, 0.7, 0.8, 0.9, 0.10, 0.11" @@ -23,3 +24,4 @@ OrdinaryDiffEq = "6.49.1" Plots = "1.9" Test = "1" Trixi2Vtk = "0.3" +TrixiBase = "0.1.1" diff --git a/docs/make.jl b/docs/make.jl index 584f151b5f3..946b803b71e 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -8,6 +8,7 @@ end using Trixi using Trixi2Vtk +using TrixiBase # Get Trixi.jl root directory trixi_root_dir = dirname(@__DIR__) @@ -82,7 +83,7 @@ tutorials = create_tutorials(files) # Make documentation makedocs( # Specify modules for which docstrings should be shown - modules = [Trixi, Trixi2Vtk], + modules = [Trixi, TrixiBase, Trixi2Vtk], # Set sitename to Trixi.jl sitename = "Trixi.jl", # Provide additional formatting options @@ -128,6 +129,7 @@ makedocs( "Troubleshooting and FAQ" => "troubleshooting.md", "Reference" => [ "Trixi.jl" => "reference-trixi.md", + "TrixiBase.jl" => "reference-trixibase.md", "Trixi2Vtk.jl" => "reference-trixi2vtk.md" ], "Authors" => "authors.md", diff --git a/docs/src/conventions.md b/docs/src/conventions.md index dab1b8533a5..4f9e0ec4e67 100644 --- a/docs/src/conventions.md +++ b/docs/src/conventions.md @@ -47,10 +47,12 @@ Trixi.jl is distributed with several examples in the form of elixirs, small Julia scripts containing everything to set up and run a simulation. Working interactively from the Julia REPL with these scripts can be quite convenient while for exploratory research and development of Trixi.jl. For example, you -can use the convenience function [`trixi_include`](@ref) to `include` an elixir -with some modified arguments. To enable this, it is helpful to use a consistent -naming scheme in elixirs, since [`trixi_include`](@ref) can only perform simple -replacements. Some standard variables names are +can use the convenience function +[`trixi_include`](@ref) +to `include` an elixir with some modified arguments. To enable this, it is +helpful to use a consistent naming scheme in elixirs, since +[`trixi_include`](@ref) +can only perform simple replacements. Some standard variables names are - `polydeg` for the polynomial degree of a solver - `surface_flux` for the numerical flux at surfaces diff --git a/docs/src/reference-trixibase.md b/docs/src/reference-trixibase.md new file mode 100644 index 00000000000..c7a970f88ec --- /dev/null +++ b/docs/src/reference-trixibase.md @@ -0,0 +1,9 @@ +# TrixiBase.jl API + +```@meta +CurrentModule = TrixiBase +``` + +```@autodocs +Modules = [TrixiBase] +``` diff --git a/src/Trixi.jl b/src/Trixi.jl index 8d74fbc9736..ea72fbc915f 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -70,6 +70,7 @@ using Triangulate: Triangulate, TriangulateIO, triangulate export TriangulateIO # for type parameter in DGMultiMesh using TriplotBase: TriplotBase using TriplotRecipes: DGTriPseudocolor +@reexport using TrixiBase: TrixiBase, trixi_include @reexport using SimpleUnPack: @unpack using SimpleUnPack: @pack! using DataStructures: BinaryHeap, FasterForward, extract_all! @@ -129,7 +130,7 @@ include("callbacks_step/callbacks_step.jl") include("callbacks_stage/callbacks_stage.jl") include("semidiscretization/semidiscretization_euler_gravity.jl") -# `trixi_include` and special elixirs such as `convergence_test` +# Special elixirs such as `convergence_test` include("auxiliary/special_elixirs.jl") # Plot recipes and conversion functions to visualize results with Plots.jl diff --git a/src/auxiliary/precompile.jl b/src/auxiliary/precompile.jl index 9cec502f6cb..4d5399b5ba3 100644 --- a/src/auxiliary/precompile.jl +++ b/src/auxiliary/precompile.jl @@ -577,9 +577,6 @@ function _precompile_manual_() @assert Base.precompile(Tuple{typeof(show), Base.TTY, lbm_collision_callback_type}) @assert Base.precompile(Tuple{typeof(show), IOContext{Base.TTY}, MIME"text/plain", lbm_collision_callback_type}) - - # infrastructure, special elixirs - @assert Base.precompile(Tuple{typeof(trixi_include), String}) end @assert Base.precompile(Tuple{typeof(init_mpi)}) diff --git a/src/auxiliary/special_elixirs.jl b/src/auxiliary/special_elixirs.jl index 5fdd9aea0c5..d71a27aa96a 100644 --- a/src/auxiliary/special_elixirs.jl +++ b/src/auxiliary/special_elixirs.jl @@ -5,58 +5,6 @@ @muladd begin #! format: noindent -# Note: We can't call the method below `Trixi.include` since that is created automatically -# inside `module Trixi` to `include` source files and evaluate them within the global scope -# of `Trixi`. However, users will want to evaluate in the global scope of `Main` or something -# similar to manage dependencies on their own. -""" - trixi_include([mod::Module=Main,] elixir::AbstractString; kwargs...) - -`include` the file `elixir` and evaluate its content in the global scope of module `mod`. -You can override specific assignments in `elixir` by supplying keyword arguments. -It's basic purpose is to make it easier to modify some parameters while running Trixi.jl from the -REPL. Additionally, this is used in tests to reduce the computational burden for CI while still -providing examples with sensible default values for users. - -Before replacing assignments in `elixir`, the keyword argument `maxiters` is inserted -into calls to `solve` and `Trixi.solve` with it's default value used in the SciML ecosystem -for ODEs, see the "Miscellaneous" section of the -[documentation](https://docs.sciml.ai/DiffEqDocs/stable/basics/common_solver_opts/). - -# Examples - -```jldoctest -julia> redirect_stdout(devnull) do - trixi_include(@__MODULE__, joinpath(examples_dir(), "tree_1d_dgsem", "elixir_advection_extended.jl"), - tspan=(0.0, 0.1)) - sol.t[end] - end -[ Info: You just called `trixi_include`. Julia may now compile the code, please be patient. -0.1 -``` -""" -function trixi_include(mod::Module, elixir::AbstractString; kwargs...) - # Check that all kwargs exist as assignments - code = read(elixir, String) - expr = Meta.parse("begin \n$code \nend") - expr = insert_maxiters(expr) - - for (key, val) in kwargs - # This will throw an error when `key` is not found - find_assignment(expr, key) - end - - # Print information on potential wait time only in non-parallel case - if !mpi_isparallel() - @info "You just called `trixi_include`. Julia may now compile the code, please be patient." - end - Base.include(ex -> replace_assignments(insert_maxiters(ex); kwargs...), mod, elixir) -end - -function trixi_include(elixir::AbstractString; kwargs...) - trixi_include(Main, elixir; kwargs...) -end - """ convergence_test([mod::Module=Main,] elixir::AbstractString, iterations; kwargs...) @@ -177,112 +125,15 @@ end # Helper methods used in the functions defined above -# Apply the function `f` to `expr` and all sub-expressions recursively. -walkexpr(f, expr::Expr) = f(Expr(expr.head, (walkexpr(f, arg) for arg in expr.args)...)) -walkexpr(f, x) = f(x) - -# Insert the keyword argument `maxiters` into calls to `solve` and `Trixi.solve` -# with default value `10^5` if it is not already present. -function insert_maxiters(expr) - maxiters_default = 10^5 - - expr = walkexpr(expr) do x - if x isa Expr - is_plain_solve = x.head === Symbol("call") && x.args[1] === Symbol("solve") - is_trixi_solve = (x.head === Symbol("call") && x.args[1] isa Expr && - x.args[1].head === Symbol(".") && - x.args[1].args[1] === Symbol("Trixi") && - x.args[1].args[2] isa QuoteNode && - x.args[1].args[2].value === Symbol("solve")) - - if is_plain_solve || is_trixi_solve - # Do nothing if `maxiters` is already set as keyword argument... - for arg in x.args - # This detects the case where `maxiters` is set as keyword argument - # without or before a semicolon - if (arg isa Expr && arg.head === Symbol("kw") && - arg.args[1] === Symbol("maxiters")) - return x - end - - # This detects the case where maxiters is set as keyword argument - # after a semicolon - if (arg isa Expr && arg.head === Symbol("parameters")) - # We need to check each keyword argument listed here - for nested_arg in arg.args - if (nested_arg isa Expr && - nested_arg.head === Symbol("kw") && - nested_arg.args[1] === Symbol("maxiters")) - return x - end - end - end - end - - # ...and insert it otherwise. - push!(x.args, Expr(Symbol("kw"), Symbol("maxiters"), maxiters_default)) - end - end - return x - end - - return expr -end - -# Replace assignments to `key` in `expr` by `key = val` for all `(key,val)` in `kwargs`. -function replace_assignments(expr; kwargs...) - # replace explicit and keyword assignments - expr = walkexpr(expr) do x - if x isa Expr - for (key, val) in kwargs - if (x.head === Symbol("=") || x.head === :kw) && - x.args[1] === Symbol(key) - x.args[2] = :($val) - # dump(x) - end - end - end - return x - end - - return expr -end - -# find a (keyword or common) assignment to `destination` in `expr` -# and return the assigned value -function find_assignment(expr, destination) - # declare result to be able to assign to it in the closure - local result - found = false - - # find explicit and keyword assignments - walkexpr(expr) do x - if x isa Expr - if (x.head === Symbol("=") || x.head === :kw) && - x.args[1] === Symbol(destination) - result = x.args[2] - found = true - # dump(x) - end - end - return x - end - - if !found - throw(ArgumentError("assignment `$destination` not found in expression")) - end - - result -end - -# searches the parameter that specifies the mesh reslution in the elixir +# Searches for the assignment that specifies the mesh resolution in the elixir function extract_initial_resolution(elixir, kwargs) code = read(elixir, String) expr = Meta.parse("begin \n$code \nend") try # get the initial_refinement_level from the elixir - initial_refinement_level = find_assignment(expr, :initial_refinement_level) + initial_refinement_level = TrixiBase.find_assignment(expr, + :initial_refinement_level) if haskey(kwargs, :initial_refinement_level) return kwargs[:initial_refinement_level] @@ -294,7 +145,8 @@ function extract_initial_resolution(elixir, kwargs) if isa(e, ArgumentError) try # get cells_per_dimension from the elixir - cells_per_dimension = eval(find_assignment(expr, :cells_per_dimension)) + cells_per_dimension = eval(TrixiBase.find_assignment(expr, + :cells_per_dimension)) if haskey(kwargs, :cells_per_dimension) return kwargs[:cells_per_dimension] diff --git a/src/callbacks_step/trivial.jl b/src/callbacks_step/trivial.jl index a55b7d85b13..fb93cf96c0c 100644 --- a/src/callbacks_step/trivial.jl +++ b/src/callbacks_step/trivial.jl @@ -8,8 +8,8 @@ """ TrivialCallback() -A callback that does nothing. This can be useful to disable some callbacks -easily via [`trixi_include`](@ref). +A callback that does nothing. This can be useful to disable some callbacks easily via +[`trixi_include`](@ref). """ function TrivialCallback() DiscreteCallback(trivial_callback, trivial_callback, diff --git a/test/test_unit.jl b/test/test_unit.jl index 7943d952f71..3b8dc3c4331 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1529,103 +1529,6 @@ end @test mesh.boundary_faces[:entire_boundary] == [1, 2] end - -@testset "trixi_include" begin - @trixi_testset "Basic" begin - example = """ - x = 4 - """ - - filename = tempname() - try - open(filename, "w") do file - write(file, example) - end - - # Use `@trixi_testset`, which wraps code in a temporary module, and call - # `trixi_include` with `@__MODULE__` in order to isolate this test. - @test_warn "You just called" trixi_include(@__MODULE__, filename) - @test @isdefined x - @test x == 4 - - @test_warn "You just called" trixi_include(@__MODULE__, filename, x = 7) - @test x == 7 - - @test_throws "assignment `y` not found in expression" trixi_include(@__MODULE__, - filename, - y = 3) - finally - rm(filename, force = true) - end - end - - @trixi_testset "With `solve` Without `maxiters`" begin - # `trixi_include` assumes this to be the `solve` function of OrdinaryDiffEq, - # and therefore tries to insert the kwarg `maxiters`, which will fail here. - example = """ - solve() = 0 - x = solve() - """ - - filename = tempname() - try - open(filename, "w") do file - write(file, example) - end - - # Use `@trixi_testset`, which wraps code in a temporary module, and call - # `trixi_include` with `@__MODULE__` in order to isolate this test. - @test_throws "no method matching solve(; maxiters::Int64)" trixi_include(@__MODULE__, - filename) - - @test_throws "no method matching solve(; maxiters::Int64)" trixi_include(@__MODULE__, - filename, - maxiters = 3) - finally - rm(filename, force = true) - end - end - - @trixi_testset "With `solve` with `maxiters`" begin - # We need another example file that we include with `Base.include` first, in order to - # define the `solve` method without `trixi_include` trying to insert `maxiters` kwargs. - # Then, we can test that `trixi_include` inserts the kwarg in the `solve()` call. - example1 = """ - solve(; maxiters=0) = maxiters - """ - - example2 = """ - x = solve() - """ - - filename1 = tempname() - filename2 = tempname() - try - open(filename1, "w") do file - write(file, example1) - end - open(filename2, "w") do file - write(file, example2) - end - - # Use `@trixi_testset`, which wraps code in a temporary module, and call - # `Base.include` and `trixi_include` with `@__MODULE__` in order to isolate this test. - Base.include(@__MODULE__, filename1) - @test_warn "You just called" trixi_include(@__MODULE__, filename2) - @test @isdefined x - # This is the default `maxiters` inserted by `trixi_include` - @test x == 10^5 - - @test_warn "You just called" trixi_include(@__MODULE__, filename2, - maxiters = 7) - # Test that `maxiters` got overwritten - @test x == 7 - finally - rm(filename1, force = true) - rm(filename2, force = true) - end - end -end end end #module From 08c6034139451ba03be2abb6748bcd402f151b5d Mon Sep 17 00:00:00 2001 From: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> Date: Thu, 15 Feb 2024 21:37:50 +0100 Subject: [PATCH 255/263] Don't export `TrixiBase` (#1846) --- src/Trixi.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Trixi.jl b/src/Trixi.jl index ea72fbc915f..8ab8085d4e8 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -70,7 +70,8 @@ using Triangulate: Triangulate, TriangulateIO, triangulate export TriangulateIO # for type parameter in DGMultiMesh using TriplotBase: TriplotBase using TriplotRecipes: DGTriPseudocolor -@reexport using TrixiBase: TrixiBase, trixi_include +@reexport using TrixiBase: trixi_include +using TrixiBase: TrixiBase @reexport using SimpleUnPack: @unpack using SimpleUnPack: @pack! using DataStructures: BinaryHeap, FasterForward, extract_all! From a872bc55e545baf36be91a949940434ae89f3426 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 16 Feb 2024 06:24:33 +0100 Subject: [PATCH 256/263] set version to v0.6.9 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index b4a06a70688..10bf79cf9a5 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.6.9-pre" +version = "0.6.9" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 29e173eb5f955771755cc28342e07c9903204327 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 16 Feb 2024 06:24:52 +0100 Subject: [PATCH 257/263] set development version to v0.6.10-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 10bf79cf9a5..af3e6b4d078 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.6.9" +version = "0.6.10-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From 3c9374bb6c336be32c56d5c13b213ae3900269a3 Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Tue, 20 Feb 2024 16:15:48 +0100 Subject: [PATCH 258/263] Classic LWR traffic flow (#1840) * Add classic LWR traffic flow model to Trixi * fmt * shorten * Update examples/structured_1d_dgsem/elixir_traffic_flow_lwr_greenlight.jl * Update examples/structured_1d_dgsem/elixir_traffic_flow_lwr_greenlight.jl * rm IC const, fmt * add davis wave speed estimate for upcoming change * news and md * Use euler * fmt * Update examples/structured_1d_dgsem/elixir_traffic_flow_lwr_greenlight.jl * Update examples/tree_1d_dgsem/elixir_traffic_flow_lwr_trafficjam.jl * Update NEWS.md Co-authored-by: Andrew Winters * Andrew's suggestions * Apply suggestions from code review Co-authored-by: Hendrik Ranocha * add domain of u * back to carpenter kennedy * Update NEWS.md Co-authored-by: Andrew Winters --------- Co-authored-by: Andrew Winters Co-authored-by: Hendrik Ranocha --- NEWS.md | 1 + README.md | 2 +- .../elixir_traffic_flow_lwr_greenlight.jl | 80 ++++++++++++ .../elixir_traffic_flow_lwr_convergence.jl | 54 ++++++++ .../elixir_traffic_flow_lwr_trafficjam.jl | 82 +++++++++++++ src/Trixi.jl | 3 +- src/equations/equations.jl | 5 + src/equations/traffic_flow_lwr_1d.jl | 116 ++++++++++++++++++ test/test_structured_1d.jl | 15 +++ test/test_tree_1d.jl | 3 + test/test_tree_1d_traffic_flow_lwr.jl | 42 +++++++ 11 files changed, 401 insertions(+), 2 deletions(-) create mode 100644 examples/structured_1d_dgsem/elixir_traffic_flow_lwr_greenlight.jl create mode 100644 examples/tree_1d_dgsem/elixir_traffic_flow_lwr_convergence.jl create mode 100644 examples/tree_1d_dgsem/elixir_traffic_flow_lwr_trafficjam.jl create mode 100644 src/equations/traffic_flow_lwr_1d.jl create mode 100644 test/test_tree_1d_traffic_flow_lwr.jl diff --git a/NEWS.md b/NEWS.md index 02a723fca45..feccd1f9852 100644 --- a/NEWS.md +++ b/NEWS.md @@ -12,6 +12,7 @@ for human readability. - Different boundary conditions for quad/hex meshes in Abaqus format, even if not generated by HOHQMesh, can now be digested by Trixi in 2D and 3D. - Subcell (positivity) limiting support for nonlinear variables in 2D for `TreeMesh` +- Added Lighthill-Whitham-Richards (LWR) traffic model ## Changes when updating to v0.6 from v0.5.x diff --git a/README.md b/README.md index c531ab4d1a4..71370d3478e 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ installation and postprocessing procedures. Its features include: * Hyperbolic diffusion equations for elliptic problems * Lattice-Boltzmann equations (D2Q9 and D3Q27 schemes) * Shallow water equations - * Several scalar conservation laws (e.g., linear advection, Burgers' equation) + * Several scalar conservation laws (e.g., linear advection, Burgers' equation, LWR traffic flow) * Multi-physics simulations * [Self-gravitating gas dynamics](https://github.com/trixi-framework/paper-self-gravitating-gas-dynamics) * Shared-memory parallelization via multithreading diff --git a/examples/structured_1d_dgsem/elixir_traffic_flow_lwr_greenlight.jl b/examples/structured_1d_dgsem/elixir_traffic_flow_lwr_greenlight.jl new file mode 100644 index 00000000000..e5badf14451 --- /dev/null +++ b/examples/structured_1d_dgsem/elixir_traffic_flow_lwr_greenlight.jl @@ -0,0 +1,80 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### + +equations = TrafficFlowLWREquations1D() + +solver = DGSEM(polydeg = 3, surface_flux = FluxHLL(min_max_speed_davis)) + +coordinates_min = (-1.0,) # minimum coordinate +coordinates_max = (1.0,) # maximum coordinate +cells_per_dimension = (64,) + +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, + periodicity = false) + +# Example inspired from http://www.clawpack.org/riemann_book/html/Traffic_flow.html#Example:-green-light +# Green light that at x = 0 which switches at t = 0 from red to green. +# To the left there are cars bumper to bumper, to the right there are no cars. +function initial_condition_greenlight(x, t, equation::TrafficFlowLWREquations1D) + scalar = x[1] < 0.0 ? 1.0 : 0.0 + + return SVector(scalar) +end + +############################################################################### +# Specify non-periodic boundary conditions + +# Assume that there are always cars waiting at the left +function inflow(x, t, equations::TrafficFlowLWREquations1D) + return initial_condition_greenlight(coordinates_min, t, equations) +end +boundary_condition_inflow = BoundaryConditionDirichlet(inflow) + +# Cars may leave the modeled domain +function boundary_condition_outflow(u_inner, orientation, normal_direction, x, t, + surface_flux_function, + equations::TrafficFlowLWREquations1D) + # Calculate the boundary flux entirely from the internal solution state + flux = Trixi.flux(u_inner, orientation, equations) + + return flux +end + +boundary_conditions = (x_neg = boundary_condition_inflow, + x_pos = boundary_condition_outflow) + +initial_condition = initial_condition_greenlight + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.5) +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.2) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + stepsize_callback) + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 42, # 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/tree_1d_dgsem/elixir_traffic_flow_lwr_convergence.jl b/examples/tree_1d_dgsem/elixir_traffic_flow_lwr_convergence.jl new file mode 100644 index 00000000000..59258018f8c --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_traffic_flow_lwr_convergence.jl @@ -0,0 +1,54 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### + +equations = TrafficFlowLWREquations1D() + +# Use first order finite volume to prevent oscillations at the shock +solver = DGSEM(polydeg = 3, surface_flux = flux_hll) + +coordinates_min = 0.0 # minimum coordinate +coordinates_max = 2.0 # maximum coordinate + +# Create a uniformly refined mesh with periodic boundaries +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 4, + n_cells_max = 30_000) + +############################################################################### +# Specify non-periodic boundary conditions + +initial_condition = initial_condition_convergence_test +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_convergence_test) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 2.0) +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.6) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + stepsize_callback) + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(), + dt = 42, # 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/tree_1d_dgsem/elixir_traffic_flow_lwr_trafficjam.jl b/examples/tree_1d_dgsem/elixir_traffic_flow_lwr_trafficjam.jl new file mode 100644 index 00000000000..d3a17b513fc --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_traffic_flow_lwr_trafficjam.jl @@ -0,0 +1,82 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### + +equations = TrafficFlowLWREquations1D() + +# Use first order finite volume to prevent oscillations at the shock +solver = DGSEM(polydeg = 0, surface_flux = flux_lax_friedrichs) + +coordinates_min = -1.0 # minimum coordinate +coordinates_max = 1.0 # maximum coordinate + +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 9, + n_cells_max = 30_000, + periodicity = false) + +# Example taken from http://www.clawpack.org/riemann_book/html/Traffic_flow.html#Example:-Traffic-jam +# Discontinuous initial condition (Riemann Problem) leading to a shock that moves to the left. +# The shock corresponds to the traffic congestion. +function initial_condition_traffic_jam(x, t, equation::TrafficFlowLWREquations1D) + scalar = x[1] < 0.0 ? 0.5 : 1.0 + + return SVector(scalar) +end + +############################################################################### +# Specify non-periodic boundary conditions + +function outflow(x, t, equations::TrafficFlowLWREquations1D) + return initial_condition_traffic_jam(coordinates_min, t, equations) +end +boundary_condition_outflow = BoundaryConditionDirichlet(outflow) + +function boundary_condition_inflow(u_inner, orientation, normal_direction, x, t, + surface_flux_function, + equations::TrafficFlowLWREquations1D) + # Calculate the boundary flux entirely from the internal solution state + flux = Trixi.flux(u_inner, orientation, equations) + + return flux +end + +boundary_conditions = (x_neg = boundary_condition_outflow, + x_pos = boundary_condition_inflow) + +initial_condition = initial_condition_traffic_jam + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.5) +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.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + stepsize_callback) + +############################################################################### +# run the simulation + +# Note: Be careful when increasing the polynomial degree and switching from first order finite volume +# to some actual DG method - in that case, you should also exchange the ODE solver. +sol = solve(ode, Euler(), + dt = 42, # 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/Trixi.jl b/src/Trixi.jl index 8ab8085d4e8..bf0986084af 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -157,7 +157,8 @@ export AcousticPerturbationEquations2D, ShallowWaterTwoLayerEquations1D, ShallowWaterTwoLayerEquations2D, ShallowWaterEquationsQuasi1D, LinearizedEulerEquations2D, - PolytropicEulerEquations2D + PolytropicEulerEquations2D, + TrafficFlowLWREquations1D export LaplaceDiffusion1D, LaplaceDiffusion2D, LaplaceDiffusion3D, CompressibleNavierStokesDiffusion1D, CompressibleNavierStokesDiffusion2D, diff --git a/src/equations/equations.jl b/src/equations/equations.jl index c041bf117ba..65875a2a7e5 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -507,4 +507,9 @@ include("linearized_euler_2d.jl") abstract type AbstractEquationsParabolic{NDIMS, NVARS, GradientVariables} <: AbstractEquations{NDIMS, NVARS} end + +# Lighthill-Witham-Richards (LWR) traffic flow model +abstract type AbstractTrafficFlowLWREquations{NDIMS, NVARS} <: + AbstractEquations{NDIMS, NVARS} end +include("traffic_flow_lwr_1d.jl") end # @muladd diff --git a/src/equations/traffic_flow_lwr_1d.jl b/src/equations/traffic_flow_lwr_1d.jl new file mode 100644 index 00000000000..a4d2613a5c8 --- /dev/null +++ b/src/equations/traffic_flow_lwr_1d.jl @@ -0,0 +1,116 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +@doc raw""" + TrafficFlowLWREquations1D + +The classic Lighthill-Witham Richards (LWR) model for 1D traffic flow. +The car density is denoted by $u \in [0, 1]$ and +the maximum possible speed (e.g. due to speed limits) is $v_{\text{max}}$. +```math +\partial_t u + v_{\text{max}} \partial_1 [u (1 - u)] = 0 +``` +For more details see e.g. Section 11.1 of +- Randall LeVeque (2002) +Finite Volume Methods for Hyperbolic Problems +[DOI: 10.1017/CBO9780511791253]https://doi.org/10.1017/CBO9780511791253 +""" +struct TrafficFlowLWREquations1D{RealT <: Real} <: AbstractTrafficFlowLWREquations{1, 1} + v_max::RealT + + function TrafficFlowLWREquations1D(v_max = 1.0) + new{typeof(v_max)}(v_max) + end +end + +varnames(::typeof(cons2cons), ::TrafficFlowLWREquations1D) = ("car-density",) +varnames(::typeof(cons2prim), ::TrafficFlowLWREquations1D) = ("car-density",) + +""" + initial_condition_convergence_test(x, t, equations::TrafficFlowLWREquations1D) + +A smooth initial condition used for convergence tests. +""" +function initial_condition_convergence_test(x, t, equations::TrafficFlowLWREquations1D) + c = 2.0 + A = 1.0 + L = 1 + f = 1 / L + omega = 2 * pi * f + scalar = c + A * sin(omega * (x[1] - t)) + + return SVector(scalar) +end + +""" + source_terms_convergence_test(u, x, t, equations::TrafficFlowLWREquations1D) + +Source terms used for convergence tests in combination with +[`initial_condition_convergence_test`](@ref). +""" +@inline function source_terms_convergence_test(u, x, t, + equations::TrafficFlowLWREquations1D) + # Same settings as in `initial_condition` + c = 2.0 + A = 1.0 + L = 1 + f = 1 / L + omega = 2 * pi * f + du = omega * cos(omega * (x[1] - t)) * + (-1 - equations.v_max * (2 * sin(omega * (x[1] - t)) + 3)) + + return SVector(du) +end + +# Calculate 1D flux in for a single point +@inline function flux(u, orientation::Integer, equations::TrafficFlowLWREquations1D) + return SVector(equations.v_max * u[1] * (1.0 - u[1])) +end + +# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation +@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, + equations::TrafficFlowLWREquations1D) + λ_max = max(abs(equations.v_max * (1.0 - 2 * u_ll[1])), + abs(equations.v_max * (1.0 - 2 * u_rr[1]))) +end + +# Calculate minimum and maximum wave speeds for HLL-type fluxes +@inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer, + equations::TrafficFlowLWREquations1D) + jac_L = equations.v_max * (1.0 - 2 * u_ll[1]) + jac_R = equations.v_max * (1.0 - 2 * u_rr[1]) + + λ_min = min(jac_L, jac_R) + λ_max = max(jac_L, jac_R) + + return λ_min, λ_max +end + +@inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer, + equations::TrafficFlowLWREquations1D) + min_max_speed_naive(u_ll, u_rr, orientation, equations) +end + +@inline function max_abs_speeds(u, equations::TrafficFlowLWREquations1D) + return (abs(equations.v_max * (1.0 - 2 * u[1])),) +end + +# Convert conservative variables to primitive +@inline cons2prim(u, equations::TrafficFlowLWREquations1D) = u + +# Convert conservative variables to entropy variables +@inline cons2entropy(u, equations::TrafficFlowLWREquations1D) = u + +# Calculate entropy for a conservative state `cons` +@inline entropy(u::Real, ::TrafficFlowLWREquations1D) = 0.5 * u^2 +@inline entropy(u, equations::TrafficFlowLWREquations1D) = entropy(u[1], equations) + +# Calculate total energy for a conservative state `cons` +@inline energy_total(u::Real, ::TrafficFlowLWREquations1D) = 0.5 * u^2 +@inline energy_total(u, equations::TrafficFlowLWREquations1D) = energy_total(u[1], + equations) +end # @muladd diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index f0eecfa9acd..fea06554c57 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -138,6 +138,21 @@ end @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000 end end + +@trixi_testset "elixir_traffic_flow_lwr_greenlight.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_traffic_flow_lwr_greenlight.jl"), + l2=[0.2005523261652845], + linf=[0.5052827913468407]) + # 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 diff --git a/test/test_tree_1d.jl b/test/test_tree_1d.jl index 4654f6313f7..8b470278ffd 100644 --- a/test/test_tree_1d.jl +++ b/test/test_tree_1d.jl @@ -47,6 +47,9 @@ isdir(outdir) && rm(outdir, recursive = true) # FDSBP methods on the TreeMesh include("test_tree_1d_fdsbp.jl") + + # Traffic flow LWR + include("test_tree_1d_traffic_flow_lwr.jl") end # Coverage test for all initial conditions diff --git a/test/test_tree_1d_traffic_flow_lwr.jl b/test/test_tree_1d_traffic_flow_lwr.jl new file mode 100644 index 00000000000..54412e314b3 --- /dev/null +++ b/test/test_tree_1d_traffic_flow_lwr.jl @@ -0,0 +1,42 @@ +module TestExamples1DTrafficFlowLWR + +using Test +using Trixi + +include("test_trixi.jl") + +EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_1d_dgsem") + +@testset "Traffic-flow LWR" begin +#! format: noindent + +@trixi_testset "elixir_traffic_flow_lwr_convergence.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_traffic_flow_lwr_convergence.jl"), + l2=[0.0008455067389588569], + linf=[0.004591951086623913]) + # 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_traffic_flow_lwr_trafficjam.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_traffic_flow_lwr_trafficjam.jl"), + l2=[0.1761758135539748], linf=[0.5]) + # 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 + +end # module From c5e743aa1b229562132e3bbfbd936e995404739f Mon Sep 17 00:00:00 2001 From: Simon Candelaresi <10759273+SimonCan@users.noreply.github.com> Date: Tue, 20 Feb 2024 18:38:26 +0000 Subject: [PATCH 259/263] WIP: Sc/polytropic 2d wave speed (#1816) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added coupling converters. * Added generic converter_function for structured 2d meshes. * Added example elixir for coupling converters. * Cleaned up converter coupling elixir. * Added equations in coupling converters. * Added converter functions. * Added identity converter function. * Autoformat for converter coupling implementation. * Added coupled converter elixir. * Corrected file name of coupled converters test. * Removed redundant doc string. * Added function signature in doc string. * Removed coverage_override in coupled tests. * Removed old commented code. * Update make.jl Added interface coupling docs to the main menu. * Update make.jl Moved converter coupling section. * Create coupling.md * Update coupling.md Added some documentation on coupling converters. * Removed troublesome AnalysisCallbackCoupled from test. * Chenged coupling converter function. * Changed coupling converter function and updated tests. * Sepcialized coupling function call. * Removed volume coupling from documentation to avoit confusion. * Update src/coupling_converters/coupling_converters.jl Co-authored-by: Hendrik Ranocha * Removed redundant converter function for coupling. * Removed redundant coupling converter file mentioned in some files. * Autoreformatted. * Removed old coupled elixir and replaced it with one using converter functions. * Updated errors for coupled tests. * Corrected test results for coupled equations. * Corrected comment. * Removed coupled test from special tests. * Removed coupled test from specials. * Chaned the coupling function to the identity. * Updated coupling tests. * Updated errors for coupled test. * Added advice about binary compatability for coupled equations in the documentation. * Typo. * Added numerical fluxes. * Corrected rs copy routine. Now loop over this semi's components. * Reformatted equations source file. * Removed problemating include of time_integration.jl. * Removed export of deleted methods. * Reverted to old version of compressible Euler multicomponent with no support for structured grid. * Renamed documentation file for multi-physics coupling. * Renamed doc reference. * Update src/semidiscretization/semidiscretization_coupled.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/src/multi-physics_coupling.md Co-authored-by: Michael Schlottke-Lakemper * Update docs/src/multi-physics_coupling.md Co-authored-by: Michael Schlottke-Lakemper * Update docs/src/multi-physics_coupling.md Co-authored-by: Michael Schlottke-Lakemper * Reinstated structured_2d_dgsem coupled in special tests. * Update examples/structured_2d_dgsem/elixir_advection_coupled.jl Co-authored-by: Michael Schlottke-Lakemper * Renamed CouplingFunction to CouplingConverter. * Update src/semidiscretization/semidiscretization_coupled.jl Co-authored-by: Michael Schlottke-Lakemper * Cleaned the copy of coupled boundary values. * Reduced time span for example coupling elixir. * Removed redundant loop. * Applied formatter. * Removed default coupling covnerter function. * Moved coupling converter function into elixir. * Apply suggestions from code review Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/make.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Removed coupling_converters.jl from the include. * Corrected introduced issue with coupling boundary copy. The latest change to clean up the boundary copying introduced a bug related to the determination of the wrong node indices. This is now corrected. * Corrected comment on final simulation time. * Updated errors for coupled test to reflect changed final simulation time. * Added miladd. * Corrected coordinate finding in semidiscretization_coupled. * Fixed issued related to memory allocation. * Corrected loop over semidiscretization. * Removed commented out code. * Fixed type instability with loops over semidiscretizations using lispy tuple programming. * Removed obsolete code. * Fixed another typa instability in coupled semidiscretization. * Cleaning up of the coupled semidiscretization. * Autoformatted coupled semidiscretization. * Fixed last type instability in coupling. * Autoformatter on semidiscretization. * Fixed bug in boundary values copy that arose when coupling multiple systems. * aplpied autoformatter on coupled semidiscretization. * Extended the structured 2d example elixir for the coupled advection to 4 semidiscretizations. This hase two purpuses: 1. Users are given an example fro 2d coupling avoiding common pitfalls. 2. This increases the code coverege for the test. * Updated test results for coupled advection in 2d to reflect the 4 semidiscretizations that are now used. * Added correct errors for tests for the coupled adveciton equations in structured 2d. * Update examples/structured_2d_dgsem/elixir_advection_coupled.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * Update examples/structured_2d_dgsem/elixir_advection_coupled.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * Update src/semidiscretization/semidiscretization_coupled.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * Update src/semidiscretization/semidiscretization_coupled.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * Update src/semidiscretization/semidiscretization_coupled.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * Update src/semidiscretization/semidiscretization_coupled.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * Update src/semidiscretization/semidiscretization_coupled.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * Update src/semidiscretization/semidiscretization_coupled.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * Update src/semidiscretization/semidiscretization_coupled.jl Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> * Corrected foreach_enumerate implementation. * Fix closing parens * Remove unused recursive rhs! * Pass equations to converter function * Apply formatting * Reverted copy_to_coupled_boundary to previou version to avoid type instability. * Corrected computation of coupled semidiscretizations and fixed memory issue. * Removed redundant nelements function, as it is no longer used. * Applied autoformatter. * Added max_abs_speed_naive( and max_abs_speed_naive for PolytropicEulerEquations2D. * Reverted coupling elixir to main branch version. The modified version should be part of a different PR. * Removed some modified coupling code as this should be part of a different PR. * Reverted changes on ooupling semidiscretization as this should be part of a different PR. * Reverted changes partaining the coupling PR. * Removed changes partaining coupling PR. * REverted to version including elixir_euler_warm_bubble.jl tests. * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Andrew Winters * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Andrew Winters * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Andrew Winters * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Andrés Rueda-Ramírez * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Andrés Rueda-Ramírez * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Daniel Doehring * Added consistency and rotation test for LAx-friedrich fluxes for polytropic equations in 2d. * Applied auto-formatter on polytropic 2d equation. * Update src/equations/polytropic_euler_2d.jl Co-authored-by: Andrew Winters --------- Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Hendrik Ranocha Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> Co-authored-by: Andrew Winters Co-authored-by: Andrés Rueda-Ramírez Co-authored-by: Daniel Doehring Co-authored-by: iomsn --- src/equations/polytropic_euler_2d.jl | 40 ++++++++++++++++++++++++++++ test/test_unit.jl | 24 +++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/src/equations/polytropic_euler_2d.jl b/src/equations/polytropic_euler_2d.jl index f5d2f7b0bad..e900fd64073 100644 --- a/src/equations/polytropic_euler_2d.jl +++ b/src/equations/polytropic_euler_2d.jl @@ -301,6 +301,46 @@ end return abs(v1) + c, abs(v2) + c end +# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation as the +# maximum velocity magnitude plus the maximum speed of sound +@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, + equations::PolytropicEulerEquations2D) + rho_ll, v1_ll, v2_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr = cons2prim(u_rr, equations) + + # Get the velocity value in the appropriate direction + if orientation == 1 + v_ll = v1_ll + v_rr = v1_rr + else # orientation == 2 + v_ll = v2_ll + v_rr = v2_rr + end + # Calculate sound speeds (we have p = kappa * rho^gamma) + c_ll = sqrt(equations.gamma * equations.kappa * rho_ll^(equations.gamma - 1)) + c_rr = sqrt(equations.gamma * equations.kappa * rho_rr^(equations.gamma - 1)) + + λ_max = max(abs(v_ll), abs(v_rr)) + max(c_ll, c_rr) +end + +@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, + equations::PolytropicEulerEquations2D) + rho_ll, v1_ll, v2_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr = cons2prim(u_rr, equations) + + # Calculate normal velocities and sound speed (we have p = kappa * rho^gamma) + # left + v_ll = (v1_ll * normal_direction[1] + + v2_ll * normal_direction[2]) + c_ll = sqrt(equations.gamma * equations.kappa * rho_ll^(equations.gamma - 1)) + # right + v_rr = (v1_rr * normal_direction[1] + + v2_rr * normal_direction[2]) + c_rr = sqrt(equations.gamma * equations.kappa * rho_rr^(equations.gamma - 1)) + + return max(abs(v_ll), abs(v_rr)) + max(c_ll, c_rr) * norm(normal_direction) +end + # Convert conservative variables to primitive @inline function cons2prim(u, equations::PolytropicEulerEquations2D) rho, rho_v1, rho_v2 = u diff --git a/test/test_unit.jl b/test/test_unit.jl index 3b8dc3c4331..c1379587cc8 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -858,6 +858,30 @@ end end end +@timed_testset "Consistency check for Lax-Friedrich flux: Polytropic CEE" begin + for gamma in [1.4, 1.0, 5 / 3] + kappa = 0.5 # Scaling factor for the pressure. + equations = PolytropicEulerEquations2D(gamma, kappa) + u = SVector(1.1, -0.5, 2.34) + + orientations = [1, 2] + for orientation in orientations + @test flux_lax_friedrichs(u, u, orientation, equations) ≈ + flux(u, orientation, equations) + end + + normal_directions = [SVector(1.0, 0.0), + SVector(0.0, 1.0), + SVector(0.5, -0.5), + SVector(-1.2, 0.3)] + + for normal_direction in normal_directions + @test flux_lax_friedrichs(u, u, normal_direction, equations) ≈ + flux(u, normal_direction, equations) + end + end +end + @timed_testset "Consistency check for HLL flux with Davis wave speed estimates: LEE" begin flux_hll = FluxHLL(min_max_speed_davis) From e98a76b92fa1272b547b2abc997cfb1d885012f4 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 21 Feb 2024 11:02:15 +0100 Subject: [PATCH 260/263] improve benchmarks --- benchmark/benchmarks.jl | 12 ++++++++---- benchmark/run_benchmarks.jl | 4 ++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/benchmark/benchmarks.jl b/benchmark/benchmarks.jl index 15d1d96c05f..0d6fabcd4a9 100644 --- a/benchmark/benchmarks.jl +++ b/benchmark/benchmarks.jl @@ -2,6 +2,9 @@ # readability #! format: off +using Pkg +Pkg.activate(@__DIR__) + using BenchmarkTools using Trixi @@ -47,13 +50,14 @@ end let SUITE["latency"] = BenchmarkGroup() SUITE["latency"]["default_example"] = @benchmarkable run( - `$(Base.julia_cmd()) -e 'using Trixi; trixi_include(default_example())'`) seconds=60 + `$(Base.julia_cmd()) --project=$(@__DIR__) -e 'using Trixi; trixi_include(default_example())'`) seconds=60 for polydeg in [3, 7] command = "using Trixi; trixi_include(joinpath(examples_dir(), \"tree_2d_dgsem\", \"elixir_advection_extended.jl\"), tspan=(0.0, 1.0e-10), polydeg=$(polydeg), save_restart=TrivialCallback(), save_solution=TrivialCallback())" - SUITE["latency"]["polydeg_$polydeg"] = @benchmarkable run($`$(Base.julia_cmd()) -e $command`) seconds=60 + SUITE["latency"]["polydeg_$polydeg"] = @benchmarkable run( + $`$(Base.julia_cmd()) --project=$(@__DIR__) -e $command`) seconds=60 end SUITE["latency"]["euler_2d"] = @benchmarkable run( - `$(Base.julia_cmd()) -e 'using Trixi; trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_euler_kelvin_helmholtz_instability.jl"), tspan=(0.0, 1.0e-10), save_restart=TrivialCallback(), save_solution=TrivialCallback())'`) seconds=60 + `$(Base.julia_cmd()) --project=$(@__DIR__) -e 'using Trixi; trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_euler_kelvin_helmholtz_instability.jl"), tspan=(0.0, 1.0e-10), save_solution=TrivialCallback())'`) seconds=60 SUITE["latency"]["mhd_2d"] = @benchmarkable run( - `$(Base.julia_cmd()) -e 'using Trixi; trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_mhd_blast_wave.jl"), tspan=(0.0, 1.0e-10), save_solution=TrivialCallback())'`) seconds=60 + `$(Base.julia_cmd()) --project=$(@__DIR__) -e 'using Trixi; trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_mhd_blast_wave.jl"), tspan=(0.0, 1.0e-10), save_solution=TrivialCallback())'`) seconds=60 end diff --git a/benchmark/run_benchmarks.jl b/benchmark/run_benchmarks.jl index 3a92a9ba700..e4e15223ea7 100644 --- a/benchmark/run_benchmarks.jl +++ b/benchmark/run_benchmarks.jl @@ -1,3 +1,7 @@ +using Pkg +Pkg.activate(@__DIR__) +Pkg.develop(PackageSpec(path=dirname(@__DIR__))) +Pkg.instantiate() using PkgBenchmark using Trixi From 40b73cfde2a707dfc8d76ea92712a2287fd2e9e2 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 21 Feb 2024 11:12:54 +0100 Subject: [PATCH 261/263] format benchmarks --- benchmark/run_benchmarks.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/run_benchmarks.jl b/benchmark/run_benchmarks.jl index e4e15223ea7..7b8c25752f8 100644 --- a/benchmark/run_benchmarks.jl +++ b/benchmark/run_benchmarks.jl @@ -1,6 +1,6 @@ using Pkg Pkg.activate(@__DIR__) -Pkg.develop(PackageSpec(path=dirname(@__DIR__))) +Pkg.develop(PackageSpec(path = dirname(@__DIR__))) Pkg.instantiate() using PkgBenchmark From c3c0986a2eaf52a145cd59ab591ea3af75b40571 Mon Sep 17 00:00:00 2001 From: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Date: Wed, 21 Feb 2024 11:39:41 +0100 Subject: [PATCH 262/263] Create Downgrade.yml (second try) (#1848) * add downgrade.yml and bump compats * also downgrade test/Project.toml * bump lower compat for ForwardDiff in tests * allow older version of HDF5 * allow newest versions of Makie and CairoMakie * allow newest version of T8code * remove compat 0.11 from CairoMakie --- .github/workflows/Downgrade.yml | 86 +++++++++++++++++++++++++++++++++ Project.toml | 24 ++++----- test/Project.toml | 6 +-- 3 files changed, 101 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/Downgrade.yml diff --git a/.github/workflows/Downgrade.yml b/.github/workflows/Downgrade.yml new file mode 100644 index 00000000000..c84b1026d1b --- /dev/null +++ b/.github/workflows/Downgrade.yml @@ -0,0 +1,86 @@ +name: Downgrade + +on: + pull_request: + paths-ignore: + - 'AUTHORS.md' + - 'CITATION.bib' + - 'CONTRIBUTING.md' + - 'LICENSE.md' + - 'NEWS.md' + - 'README.md' + - '.zenodo.json' + - '.github/workflows/benchmark.yml' + - '.github/workflows/CompatHelper.yml' + - '.github/workflows/TagBot.yml' + - 'benchmark/**' + - 'docs/**' + - 'utils/**' + workflow_dispatch: + +# Cancel redundant CI tests automatically +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + downgrade_test: + if: "!contains(github.event.head_commit.message, 'skip ci')" + # We could also include the Julia version as in + # name: ${{ matrix.trixi_test }} - ${{ matrix.os }} - Julia ${{ matrix.version }} - ${{ matrix.arch }} - ${{ github.event_name }} + # to be more specific. However, that requires us updating the required CI tests whenever we update Julia. + name: Downgrade ${{ matrix.trixi_test }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + version: + - '1.9' + # - '~1.9.0-0' # including development versions + # - 'nightly' + os: + - ubuntu-latest + arch: + - x64 + trixi_test: + # - tree_part1 + # - tree_part2 + # - tree_part3 + # - tree_part4 + # - tree_part5 + # - tree_part6 + # - structured + # - p4est_part1 + # - p4est_part2 + # - t8code_part1 + # - unstructured_dgmulti + # - parabolic + # - paper_self_gravitating_gas_dynamics + # - misc_part1 + # - misc_part2 + # - performance_specializations_part1 + # - performance_specializations_part2 + # - mpi + - threaded + steps: + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v1 + with: + version: ${{ matrix.version }} + arch: ${{ matrix.arch }} + - run: julia -e 'using InteractiveUtils; versioninfo(verbose=true)' + - uses: julia-actions/cache@v1 + - uses: julia-actions/julia-downgrade-compat@v1 + with: + skip: LinearAlgebra,Printf,SparseArrays,DiffEqBase + projects: ., test + - uses: julia-actions/julia-buildpkg@v1 + env: + PYTHON: "" + - name: Run tests without coverage + uses: julia-actions/julia-runtest@v1 + with: + coverage: false + env: + PYTHON: "" + TRIXI_TEST: ${{ matrix.trixi_test }} diff --git a/Project.toml b/Project.toml index af3e6b4d078..9bed045637a 100644 --- a/Project.toml +++ b/Project.toml @@ -62,17 +62,17 @@ DiffEqCallbacks = "2.25" Downloads = "1.6" EllipsisNotation = "1.0" FillArrays = "0.13.2, 1" -ForwardDiff = "0.10.18" -HDF5 = "0.14, 0.15, 0.16, 0.17" +ForwardDiff = "0.10.24" +HDF5 = "0.16.10, 0.17" IfElse = "0.1" LinearAlgebra = "1" LinearMaps = "2.7, 3.0" -LoopVectorization = "0.12.118" +LoopVectorization = "0.12.151" MPI = "0.20" Makie = "0.19, 0.20" MuladdMacro = "0.2.2" -Octavian = "0.3.5" -OffsetArrays = "1.3" +Octavian = "0.3.21" +OffsetArrays = "1.12" P4est = "0.4.9" Polyester = "0.7.5" PrecompileTools = "1.1" @@ -81,19 +81,19 @@ RecipesBase = "1.1" Reexport = "1.0" Requires = "1.1" SciMLBase = "1.90, 2" -Setfield = "0.8, 1" +Setfield = "1" SimpleUnPack = "1.1" SparseArrays = "1" -StartUpDG = "0.17" -Static = "0.3, 0.4, 0.5, 0.6, 0.7, 0.8" +StartUpDG = "0.17.7" +Static = "0.8.7" StaticArrayInterface = "1.4" -StaticArrays = "1" -StrideArrays = "0.1.18" -StructArrays = "0.6" +StaticArrays = "1.5" +StrideArrays = "0.1.26" +StructArrays = "0.6.11" SummationByPartsOperators = "0.5.41" T8code = "0.4.3, 0.5" TimerOutputs = "0.5.7" -Triangulate = "2.0" +Triangulate = "2.2" TriplotBase = "0.1" TriplotRecipes = "0.1" TrixiBase = "0.1.1" diff --git a/test/Project.toml b/test/Project.toml index ecae0ac0900..a376c2805ea 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -13,13 +13,13 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] Aqua = "0.8" -CairoMakie = "0.6, 0.7, 0.8, 0.9, 0.10" +CairoMakie = "0.10" Downloads = "1" -ForwardDiff = "0.10" +ForwardDiff = "0.10.24" LinearAlgebra = "1" MPI = "0.20" OrdinaryDiffEq = "6.49.1" -Plots = "1.16" +Plots = "1.19" Printf = "1" Random = "1" Test = "1" From 1b2abd00e9b74d2cd185b0d06c5cf3182011e6c4 Mon Sep 17 00:00:00 2001 From: ArseniyKholod <119304909+ArseniyKholod@users.noreply.github.com> Date: Wed, 21 Feb 2024 12:48:03 +0200 Subject: [PATCH 263/263] Doc: Core aspects of the basic setup (#1699) * Doc: Core aspects of the basic setup * update pictures * Update innards_of_the_basic_setup.jl * mention ODE-Solvers * Revert "Revert "Merge branch 'main' into semidiscretization-doc"" This reverts commit 85d6e8b50261885ad198ae4036e8599189912e56. * Revert "Merge branch 'main' into semidiscretization-doc" This reverts commit b8f8b0bc167a476b3dead39f6aadf4fe43601e7d, reversing changes made to bb518f50053cef054220fd35542f52a47214a997. * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/literate/src/files/innards_of_the_basic_setup.jl Co-authored-by: Michael Schlottke-Lakemper * Update docs/make.jl Co-authored-by: Michael Schlottke-Lakemper * Rename innards_of_the_basic_setup.jl to behind_the_scenes_simulation_setup.jl * add plot scripts * Format_and_last_review_changes * spell+output_directory_figures * spell * N->polydeg * add README for plots * line length <=100 * Update docs/literate/src/files/behind_the_scenes_simulation_setup_plots/README.md * add empty lines * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Andrew Winters * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Andrew Winters * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Andrew Winters * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Andrew Winters * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Andrew Winters * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Andrew Winters * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Andrew Winters * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * mention method of lines * Update behind_the_scenes_simulation_setup.jl * Update behind_the_scenes_simulation_setup.jl * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Daniel Doehring * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Daniel Doehring * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Daniel Doehring * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Daniel Doehring * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Daniel Doehring * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Daniel Doehring * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Daniel Doehring * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Daniel Doehring * simplify rhs description * format * add interpolation to mortars * Update behind_the_scenes_simulation_setup.jl * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Daniel Doehring * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Daniel Doehring * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Daniel Doehring * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Daniel Doehring * add resizability explanation * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Daniel Doehring * format * add introduction as 2nd tutorial * fix * Update docs/literate/src/files/behind_the_scenes_simulation_setup.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> * add unsafe_wrap explanation --------- Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Andrew Winters Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Co-authored-by: Daniel Doehring --- .../behind_the_scenes_simulation_setup.jl | 253 ++++++++++++++++++ .../Project.toml | 2 + .../README.md | 15 ++ ...scretizationHyperbolic_structure_figure.jl | 64 +++++ .../src/generate_boundary_figure.jl | 190 +++++++++++++ .../src/generate_elements_figure.jl | 117 ++++++++ .../src/generate_interfaces_figure.jl | 157 +++++++++++ .../src/generate_mortars_figure.jl | 166 ++++++++++++ .../src/generate_nodes_figure.jl | 6 + .../src/generate_treemesh_figure.jl | 26 ++ .../src/rhs_structure_figure.jl | 43 +++ .../src/semidiscretize_structure_figure.jl | 51 ++++ docs/literate/src/files/index.jl | 45 ++-- docs/make.jl | 3 +- 14 files changed, 1119 insertions(+), 19 deletions(-) create mode 100644 docs/literate/src/files/behind_the_scenes_simulation_setup.jl create mode 100644 docs/literate/src/files/behind_the_scenes_simulation_setup_plots/Project.toml create mode 100644 docs/literate/src/files/behind_the_scenes_simulation_setup_plots/README.md create mode 100644 docs/literate/src/files/behind_the_scenes_simulation_setup_plots/src/SemidiscretizationHyperbolic_structure_figure.jl create mode 100644 docs/literate/src/files/behind_the_scenes_simulation_setup_plots/src/generate_boundary_figure.jl create mode 100644 docs/literate/src/files/behind_the_scenes_simulation_setup_plots/src/generate_elements_figure.jl create mode 100644 docs/literate/src/files/behind_the_scenes_simulation_setup_plots/src/generate_interfaces_figure.jl create mode 100644 docs/literate/src/files/behind_the_scenes_simulation_setup_plots/src/generate_mortars_figure.jl create mode 100644 docs/literate/src/files/behind_the_scenes_simulation_setup_plots/src/generate_nodes_figure.jl create mode 100644 docs/literate/src/files/behind_the_scenes_simulation_setup_plots/src/generate_treemesh_figure.jl create mode 100644 docs/literate/src/files/behind_the_scenes_simulation_setup_plots/src/rhs_structure_figure.jl create mode 100644 docs/literate/src/files/behind_the_scenes_simulation_setup_plots/src/semidiscretize_structure_figure.jl diff --git a/docs/literate/src/files/behind_the_scenes_simulation_setup.jl b/docs/literate/src/files/behind_the_scenes_simulation_setup.jl new file mode 100644 index 00000000000..c93660e9bc1 --- /dev/null +++ b/docs/literate/src/files/behind_the_scenes_simulation_setup.jl @@ -0,0 +1,253 @@ +#src # Behind the scenes of a simulation setup + +# This tutorial will guide you through a simple Trixi.jl setup ("elixir"), giving an overview of +# what happens in the background during the initialization of a simulation. While the setup +# described herein does not cover all details, it involves relatively stable parts of Trixi.jl that +# are unlikely to undergo significant changes in the near future. The goal is to clarify some of +# the more fundamental, *technical* concepts that are applicable to a variety of +# (also more complex) configurations. + +# Trixi.jl follows the [method of lines](http://www.scholarpedia.org/article/Method_of_lines) concept for solving partial differential equations (PDEs). +# Firstly, the PDEs are reduced to a (potentially huge) system of +# ordinary differential equations (ODEs) by discretizing the spatial derivatives. Subsequently, +# these generated ODEs may be solved with methods available in OrdinaryDiffEq.jl or those specifically +# implemented in Trixi.jl. The following steps elucidate the process of transitioning from PDEs to +# ODEs within the framework of Trixi.jl. + +# ## Basic setup + +# Import essential libraries and specify an equation. + +using Trixi, OrdinaryDiffEq +equations = LinearScalarAdvectionEquation2D((-0.2, 0.7)) + +# Generate a spatial discretization using a [`TreeMesh`](@ref) with a pre-coarsened set of cells. + +coordinates_min = (-2.0, -2.0) +coordinates_max = (2.0, 2.0) + +coarsening_patches = ((type = "box", coordinates_min = [0.0, -2.0], + coordinates_max = [2.0, 0.0]),) + +mesh = TreeMesh(coordinates_min, coordinates_max, initial_refinement_level = 2, + n_cells_max = 30_000, + coarsening_patches = coarsening_patches) + +# The created `TreeMesh` looks like the following: + +# ![TreeMesh_example](https://github.com/trixi-framework/Trixi.jl/assets/119304909/d5ef76ee-8246-4730-a692-b472c06063a3) + +# Instantiate a [`DGSEM`](@ref) solver with a user-specified polynomial degree. The solver +# will define `polydeg + 1` [Gauss-Lobatto nodes](https://en.wikipedia.org/wiki/Gaussian_quadrature#Gauss%E2%80%93Lobatto_rules) and their associated weights within +# the reference interval ``[-1, 1]`` in each spatial direction. These nodes will be subsequently +# used to approximate solutions on each leaf cell of the `TreeMesh`. + +solver = DGSEM(polydeg = 3) + +# Gauss-Lobatto nodes with `polydeg = 3`: + +# ![Gauss-Lobatto_nodes_example](https://github.com/trixi-framework/Trixi.jl/assets/119304909/1d894611-801e-4f75-bff0-d77ca1c672e5) + +# ## Overview of the [`SemidiscretizationHyperbolic`](@ref) type + +# At this stage, all necessary components for configuring the spatial discretization are in place. +# The remaining task is to combine these components into a single structure that will be used +# throughout the entire simulation process. This is where [`SemidiscretizationHyperbolic`](@ref) +# comes into play. + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_convergence_test, + solver) + +# The constructor for the `SemidiscretizationHyperbolic` object calls numerous sub-functions to +# perform the necessary initialization steps. A brief description of the key sub-functions is +# provided below. + + +# - `init_elements(leaf_cell_ids, mesh, equations, dg.basis, RealT, uEltype)` + +# The fundamental elements for approximating the solution are the leaf +# cells. The solution is constructed as a polynomial of the degree specified in the `DGSEM` +# solver in each spatial direction on each leaf cell. This polynomial approximation is evaluated +# at the Gauss-Lobatto nodes mentioned earlier. The `init_elements` function extracts +# these leaf cells from the `TreeMesh`, assigns them the label "elements", records their +# coordinates, and maps the Gauss-Lobatto nodes from the 1D interval ``[-1, 1]`` onto each coordinate axis +# of every element. + + +# ![elements_example](https://github.com/trixi-framework/Trixi.jl/assets/119304909/9f486670-b579-4e42-8697-439540c8bbb4) + +# The visualization of elements with nodes shown here includes spaces between elements, which do +# not exist in reality. This spacing is included only for illustrative purposes to underscore the +# separation of elements and the independent projection of nodes onto each element. + + +# - `init_interfaces(leaf_cell_ids, mesh, elements)` + +# At this point, the elements with nodes have been defined; however, they lack the necessary +# communication functionality. This is crucial because the local solution polynomials on the +# elements are not independent of each other. Furthermore, nodes on the boundary of adjacent +# elements share the same spatial location, which requires a method to combine this into a +# meaningful solution. +# Here [Riemann solvers](https://en.wikipedia.org/wiki/Riemann_solver#Approximate_solvers) +# come into play which can handle the principal ambiguity of a multi-valued solution at the +# same spatial location. + +# As demonstrated earlier, the elements can have varying sizes. Let us initially consider +# neighbors with equal size. For these elements, the `init_interfaces` function generates +# interfaces that store information about adjacent elements, their relative positions, and +# allocate containers for sharing solution data between neighbors during the solution process. + +# In our visualization, these interfaces would conceptually resemble tubes connecting the +# corresponding elements. + +# ![interfaces_example](https://github.com/trixi-framework/Trixi.jl/assets/119304909/bc3b6b02-afbc-4371-aaf7-c7bdc5a6c540) + + +# - `init_mortars(leaf_cell_ids, mesh, elements, dg.mortar)` + +# Returning to the consideration of different sizes among adjacent elements, within the +# `TreeMesh`, adjacent leaf cells can vary in side length by a maximum factor of two. This +# implies that a large element has one neighbor of +# equal size with a connection through an interface, or two neighbors at half the size, +# requiring a connection through so called "mortars". In 3D, a large element would have +# four small neighbor elements. + +# Mortars store information about the connected elements, their relative positions, and allocate +# containers for storing the solutions along the boundaries between these elements. + +# Due to the differing sizes of adjacent elements, it is not feasible to directly map boundary +# nodes of adjacent elements. Therefore, the concept of mortars employs a mass-conserving +# interpolation function to map boundary nodes from a larger element to a smaller one. + +# In our visualization, mortars are represented as branched tubes. + +# ![mortars_example](https://github.com/trixi-framework/Trixi.jl/assets/119304909/43a95a60-3a31-4b1f-8724-14049e7a0481) + + +# - `init_boundaries(leaf_cell_ids, mesh, elements)` + +# In order to apply boundary conditions, it is necessary to identify the locations of the +# boundaries. Therefore, we initialize a "boundaries" object, which records the elements that +# contain boundaries, specifies which side of an element is a boundary, stores the coordinates +# of boundary nodes, and allocates containers for managing solutions at these boundaries. + +# In our visualization, boundaries and their corresponding nodes are highlighted with green, +# semi-transparent lines. + +# ![boundaries_example](https://github.com/trixi-framework/Trixi.jl/assets/119304909/21996b20-4a22-4dfb-b16a-e2c22c2f29fe) + +# All the structures mentioned earlier are collected as a cache of type `NamedTuple`. Subsequently, +# an object of type `SemidiscretizationHyperbolic` is initialized using this cache, initial and +# boundary conditions, equations, mesh and solver. + +# In conclusion, the primary purpose of a `SemidiscretizationHyperbolic` is to collect equations, +# the geometric representation of the domain, and approximation instructions, creating specialized +# structures to interconnect these components in a manner that enables their utilization for +# the numerical solution of partial differential equations (PDEs). + +# As evident from the earlier description of `SemidiscretizationHyperbolic`, it comprises numerous +# functions called subsequently. Without delving into details, the structure of the primary calls +# are illustrated as follows: + +# ![SemidiscretizationHyperbolic_structure](https://github.com/trixi-framework/Trixi.jl/assets/119304909/8bf59422-0537-4d7a-9f13-d9b2253c19d7) + +# ## Overview of the [`semidiscretize`](@ref) function + +# At this stage, we have defined the equations and configured the domain's discretization. The +# final step before solving is to select a suitable time span and apply the corresponding initial +# conditions, which are already stored in the initialized `SemidiscretizationHyperbolic` object. + +# The purpose of the [`semidiscretize`](@ref) function is to wrap the semidiscretization as an +# `ODEProblem` within the specified time interval. During this procedure the approximate solution +# is created at the given initial time via the specified `initial_condition` function from the +# `SemidiscretizationHyperbolic` object. This `ODEProblem` can be subsequently passed to the +# `solve` function from the [OrdinaryDiffEq.jl](https://github.com/SciML/OrdinaryDiffEq.jl) package +# or to [`Trixi.solve`](@ref). + +ode = semidiscretize(semi, (0.0, 1.0)); + +# The `semidiscretize` function involves a deep tree of subsequent calls, with the primary ones +# explained below. + + +# - `allocate_coefficients(mesh, equations, solver, cache)` + +# To apply initial conditions, a data structure ("container") needs to be generated to store the +# initial values of the target variables for each node within each element. + +# Since only one-dimensional `Array`s are `resize!`able in Julia, we use `Vector`s as an internal +# storage for the target variables and `resize!` them whenever needed, e.g. to change the number +# of elements. Then, during the solving process the same memory is reused by `unsafe_wrap`ping +# multi-dimensional `Array`s around the internal storage. + +# - `wrap_array(u_ode, semi)` + +# As previously noted, `u_ode` is constructed as a 1D vector to ensure compatibility with +# OrdinaryDiffEq.jl. However, for internal use within Trixi.jl, identifying which part of the +# vector relates to specific variables, elements, or nodes can be challenging. + +# This is why the `u_ode` vector is wrapped by the `wrap_array` function using `unsafe_wrap` +# to form a multidimensional array `u`. In this array, the first dimension corresponds to +# variables, followed by N dimensions corresponding to nodes for each of N space dimensions. +# The last dimension corresponds to the elements. +# Consequently, navigation within this multidimensional array becomes noticeably easier. + +# "Wrapping" in this context involves the creation of a reference to the same storage location +# but with an alternative structural representation. This approach enables the use of both +# instances `u` and `u_ode` as needed, so that changes are simultaneously reflected in both. +# This is possible because, from a storage perspective, they share the same stored data, while +# access to this data is provided in different ways. + + +# - `compute_coefficients!(u, initial_conditions, t, mesh::DG, equations, solver, cache)` + +# Now the variable `u`, intended to store solutions, has been allocated and wrapped, it is time +# to apply the initial conditions. The `compute_coefficients!` function calculates the initial +# conditions for each variable at every node within each element and properly stores them in the +# `u` array. + +# At this stage, the `semidiscretize` function has all the necessary components to initialize and +# return an `ODEProblem` object, which will be used by the `solve` function to compute the +# solution. + +# In summary, the internal workings of `semidiscretize` with brief descriptions can be presented +# as follows. + +# ![semidiscretize_structure](https://github.com/trixi-framework/Trixi.jl/assets/119304909/491eddc4-aadb-4e29-8c76-a7c821d0674e) + +# ## Functions `solve` and `rhs!` + +# Once the `ODEProblem` object is initialized, the `solve` function and one of the ODE solvers from +# the OrdinaryDiffEq.jl package can be utilized to compute an approximated solution using the +# instructions contained in the `ODEProblem` object. + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 0.01, + save_everystep = false); + +# Since the `solve` function and the ODE solver have no knowledge +# of a particular spatial discretization, it is necessary to define a +# "right-hand-side function", `rhs!`, within Trixi.jl. + +# Trixi.jl includes a set of `rhs!` functions designed to compute `du`, i.e., +# ``\frac{\partial u}{\partial t}`` according to the structure +# of the setup. These `rhs!` functions calculate interface, mortars, and boundary fluxes, in +# addition to surface and volume integrals, in order to construct the `du` vector. This `du` vector +# is then used by the time integration method to obtain the solution at the subsequent time step. +# The `rhs!` function is called by time integration methods in each iteration of the solve loop +# within OrdinaryDiffEq.jl, with arguments `du`, `u`, `semidiscretization`, and the current time. + +# Trixi.jl uses a two-levels approach for `rhs!` functions. The first level is limited to a +# single function for each `semidiscretization` type, and its role is to redirect data to the +# target `rhs!` for specific solver and mesh types. This target `rhs!` function is responsible +# for calculating `du`. + +# Path from the `solve` function call to the appropriate `rhs!` function call: + +# ![rhs_structure](https://github.com/trixi-framework/Trixi.jl/assets/119304909/dbea9a0e-25a4-4afa-855e-01f1ad619982) + +# Computed solution: + +using Plots +plot(sol) +pd = PlotData2D(sol) +plot!(getmesh(pd)) diff --git a/docs/literate/src/files/behind_the_scenes_simulation_setup_plots/Project.toml b/docs/literate/src/files/behind_the_scenes_simulation_setup_plots/Project.toml new file mode 100644 index 00000000000..43aec5b7f54 --- /dev/null +++ b/docs/literate/src/files/behind_the_scenes_simulation_setup_plots/Project.toml @@ -0,0 +1,2 @@ +[deps] +Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" diff --git a/docs/literate/src/files/behind_the_scenes_simulation_setup_plots/README.md b/docs/literate/src/files/behind_the_scenes_simulation_setup_plots/README.md new file mode 100644 index 00000000000..011b5c75860 --- /dev/null +++ b/docs/literate/src/files/behind_the_scenes_simulation_setup_plots/README.md @@ -0,0 +1,15 @@ +# Plots for the tutorial "Behind the scenes of a simulation setup" + +To create all the images for the tutorial, execute the following command from the directory of this `README.md`: +```julia +pkg> activate . +julia> include.(readdir("src"; join=true)) +``` +To create all images from a different directory, substitute `"src"` with the path to the `src` +folder. The resulting images will be generated in your current directory as PNG files. + +To generate a specific image, run the following command while replacing `"path/to/src"` and `"file_name"` with the appropriate values: +```julia +pkg> activate . +julia> include(joinpath("path/to/src", "file_name")) +``` \ No newline at end of file diff --git a/docs/literate/src/files/behind_the_scenes_simulation_setup_plots/src/SemidiscretizationHyperbolic_structure_figure.jl b/docs/literate/src/files/behind_the_scenes_simulation_setup_plots/src/SemidiscretizationHyperbolic_structure_figure.jl new file mode 100644 index 00000000000..cae7b19d470 --- /dev/null +++ b/docs/literate/src/files/behind_the_scenes_simulation_setup_plots/src/SemidiscretizationHyperbolic_structure_figure.jl @@ -0,0 +1,64 @@ +using Plots +plot(Shape([(-2.3,4.5), (2.35,4.5), (2.35,2.5), (-2.3,2.5)]), linecolor="black", fillcolor="white", label=false,linewidth=2, size=(800,600), showaxis=false, grid=false, xlim=(-2.4,2.8), ylim=(-25,5.5)) +annotate!(2.3, 3.5, ("SemidiscretizationHyperbolic(mesh, equations, initial_conditions, solver; source_terms, +boundary_conditions, RealT, uEltype, initial_cache) ", 10, :black, :right)) +annotate!(-2.3, 1.5, ("creates and returns SemidiscretizationHyperbolic object, initialized using a mesh, equations, +initial_conditions, boundary_conditions, source_terms, solver and cache", 9, :black, :left)) +plot!([-1.2,-1.2],[0.6,-2],arrow=true,color=:black,linewidth=2,label="") +plot!([-1.2,-1.4],[0.6,-2],arrow=true,color=:black,linewidth=2,label="") +plot!([-1.2,-1.],[0.6,-2],arrow=true,color=:black,linewidth=2,label="") +annotate!(-1, -0.7, ("specialized for mesh +and solver types", 9, :black, :left)) +plot!([1.25,1.25],[0.6,-2],arrow=true,color=:black,linewidth=2,label="") +plot!([1.25,1.05],[0.6,-2],arrow=true,color=:black,linewidth=2,label="") +plot!([1.25,1.45],[0.6,-2],arrow=true,color=:black,linewidth=2,label="") +annotate!(1.48, -0.7, ("specialized for mesh +and boundary_conditions +types", 9, :black, :left)) + +plot!(Shape([(-2.3,-2), (-0.1,-2), (-0.1,-4), (-2.3,-4)]), linecolor="black", fillcolor="white", label=false,linewidth=2) +annotate!(-1.2, -3, ("create_cache(mesh::TreeMesh, equations, + solver::Dg, RealT, uEltype)", 10, :black, :center)) +plot!([-2.22,-2.22],[-4,-22],arrow=false,color=:black,linewidth=2,label="") + +plot!(Shape([(-0.05,-2), (2.6,-2), (2.6,-4), (-0.05,-4)]), linecolor="black", fillcolor="white", label=false,linewidth=2) +annotate!(1.27, -3, ("digest_boundary_conditions(boundary_conditions, + mesh, solver, cache)", 10, :black, :center)) +annotate!(2.6, -5, ("if necessary, converts passed boundary_conditions + into a suitable form for processing by Trixi.jl", 9, :black, :right)) + +plot!(Shape([(-2,-6), (-0.55,-6), (-0.55,-7.1), (-2,-7.1)]), linecolor="black", fillcolor="white", label=false,linewidth=2) +annotate!(-1.95, -6.5, ("local_leaf_cells(mesh.tree)", 10, :black, :left)) +annotate!(-2, -7.5, ("returns cells for which an element needs to be created (i.e. all leaf cells)", 9, :black, :left)) +plot!([-2.22,-2],[-6.5,-6.5],arrow=true,color=:black,linewidth=2,label="") + +plot!(Shape([(-2,-9), (1.73,-9), (1.73,-10.1), (-2,-10.1)]), linecolor="black", fillcolor="white", label=false,linewidth=2) +annotate!(-1.95, -9.5, ("init_elements(leaf_cell_ids, mesh, equations, dg.basis, RealT, uEltype)", 10, :black, :left)) +annotate!(-2, -10.5, ("creates and initializes elements, projects Gauss-Lobatto basis onto each of them", 9, :black, :left)) +plot!([-2.22,-2],[-9.5,-9.5],arrow=true,color=:black,linewidth=2,label="") + +plot!(Shape([(-2,-12), (0.4,-12), (0.4,-13.1), (-2,-13.1)]), linecolor="black", fillcolor="white", label=false,linewidth=2) +annotate!(-1.95, -12.5, ("init_interfaces(leaf_cell_ids, mesh, elements)", 10, :black, :left)) +annotate!(-2, -13.5, ("creates and initializes interfaces between each pair of adjacent elements of the same size", 9, :black, :left)) +plot!([-2.22,-2],[-12.5,-12.5],arrow=true,color=:black,linewidth=2,label="") + +plot!(Shape([(-2,-15), (0.5,-15), (0.5,-16.1), (-2,-16.1)]), linecolor="black", fillcolor="white", label=false,linewidth=2) +annotate!(-1.95, -15.5, ("init_boundaries(leaf_cell_ids, mesh, elements)", 10, :black, :left)) +annotate!(-2, -17, ("creates and initializes boundaries, remembers each boundary element, as well as the coordinates of +each boundary node", 9, :black, :left)) +plot!([-2.22,-2],[-15.5,-15.5],arrow=true,color=:black,linewidth=2,label="") + +plot!(Shape([(-1.6,-18), (1.3,-18), (1.3,-19.1), (-1.6,-19.1)]), linecolor="black", fillcolor="white", label=false,linewidth=2) +annotate!(-1.55, -18.5, ("init_mortars(leaf_cell_ids, mesh, elements, dg.mortar)", 10, :black, :left)) +annotate!(-1.6, -20, ("creates and initializes mortars (type of interfaces) between each triple of adjacent coarsened +and corresponding small elements", 9, :black, :left)) +plot!([-2.22,-1.6],[-18.5,-18.5],arrow=true,color=:black,linewidth=2,label="") +annotate!(-2.15, -19, ("2D and 3D", 8, :black, :left)) + +plot!(Shape([(-2,-21), (1.5,-21), (1.5,-23.1), (-2,-23.1)]), linecolor="black", fillcolor="white", label=false,linewidth=2) +annotate!(-1.95, -22, ("create_cache(mesh, equations, dg.volume_integral, dg, uEltype) +for 2D and 3D create_cache(mesh, equations, dg.mortar, uEltype)", 10, :black, :left)) +annotate!(-2, -23.5, ("add specialized parts of the cache required to compute the volume integral, etc.", 9, :black, :left)) +plot!([-2.22,-2],[-22,-22],arrow=true,color=:black,linewidth=2,label="") + +savefig("./SemidiscretizationHyperbolic") \ No newline at end of file diff --git a/docs/literate/src/files/behind_the_scenes_simulation_setup_plots/src/generate_boundary_figure.jl b/docs/literate/src/files/behind_the_scenes_simulation_setup_plots/src/generate_boundary_figure.jl new file mode 100644 index 00000000000..14475d21339 --- /dev/null +++ b/docs/literate/src/files/behind_the_scenes_simulation_setup_plots/src/generate_boundary_figure.jl @@ -0,0 +1,190 @@ +using Plots + +function min(coordinates::Vector{Tuple{Float64, Float64}}, i) + min=coordinates[1][i] + for j in coordinates + if min>j[i] + min=j[i] + end + end + return min +end + +function max(coordinates::Vector{Tuple{Float64, Float64}}, i) + max=coordinates[1][i] + for j in coordinates + if maxj[i] + min=j[i] + end + end + return min +end + +function max(coordinates::Vector{Tuple{Float64, Float64}}, i) + max=coordinates[1][i] + for j in coordinates + if maxj[i] + min=j[i] + end + end + return min +end + +function max(coordinates::Vector{Tuple{Float64, Float64}}, i) + max=coordinates[1][i] + for j in coordinates + if maxj[i] + min=j[i] + end + end + return min +end + +function max(coordinates::Vector{Tuple{Float64, Float64}}, i) + max=coordinates[1][i] + for j in coordinates + if max ("first_steps", "create_first_setup.jl"), "Changing Trixi.jl itself" => ("first_steps", "changing_trixi.jl"), ], + "Behind the scenes of a simulation setup" => "behind_the_scenes_simulation_setup.jl", # Topic: DG semidiscretizations "Introduction to DG methods" => "scalar_linear_advection_1d.jl", "DGSEM with flux differencing" => "DGSEM_FluxDiff.jl", @@ -76,7 +77,7 @@ files = [ # Topic: other stuff "Explicit time stepping" => "time_stepping.jl", "Differentiable programming" => "differentiable_programming.jl", - "Custom semidiscretizations" => "custom_semidiscretization.jl" + "Custom semidiscretizations" => "custom_semidiscretization.jl", ] tutorials = create_tutorials(files)