From da330cc1318eca7c55694347c7f873ca24beb36b Mon Sep 17 00:00:00 2001 From: Warisa Date: Sat, 25 May 2024 17:52:44 +0200 Subject: [PATCH 001/160] make NLsolve a weapdep --- Project.toml | 6 +- .../elixir_burgers_perk3.jl | 56 +++ ext/TrixiNLsolveExt.jl | 62 +++ src/Trixi.jl | 6 + .../methods_PERK3.jl | 365 ++++++++++++++++++ .../paired_explicit_runge_kutta.jl | 6 + 6 files changed, 500 insertions(+), 1 deletion(-) create mode 100644 examples/structured_1d_dgsem/elixir_burgers_perk3.jl create mode 100644 ext/TrixiNLsolveExt.jl create mode 100644 src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl diff --git a/Project.toml b/Project.toml index b605cb2c6b1..6ae18fb29a4 100644 --- a/Project.toml +++ b/Project.toml @@ -53,10 +53,12 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" Convex = "f65535da-76fb-5f13-bab9-19810c17039a" ECOS = "e2685f51-7e38-5353-a97d-a921fd2c8199" +NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" [extensions] TrixiMakieExt = "Makie" TrixiConvexECOSExt = ["Convex", "ECOS"] +TrixiNLsolveExt = "NLsolve" [compat] CodeTracking = "1.0.5" @@ -79,6 +81,7 @@ LoopVectorization = "0.12.151" MPI = "0.20" Makie = "0.19, 0.20" MuladdMacro = "0.2.2" +NLsolve = "4.5.1" Octavian = "0.3.21" OffsetArrays = "1.12" P4est = "0.4.9" @@ -111,4 +114,5 @@ julia = "1.8" [extras] Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" Convex = "f65535da-76fb-5f13-bab9-19810c17039a" -ECOS = "e2685f51-7e38-5353-a97d-a921fd2c8199" \ No newline at end of file +ECOS = "e2685f51-7e38-5353-a97d-a921fd2c8199" +NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" \ No newline at end of file diff --git a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl new file mode 100644 index 00000000000..3feb89c6b7b --- /dev/null +++ b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl @@ -0,0 +1,56 @@ +using Convex, ECOS +using NLsolve +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the (inviscid) Burgers' equation + +equations = InviscidBurgersEquation1D() + +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 = 4, surface_flux = flux_lax_friedrichs) + +coordinates_min = (0.0,) # minimum coordinate +coordinates_max = (1.0,) # maximum coordinate +cells_per_dimension = (64,) + +# Create curved mesh with 16 cells +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, 2.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) + +stepsize_callback = StepsizeCallback() + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + stepsize_callback) + +############################################################################### +# run the simulation + +ode_algorithm = Trixi.PairedExplicitRK3(8, tspan, semi) + +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); + +# Print the timer summary +summary_callback() +analysis_callback(sol) \ No newline at end of file diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl new file mode 100644 index 00000000000..47ea16707cc --- /dev/null +++ b/ext/TrixiNLsolveExt.jl @@ -0,0 +1,62 @@ +# Package extension for adding Convex-based features to Trixi.jl +module TrixiNLsolveExt + +# Required for coefficient optimization in P-ERK scheme integrators +if isdefined(Base, :get_extension) + using NLsolve:nlsolve +else + # Until Julia v1.9 is the minimum required version for Trixi.jl, we still support Requires.jl + using ..NLsolve:nlsolve +end + +# Use functions and additional symbols that are not exported +using Trixi: Trixi, @muladd, PairedExplicitRK3_butcher_tableau_objective_function + +# Use functions that are to be extended +using Trixi: Trixi, solve_a_unknown + +# 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: edit the comment this function +# Define the new function that includes the nlsolve features +function Trixi.solve_a_unknown(num_stages, monomial_coeffs, c_s2, c; verbose) + is_sol_valid = false + a_unknown = zeros(num_stages) + + # Define the objective_function + function objective_function(x) + return Trixi.PairedExplicitRK3_butcher_tableau_objective_function(x, num_stages, num_stages, + monomial_coeffs, c_s2) + end + + while !is_sol_valid + # Initialize initial guess + x0 = 0.1 .* rand(num_stages) + x0[1] = 0.0 + x0[2] = c[2] + + sol = nlsolve(objective_function, x0, method = :trust_region, ftol = 4e-16, + iterations = 10^4, xtol = 1e-13) + + a_unknown = sol.zero + + # Check if the values a[i, i-1] >= 0.0 (which stem from the nonlinear solver) and subsequently c[i] - a[i, i-1] >= 0.0 + is_sol_valid = all(x -> !isnan(x) && x >= 0, a_unknown[3:end]) && + all(x -> !isnan(x) && x >= 0, c[3:end] .- a_unknown[3:end]) + + if verbose && !is_sol_valid + println("Solution invalid. Restart the process of solving non-linear system of equations again.") + end + + end + + return a_unknown +end +end # @muladd + +end # module TrixiNLsolveExt diff --git a/src/Trixi.jl b/src/Trixi.jl index 3a882d0962c..0b5f0d0f675 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -318,6 +318,12 @@ function __init__() end end + @static if !isdefined(Base, :get_extension) + @require NLsolve="2774e3e8-f4cf-5e23-947b-6d7e65073b56" begin + include("../ext/TrixiNLsolveExt.jl") + end + 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/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl new file mode 100644 index 00000000000..a44e78093a5 --- /dev/null +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -0,0 +1,365 @@ +# 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. +using DelimitedFiles: readdlm + +@muladd begin +#! format: noindent + +# Initialize Butcher array abscissae c for PairedExplicitRK3 based on SSPRK33 base method +function compute_c_coeff_SSP33(num_stages, c_s2) + c = zeros(num_stages) + + # Last timesteps as for SSPRK33 + c[num_stages] = 0.5 + c[num_stages - 1] = 1 + + # Linear increasing timestep for remainder + for i in 2:(num_stages - 2) + c[i] = c_s2 * (i - 1) / (num_stages - 3) + end + + return c +end + +function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_stages, + num_stage_evals, + monomial_coeffs, c_s2) + c_ts = compute_c_coeff_SSP33(num_stages, c_s2) # ts = timestep + + # Equality Constraint array that ensures that the stability polynomial computed from + # the to-be-constructed Butcher-Tableau matches the monomial coefficients of the + # optimized stability polynomial. + c_eq = zeros(num_stage_evals - 2) # Add equality constraint that c_s2 is equal to 1 + # Both terms should be present + for i in 1:(num_stage_evals - 4) + term1 = a_unknown[num_stage_evals - 1] + term2 = a_unknown[num_stage_evals] + for j in 1:i + term1 *= a_unknown[num_stage_evals - 1 - j] + term2 *= a_unknown[num_stage_evals - j] + end + term1 *= c_ts[num_stages - 2 - i] * 1 / 6 + term2 *= c_ts[num_stages - 1 - i] * 4 / 6 + + c_eq[i] = monomial_coeffs[i] - (term1 + term2) + end + + # Highest coefficient: Only one term present + i = num_stage_evals - 3 + term2 = a_unknown[num_stage_evals] + for j in 1:i + term2 *= a_unknown[num_stage_evals - j] + end + term2 *= c_ts[num_stages - 1 - i] * 4 / 6 + + c_eq[i] = monomial_coeffs[i] - term2 + c_eq[num_stage_evals - 2] = 1.0 - 4 * a_unknown[num_stage_evals] - + a_unknown[num_stage_evals - 1] + + return c_eq +end + +function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, eig_vals::Vector{ComplexF64}; + verbose = false, c_s2) + # Initialize array of c + c = compute_c_coeff_SSP33(num_stages, c_s2) + + # Initialize the array of our solution + a_unknown = zeros(num_stages) + + # Special case of e = 3 + if num_stages == 3 + a_unknown = [0, c[2], 0.25] + else + # Calculate coefficients of the stability polynomial in monomial form + consistency_order = 3 + dtmax = tspan[2] - tspan[1] + dteps = 1e-9 + + num_eig_vals, eig_vals = filter_eig_vals(eig_vals; verbose) + + monomial_coeffs, dt_opt = bisect_stability_polynomial(consistency_order, + num_eig_vals, num_stages, + dtmax, + dteps, + eig_vals; verbose) + monomial_coeffs = undo_normalization!(monomial_coeffs, consistency_order, + num_stages) + + # Call function that use the library NLsolve to solve the nonlinear system + a_unknown = solve_a_unknown(num_stages, monomial_coeffs, c_s2, c; verbose) + end + + # For debugging purpose + println("a_unknown") + println(a_unknown[3:end]) + + a_matrix = zeros(num_stages - 2, 2) + a_matrix[:, 1] = c[3:end] + a_matrix[:, 1] -= a_unknown[3:end] + a_matrix[:, 2] = a_unknown[3:end] + + return a_matrix, c, dt_opt +end + +function compute_PairedExplicitRK3_butcher_tableau(num_stages, base_path_monomial_coeffs::AbstractString, + c_s2) + + # Initialize array of c + c = compute_c_coeff_SSP33(num_stages, c_s2) + + # - 2 Since First entry of A is always zero (explicit method) and second is given by c_2 (consistency) + coeffs_max = num_stages - 2 + + a_matrix = zeros(coeffs_max, 2) + a_matrix[:, 1] = c[3:end] + + # TODO: update this to work with CI mktempdir() + path_monomial_coeffs = base_path_monomial_coeffs * "a_" * string(num_stages) * "_" * + string(num_stages) * ".txt" + @assert isfile(path_monomial_coeffs) "Couldn't find file" + A = readdlm(path_monomial_coeffs, Float64) + num_monomial_coeffs = size(A, 1) + + @assert num_monomial_coeffs == coeffs_max + a_matrix[:, 1] -= A + a_matrix[:, 2] = A + + println("A matrix: ") + display(a_matrix) + println() + + return a_matrix, c +end + +""" + PairedExplicitRK3() +The following structures and methods provide a implementation of +the third-order paired explicit Runge-Kutta method +optimized for a certain simulation setup (PDE, IC & BC, Riemann Solver, DG Solver). +The original paper is +- Nasab, Vermeire (2022) +Third-order Paired Explicit Runge-Kutta schemes for stiff systems of equations +[DOI: 10.1016/j.jcp.2022.111470](https://doi.org/10.1016/j.jcp.2022.111470) +While the changes to SSPRK33 base-scheme are described in +- Doehring, Schlottke-Lakemper, Gassner, Torrilhon (2024) +Multirate Time-Integration based on Dynamic ODE Partitioning through Adaptively Refined Meshes for Compressible Fluid Dynamics +[Arxiv: 10.48550/arXiv.2403.05144](https://doi.org/10.48550/arXiv.2403.05144) +""" +mutable struct PairedExplicitRK3 <: AbstractPairedExplicitRKSingle + const num_stages::Int + + a_matrix::Matrix{Float64} + c::Vector{Float64} + dt_opt::Float64 +end # struct PairedExplicitRK3 + + # Constructor for previously computed A Coeffs + function PairedExplicitRK3(num_stages, base_path_monomial_coeffs::AbstractString, dt_opt; + c_s2 = 1.0) + + a_matrix, c = compute_PairedExplicitRK3_butcher_tableau(num_stages, + base_path_monomial_coeffs; + c_s2) + + return PairedExplicitRK3(num_stages, a_matrix, c, dt_opt) +end + +# Constructor that computes Butcher matrix A coefficients from a semidiscretization +function PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; + verbose = false, c_s2 = 1.0) + eig_vals = eigvals(jacobian_ad_forward(semi)) + + return PairedExplicitRK3(num_stages, tspan, eig_vals; verbose, c_s2) +end + +# Constructor that calculates the coefficients with polynomial optimizer from a list of eigenvalues +function PairedExplicitRK3(num_stages, tspan, eig_vals::Vector{ComplexF64}; + verbose = false, c_s2 = 1.0) + + a_matrix, c, dt_opt = compute_PairedExplicitRK3_butcher_tableau(num_stages, + tspan, + eig_vals; + verbose, c_s2) + return PairedExplicitRK3(num_stages, a_matrix, c, dt_opt) +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 PairedExplicitRK3Integrator{RealT <: Real, uType, Params, Sol, F, Alg, + PairedExplicitRKOptions} <: AbstractPairedExplicitRKSingleIntegrator + u::uType + du::uType + u_tmp::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 # This is our own class written above; Abbreviation for ALGorithm + opts::PairedExplicitRKOptions + finalstep::Bool # added for convenience + # PairedExplicitRK stages: + k1::uType + k_higher::uType + k_s1::uType # Required for custom third order version of PairedExplicitRK3 +end + +# Fakes `solve`: https://diffeq.sciml.ai/v6.8/basics/overview/#Solving-the-Problems-1 +function solve(ode::ODEProblem, alg::PairedExplicitRK3; + dt, callback = nothing, kwargs...) + u0 = copy(ode.u0) + du = zero(u0) + u_tmp = zero(u0) + + # PairedExplicitRK stages + k1 = zero(u0) + k_higher = zero(u0) + k_s1 = zero(u0) + + t0 = first(ode.tspan) + iter = 0 + + integrator = PairedExplicitRK3Integrator(u0, du, u_tmp, t0, dt, zero(dt), iter, ode.p, + (prob = ode,), ode.f, alg, + PairedExplicitRKOptions(callback, ode.tspan; kwargs...), + false, + k1, k_higher, k_s1) + + # 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 + + solve!(integrator) +end + +function solve!(integrator::PairedExplicitRK3Integrator) + @unpack prob = integrator.sol + @unpack alg = integrator + t_end = last(prob.tspan) + callbacks = integrator.opts.callback + + integrator.finalstep = false + + #@trixi_timeit timer() "main loop" while !integrator.finalstep + 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 + + @trixi_timeit timer() "Paired Explicit Runge-Kutta ODE integration step" begin + # k1 + integrator.f(integrator.du, integrator.u, prob.p, integrator.t) + @threaded for i in eachindex(integrator.du) + integrator.k1[i] = integrator.du[i] * integrator.dt + end + + # Construct current state + @threaded for i in eachindex(integrator.du) + integrator.u_tmp[i] = integrator.u[i] + alg.c[2] * integrator.k1[i] + end + # k2 + integrator.f(integrator.du, integrator.u_tmp, prob.p, + integrator.t + alg.c[2] * integrator.dt) + + @threaded for i in eachindex(integrator.du) + integrator.k_higher[i] = integrator.du[i] * integrator.dt + end + + if alg.num_stages == 3 + @threaded for i in eachindex(integrator.du) + integrator.k_s1[i] = integrator.k_higher[i] + end + end + + # Higher stages + for stage in 3:(alg.num_stages) + # Construct current state + @threaded for i in eachindex(integrator.du) + integrator.u_tmp[i] = integrator.u[i] + + alg.a_matrix[stage - 2, 1] * + integrator.k1[i] + + alg.a_matrix[stage - 2, 2] * + integrator.k_higher[i] + end + + integrator.f(integrator.du, integrator.u_tmp, prob.p, + integrator.t + alg.c[stage] * integrator.dt) + + @threaded for i in eachindex(integrator.du) + integrator.k_higher[i] = integrator.du[i] * integrator.dt + end + + # IDEA: Stop for loop at num_stages -1 to avoid if (maybe more performant?) + if stage == alg.num_stages - 1 + @threaded for i in eachindex(integrator.du) + integrator.k_s1[i] = integrator.k_higher[i] + end + end + end + + @threaded for i in eachindex(integrator.u) + # "Own" PairedExplicitRK based on SSPRK33 + integrator.u[i] += (integrator.k1[i] + integrator.k_s1[i] + + 4.0 * integrator.k_higher[i]) / 6.0 + end + end # PairedExplicitRK step timer + + 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 # "main loop" timer + + return TimeIntegratorSolution((first(prob.tspan), integrator.t), + (prob.u0, integrator.u), + integrator.sol.prob) +end + +# used for AMR (Adaptive Mesh Refinement) +function Base.resize!(integrator::PairedExplicitRK3Integrator, new_size) + resize!(integrator.u, new_size) + resize!(integrator.du, new_size) + resize!(integrator.u_tmp, new_size) + + resize!(integrator.k1, new_size) + resize!(integrator.k_higher, new_size) + resize!(integrator.k_s1, new_size) +end +end # @muladd \ No newline at end of file diff --git a/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl b/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl index b73ea758312..66fa11e68a3 100644 --- a/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl +++ b/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl @@ -7,6 +7,12 @@ # Basic implementation of the second-order paired explicit Runge-Kutta (PERK) method include("methods_PERK2.jl") +include("methods_PERK3.jl") # Define all of the functions necessary for polynomial optimizations include("polynomial_optimizer.jl") + +# Add definitions of functions related to polynomial optimization by NLsolve here +# such that hey can be exported from Trixi.jl and extended in the TrixiConvexECOSExt package +# extension or by the NLsolve-specific code loaded by Requires.jl +function solve_a_unknown end end # @muladd From a6789b3a0696c61868c3667dc382bef0a4248c81 Mon Sep 17 00:00:00 2001 From: Warisa Date: Sat, 25 May 2024 17:57:39 +0200 Subject: [PATCH 002/160] fmt --- .../elixir_burgers_perk3.jl | 2 +- ext/TrixiNLsolveExt.jl | 17 +++---- .../methods_PERK3.jl | 47 ++++++++++--------- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl index 3feb89c6b7b..08c88f0a012 100644 --- a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl +++ b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl @@ -53,4 +53,4 @@ sol = Trixi.solve(ode, ode_algorithm, # Print the timer summary summary_callback() -analysis_callback(sol) \ No newline at end of file + diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 47ea16707cc..0e92e807c50 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -3,10 +3,10 @@ module TrixiNLsolveExt # Required for coefficient optimization in P-ERK scheme integrators if isdefined(Base, :get_extension) - using NLsolve:nlsolve + using NLsolve: nlsolve else # Until Julia v1.9 is the minimum required version for Trixi.jl, we still support Requires.jl - using ..NLsolve:nlsolve + using ..NLsolve: nlsolve end # Use functions and additional symbols that are not exported @@ -30,10 +30,12 @@ function Trixi.solve_a_unknown(num_stages, monomial_coeffs, c_s2, c; verbose) # Define the objective_function function objective_function(x) - return Trixi.PairedExplicitRK3_butcher_tableau_objective_function(x, num_stages, num_stages, - monomial_coeffs, c_s2) + return Trixi.PairedExplicitRK3_butcher_tableau_objective_function(x, num_stages, + num_stages, + monomial_coeffs, + c_s2) end - + while !is_sol_valid # Initialize initial guess x0 = 0.1 .* rand(num_stages) @@ -48,13 +50,12 @@ function Trixi.solve_a_unknown(num_stages, monomial_coeffs, c_s2, c; verbose) # Check if the values a[i, i-1] >= 0.0 (which stem from the nonlinear solver) and subsequently c[i] - a[i, i-1] >= 0.0 is_sol_valid = all(x -> !isnan(x) && x >= 0, a_unknown[3:end]) && all(x -> !isnan(x) && x >= 0, c[3:end] .- a_unknown[3:end]) - + if verbose && !is_sol_valid println("Solution invalid. Restart the process of solving non-linear system of equations again.") end - end - + return a_unknown end end # @muladd diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index a44e78093a5..fef3eebc908 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -61,7 +61,8 @@ function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_sta return c_eq end -function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, eig_vals::Vector{ComplexF64}; +function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, + eig_vals::Vector{ComplexF64}; verbose = false, c_s2) # Initialize array of c c = compute_c_coeff_SSP33(num_stages, c_s2) @@ -104,8 +105,9 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, eig_vals:: return a_matrix, c, dt_opt end -function compute_PairedExplicitRK3_butcher_tableau(num_stages, base_path_monomial_coeffs::AbstractString, - c_s2) +function compute_PairedExplicitRK3_butcher_tableau(num_stages, + base_path_monomial_coeffs::AbstractString, + c_s2) # Initialize array of c c = compute_c_coeff_SSP33(num_stages, c_s2) @@ -118,7 +120,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, base_path_monomia # TODO: update this to work with CI mktempdir() path_monomial_coeffs = base_path_monomial_coeffs * "a_" * string(num_stages) * "_" * - string(num_stages) * ".txt" + string(num_stages) * ".txt" @assert isfile(path_monomial_coeffs) "Couldn't find file" A = readdlm(path_monomial_coeffs, Float64) num_monomial_coeffs = size(A, 1) @@ -156,20 +158,20 @@ mutable struct PairedExplicitRK3 <: AbstractPairedExplicitRKSingle dt_opt::Float64 end # struct PairedExplicitRK3 - # Constructor for previously computed A Coeffs - function PairedExplicitRK3(num_stages, base_path_monomial_coeffs::AbstractString, dt_opt; - c_s2 = 1.0) - +# Constructor for previously computed A Coeffs +function PairedExplicitRK3(num_stages, base_path_monomial_coeffs::AbstractString, + dt_opt; + c_s2 = 1.0) a_matrix, c = compute_PairedExplicitRK3_butcher_tableau(num_stages, - base_path_monomial_coeffs; - c_s2) + base_path_monomial_coeffs; + c_s2) return PairedExplicitRK3(num_stages, a_matrix, c, dt_opt) end # Constructor that computes Butcher matrix A coefficients from a semidiscretization function PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; - verbose = false, c_s2 = 1.0) + verbose = false, c_s2 = 1.0) eig_vals = eigvals(jacobian_ad_forward(semi)) return PairedExplicitRK3(num_stages, tspan, eig_vals; verbose, c_s2) @@ -177,8 +179,7 @@ end # Constructor that calculates the coefficients with polynomial optimizer from a list of eigenvalues function PairedExplicitRK3(num_stages, tspan, eig_vals::Vector{ComplexF64}; - verbose = false, c_s2 = 1.0) - + verbose = false, c_s2 = 1.0) a_matrix, c, dt_opt = compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, eig_vals; @@ -186,14 +187,13 @@ function PairedExplicitRK3(num_stages, tspan, eig_vals::Vector{ComplexF64}; return PairedExplicitRK3(num_stages, a_matrix, c, dt_opt) 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 PairedExplicitRK3Integrator{RealT <: Real, uType, Params, Sol, F, Alg, - PairedExplicitRKOptions} <: AbstractPairedExplicitRKSingleIntegrator + PairedExplicitRKOptions} <: + AbstractPairedExplicitRKSingleIntegrator u::uType du::uType u_tmp::uType @@ -228,11 +228,14 @@ function solve(ode::ODEProblem, alg::PairedExplicitRK3; t0 = first(ode.tspan) iter = 0 - integrator = PairedExplicitRK3Integrator(u0, du, u_tmp, t0, dt, zero(dt), iter, ode.p, - (prob = ode,), ode.f, alg, - PairedExplicitRKOptions(callback, ode.tspan; kwargs...), - false, - k1, k_higher, k_s1) + integrator = PairedExplicitRK3Integrator(u0, du, u_tmp, t0, dt, zero(dt), iter, + ode.p, + (prob = ode,), ode.f, alg, + PairedExplicitRKOptions(callback, + ode.tspan; + kwargs...), + false, + k1, k_higher, k_s1) # initialize callbacks if callback isa CallbackSet @@ -362,4 +365,4 @@ function Base.resize!(integrator::PairedExplicitRK3Integrator, new_size) resize!(integrator.k_higher, new_size) resize!(integrator.k_s1, new_size) end -end # @muladd \ No newline at end of file +end # @muladd From bcd40912eec96b34d5d7e9df924a36576e284b0a Mon Sep 17 00:00:00 2001 From: Warisa Date: Sat, 25 May 2024 18:03:05 +0200 Subject: [PATCH 003/160] add NEWS.md but TBD on the ref pull request --- NEWS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS.md b/NEWS.md index ecbd70ce472..d27ec29cebb 100644 --- a/NEWS.md +++ b/NEWS.md @@ -15,6 +15,9 @@ for human readability. - New time integrator `PairedExplicitRK2`, implementing the second-order paired explicit Runge-Kutta method with [Convex.jl](https://github.com/jump-dev/Convex.jl) and [ECOS.jl](https://github.com/jump-dev/ECOS.jl) ([#1908]) - Add subcell limiting support for `StructuredMesh` ([#1946]). +- New time integrator `PairedExplicitRK3`, implementing the third-order paired explicit Runge-Kutta + method with [Convex.jl](https://github.com/jump-dev/Convex.jl), [ECOS.jl](https://github.com/jump-dev/ECOS.jl) + , and [NLsolve.jl](https://github.com/JuliaNLSolvers/NLsolve.jl) ([TBD]) ## Changes when updating to v0.7 from v0.6.x From fd3d4ca9fc69e4e3651dfb24f465ad0cc59ce371 Mon Sep 17 00:00:00 2001 From: Warisa Date: Sat, 25 May 2024 23:10:27 +0200 Subject: [PATCH 004/160] add comments and adjustment on solve_a_unknown --- .../elixir_burgers_perk3.jl | 1 - ext/TrixiNLsolveExt.jl | 12 +-- .../methods_PERK3.jl | 83 ++++++++++++------- .../paired_explicit_runge_kutta.jl | 2 +- 4 files changed, 59 insertions(+), 39 deletions(-) diff --git a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl index 08c88f0a012..78d5c003742 100644 --- a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl +++ b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl @@ -53,4 +53,3 @@ sol = Trixi.solve(ode, ode_algorithm, # Print the timer summary summary_callback() - diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 0e92e807c50..4d2c1108ea7 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -10,10 +10,10 @@ else end # Use functions and additional symbols that are not exported -using Trixi: Trixi, @muladd, PairedExplicitRK3_butcher_tableau_objective_function +using Trixi: Trixi, PairedExplicitRK3_butcher_tableau_objective_function, @muladd # Use functions that are to be extended -using Trixi: Trixi, solve_a_unknown +using Trixi: Trixi, solve_a_unknown! # By default, Julia/LLVM does not use fused multiply-add operations (FMAs). # Since these FMAs can increase the performance of many numerical algorithms, @@ -22,11 +22,11 @@ using Trixi: Trixi, solve_a_unknown @muladd begin #! format: noindent -# TODO: edit the comment this function -# Define the new function that includes the nlsolve features -function Trixi.solve_a_unknown(num_stages, monomial_coeffs, c_s2, c; verbose) +# Find the values of a in the Butcher tableau by solving a system of +# non-linear equations +function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; + verbose) is_sol_valid = false - a_unknown = zeros(num_stages) # Define the objective_function function objective_function(x) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index fef3eebc908..15bad4c2f64 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -8,7 +8,7 @@ using DelimitedFiles: readdlm #! format: noindent # Initialize Butcher array abscissae c for PairedExplicitRK3 based on SSPRK33 base method -function compute_c_coeff_SSP33(num_stages, c_s2) +function compute_c_coeffs_SSP33(num_stages, cS2) c = zeros(num_stages) # Last timesteps as for SSPRK33 @@ -17,21 +17,23 @@ function compute_c_coeff_SSP33(num_stages, c_s2) # Linear increasing timestep for remainder for i in 2:(num_stages - 2) - c[i] = c_s2 * (i - 1) / (num_stages - 3) + c[i] = cS2 * (i - 1) / (num_stages - 3) end return c end +# Compute residuals for nonlinear equations to match a stability polynomial with given coefficients, +# in order to find A matrix in the Butcher-Tableau function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_stages, num_stage_evals, - monomial_coeffs, c_s2) - c_ts = compute_c_coeff_SSP33(num_stages, c_s2) # ts = timestep + monomial_coeffs, cS2) + c_ts = compute_c_coeffs_SSP33(num_stages, cS2) # ts = timestep # Equality Constraint array that ensures that the stability polynomial computed from # the to-be-constructed Butcher-Tableau matches the monomial coefficients of the # optimized stability polynomial. - c_eq = zeros(num_stage_evals - 2) # Add equality constraint that c_s2 is equal to 1 + c_eq = zeros(num_stage_evals - 2) # Add equality constraint that cS2 is equal to 1 # Both terms should be present for i in 1:(num_stage_evals - 4) term1 = a_unknown[num_stage_evals - 1] @@ -61,11 +63,13 @@ function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_sta return c_eq end +# Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 +# using a list of eigenvalues function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, eig_vals::Vector{ComplexF64}; - verbose = false, c_s2) + verbose = false, cS2) # Initialize array of c - c = compute_c_coeff_SSP33(num_stages, c_s2) + c = compute_c_coeffs_SSP33(num_stages, cS2) # Initialize the array of our solution a_unknown = zeros(num_stages) @@ -89,14 +93,12 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, monomial_coeffs = undo_normalization!(monomial_coeffs, consistency_order, num_stages) - # Call function that use the library NLsolve to solve the nonlinear system - a_unknown = solve_a_unknown(num_stages, monomial_coeffs, c_s2, c; verbose) + # Solve the nonlinear system of equations from monomial coefficient and + # Butcher array abscissae c to find Butcher matrix A + a_unknown = solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, cS2, c; + verbose) end - # For debugging purpose - println("a_unknown") - println(a_unknown[3:end]) - a_matrix = zeros(num_stages - 2, 2) a_matrix[:, 1] = c[3:end] a_matrix[:, 1] -= a_unknown[3:end] @@ -105,12 +107,14 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, return a_matrix, c, dt_opt end +# Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 +# using provided file containing A matrix from Butcher-Tableau function compute_PairedExplicitRK3_butcher_tableau(num_stages, - base_path_monomial_coeffs::AbstractString, - c_s2) + base_path_a_matrix::AbstractString, + cS2) # Initialize array of c - c = compute_c_coeff_SSP33(num_stages, c_s2) + c = compute_c_coeffs_SSP33(num_stages, cS2) # - 2 Since First entry of A is always zero (explicit method) and second is given by c_2 (consistency) coeffs_max = num_stages - 2 @@ -119,7 +123,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, a_matrix[:, 1] = c[3:end] # TODO: update this to work with CI mktempdir() - path_monomial_coeffs = base_path_monomial_coeffs * "a_" * string(num_stages) * "_" * + path_monomial_coeffs = base_path_a_matrix * "a_" * string(num_stages) * "_" * string(num_stages) * ".txt" @assert isfile(path_monomial_coeffs) "Couldn't find file" A = readdlm(path_monomial_coeffs, Float64) @@ -129,17 +133,34 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, a_matrix[:, 1] -= A a_matrix[:, 2] = A - println("A matrix: ") - display(a_matrix) - println() - return a_matrix, c end -""" - PairedExplicitRK3() +@doc raw""" + PairedExplicitRK3(num_stages, base_path_a_matrix::AbstractString, + dt_opt; + cS2 = 1.0) + PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; + verbose = false, cS2 = 1.0) + PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; + verbose = false, cS2 = 1.0) + + Parameters: + - `num_stages` (`Int`): Number of stages in the PERK method. + - `base_path_a_matrix` (`AbstractString`): Path to a file containing + monomial coefficients of the stability polynomial of PERK method. + The coefficients should be stored in a text file at `joinpath(base_path_a_matrix, "a_$(num_stages).txt")` and separated by line breaks. + - `tspan`: Time span of the simulation. + - `semi` (`AbstractSemidiscretization`): Semidiscretization setup. + - `eig_vals` (`Vector{ComplexF64}`): Eigenvalues of the Jacobian of the right-hand side (rhs) of the ODEProblem after the + equation has been semidiscretized. + - `verbose` (`Bool`, optional): Verbosity flag, default is false. + - `cS2` (`Float64`, optional): Value of c in the Butcher tableau at c_{s-2}, when + s is the number of stages, default is 1.0. + The following structures and methods provide a implementation of the third-order paired explicit Runge-Kutta method + optimized for a certain simulation setup (PDE, IC & BC, Riemann Solver, DG Solver). The original paper is - Nasab, Vermeire (2022) @@ -159,31 +180,31 @@ mutable struct PairedExplicitRK3 <: AbstractPairedExplicitRKSingle end # struct PairedExplicitRK3 # Constructor for previously computed A Coeffs -function PairedExplicitRK3(num_stages, base_path_monomial_coeffs::AbstractString, +function PairedExplicitRK3(num_stages, base_path_a_matrix::AbstractString, dt_opt; - c_s2 = 1.0) + cS2 = 1.0) a_matrix, c = compute_PairedExplicitRK3_butcher_tableau(num_stages, - base_path_monomial_coeffs; - c_s2) + base_path_a_matrix; + cS2) return PairedExplicitRK3(num_stages, a_matrix, c, dt_opt) end # Constructor that computes Butcher matrix A coefficients from a semidiscretization function PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; - verbose = false, c_s2 = 1.0) + verbose = false, cS2 = 1.0) eig_vals = eigvals(jacobian_ad_forward(semi)) - return PairedExplicitRK3(num_stages, tspan, eig_vals; verbose, c_s2) + return PairedExplicitRK3(num_stages, tspan, eig_vals; verbose, cS2) end # Constructor that calculates the coefficients with polynomial optimizer from a list of eigenvalues function PairedExplicitRK3(num_stages, tspan, eig_vals::Vector{ComplexF64}; - verbose = false, c_s2 = 1.0) + verbose = false, cS2 = 1.0) a_matrix, c, dt_opt = compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, eig_vals; - verbose, c_s2) + verbose, cS2) return PairedExplicitRK3(num_stages, a_matrix, c, dt_opt) end diff --git a/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl b/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl index 66fa11e68a3..cc48c3ca458 100644 --- a/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl +++ b/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl @@ -14,5 +14,5 @@ include("polynomial_optimizer.jl") # Add definitions of functions related to polynomial optimization by NLsolve here # such that hey can be exported from Trixi.jl and extended in the TrixiConvexECOSExt package # extension or by the NLsolve-specific code loaded by Requires.jl -function solve_a_unknown end +function solve_a_unknown! end end # @muladd From c28029278d78c56cf7bc1f3fdcd62f05c1025e63 Mon Sep 17 00:00:00 2001 From: Warisa Date: Sat, 25 May 2024 23:29:41 +0200 Subject: [PATCH 005/160] modular implementation with init, step!, and solve_step! --- .../methods_PERK3.jl | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 15bad4c2f64..1ae788e21e4 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -234,8 +234,7 @@ mutable struct PairedExplicitRK3Integrator{RealT <: Real, uType, Params, Sol, F, k_s1::uType # Required for custom third order version of PairedExplicitRK3 end -# Fakes `solve`: https://diffeq.sciml.ai/v6.8/basics/overview/#Solving-the-Problems-1 -function solve(ode::ODEProblem, alg::PairedExplicitRK3; +function init(ode::ODEProblem, alg::PairedExplicitRK3; dt, callback = nothing, kwargs...) u0 = copy(ode.u0) du = zero(u0) @@ -270,10 +269,33 @@ function solve(ode::ODEProblem, alg::PairedExplicitRK3; error("unsupported") end - solve!(integrator) + return integrator +end + +# Fakes `solve`: https://diffeq.sciml.ai/v6.8/basics/overview/#Solving-the-Problems-1 +function solve(ode::ODEProblem, alg::PairedExplicitRK3; + dt, callback = nothing, kwargs...) + integrator = init(ode, alg, dt = dt, callback = callback; kwargs...) + + # Start actual solve + solve_steps!(integrator) +end + +function solve_steps!(integrator::PairedExplicitRK3Integrator) + @unpack prob = integrator.sol + + integrator.finalstep = false + + @trixi_timeit timer() "main loop" while !integrator.finalstep + step!(integrator) + end # "main loop" timer + + return TimeIntegratorSolution((first(prob.tspan), integrator.t), + (prob.u0, integrator.u), + integrator.sol.prob) end -function solve!(integrator::PairedExplicitRK3Integrator) +function step!(integrator::PairedExplicitRK3Integrator) @unpack prob = integrator.sol @unpack alg = integrator t_end = last(prob.tspan) @@ -370,10 +392,6 @@ function solve!(integrator::PairedExplicitRK3Integrator) terminate!(integrator) end end # "main loop" timer - - return TimeIntegratorSolution((first(prob.tspan), integrator.t), - (prob.u0, integrator.u), - integrator.sol.prob) end # used for AMR (Adaptive Mesh Refinement) From 3ddf5c4b14b8901307de7d7f693443b744208357 Mon Sep 17 00:00:00 2001 From: Warisa Date: Sat, 25 May 2024 23:31:38 +0200 Subject: [PATCH 006/160] fmt --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 1ae788e21e4..b656328a86f 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -235,7 +235,7 @@ mutable struct PairedExplicitRK3Integrator{RealT <: Real, uType, Params, Sol, F, end function init(ode::ODEProblem, alg::PairedExplicitRK3; - dt, callback = nothing, kwargs...) + dt, callback = nothing, kwargs...) u0 = copy(ode.u0) du = zero(u0) u_tmp = zero(u0) @@ -274,7 +274,7 @@ end # Fakes `solve`: https://diffeq.sciml.ai/v6.8/basics/overview/#Solving-the-Problems-1 function solve(ode::ODEProblem, alg::PairedExplicitRK3; - dt, callback = nothing, kwargs...) + dt, callback = nothing, kwargs...) integrator = init(ode, alg, dt = dt, callback = callback; kwargs...) # Start actual solve @@ -287,7 +287,7 @@ function solve_steps!(integrator::PairedExplicitRK3Integrator) integrator.finalstep = false @trixi_timeit timer() "main loop" while !integrator.finalstep - step!(integrator) + step!(integrator) end # "main loop" timer return TimeIntegratorSolution((first(prob.tspan), integrator.t), From b9b4243e0b2b249f9c9327c9cb2fbba6d6c0ee20 Mon Sep 17 00:00:00 2001 From: Warisa Date: Sun, 26 May 2024 20:58:43 +0200 Subject: [PATCH 007/160] add test --- test/test_structured_1d.jl | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index f97696d089a..3401b314ceb 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -58,6 +58,21 @@ end end end + +@trixi_testset "elixir_burgers_perk3.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_perk3.jl"), + l2=[8.120426329330083e-8], + linf=[4.906376900315479e-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_sedov.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov.jl"), l2=[3.67478226e-01, 3.49491179e-01, 8.08910759e-01], From a727a871fef3525d3f0c9bfbf5c5ea39357dacfc Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 28 May 2024 23:39:51 +0200 Subject: [PATCH 008/160] adda body of p3 constructor test --- test/test_unit.jl | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/test/test_unit.jl b/test/test_unit.jl index de13d41e931..c94193201e9 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -10,6 +10,10 @@ using DelimitedFiles: readdlm using Convex: Convex using ECOS: Optimizer +# Use NLsolve to load the extension that extends functions for testing +# PERK Single p3 Constructors +using NLsolve: nlsolve + include("test_trixi.jl") # Start with a clean environment: remove Trixi.jl output directory if it exists @@ -1674,6 +1678,40 @@ end 0.13942836392940833 0.3605716360705917], atol = 1e-13) end +@testset "PERK Single p3 Constructors" begin + #TODO: make this a p3 Constructors + path_coeff_file = mktempdir() + Trixi.download("https://gist.githubusercontent.com/DanielDoehring/8db0808b6f80e59420c8632c0d8e2901/raw/39aacf3c737cd642636dd78592dbdfe4cb9499af/MonCoeffsS6p2.txt", + joinpath(path_coeff_file, "gamma_6.txt")) + + ode_algorithm = Trixi.PairedExplicitRK2(6, path_coeff_file) + + @test isapprox(ode_algorithm.a_matrix, + [0.12405417889682908 0.07594582110317093 + 0.16178873711001726 0.13821126288998273 + 0.16692313960864164 0.2330768603913584 + 0.12281292901258256 0.37718707098741744], atol = 1e-13) + + Trixi.download("https://gist.githubusercontent.com/DanielDoehring/c7a89eaaa857e87dde055f78eae9b94a/raw/2937f8872ffdc08e0dcf444ee35f9ebfe18735b0/Spectrum_2D_IsentropicVortex_CEE.txt", + joinpath(path_coeff_file, "spectrum_2d.txt")) + + eig_vals = readdlm(joinpath(path_coeff_file, "spectrum_2d.txt"), ComplexF64) + tspan = (0.0, 1.0) + ode_algorithm = Trixi.PairedExplicitRK2(12, tspan, vec(eig_vals)) + + @test isapprox(ode_algorithm.a_matrix, + [0.06453812656705388 0.02637096434203703 + 0.09470601372266194 0.04165762264097442 + 0.12332877820057538 0.05848940361760645 + 0.1498701503275483 0.07740257694517898 + 0.173421149536068 0.09930612319120471 + 0.19261978147927503 0.12556203670254315 + 0.2052334022622969 0.15840296137406676 + 0.2073489042901963 0.2017420048007128 + 0.19135142349998963 0.2631940310454649 + 0.13942836392940833 0.3605716360705917], atol = 1e-13) +end + @testset "Sutherlands Law" begin function mu(u, equations) T_ref = 291.15 From cb98a3fe8f3c9aad32a978ff06a325316b4457e5 Mon Sep 17 00:00:00 2001 From: Warisa Date: Wed, 29 May 2024 15:07:13 +0200 Subject: [PATCH 009/160] changes according to test and correct variable names --- .../methods_PERK3.jl | 16 ++++++++-------- test/test_unit.jl | 19 +++++++++++-------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index b656328a86f..3cfa3d70a26 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -108,9 +108,9 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, end # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 -# using provided file containing A matrix from Butcher-Tableau +# using provided monomial coefficients file function compute_PairedExplicitRK3_butcher_tableau(num_stages, - base_path_a_matrix::AbstractString, + base_path_monomial_coeffs::AbstractString, cS2) # Initialize array of c @@ -122,9 +122,9 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, a_matrix = zeros(coeffs_max, 2) a_matrix[:, 1] = c[3:end] - # TODO: update this to work with CI mktempdir() - path_monomial_coeffs = base_path_a_matrix * "a_" * string(num_stages) * "_" * - string(num_stages) * ".txt" + path_monomial_coeffs = joinpath(base_path_monomial_coeffs, + "gamma_" * string(num_stages) * ".txt") + @assert isfile(path_monomial_coeffs) "Couldn't find file" A = readdlm(path_monomial_coeffs, Float64) num_monomial_coeffs = size(A, 1) @@ -137,7 +137,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, end @doc raw""" - PairedExplicitRK3(num_stages, base_path_a_matrix::AbstractString, + PairedExplicitRK3(num_stages, base_path_monomial_coeffs::AbstractString, dt_opt; cS2 = 1.0) PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; @@ -147,9 +147,9 @@ end Parameters: - `num_stages` (`Int`): Number of stages in the PERK method. - - `base_path_a_matrix` (`AbstractString`): Path to a file containing + - `base_path_monomial_coeffs` (`AbstractString`): Path to a file containing monomial coefficients of the stability polynomial of PERK method. - The coefficients should be stored in a text file at `joinpath(base_path_a_matrix, "a_$(num_stages).txt")` and separated by line breaks. + The coefficients should be stored in a text file at `joinpath(base_path_monomial_coeffs, "gamma_$(num_stages).txt")` and separated by line breaks. - `tspan`: Time span of the simulation. - `semi` (`AbstractSemidiscretization`): Semidiscretization setup. - `eig_vals` (`Vector{ComplexF64}`): Eigenvalues of the Jacobian of the right-hand side (rhs) of the ODEProblem after the diff --git a/test/test_unit.jl b/test/test_unit.jl index c94193201e9..05bc216e97e 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1679,19 +1679,22 @@ end end @testset "PERK Single p3 Constructors" begin - #TODO: make this a p3 Constructors path_coeff_file = mktempdir() - Trixi.download("https://gist.githubusercontent.com/DanielDoehring/8db0808b6f80e59420c8632c0d8e2901/raw/39aacf3c737cd642636dd78592dbdfe4cb9499af/MonCoeffsS6p2.txt", - joinpath(path_coeff_file, "gamma_6.txt")) + Trixi.download("https://gist.githubusercontent.com/warisa-r/0796db36abcd5abe735ac7eebf41b973/raw/d55cb5bc1837d40febcf47ff620deb1f23185e15/monomial_coeff_s8_p3.txt", + joinpath(path_coeff_file, "gamma_8.txt")) - ode_algorithm = Trixi.PairedExplicitRK2(6, path_coeff_file) + ode_algorithm = Trixi.PairedExplicitRK2(8, path_coeff_file) + #TODO: adjust this value according to the result in the test pipeline @test isapprox(ode_algorithm.a_matrix, - [0.12405417889682908 0.07594582110317093 - 0.16178873711001726 0.13821126288998273 - 0.16692313960864164 0.2330768603913584 - 0.12281292901258256 0.37718707098741744], atol = 1e-13) + [0.335517 0.0644832 + 0.496535 0.103465 + 0.649689 0.150311 + 0.789172 0.210828 + 0.752297 0.247703 + 0.311926 0.188074], atol = 1e-13) + #TODO: make this a p3 Constructors Trixi.download("https://gist.githubusercontent.com/DanielDoehring/c7a89eaaa857e87dde055f78eae9b94a/raw/2937f8872ffdc08e0dcf444ee35f9ebfe18735b0/Spectrum_2D_IsentropicVortex_CEE.txt", joinpath(path_coeff_file, "spectrum_2d.txt")) From d84daedc4e55e5813686ead6eade7b3448212b97 Mon Sep 17 00:00:00 2001 From: Warisa Date: Fri, 31 May 2024 15:39:03 +0200 Subject: [PATCH 010/160] only check the values of a_matrix from second row to end --- test/test_unit.jl | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/test/test_unit.jl b/test/test_unit.jl index 05bc216e97e..0dbac652257 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1683,7 +1683,7 @@ end Trixi.download("https://gist.githubusercontent.com/warisa-r/0796db36abcd5abe735ac7eebf41b973/raw/d55cb5bc1837d40febcf47ff620deb1f23185e15/monomial_coeff_s8_p3.txt", joinpath(path_coeff_file, "gamma_8.txt")) - ode_algorithm = Trixi.PairedExplicitRK2(8, path_coeff_file) + ode_algorithm = Trixi.PairedExplicitRK3(8, path_coeff_file) #TODO: adjust this value according to the result in the test pipeline @test isapprox(ode_algorithm.a_matrix, @@ -1695,24 +1695,33 @@ end 0.311926 0.188074], atol = 1e-13) #TODO: make this a p3 Constructors - Trixi.download("https://gist.githubusercontent.com/DanielDoehring/c7a89eaaa857e87dde055f78eae9b94a/raw/2937f8872ffdc08e0dcf444ee35f9ebfe18735b0/Spectrum_2D_IsentropicVortex_CEE.txt", - joinpath(path_coeff_file, "spectrum_2d.txt")) + Trixi.download("https://gist.githubusercontent.com/warisa-r/8d93f6a3ae0635e13b9f51ee32ab7fff/raw/54dc5b14be9288e186b745facb5bbcb04d1476f8/EigenvalueList_Refined2.txt", + joinpath(path_coeff_file, "spectrum.txt")) - eig_vals = readdlm(joinpath(path_coeff_file, "spectrum_2d.txt"), ComplexF64) + eig_vals = readdlm(joinpath(path_coeff_file, "spectrum.txt"), ComplexF64) tspan = (0.0, 1.0) - ode_algorithm = Trixi.PairedExplicitRK2(12, tspan, vec(eig_vals)) + ode_algorithm = Trixi.PairedExplicitRK3(10, tspan, vec(eig_vals)) - @test isapprox(ode_algorithm.a_matrix, - [0.06453812656705388 0.02637096434203703 - 0.09470601372266194 0.04165762264097442 - 0.12332877820057538 0.05848940361760645 - 0.1498701503275483 0.07740257694517898 - 0.173421149536068 0.09930612319120471 - 0.19261978147927503 0.12556203670254315 - 0.2052334022622969 0.15840296137406676 - 0.2073489042901963 0.2017420048007128 - 0.19135142349998963 0.2631940310454649 - 0.13942836392940833 0.3605716360705917], atol = 1e-13) + #TODO: adjust this value according to the result in the test pipeline + display(ode_algorithm.a_matrix) # Value in CI differs slightly from what I get locally + + # We are only testing from the second row to the end of `ode_algorithm.a_matrix` due to the nature of the system of equations + # used to find the `a_matrix` in the Butcher tableau. This system can have multiple valid solutions, which can cause slight + # variations in the results of the tests. These variations don't affect the validity of the solutions, but they can cause + # the tests to fail due to small differences in the expected and actual values. + + # The first row of `ode_algorithm.a_matrix` is particularly susceptible to these variations, while the rest of the rows + # remain consistent across different runs. Therefore, to make the tests more robust and less prone to false negatives, + # we are excluding the first row from the test. This approach allows us to verify the correctness of the majority of the + # `a_matrix` while avoiding the issue of test instability caused by the multiple valid solutions of the system of equations. + @test isapprox(ode_algorithm.a_matrix[2:end, :], + [0.406023 0.0225489 + 0.534288 0.0371408 + 0.654943 0.0593431 + 0.76216 0.0949827 + 0.844659 0.155341 + 0.771998 0.228002 + 0.307001 0.192999], atol = 1e-13) end @testset "Sutherlands Law" begin From 1332c289dcd0d79c9440c56c1ab8b070ca2f16f0 Mon Sep 17 00:00:00 2001 From: Warisa Date: Fri, 31 May 2024 16:50:50 +0200 Subject: [PATCH 011/160] adjust the the constructor of path coefficient and its test --- .../methods_PERK3.jl | 22 +++++----- test/test_unit.jl | 41 ++++++++++--------- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 3cfa3d70a26..6c6057f4bc3 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -107,10 +107,11 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, return a_matrix, c, dt_opt end +#TODO: Correct this and make it actually import A matrix # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 # using provided monomial coefficients file function compute_PairedExplicitRK3_butcher_tableau(num_stages, - base_path_monomial_coeffs::AbstractString, + base_path_a_coeffs::AbstractString; cS2) # Initialize array of c @@ -122,22 +123,23 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, a_matrix = zeros(coeffs_max, 2) a_matrix[:, 1] = c[3:end] - path_monomial_coeffs = joinpath(base_path_monomial_coeffs, - "gamma_" * string(num_stages) * ".txt") + path_a_coeffs = joinpath(base_path_a_coeffs, + "a_" * string(num_stages) * "_" * string(num_stages) * ".txt") - @assert isfile(path_monomial_coeffs) "Couldn't find file" - A = readdlm(path_monomial_coeffs, Float64) - num_monomial_coeffs = size(A, 1) + @assert isfile(path_a_coeffs) "Couldn't find file" + A = readdlm(path_a_coeffs, Float64) + num_a_coeffs = size(A, 1) - @assert num_monomial_coeffs == coeffs_max + @assert num_a_coeffs == coeffs_max a_matrix[:, 1] -= A a_matrix[:, 2] = A return a_matrix, c end +#TODO: explain dt_opt and also explain base_path_a_coeffs in the first constructor @doc raw""" - PairedExplicitRK3(num_stages, base_path_monomial_coeffs::AbstractString, + PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString, dt_opt; cS2 = 1.0) PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; @@ -180,11 +182,11 @@ mutable struct PairedExplicitRK3 <: AbstractPairedExplicitRKSingle end # struct PairedExplicitRK3 # Constructor for previously computed A Coeffs -function PairedExplicitRK3(num_stages, base_path_a_matrix::AbstractString, +function PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString, dt_opt; cS2 = 1.0) a_matrix, c = compute_PairedExplicitRK3_butcher_tableau(num_stages, - base_path_a_matrix; + base_path_a_coeffs; cS2) return PairedExplicitRK3(num_stages, a_matrix, c, dt_opt) diff --git a/test/test_unit.jl b/test/test_unit.jl index 0dbac652257..eecbe315bc8 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1679,20 +1679,31 @@ end end @testset "PERK Single p3 Constructors" begin + # We are only testing from the second row to the end of `ode_algorithm.a_matrix` due to the nature of the system of equations + # used to find the `a_matrix` in the Butcher tableau. This system can have multiple valid solutions, which can cause slight + # variations in the results of the tests. These variations don't affect the validity of the solutions, but they can cause + # the tests to fail due to small differences in the expected and actual values. + + # The first row of `ode_algorithm.a_matrix` is particularly susceptible to these variations, while the rest of the rows + # remain consistent across different runs. Therefore, to make the tests more robust and less prone to false negatives, + # we are excluding the first row from the test. This approach allows us to verify the correctness of the majority of the + # `a_matrix` while avoiding the issue of test instability caused by the multiple valid solutions of the system of equations. path_coeff_file = mktempdir() - Trixi.download("https://gist.githubusercontent.com/warisa-r/0796db36abcd5abe735ac7eebf41b973/raw/d55cb5bc1837d40febcf47ff620deb1f23185e15/monomial_coeff_s8_p3.txt", - joinpath(path_coeff_file, "gamma_8.txt")) + Trixi.download("https://gist.githubusercontent.com/warisa-r/0796db36abcd5abe735ac7eebf41b973/raw/32889062fd5dcf7f450748f4f5f0797c8155a18d/a_8_8.txt", + joinpath(path_coeff_file, "a_8_8.txt")) - ode_algorithm = Trixi.PairedExplicitRK3(8, path_coeff_file) + # Value of dt_opt obtained from running the simulation in elixir_burgers_perk3 + # The value plays no role in the result but added so that the constructor can be called + dt_opt = 0.004485771991312504 + ode_algorithm = Trixi.PairedExplicitRK3(8, path_coeff_file, dt_opt) #TODO: adjust this value according to the result in the test pipeline - @test isapprox(ode_algorithm.a_matrix, - [0.335517 0.0644832 - 0.496535 0.103465 - 0.649689 0.150311 - 0.789172 0.210828 - 0.752297 0.247703 - 0.311926 0.188074], atol = 1e-13) + @test isapprox(ode_algorithm.a_matrix[2:end, :], + [0.496535 0.103465 + 0.649689 0.150311 + 0.789172 0.210828 + 0.752297 0.247703 + 0.311926 0.188074], atol = 1e-13) #TODO: make this a p3 Constructors Trixi.download("https://gist.githubusercontent.com/warisa-r/8d93f6a3ae0635e13b9f51ee32ab7fff/raw/54dc5b14be9288e186b745facb5bbcb04d1476f8/EigenvalueList_Refined2.txt", @@ -1704,16 +1715,6 @@ end #TODO: adjust this value according to the result in the test pipeline display(ode_algorithm.a_matrix) # Value in CI differs slightly from what I get locally - - # We are only testing from the second row to the end of `ode_algorithm.a_matrix` due to the nature of the system of equations - # used to find the `a_matrix` in the Butcher tableau. This system can have multiple valid solutions, which can cause slight - # variations in the results of the tests. These variations don't affect the validity of the solutions, but they can cause - # the tests to fail due to small differences in the expected and actual values. - - # The first row of `ode_algorithm.a_matrix` is particularly susceptible to these variations, while the rest of the rows - # remain consistent across different runs. Therefore, to make the tests more robust and less prone to false negatives, - # we are excluding the first row from the test. This approach allows us to verify the correctness of the majority of the - # `a_matrix` while avoiding the issue of test instability caused by the multiple valid solutions of the system of equations. @test isapprox(ode_algorithm.a_matrix[2:end, :], [0.406023 0.0225489 0.534288 0.0371408 From 7bf717ad12157a0ea853696dba714c1c838e28ed Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 4 Jun 2024 20:44:23 +0200 Subject: [PATCH 012/160] adjust the test and add a seed to the randomized initial guess for reproducibility --- Project.toml | 9 ++-- ext/TrixiNLsolveExt.jl | 11 ++++- .../methods_PERK3.jl | 30 ++++++------ test/test_structured_1d.jl | 8 +-- test/test_unit.jl | 49 ++++++++----------- 5 files changed, 55 insertions(+), 52 deletions(-) diff --git a/Project.toml b/Project.toml index 6ae18fb29a4..9abf4d36b5d 100644 --- a/Project.toml +++ b/Project.toml @@ -28,6 +28,7 @@ Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" Preferences = "21216c6a-2e73-6563-6e65-726566657250" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" Requires = "ae029012-a4dd-5104-9daa-d747884805df" @@ -50,14 +51,14 @@ TrixiBase = "9a0f1c46-06d5-4909-a5a3-ce25d3fa3284" UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [weakdeps] -Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" Convex = "f65535da-76fb-5f13-bab9-19810c17039a" ECOS = "e2685f51-7e38-5353-a97d-a921fd2c8199" +Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" [extensions] -TrixiMakieExt = "Makie" TrixiConvexECOSExt = ["Convex", "ECOS"] +TrixiMakieExt = "Makie" TrixiNLsolveExt = "NLsolve" [compat] @@ -112,7 +113,7 @@ UUIDs = "1.6" julia = "1.8" [extras] -Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" Convex = "f65535da-76fb-5f13-bab9-19810c17039a" ECOS = "e2685f51-7e38-5353-a97d-a921fd2c8199" -NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" \ No newline at end of file +Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" +NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 4d2c1108ea7..cbe022b1f3a 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -9,6 +9,9 @@ else using ..NLsolve: nlsolve end +# Use other necessary libraries +using Random: seed! + # Use functions and additional symbols that are not exported using Trixi: Trixi, PairedExplicitRK3_butcher_tableau_objective_function, @muladd @@ -36,8 +39,13 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; c_s2) end + # Set the seed for reproducibility of the initial guess of a_unknown + seed!(5555) + while !is_sol_valid + # Initialize initial guess + # The nonlinear system may have multiple valid solutions, so a reproducible initial guess is important x0 = 0.1 .* rand(num_stages) x0[1] = 0.0 x0[2] = c[2] @@ -47,7 +55,8 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; a_unknown = sol.zero - # Check if the values a[i, i-1] >= 0.0 (which stem from the nonlinear solver) and subsequently c[i] - a[i, i-1] >= 0.0 + # Check if the values a[i, i-1] >= 0.0 (which stem from the nonlinear solver) + # and subsequently c[i] - a[i, i-1] >= 0.0 is_sol_valid = all(x -> !isnan(x) && x >= 0, a_unknown[3:end]) && all(x -> !isnan(x) && x >= 0, c[3:end] .- a_unknown[3:end]) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 6c6057f4bc3..ae2042872af 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -94,7 +94,8 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, num_stages) # Solve the nonlinear system of equations from monomial coefficient and - # Butcher array abscissae c to find Butcher matrix A + # Butcher array abscissae c to find Butcher matrix A + # This function is extended in TrixiNLsolveExt.jl a_unknown = solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, cS2, c; verbose) end @@ -107,9 +108,8 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, return a_matrix, c, dt_opt end -#TODO: Correct this and make it actually import A matrix # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 -# using provided monomial coefficients file +# using provided values of coefficients a in a matrix of Butcher tableau function compute_PairedExplicitRK3_butcher_tableau(num_stages, base_path_a_coeffs::AbstractString; cS2) @@ -118,26 +118,26 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, c = compute_c_coeffs_SSP33(num_stages, cS2) # - 2 Since First entry of A is always zero (explicit method) and second is given by c_2 (consistency) - coeffs_max = num_stages - 2 + a_coeffs_max = num_stages - 2 - a_matrix = zeros(coeffs_max, 2) + a_matrix = zeros(a_coeffs_max, 2) a_matrix[:, 1] = c[3:end] path_a_coeffs = joinpath(base_path_a_coeffs, - "a_" * string(num_stages) * "_" * string(num_stages) * ".txt") + "a_" * string(num_stages) * "_" * string(num_stages) * + ".txt") @assert isfile(path_a_coeffs) "Couldn't find file" - A = readdlm(path_a_coeffs, Float64) - num_a_coeffs = size(A, 1) + a_coeffs = readdlm(path_a_coeffs, Float64) + num_a_coeffs = size(a_coeffs, 1) - @assert num_a_coeffs == coeffs_max - a_matrix[:, 1] -= A - a_matrix[:, 2] = A + @assert num_a_coeffs == a_coeffs_max + a_matrix[:, 1] -= a_coeffs + a_matrix[:, 2] = a_coeffs return a_matrix, c end -#TODO: explain dt_opt and also explain base_path_a_coeffs in the first constructor @doc raw""" PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString, dt_opt; @@ -149,9 +149,9 @@ end Parameters: - `num_stages` (`Int`): Number of stages in the PERK method. - - `base_path_monomial_coeffs` (`AbstractString`): Path to a file containing - monomial coefficients of the stability polynomial of PERK method. - The coefficients should be stored in a text file at `joinpath(base_path_monomial_coeffs, "gamma_$(num_stages).txt")` and separated by line breaks. + - `base_path_a_coeffs` (`AbstractString`): Path to a file containing some coefficients in the matrix A in + the Butcher tableau of the Runge Kutta method. + The matrix should be stored in a text file at `joinpath(base_path_a_coeffs, "a_$(num_stages)_.$(num_stages)txt")` and separated by line breaks. - `tspan`: Time span of the simulation. - `semi` (`AbstractSemidiscretization`): Semidiscretization setup. - `eig_vals` (`Vector{ComplexF64}`): Eigenvalues of the Jacobian of the right-hand side (rhs) of the ODEProblem after the diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index 3401b314ceb..7b1c28aa1d6 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -47,7 +47,7 @@ end @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_shockcapturing.jl"), l2=[0.08015029105233593], linf=[0.610709468736576], - atol=1.0e-5) + atol=1.0e-12) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let @@ -58,11 +58,11 @@ end end end - @trixi_testset "elixir_burgers_perk3.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_perk3.jl"), - l2=[8.120426329330083e-8], - linf=[4.906376900315479e-7]) + l2=[8.120426320528704e-8], + linf=[4.906376875890572e-7], + atol=1.0e-5) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let diff --git a/test/test_unit.jl b/test/test_unit.jl index eecbe315bc8..62a04496c07 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1679,18 +1679,9 @@ end end @testset "PERK Single p3 Constructors" begin - # We are only testing from the second row to the end of `ode_algorithm.a_matrix` due to the nature of the system of equations - # used to find the `a_matrix` in the Butcher tableau. This system can have multiple valid solutions, which can cause slight - # variations in the results of the tests. These variations don't affect the validity of the solutions, but they can cause - # the tests to fail due to small differences in the expected and actual values. - - # The first row of `ode_algorithm.a_matrix` is particularly susceptible to these variations, while the rest of the rows - # remain consistent across different runs. Therefore, to make the tests more robust and less prone to false negatives, - # we are excluding the first row from the test. This approach allows us to verify the correctness of the majority of the - # `a_matrix` while avoiding the issue of test instability caused by the multiple valid solutions of the system of equations. path_coeff_file = mktempdir() Trixi.download("https://gist.githubusercontent.com/warisa-r/0796db36abcd5abe735ac7eebf41b973/raw/32889062fd5dcf7f450748f4f5f0797c8155a18d/a_8_8.txt", - joinpath(path_coeff_file, "a_8_8.txt")) + joinpath(path_coeff_file, "a_8_8.txt")) # Value of dt_opt obtained from running the simulation in elixir_burgers_perk3 # The value plays no role in the result but added so that the constructor can be called @@ -1698,31 +1689,33 @@ end ode_algorithm = Trixi.PairedExplicitRK3(8, path_coeff_file, dt_opt) #TODO: adjust this value according to the result in the test pipeline - @test isapprox(ode_algorithm.a_matrix[2:end, :], - [0.496535 0.103465 - 0.649689 0.150311 - 0.789172 0.210828 - 0.752297 0.247703 - 0.311926 0.188074], atol = 1e-13) - - #TODO: make this a p3 Constructors + println(ode_algorithm.a_matrix) # Value in CI differs slightly from what I get locally + @test isapprox(ode_algorithm.a_matrix, + [0.3355167784195604 0.06448322158043965 + 0.4965349205803965 0.10346507941960345 + 0.6496890792935297 0.15031092070647037 + 0.789172498521197 0.21082750147880308 + 0.7522972036571336 0.2477027963428664 + 0.31192569908571666 0.18807430091428337], atol = 1e-13) + Trixi.download("https://gist.githubusercontent.com/warisa-r/8d93f6a3ae0635e13b9f51ee32ab7fff/raw/54dc5b14be9288e186b745facb5bbcb04d1476f8/EigenvalueList_Refined2.txt", joinpath(path_coeff_file, "spectrum.txt")) eig_vals = readdlm(joinpath(path_coeff_file, "spectrum.txt"), ComplexF64) tspan = (0.0, 1.0) - ode_algorithm = Trixi.PairedExplicitRK3(10, tspan, vec(eig_vals)) + ode_algorithm = Trixi.PairedExplicitRK3(13, tspan, vec(eig_vals)) #TODO: adjust this value according to the result in the test pipeline - display(ode_algorithm.a_matrix) # Value in CI differs slightly from what I get locally - @test isapprox(ode_algorithm.a_matrix[2:end, :], - [0.406023 0.0225489 - 0.534288 0.0371408 - 0.654943 0.0593431 - 0.76216 0.0949827 - 0.844659 0.155341 - 0.771998 0.228002 - 0.307001 0.192999], atol = 1e-13) + println(ode_algorithm.a_matrix) # Value in CI differs slightly from what I get locally + @test isapprox(ode_algorithm.a_matrix, + [0.27321088155198703 0.01250340416229867 + 0.4060225225166573 0.022548906054771216 + 0.534287756076577 0.03714081535199439 + 0.6549425779583463 0.05934313632736803 + 0.7621601562844809 0.09498270085837623 + 0.8446587253087918 0.1553412746912082 + 0.7719976108598626 0.22800238914013735 + 0.30700059728503437 0.1929994027149656], atol = 1e-13) end @testset "Sutherlands Law" begin From 43cf02d08d7bff63467e6b6cb80c1696e0a03846 Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 4 Jun 2024 20:49:09 +0200 Subject: [PATCH 013/160] add NLsolve as a dependency for testing --- Project.toml | 1 + test/Project.toml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Project.toml b/Project.toml index 901e9477840..5f558090316 100644 --- a/Project.toml +++ b/Project.toml @@ -90,6 +90,7 @@ Polyester = "0.7.10" PrecompileTools = "1.1" Preferences = "1.3" Printf = "1" +Random = "1" RecipesBase = "1.1" Reexport = "1.0" Requires = "1.1" diff --git a/test/Project.toml b/test/Project.toml index c8ae33a40ae..84d35d6ca26 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -10,6 +10,7 @@ FFMPEG = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195" +NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" @@ -28,6 +29,7 @@ FFMPEG = "0.4" ForwardDiff = "0.10.24" LinearAlgebra = "1" MPI = "0.20" +NLsolve = "4.5.1" OrdinaryDiffEq = "6.49.1" Plots = "1.19" Printf = "1" From 9ed5e2b22e59baa6e226625eb8435a22f84704d0 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Thu, 6 Jun 2024 19:20:36 +0200 Subject: [PATCH 014/160] Update ext/TrixiNLsolveExt.jl Co-authored-by: Daniel Doehring --- ext/TrixiNLsolveExt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index cbe022b1f3a..f86309f54a4 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -25,7 +25,7 @@ using Trixi: Trixi, solve_a_unknown! @muladd begin #! format: noindent -# Find the values of a in the Butcher tableau by solving a system of +# Find the values of the a_{i, i-1} in the Butcher tableau matrix A by solving a system of # non-linear equations function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; verbose) From a7393507e770da92f26570f4346793d413503500 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Thu, 6 Jun 2024 19:20:43 +0200 Subject: [PATCH 015/160] Update ext/TrixiNLsolveExt.jl Co-authored-by: Daniel Doehring --- ext/TrixiNLsolveExt.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index f86309f54a4..d894198127a 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -45,7 +45,8 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; while !is_sol_valid # Initialize initial guess - # The nonlinear system may have multiple valid solutions, so a reproducible initial guess is important + # The nonlinear system may have multiple valid solutions. + # For the sake of reproducibility, we use a seeded random initial guess x0 = 0.1 .* rand(num_stages) x0[1] = 0.0 x0[2] = c[2] From cf7178422a8bcd5cb3288a9dffa2db5b838f91f5 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Thu, 6 Jun 2024 19:20:57 +0200 Subject: [PATCH 016/160] Update ext/TrixiNLsolveExt.jl Co-authored-by: Daniel Doehring --- ext/TrixiNLsolveExt.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index d894198127a..61810115157 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -26,7 +26,9 @@ using Trixi: Trixi, solve_a_unknown! #! format: noindent # Find the values of the a_{i, i-1} in the Butcher tableau matrix A by solving a system of -# non-linear equations +# non-linear equations that arise from the relation of the stability polynomial to the Butcher tableau. +# For details, see Proposition 3.2, Equation (3.3) from +# Hairer, Wanner: Solving Ordinary Differential Equations 2 function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; verbose) is_sol_valid = false From 01a43433222727f32291c9705cdcf8502e7f5486 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Thu, 6 Jun 2024 19:21:02 +0200 Subject: [PATCH 017/160] Update ext/TrixiNLsolveExt.jl Co-authored-by: Daniel Doehring --- ext/TrixiNLsolveExt.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 61810115157..27438b69859 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -50,6 +50,7 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; # The nonlinear system may have multiple valid solutions. # For the sake of reproducibility, we use a seeded random initial guess x0 = 0.1 .* rand(num_stages) + # For explicit methods, a_{1,1} = 0 and a_{2,1} = c_2 (Butcher's condition) x0[1] = 0.0 x0[2] = c[2] From 0deb7bce70b105db5c5bd556d1df30e28ed6e0f3 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Thu, 6 Jun 2024 19:21:09 +0200 Subject: [PATCH 018/160] Update ext/TrixiNLsolveExt.jl Co-authored-by: Daniel Doehring --- ext/TrixiNLsolveExt.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 27438b69859..01919914d6c 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -54,7 +54,8 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; x0[1] = 0.0 x0[2] = c[2] - sol = nlsolve(objective_function, x0, method = :trust_region, ftol = 4e-16, + sol = nlsolve(objective_function, x0, method = :trust_region, + ftol = 4e-16, # Enforce objective up to machine precision iterations = 10^4, xtol = 1e-13) a_unknown = sol.zero From 0708bc4b697b7620ba7a770bb09072af4ef0af16 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Thu, 6 Jun 2024 19:21:27 +0200 Subject: [PATCH 019/160] Update src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl Co-authored-by: Daniel Doehring --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index ae2042872af..fe3f30dd011 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -12,8 +12,8 @@ function compute_c_coeffs_SSP33(num_stages, cS2) c = zeros(num_stages) # Last timesteps as for SSPRK33 - c[num_stages] = 0.5 c[num_stages - 1] = 1 + c[num_stages] = 0.5 # Linear increasing timestep for remainder for i in 2:(num_stages - 2) From 0a5ad480653814c70e07080be2fbac509d526f8f Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Thu, 6 Jun 2024 19:21:32 +0200 Subject: [PATCH 020/160] Update src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl Co-authored-by: Daniel Doehring --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index fe3f30dd011..13435fe5c58 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -132,6 +132,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, num_a_coeffs = size(a_coeffs, 1) @assert num_a_coeffs == a_coeffs_max + # Fill A-matrix in P-ERK style a_matrix[:, 1] -= a_coeffs a_matrix[:, 2] = a_coeffs From 0a3ab554c1ddb9f94fa6ee919cf19147f34ae9bb Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Thu, 6 Jun 2024 19:21:36 +0200 Subject: [PATCH 021/160] Update src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl Co-authored-by: Daniel Doehring --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 13435fe5c58..a571859eb28 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -163,7 +163,6 @@ end The following structures and methods provide a implementation of the third-order paired explicit Runge-Kutta method - optimized for a certain simulation setup (PDE, IC & BC, Riemann Solver, DG Solver). The original paper is - Nasab, Vermeire (2022) From 8c978e2cb48222da7ce6bc74a2377ddbefe0d252 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Thu, 6 Jun 2024 19:21:44 +0200 Subject: [PATCH 022/160] Update src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl Co-authored-by: Daniel Doehring --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index a571859eb28..28d2bc153c5 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -99,7 +99,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, a_unknown = solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, cS2, c; verbose) end - + # Fill A-matrix in P-ERK style a_matrix = zeros(num_stages - 2, 2) a_matrix[:, 1] = c[3:end] a_matrix[:, 1] -= a_unknown[3:end] From 45324a26d5ead88f7c96948dab358fb17bbcf80a Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 10 Jun 2024 14:44:33 +0200 Subject: [PATCH 023/160] optimize the loop for step! by moving the condition outside --- ext/TrixiConvexECOSExt.jl | 2 +- .../paired_explicit_runge_kutta/methods_PERK3.jl | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/ext/TrixiConvexECOSExt.jl b/ext/TrixiConvexECOSExt.jl index 948dbf103cd..fac127699ce 100644 --- a/ext/TrixiConvexECOSExt.jl +++ b/ext/TrixiConvexECOSExt.jl @@ -136,7 +136,7 @@ function Trixi.bisect_stability_polynomial(consistency_order, num_eig_vals, "reltol_inacc" => 5e-5, "nitref" => 9, "maxit" => 100, - "verbose" => 3); silent = true) + "verbose" => 3); silent_solver = true) abs_p = problem.optval diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 28d2bc153c5..cc4cad7ba76 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -344,7 +344,7 @@ function step!(integrator::PairedExplicitRK3Integrator) end # Higher stages - for stage in 3:(alg.num_stages) + for stage in 3:(alg.num_stages-1) # Construct current state @threaded for i in eachindex(integrator.du) integrator.u_tmp[i] = integrator.u[i] + @@ -360,13 +360,11 @@ function step!(integrator::PairedExplicitRK3Integrator) @threaded for i in eachindex(integrator.du) integrator.k_higher[i] = integrator.du[i] * integrator.dt end + end - # IDEA: Stop for loop at num_stages -1 to avoid if (maybe more performant?) - if stage == alg.num_stages - 1 - @threaded for i in eachindex(integrator.du) - integrator.k_s1[i] = integrator.k_higher[i] - end - end + # IDEA: Stop for loop at num_stages -1 to avoid if (maybe more performant?) + @threaded for i in eachindex(integrator.du) + integrator.k_s1[i] = integrator.k_higher[i] end @threaded for i in eachindex(integrator.u) From ca5951ae41ff615a9ea27cfbba2f1916fc15249d Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 10 Jun 2024 14:53:55 +0200 Subject: [PATCH 024/160] fmt --- ext/TrixiNLsolveExt.jl | 2 +- .../paired_explicit_runge_kutta/methods_PERK3.jl | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 01919914d6c..0d6eae1ba7c 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -54,7 +54,7 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; x0[1] = 0.0 x0[2] = c[2] - sol = nlsolve(objective_function, x0, method = :trust_region, + sol = nlsolve(objective_function, x0, method = :trust_region, ftol = 4e-16, # Enforce objective up to machine precision iterations = 10^4, xtol = 1e-13) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index cc4cad7ba76..89a89788975 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -24,7 +24,7 @@ function compute_c_coeffs_SSP33(num_stages, cS2) end # Compute residuals for nonlinear equations to match a stability polynomial with given coefficients, -# in order to find A matrix in the Butcher-Tableau +# in order to find A-matrix in the Butcher-Tableau function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_stages, num_stage_evals, monomial_coeffs, cS2) @@ -99,7 +99,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, a_unknown = solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, cS2, c; verbose) end - # Fill A-matrix in P-ERK style + # Fill A-matrix in P-ERK style a_matrix = zeros(num_stages - 2, 2) a_matrix[:, 1] = c[3:end] a_matrix[:, 1] -= a_unknown[3:end] @@ -109,7 +109,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, end # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 -# using provided values of coefficients a in a matrix of Butcher tableau +# using provided values of coefficients a in A-matrix of Butcher tableau function compute_PairedExplicitRK3_butcher_tableau(num_stages, base_path_a_coeffs::AbstractString; cS2) @@ -150,7 +150,7 @@ end Parameters: - `num_stages` (`Int`): Number of stages in the PERK method. - - `base_path_a_coeffs` (`AbstractString`): Path to a file containing some coefficients in the matrix A in + - `base_path_a_coeffs` (`AbstractString`): Path to a file containing some coefficients in the A-matrix in the Butcher tableau of the Runge Kutta method. The matrix should be stored in a text file at `joinpath(base_path_a_coeffs, "a_$(num_stages)_.$(num_stages)txt")` and separated by line breaks. - `tspan`: Time span of the simulation. @@ -344,7 +344,7 @@ function step!(integrator::PairedExplicitRK3Integrator) end # Higher stages - for stage in 3:(alg.num_stages-1) + for stage in 3:(alg.num_stages - 1) # Construct current state @threaded for i in eachindex(integrator.du) integrator.u_tmp[i] = integrator.u[i] + @@ -362,7 +362,6 @@ function step!(integrator::PairedExplicitRK3Integrator) end end - # IDEA: Stop for loop at num_stages -1 to avoid if (maybe more performant?) @threaded for i in eachindex(integrator.du) integrator.k_s1[i] = integrator.k_higher[i] end From 76a7a6bf8f52cb5ef5fb7a59345740cda7181650 Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 10 Jun 2024 15:03:28 +0200 Subject: [PATCH 025/160] more type generic --- ext/TrixiNLsolveExt.jl | 4 ++-- .../paired_explicit_runge_kutta/methods_PERK3.jl | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 0d6eae1ba7c..5830d23fae6 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -51,7 +51,7 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; # For the sake of reproducibility, we use a seeded random initial guess x0 = 0.1 .* rand(num_stages) # For explicit methods, a_{1,1} = 0 and a_{2,1} = c_2 (Butcher's condition) - x0[1] = 0.0 + x0[1] = 0 x0[2] = c[2] sol = nlsolve(objective_function, x0, method = :trust_region, @@ -61,7 +61,7 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; a_unknown = sol.zero # Check if the values a[i, i-1] >= 0.0 (which stem from the nonlinear solver) - # and subsequently c[i] - a[i, i-1] >= 0.0 + # and subsequently c[i] - a[i, i-1] >= 0.0 since all coefficients are non-negative is_sol_valid = all(x -> !isnan(x) && x >= 0, a_unknown[3:end]) && all(x -> !isnan(x) && x >= 0, c[3:end] .- a_unknown[3:end]) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 89a89788975..1972ca89d87 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -57,7 +57,7 @@ function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_sta term2 *= c_ts[num_stages - 1 - i] * 4 / 6 c_eq[i] = monomial_coeffs[i] - term2 - c_eq[num_stage_evals - 2] = 1.0 - 4 * a_unknown[num_stage_evals] - + c_eq[num_stage_evals - 2] = 1 - 4 * a_unknown[num_stage_evals] - a_unknown[num_stage_evals - 1] return c_eq @@ -194,7 +194,7 @@ end # Constructor that computes Butcher matrix A coefficients from a semidiscretization function PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; - verbose = false, cS2 = 1.0) + verbose = false, cS2 = 1) eig_vals = eigvals(jacobian_ad_forward(semi)) return PairedExplicitRK3(num_stages, tspan, eig_vals; verbose, cS2) @@ -202,7 +202,7 @@ end # Constructor that calculates the coefficients with polynomial optimizer from a list of eigenvalues function PairedExplicitRK3(num_stages, tspan, eig_vals::Vector{ComplexF64}; - verbose = false, cS2 = 1.0) + verbose = false, cS2 = 1) a_matrix, c, dt_opt = compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, eig_vals; From 03fad1bf8bcf76cd4f7794a374b36cb9c3ae2612 Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 10 Jun 2024 15:05:00 +0200 Subject: [PATCH 026/160] change some names --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 1972ca89d87..201bfffeb54 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -233,7 +233,7 @@ mutable struct PairedExplicitRK3Integrator{RealT <: Real, uType, Params, Sol, F, # PairedExplicitRK stages: k1::uType k_higher::uType - k_s1::uType # Required for custom third order version of PairedExplicitRK3 + k_S1::uType # Required for custom third order version of PairedExplicitRK3 end function init(ode::ODEProblem, alg::PairedExplicitRK3; @@ -245,7 +245,7 @@ function init(ode::ODEProblem, alg::PairedExplicitRK3; # PairedExplicitRK stages k1 = zero(u0) k_higher = zero(u0) - k_s1 = zero(u0) + k_S1 = zero(u0) t0 = first(ode.tspan) iter = 0 @@ -257,7 +257,7 @@ function init(ode::ODEProblem, alg::PairedExplicitRK3; ode.tspan; kwargs...), false, - k1, k_higher, k_s1) + k1, k_higher, k_S1) # initialize callbacks if callback isa CallbackSet @@ -339,7 +339,7 @@ function step!(integrator::PairedExplicitRK3Integrator) if alg.num_stages == 3 @threaded for i in eachindex(integrator.du) - integrator.k_s1[i] = integrator.k_higher[i] + integrator.k_S1[i] = integrator.k_higher[i] end end @@ -363,12 +363,12 @@ function step!(integrator::PairedExplicitRK3Integrator) end @threaded for i in eachindex(integrator.du) - integrator.k_s1[i] = integrator.k_higher[i] + integrator.k_S1[i] = integrator.k_higher[i] end @threaded for i in eachindex(integrator.u) # "Own" PairedExplicitRK based on SSPRK33 - integrator.u[i] += (integrator.k1[i] + integrator.k_s1[i] + + integrator.u[i] += (integrator.k1[i] + integrator.k_S1[i] + 4.0 * integrator.k_higher[i]) / 6.0 end end # PairedExplicitRK step timer @@ -401,6 +401,6 @@ function Base.resize!(integrator::PairedExplicitRK3Integrator, new_size) resize!(integrator.k1, new_size) resize!(integrator.k_higher, new_size) - resize!(integrator.k_s1, new_size) + resize!(integrator.k_S1, new_size) end end # @muladd From 78ae8da84b8104e750d8350966e55c97bd018eac Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 10 Jun 2024 15:08:26 +0200 Subject: [PATCH 027/160] update test --- test/test_structured_1d.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index 7b1c28aa1d6..513d7e710ad 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -60,9 +60,9 @@ end @trixi_testset "elixir_burgers_perk3.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_perk3.jl"), - l2=[8.120426320528704e-8], - linf=[4.906376875890572e-7], - atol=1.0e-5) + l2=[NaN], + linf=[0.0], + atol=1.0e-12) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let From c5c455f8df8db8fd4a82405b4969a4fb82b09212 Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 10 Jun 2024 21:28:10 +0200 Subject: [PATCH 028/160] Correcting steps! --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 15 +++++++++++++++ test/test_structured_1d.jl | 6 +++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 201bfffeb54..4938d37d5ef 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -366,6 +366,21 @@ function step!(integrator::PairedExplicitRK3Integrator) integrator.k_S1[i] = integrator.k_higher[i] end + # Last stage + @threaded for i in eachindex(integrator.du) + integrator.u_tmp[i] = integrator.u[i] + + alg.a_matrix[alg.num_stages - 2, 1] * + integrator.k1[i] + + alg.a_matrix[alg.num_stages - 2, 2] * + integrator.k_higher[i] + end + + integrator.f(integrator.du, integrator.u_tmp, prob.p, + integrator.t + alg.c[alg.num_stages] * integrator.dt) + @threaded for i in eachindex(integrator.du) + integrator.k_higher[i] = integrator.du[i] * integrator.dt + end + @threaded for i in eachindex(integrator.u) # "Own" PairedExplicitRK based on SSPRK33 integrator.u[i] += (integrator.k1[i] + integrator.k_S1[i] + diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index 513d7e710ad..279febbd5b9 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -60,9 +60,9 @@ end @trixi_testset "elixir_burgers_perk3.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_perk3.jl"), - l2=[NaN], - linf=[0.0], - atol=1.0e-12) + l2=[8.120426320528704e-8], + linf=[4.906376875890572e-7], + atol=1.0e-6) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let From 1bfb576c9fb105d4990cbd8a0700ed3901cced80 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Mon, 10 Jun 2024 21:31:33 +0200 Subject: [PATCH 029/160] Apply suggestions from code review Co-authored-by: Daniel Doehring --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 4938d37d5ef..33980d85adb 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -11,7 +11,9 @@ using DelimitedFiles: readdlm function compute_c_coeffs_SSP33(num_stages, cS2) c = zeros(num_stages) - # Last timesteps as for SSPRK33 + # Last timesteps as for SSPRK33, see motivation in + # https://doi.org/10.48550/arXiv.2403.05144 + c[num_stages - 1] = 1 c[num_stages] = 0.5 @@ -33,8 +35,10 @@ function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_sta # Equality Constraint array that ensures that the stability polynomial computed from # the to-be-constructed Butcher-Tableau matches the monomial coefficients of the # optimized stability polynomial. + # For details, see Chapter4.3, Proposition 3.2, Equation (3.3) from + # Hairer, Wanner: Solving Ordinary Differential Equations 2 c_eq = zeros(num_stage_evals - 2) # Add equality constraint that cS2 is equal to 1 - # Both terms should be present + # Lower-order terms: Two summands present for i in 1:(num_stage_evals - 4) term1 = a_unknown[num_stage_evals - 1] term2 = a_unknown[num_stage_evals] @@ -42,8 +46,8 @@ function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_sta term1 *= a_unknown[num_stage_evals - 1 - j] term2 *= a_unknown[num_stage_evals - j] end - term1 *= c_ts[num_stages - 2 - i] * 1 / 6 - term2 *= c_ts[num_stages - 1 - i] * 4 / 6 + term1 *= c_ts[num_stages - 2 - i] * 1 / 6 # 1/ 6 = b_{S-1} + term2 *= c_ts[num_stages - 1 - i] * 2 / 3 # 2 / 3 = b_S c_eq[i] = monomial_coeffs[i] - (term1 + term2) end @@ -54,7 +58,7 @@ function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_sta for j in 1:i term2 *= a_unknown[num_stage_evals - j] end - term2 *= c_ts[num_stages - 1 - i] * 4 / 6 + term2 *= c_ts[num_stages - 1 - i] * 2 / 3 # 2 / 3 = b_S c_eq[i] = monomial_coeffs[i] - term2 c_eq[num_stage_evals - 2] = 1 - 4 * a_unknown[num_stage_evals] - From 86a4daade36710989e773e1eb3605dd125de65ba Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Mon, 10 Jun 2024 21:31:56 +0200 Subject: [PATCH 030/160] Update examples/structured_1d_dgsem/elixir_burgers_perk3.jl Co-authored-by: Daniel Doehring --- examples/structured_1d_dgsem/elixir_burgers_perk3.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl index 78d5c003742..1c54731c2d3 100644 --- a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl +++ b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl @@ -10,7 +10,7 @@ equations = InviscidBurgersEquation1D() initial_condition = initial_condition_convergence_test -# Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux +# 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) coordinates_min = (0.0,) # minimum coordinate From 786de996e447bb994a7f2b00738a355d0ccde243 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Mon, 10 Jun 2024 21:32:09 +0200 Subject: [PATCH 031/160] Update examples/structured_1d_dgsem/elixir_burgers_perk3.jl Co-authored-by: Daniel Doehring --- examples/structured_1d_dgsem/elixir_burgers_perk3.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl index 1c54731c2d3..d93d3d0fbb2 100644 --- a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl +++ b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl @@ -17,7 +17,6 @@ coordinates_min = (0.0,) # minimum coordinate coordinates_max = (1.0,) # maximum coordinate cells_per_dimension = (64,) -# Create curved mesh with 16 cells mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, From a3d6df5a8c5a8e1b84a889470daba98f21c46100 Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 10 Jun 2024 22:46:24 +0200 Subject: [PATCH 032/160] add docstring about dt_opt --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 33980d85adb..e645ee37fcb 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -157,6 +157,8 @@ end - `base_path_a_coeffs` (`AbstractString`): Path to a file containing some coefficients in the A-matrix in the Butcher tableau of the Runge Kutta method. The matrix should be stored in a text file at `joinpath(base_path_a_coeffs, "a_$(num_stages)_.$(num_stages)txt")` and separated by line breaks. + - `dt_opt` (`Float64`): The optimal time step size that must be supplied when using the first constructor with A-matrix coefficients, + unlike the second or third constructors which calculate it automatically. - `tspan`: Time span of the simulation. - `semi` (`AbstractSemidiscretization`): Semidiscretization setup. - `eig_vals` (`Vector{ComplexF64}`): Eigenvalues of the Jacobian of the right-hand side (rhs) of the ODEProblem after the From 4e35589736c74961dbe0a4aed1f882b1a185d135 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Tue, 11 Jun 2024 17:30:05 +0200 Subject: [PATCH 033/160] Update src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl Co-authored-by: Daniel Doehring --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index e645ee37fcb..32f0a152c43 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -368,6 +368,7 @@ function step!(integrator::PairedExplicitRK3Integrator) end end + # Store K_{S-1} @threaded for i in eachindex(integrator.du) integrator.k_S1[i] = integrator.k_higher[i] end From a4b3df6d893f8f4ea9da9154047d5f0e5af25d22 Mon Sep 17 00:00:00 2001 From: Warisa Date: Wed, 12 Jun 2024 09:41:10 +0200 Subject: [PATCH 034/160] merge k_higher in the last stage to a bigger loop --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 32f0a152c43..08a107a5369 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -384,14 +384,11 @@ function step!(integrator::PairedExplicitRK3Integrator) integrator.f(integrator.du, integrator.u_tmp, prob.p, integrator.t + alg.c[alg.num_stages] * integrator.dt) - @threaded for i in eachindex(integrator.du) - integrator.k_higher[i] = integrator.du[i] * integrator.dt - end @threaded for i in eachindex(integrator.u) # "Own" PairedExplicitRK based on SSPRK33 integrator.u[i] += (integrator.k1[i] + integrator.k_S1[i] + - 4.0 * integrator.k_higher[i]) / 6.0 + 4.0 * integrator.du[i] * integrator.dt) / 6.0 end end # PairedExplicitRK step timer From 6a03a3ae1a25f331d46e61ae4dfcf7f1bb3eba9f Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Wed, 12 Jun 2024 09:44:54 +0200 Subject: [PATCH 035/160] Update src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl Co-authored-by: Daniel Doehring --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 08a107a5369..78523b33664 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -61,6 +61,7 @@ function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_sta term2 *= c_ts[num_stages - 1 - i] * 2 / 3 # 2 / 3 = b_S c_eq[i] = monomial_coeffs[i] - term2 + # Third-order consistency condition (Cf. eq. (27) from https://doi.org/10.1016/j.jcp.2022.111470 c_eq[num_stage_evals - 2] = 1 - 4 * a_unknown[num_stage_evals] - a_unknown[num_stage_evals - 1] From b5f227aefa9f846c3d0f0fa3d99cdb357917cdad Mon Sep 17 00:00:00 2001 From: Warisa Date: Fri, 14 Jun 2024 11:50:47 +0200 Subject: [PATCH 036/160] change solve_step! to solve! --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 78523b33664..f2565dea687 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -287,10 +287,10 @@ function solve(ode::ODEProblem, alg::PairedExplicitRK3; integrator = init(ode, alg, dt = dt, callback = callback; kwargs...) # Start actual solve - solve_steps!(integrator) + solve!(integrator) end -function solve_steps!(integrator::PairedExplicitRK3Integrator) +function solve!(integrator::PairedExplicitRK3Integrator) @unpack prob = integrator.sol integrator.finalstep = false From d029c218a201c614b47db0051272e010bde4c9b9 Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 17 Jun 2024 14:53:29 +0200 Subject: [PATCH 037/160] Correct the logic of step! --- .../methods_PERK2.jl | 4 +- .../methods_PERK3.jl | 148 +++++++++--------- 2 files changed, 74 insertions(+), 78 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK2.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK2.jl index b3b917dc18d..1d9680153e6 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK2.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK2.jl @@ -273,10 +273,10 @@ function solve(ode::ODEProblem, alg::PairedExplicitRK2; integrator = init(ode, alg, dt = dt, callback = callback; kwargs...) # Start actual solve - solve_steps!(integrator) + solve!(integrator) end -function solve_steps!(integrator::PairedExplicitRK2Integrator) +function solve!(integrator::PairedExplicitRK2Integrator) @unpack prob = integrator.sol integrator.finalstep = false diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index f2565dea687..839b5629e8f 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -310,107 +310,103 @@ function step!(integrator::PairedExplicitRK3Integrator) t_end = last(prob.tspan) callbacks = integrator.opts.callback - integrator.finalstep = false + @assert !integrator.finalstep + if isnan(integrator.dt) + error("time step size `dt` is NaN") + end - #@trixi_timeit timer() "main loop" while !integrator.finalstep - while !integrator.finalstep - if isnan(integrator.dt) - error("time step size `dt` is NaN") + # 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 + + @trixi_timeit timer() "Paired Explicit Runge-Kutta ODE integration step" begin + # k1 + integrator.f(integrator.du, integrator.u, prob.p, integrator.t) + @threaded for i in eachindex(integrator.du) + integrator.k1[i] = integrator.du[i] * integrator.dt 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) + # Construct current state + @threaded for i in eachindex(integrator.du) + integrator.u_tmp[i] = integrator.u[i] + alg.c[2] * integrator.k1[i] end + # k2 + integrator.f(integrator.du, integrator.u_tmp, prob.p, + integrator.t + alg.c[2] * integrator.dt) - @trixi_timeit timer() "Paired Explicit Runge-Kutta ODE integration step" begin - # k1 - integrator.f(integrator.du, integrator.u, prob.p, integrator.t) + @threaded for i in eachindex(integrator.du) + integrator.k_higher[i] = integrator.du[i] * integrator.dt + end + + if alg.num_stages == 3 @threaded for i in eachindex(integrator.du) - integrator.k1[i] = integrator.du[i] * integrator.dt + integrator.k_S1[i] = integrator.k_higher[i] end + end + # Higher stages + for stage in 3:(alg.num_stages - 1) # Construct current state @threaded for i in eachindex(integrator.du) - integrator.u_tmp[i] = integrator.u[i] + alg.c[2] * integrator.k1[i] + integrator.u_tmp[i] = integrator.u[i] + + alg.a_matrix[stage - 2, 1] * + integrator.k1[i] + + alg.a_matrix[stage - 2, 2] * + integrator.k_higher[i] end - # k2 + integrator.f(integrator.du, integrator.u_tmp, prob.p, - integrator.t + alg.c[2] * integrator.dt) + integrator.t + alg.c[stage] * integrator.dt) @threaded for i in eachindex(integrator.du) integrator.k_higher[i] = integrator.du[i] * integrator.dt end + end - if alg.num_stages == 3 - @threaded for i in eachindex(integrator.du) - integrator.k_S1[i] = integrator.k_higher[i] - end - end - - # Higher stages - for stage in 3:(alg.num_stages - 1) - # Construct current state - @threaded for i in eachindex(integrator.du) - integrator.u_tmp[i] = integrator.u[i] + - alg.a_matrix[stage - 2, 1] * - integrator.k1[i] + - alg.a_matrix[stage - 2, 2] * - integrator.k_higher[i] - end - - integrator.f(integrator.du, integrator.u_tmp, prob.p, - integrator.t + alg.c[stage] * integrator.dt) - - @threaded for i in eachindex(integrator.du) - integrator.k_higher[i] = integrator.du[i] * integrator.dt - end - end - - # Store K_{S-1} - @threaded for i in eachindex(integrator.du) - integrator.k_S1[i] = integrator.k_higher[i] - end + # Store K_{S-1} + @threaded for i in eachindex(integrator.du) + integrator.k_S1[i] = integrator.k_higher[i] + end - # Last stage - @threaded for i in eachindex(integrator.du) - integrator.u_tmp[i] = integrator.u[i] + - alg.a_matrix[alg.num_stages - 2, 1] * - integrator.k1[i] + - alg.a_matrix[alg.num_stages - 2, 2] * - integrator.k_higher[i] - end + # Last stage + @threaded for i in eachindex(integrator.du) + integrator.u_tmp[i] = integrator.u[i] + + alg.a_matrix[alg.num_stages - 2, 1] * + integrator.k1[i] + + alg.a_matrix[alg.num_stages - 2, 2] * + integrator.k_higher[i] + end - integrator.f(integrator.du, integrator.u_tmp, prob.p, - integrator.t + alg.c[alg.num_stages] * integrator.dt) + integrator.f(integrator.du, integrator.u_tmp, prob.p, + integrator.t + alg.c[alg.num_stages] * integrator.dt) - @threaded for i in eachindex(integrator.u) - # "Own" PairedExplicitRK based on SSPRK33 - integrator.u[i] += (integrator.k1[i] + integrator.k_S1[i] + - 4.0 * integrator.du[i] * integrator.dt) / 6.0 - end - end # PairedExplicitRK step timer + @threaded for i in eachindex(integrator.u) + # "Own" PairedExplicitRK based on SSPRK33 + integrator.u[i] += (integrator.k1[i] + integrator.k_S1[i] + + 4.0 * integrator.du[i] * integrator.dt) / 6.0 + end + end # PairedExplicitRK step timer - integrator.iter += 1 - integrator.t += integrator.dt + 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 + # 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 # "main loop" timer + # respect maximum number of iterations + if integrator.iter >= integrator.opts.maxiters && !integrator.finalstep + @warn "Interrupted. Larger maxiters is needed." + terminate!(integrator) + end end # used for AMR (Adaptive Mesh Refinement) From ff5c590ef3831f8f2c8203c9602ed278c211099c Mon Sep 17 00:00:00 2001 From: Daniel_Doehring Date: Tue, 18 Jun 2024 14:52:43 +0200 Subject: [PATCH 038/160] deprecation --- ext/TrixiConvexECOSExt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/TrixiConvexECOSExt.jl b/ext/TrixiConvexECOSExt.jl index fac127699ce..948dbf103cd 100644 --- a/ext/TrixiConvexECOSExt.jl +++ b/ext/TrixiConvexECOSExt.jl @@ -136,7 +136,7 @@ function Trixi.bisect_stability_polynomial(consistency_order, num_eig_vals, "reltol_inacc" => 5e-5, "nitref" => 9, "maxit" => 100, - "verbose" => 3); silent_solver = true) + "verbose" => 3); silent = true) abs_p = problem.optval From df7ec64a719604210b15c0aac8be118755158702 Mon Sep 17 00:00:00 2001 From: Daniel_Doehring Date: Tue, 18 Jun 2024 15:20:43 +0200 Subject: [PATCH 039/160] Optimize K_S1 away --- .../methods_PERK3.jl | 23 +++++-------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 839b5629e8f..235576d805e 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -82,6 +82,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, # Special case of e = 3 if num_stages == 3 a_unknown = [0, c[2], 0.25] + dt_opt = 42.0 # TODO! This is a placeholder value else # Calculate coefficients of the stability polynomial in monomial form consistency_order = 3 @@ -240,7 +241,6 @@ mutable struct PairedExplicitRK3Integrator{RealT <: Real, uType, Params, Sol, F, # PairedExplicitRK stages: k1::uType k_higher::uType - k_S1::uType # Required for custom third order version of PairedExplicitRK3 end function init(ode::ODEProblem, alg::PairedExplicitRK3; @@ -252,7 +252,6 @@ function init(ode::ODEProblem, alg::PairedExplicitRK3; # PairedExplicitRK stages k1 = zero(u0) k_higher = zero(u0) - k_S1 = zero(u0) t0 = first(ode.tspan) iter = 0 @@ -264,7 +263,7 @@ function init(ode::ODEProblem, alg::PairedExplicitRK3; ode.tspan; kwargs...), false, - k1, k_higher, k_S1) + k1, k_higher) # initialize callbacks if callback isa CallbackSet @@ -341,12 +340,6 @@ function step!(integrator::PairedExplicitRK3Integrator) integrator.k_higher[i] = integrator.du[i] * integrator.dt end - if alg.num_stages == 3 - @threaded for i in eachindex(integrator.du) - integrator.k_S1[i] = integrator.k_higher[i] - end - end - # Higher stages for stage in 3:(alg.num_stages - 1) # Construct current state @@ -366,11 +359,6 @@ function step!(integrator::PairedExplicitRK3Integrator) end end - # Store K_{S-1} - @threaded for i in eachindex(integrator.du) - integrator.k_S1[i] = integrator.k_higher[i] - end - # Last stage @threaded for i in eachindex(integrator.du) integrator.u_tmp[i] = integrator.u[i] + @@ -384,8 +372,10 @@ function step!(integrator::PairedExplicitRK3Integrator) integrator.t + alg.c[alg.num_stages] * integrator.dt) @threaded for i in eachindex(integrator.u) - # "Own" PairedExplicitRK based on SSPRK33 - integrator.u[i] += (integrator.k1[i] + integrator.k_S1[i] + + # "Own" PairedExplicitRK based on SSPRK33. + # Note that 'k_higher' carries the values of K_{S-1} + # and that we construct 'K_S' "in-place" from 'integrator.du' + integrator.u[i] += (integrator.k1[i] + integrator.k_higher[i] + 4.0 * integrator.du[i] * integrator.dt) / 6.0 end end # PairedExplicitRK step timer @@ -417,6 +407,5 @@ function Base.resize!(integrator::PairedExplicitRK3Integrator, new_size) resize!(integrator.k1, new_size) resize!(integrator.k_higher, new_size) - resize!(integrator.k_S1, new_size) end end # @muladd From b9977c0a946a4e75d3f86a185b380d8cf661911d Mon Sep 17 00:00:00 2001 From: Daniel_Doehring Date: Tue, 18 Jun 2024 15:22:47 +0200 Subject: [PATCH 040/160] fmt --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 235576d805e..fa71fcefc61 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -371,7 +371,7 @@ function step!(integrator::PairedExplicitRK3Integrator) integrator.f(integrator.du, integrator.u_tmp, prob.p, integrator.t + alg.c[alg.num_stages] * integrator.dt) - @threaded for i in eachindex(integrator.u) + @threaded for i in eachindex(integrator.u) # "Own" PairedExplicitRK based on SSPRK33. # Note that 'k_higher' carries the values of K_{S-1} # and that we construct 'K_S' "in-place" from 'integrator.du' From 34d0eb58d8d601de77218a5d850c4aa345446c64 Mon Sep 17 00:00:00 2001 From: Warisa Date: Thu, 20 Jun 2024 18:25:21 +0200 Subject: [PATCH 041/160] remove dt_opt as an attribute of PERK3 --- .../methods_PERK3.jl | 17 ++++++----------- test/test_unit.jl | 5 +---- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index fa71fcefc61..f38a77f82a8 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -111,7 +111,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, a_matrix[:, 1] -= a_unknown[3:end] a_matrix[:, 2] = a_unknown[3:end] - return a_matrix, c, dt_opt + return a_matrix, c end # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 @@ -146,8 +146,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, end @doc raw""" - PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString, - dt_opt; + PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString; cS2 = 1.0) PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; verbose = false, cS2 = 1.0) @@ -159,8 +158,6 @@ end - `base_path_a_coeffs` (`AbstractString`): Path to a file containing some coefficients in the A-matrix in the Butcher tableau of the Runge Kutta method. The matrix should be stored in a text file at `joinpath(base_path_a_coeffs, "a_$(num_stages)_.$(num_stages)txt")` and separated by line breaks. - - `dt_opt` (`Float64`): The optimal time step size that must be supplied when using the first constructor with A-matrix coefficients, - unlike the second or third constructors which calculate it automatically. - `tspan`: Time span of the simulation. - `semi` (`AbstractSemidiscretization`): Semidiscretization setup. - `eig_vals` (`Vector{ComplexF64}`): Eigenvalues of the Jacobian of the right-hand side (rhs) of the ODEProblem after the @@ -186,18 +183,16 @@ mutable struct PairedExplicitRK3 <: AbstractPairedExplicitRKSingle a_matrix::Matrix{Float64} c::Vector{Float64} - dt_opt::Float64 end # struct PairedExplicitRK3 # Constructor for previously computed A Coeffs -function PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString, - dt_opt; +function PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString; cS2 = 1.0) a_matrix, c = compute_PairedExplicitRK3_butcher_tableau(num_stages, base_path_a_coeffs; cS2) - return PairedExplicitRK3(num_stages, a_matrix, c, dt_opt) + return PairedExplicitRK3(num_stages, a_matrix, c) end # Constructor that computes Butcher matrix A coefficients from a semidiscretization @@ -211,11 +206,11 @@ end # Constructor that calculates the coefficients with polynomial optimizer from a list of eigenvalues function PairedExplicitRK3(num_stages, tspan, eig_vals::Vector{ComplexF64}; verbose = false, cS2 = 1) - a_matrix, c, dt_opt = compute_PairedExplicitRK3_butcher_tableau(num_stages, + a_matrix, c = compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, eig_vals; verbose, cS2) - return PairedExplicitRK3(num_stages, a_matrix, c, dt_opt) + return PairedExplicitRK3(num_stages, a_matrix, c,) end # This struct is needed to fake https://github.com/SciML/OrdinaryDiffEq.jl/blob/0c2048a502101647ac35faabd80da8a5645beac7/src/integrators/type.jl#L77 diff --git a/test/test_unit.jl b/test/test_unit.jl index 4157f26dc65..ecc96a8b21a 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1683,10 +1683,7 @@ end Trixi.download("https://gist.githubusercontent.com/warisa-r/0796db36abcd5abe735ac7eebf41b973/raw/32889062fd5dcf7f450748f4f5f0797c8155a18d/a_8_8.txt", joinpath(path_coeff_file, "a_8_8.txt")) - # Value of dt_opt obtained from running the simulation in elixir_burgers_perk3 - # The value plays no role in the result but added so that the constructor can be called - dt_opt = 0.004485771991312504 - ode_algorithm = Trixi.PairedExplicitRK3(8, path_coeff_file, dt_opt) + ode_algorithm = Trixi.PairedExplicitRK3(8, path_coeff_file) #TODO: adjust this value according to the result in the test pipeline println(ode_algorithm.a_matrix) # Value in CI differs slightly from what I get locally From 13ac6dc60310db30857037df0223833fb95ef706 Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 24 Jun 2024 14:30:17 +0200 Subject: [PATCH 042/160] change the objective function to match the number of equations --- ext/TrixiConvexECOSExt.jl | 2 +- ext/TrixiNLsolveExt.jl | 13 ++++----- .../methods_PERK3.jl | 29 ++++++++++--------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/ext/TrixiConvexECOSExt.jl b/ext/TrixiConvexECOSExt.jl index 948dbf103cd..fac127699ce 100644 --- a/ext/TrixiConvexECOSExt.jl +++ b/ext/TrixiConvexECOSExt.jl @@ -136,7 +136,7 @@ function Trixi.bisect_stability_polynomial(consistency_order, num_eig_vals, "reltol_inacc" => 5e-5, "nitref" => 9, "maxit" => 100, - "verbose" => 3); silent = true) + "verbose" => 3); silent_solver = true) abs_p = problem.optval diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 5830d23fae6..ea418cf837b 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -11,6 +11,7 @@ end # Use other necessary libraries using Random: seed! +using LinearAlgebra: norm # Use functions and additional symbols that are not exported using Trixi: Trixi, PairedExplicitRK3_butcher_tableau_objective_function, @muladd @@ -42,17 +43,13 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; end # Set the seed for reproducibility of the initial guess of a_unknown - seed!(5555) + #seed!(5555) while !is_sol_valid - # Initialize initial guess # The nonlinear system may have multiple valid solutions. # For the sake of reproducibility, we use a seeded random initial guess - x0 = 0.1 .* rand(num_stages) - # For explicit methods, a_{1,1} = 0 and a_{2,1} = c_2 (Butcher's condition) - x0[1] = 0 - x0[2] = c[2] + x0 = 0.1 .* rand(num_stages-2) sol = nlsolve(objective_function, x0, method = :trust_region, ftol = 4e-16, # Enforce objective up to machine precision @@ -62,8 +59,8 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; # Check if the values a[i, i-1] >= 0.0 (which stem from the nonlinear solver) # and subsequently c[i] - a[i, i-1] >= 0.0 since all coefficients are non-negative - is_sol_valid = all(x -> !isnan(x) && x >= 0, a_unknown[3:end]) && - all(x -> !isnan(x) && x >= 0, c[3:end] .- a_unknown[3:end]) + is_sol_valid = all(x -> !isnan(x) && x >= 0, a_unknown) && + all(x -> !isnan(x) && x >= 0, c[3:end] .- a_unknown) if verbose && !is_sol_valid println("Solution invalid. Restart the process of solving non-linear system of equations again.") diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index f38a77f82a8..e623d4f7d03 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -31,7 +31,8 @@ function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_sta num_stage_evals, monomial_coeffs, cS2) c_ts = compute_c_coeffs_SSP33(num_stages, cS2) # ts = timestep - + # For explicit methods, a_{1,1} = 0 and a_{2,1} = c_2 (Butcher's condition) + a_coeff = [0.0, c_ts[2], a_unknown...] # Equality Constraint array that ensures that the stability polynomial computed from # the to-be-constructed Butcher-Tableau matches the monomial coefficients of the # optimized stability polynomial. @@ -40,11 +41,11 @@ function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_sta c_eq = zeros(num_stage_evals - 2) # Add equality constraint that cS2 is equal to 1 # Lower-order terms: Two summands present for i in 1:(num_stage_evals - 4) - term1 = a_unknown[num_stage_evals - 1] - term2 = a_unknown[num_stage_evals] + term1 = a_coeff[num_stage_evals - 1] + term2 = a_coeff[num_stage_evals] for j in 1:i - term1 *= a_unknown[num_stage_evals - 1 - j] - term2 *= a_unknown[num_stage_evals - j] + term1 *= a_coeff[num_stage_evals - 1 - j] + term2 *= a_coeff[num_stage_evals - j] end term1 *= c_ts[num_stages - 2 - i] * 1 / 6 # 1/ 6 = b_{S-1} term2 *= c_ts[num_stages - 1 - i] * 2 / 3 # 2 / 3 = b_S @@ -54,16 +55,16 @@ function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_sta # Highest coefficient: Only one term present i = num_stage_evals - 3 - term2 = a_unknown[num_stage_evals] + term2 = a_coeff[num_stage_evals] for j in 1:i - term2 *= a_unknown[num_stage_evals - j] + term2 *= a_coeff[num_stage_evals - j] end term2 *= c_ts[num_stages - 1 - i] * 2 / 3 # 2 / 3 = b_S c_eq[i] = monomial_coeffs[i] - term2 # Third-order consistency condition (Cf. eq. (27) from https://doi.org/10.1016/j.jcp.2022.111470 - c_eq[num_stage_evals - 2] = 1 - 4 * a_unknown[num_stage_evals] - - a_unknown[num_stage_evals - 1] + c_eq[num_stage_evals - 2] = 1 - 4 * a_coeff[num_stage_evals] - + a_coeff[num_stage_evals - 1] return c_eq end @@ -77,10 +78,12 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, c = compute_c_coeffs_SSP33(num_stages, cS2) # Initialize the array of our solution - a_unknown = zeros(num_stages) + a_unknown = zeros(num_stages-2) # Special case of e = 3 if num_stages == 3 + #TODO: with this new defining of what we are solving from nlsolve, this array shouldn't be called a_unknown anymore + # or maybe it should be called a_unknown but only with one member a_unknown = [0, c[2], 0.25] dt_opt = 42.0 # TODO! This is a placeholder value else @@ -108,9 +111,9 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, # Fill A-matrix in P-ERK style a_matrix = zeros(num_stages - 2, 2) a_matrix[:, 1] = c[3:end] - a_matrix[:, 1] -= a_unknown[3:end] - a_matrix[:, 2] = a_unknown[3:end] - + a_matrix[:, 1] -= a_unknown + a_matrix[:, 2] = a_unknown + return a_matrix, c end From 516e95f779a0215bbffee37e31e038a71aef2633 Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 24 Jun 2024 14:50:50 +0200 Subject: [PATCH 043/160] fmt --- ext/TrixiNLsolveExt.jl | 2 +- .../paired_explicit_runge_kutta/methods_PERK3.jl | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index ea418cf837b..c552f9b5840 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -49,7 +49,7 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; # Initialize initial guess # The nonlinear system may have multiple valid solutions. # For the sake of reproducibility, we use a seeded random initial guess - x0 = 0.1 .* rand(num_stages-2) + x0 = 0.1 .* rand(num_stages - 2) sol = nlsolve(objective_function, x0, method = :trust_region, ftol = 4e-16, # Enforce objective up to machine precision diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index e623d4f7d03..7fcc6a93d9e 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -78,7 +78,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, c = compute_c_coeffs_SSP33(num_stages, cS2) # Initialize the array of our solution - a_unknown = zeros(num_stages-2) + a_unknown = zeros(num_stages - 2) # Special case of e = 3 if num_stages == 3 @@ -113,7 +113,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, a_matrix[:, 1] = c[3:end] a_matrix[:, 1] -= a_unknown a_matrix[:, 2] = a_unknown - + return a_matrix, c end @@ -210,10 +210,10 @@ end function PairedExplicitRK3(num_stages, tspan, eig_vals::Vector{ComplexF64}; verbose = false, cS2 = 1) a_matrix, c = compute_PairedExplicitRK3_butcher_tableau(num_stages, - tspan, - eig_vals; - verbose, cS2) - return PairedExplicitRK3(num_stages, a_matrix, c,) + tspan, + eig_vals; + verbose, cS2) + return PairedExplicitRK3(num_stages, a_matrix, c) end # This struct is needed to fake https://github.com/SciML/OrdinaryDiffEq.jl/blob/0c2048a502101647ac35faabd80da8a5645beac7/src/integrators/type.jl#L77 From fdba17d4edc6d8e435bb617d6fe4dd789554d7da Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 24 Jun 2024 19:54:37 +0200 Subject: [PATCH 044/160] minor comment fix --- ext/TrixiNLsolveExt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index c552f9b5840..b677f2920af 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -58,7 +58,7 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; a_unknown = sol.zero # Check if the values a[i, i-1] >= 0.0 (which stem from the nonlinear solver) - # and subsequently c[i] - a[i, i-1] >= 0.0 since all coefficients are non-negative + # and also c[i] - a[i, i-1] >= 0.0 since all coefficients are non-negative is_sol_valid = all(x -> !isnan(x) && x >= 0, a_unknown) && all(x -> !isnan(x) && x >= 0, c[3:end] .- a_unknown) From b78f39a00c1f4d58b3117536ef04c6648a0f1337 Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 24 Jun 2024 21:20:42 +0200 Subject: [PATCH 045/160] delete some stuff left from random --- ext/TrixiNLsolveExt.jl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index b677f2920af..e1a8c9b72cb 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -10,7 +10,6 @@ else end # Use other necessary libraries -using Random: seed! using LinearAlgebra: norm # Use functions and additional symbols that are not exported @@ -42,9 +41,6 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; c_s2) end - # Set the seed for reproducibility of the initial guess of a_unknown - #seed!(5555) - while !is_sol_valid # Initialize initial guess # The nonlinear system may have multiple valid solutions. From 000f117a9d33447a342eeeb9c001222433904e00 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Tue, 25 Jun 2024 10:48:02 +0200 Subject: [PATCH 046/160] Update src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl Co-authored-by: Daniel Doehring --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 7fcc6a93d9e..2bab82f9dad 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -182,7 +182,7 @@ Multirate Time-Integration based on Dynamic ODE Partitioning through Adaptively [Arxiv: 10.48550/arXiv.2403.05144](https://doi.org/10.48550/arXiv.2403.05144) """ mutable struct PairedExplicitRK3 <: AbstractPairedExplicitRKSingle - const num_stages::Int + const num_stages::Int # S a_matrix::Matrix{Float64} c::Vector{Float64} From 3289fafeeb0773ab7748fe1373f35dbe5d21b7fb Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 25 Jun 2024 14:41:44 +0200 Subject: [PATCH 047/160] minor adjustments --- ext/TrixiNLsolveExt.jl | 4 +--- .../paired_explicit_runge_kutta/methods_PERK3.jl | 12 +++++------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index e1a8c9b72cb..583ddf6c42d 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -42,9 +42,7 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; end while !is_sol_valid - # Initialize initial guess - # The nonlinear system may have multiple valid solutions. - # For the sake of reproducibility, we use a seeded random initial guess + # Initialize an initial guess x0 = 0.1 .* rand(num_stages - 2) sol = nlsolve(objective_function, x0, method = :trust_region, diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 2bab82f9dad..2799cea5128 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -8,7 +8,7 @@ using DelimitedFiles: readdlm #! format: noindent # Initialize Butcher array abscissae c for PairedExplicitRK3 based on SSPRK33 base method -function compute_c_coeffs_SSP33(num_stages, cS2) +function compute_c_coeffs(num_stages, cS2) c = zeros(num_stages) # Last timesteps as for SSPRK33, see motivation in @@ -30,7 +30,7 @@ end function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_stages, num_stage_evals, monomial_coeffs, cS2) - c_ts = compute_c_coeffs_SSP33(num_stages, cS2) # ts = timestep + c_ts = compute_c_coeffs(num_stages, cS2) # ts = timestep # For explicit methods, a_{1,1} = 0 and a_{2,1} = c_2 (Butcher's condition) a_coeff = [0.0, c_ts[2], a_unknown...] # Equality Constraint array that ensures that the stability polynomial computed from @@ -75,16 +75,14 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, eig_vals::Vector{ComplexF64}; verbose = false, cS2) # Initialize array of c - c = compute_c_coeffs_SSP33(num_stages, cS2) + c = compute_c_coeffs(num_stages, cS2) # Initialize the array of our solution a_unknown = zeros(num_stages - 2) # Special case of e = 3 if num_stages == 3 - #TODO: with this new defining of what we are solving from nlsolve, this array shouldn't be called a_unknown anymore - # or maybe it should be called a_unknown but only with one member - a_unknown = [0, c[2], 0.25] + a_unknown = [0.25] dt_opt = 42.0 # TODO! This is a placeholder value else # Calculate coefficients of the stability polynomial in monomial form @@ -124,7 +122,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, cS2) # Initialize array of c - c = compute_c_coeffs_SSP33(num_stages, cS2) + c = compute_c_coeffs(num_stages, cS2) # - 2 Since First entry of A is always zero (explicit method) and second is given by c_2 (consistency) a_coeffs_max = num_stages - 2 From d73c377309b05655c088f0f6fa5b42c783e1fa08 Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 25 Jun 2024 14:43:01 +0200 Subject: [PATCH 048/160] minor change to the comment --- ext/TrixiNLsolveExt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 583ddf6c42d..1f27239fd64 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -52,7 +52,7 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; a_unknown = sol.zero # Check if the values a[i, i-1] >= 0.0 (which stem from the nonlinear solver) - # and also c[i] - a[i, i-1] >= 0.0 since all coefficients are non-negative + # and also c[i] - a[i, i-1] >= 0.0 since all coefficients should be non-negative is_sol_valid = all(x -> !isnan(x) && x >= 0, a_unknown) && all(x -> !isnan(x) && x >= 0, c[3:end] .- a_unknown) From b22476e8e0ffe1cf4e4c6455f5b38b4c8273536d Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 25 Jun 2024 15:10:07 +0200 Subject: [PATCH 049/160] add proper comment and bring seed back --- ext/TrixiNLsolveExt.jl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 1f27239fd64..0e0cfba338b 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -12,6 +12,8 @@ end # Use other necessary libraries using LinearAlgebra: norm +using Random: seed! + # Use functions and additional symbols that are not exported using Trixi: Trixi, PairedExplicitRK3_butcher_tableau_objective_function, @muladd @@ -41,8 +43,13 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; c_s2) end + seed!(5555) + while !is_sol_valid - # Initialize an initial guess + # Due to the nature of the nonlinear solver, different initial guesses can lead to + # small numerical differences in the solution. + # To ensure consistency and reproducibility of results across runs, we use + # a seeded random initial guess. x0 = 0.1 .* rand(num_stages - 2) sol = nlsolve(objective_function, x0, method = :trust_region, From 2ec41faeb62530e10e4d941d37df14d3b0c59af4 Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 25 Jun 2024 15:21:01 +0200 Subject: [PATCH 050/160] update test values --- test/test_unit.jl | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/test/test_unit.jl b/test/test_unit.jl index ecc96a8b21a..607631d2537 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1705,14 +1705,17 @@ end #TODO: adjust this value according to the result in the test pipeline println(ode_algorithm.a_matrix) # Value in CI differs slightly from what I get locally @test isapprox(ode_algorithm.a_matrix, - [0.27321088155198703 0.01250340416229867 - 0.4060225225166573 0.022548906054771216 - 0.534287756076577 0.03714081535199439 - 0.6549425779583463 0.05934313632736803 - 0.7621601562844809 0.09498270085837623 - 0.8446587253087918 0.1553412746912082 - 0.7719976108598626 0.22800238914013735 - 0.30700059728503437 0.1929994027149656], atol = 1e-13) + [0.19258805209433105 0.007411947905668948 + 0.28723273300165075 0.012767266998349255 + 0.38017685928843065 0.0198231407115694 + 0.4706744386325171 0.029325561367482902 + 0.5575742010881195 0.04242579891188053 + 0.6390910444606461 0.060908955539353826 + 0.7124869884931394 0.08751301150686068 + 0.7736366314117405 0.12636336858825947 + 0.8161317899892583 0.18386821001074174 + 0.7532715707531655 0.2467284292468345 + 0.31168210731170864 0.18831789268829138], atol = 1e-13) end @testset "Sutherlands Law" begin From 03fb32f4576a649e61039d2ce7ce7a42f5a12e1c Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 25 Jun 2024 15:35:57 +0200 Subject: [PATCH 051/160] fmt --- .../methods_PERK3.jl | 2 +- test/test_unit.jl | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 2799cea5128..4562d0fc8b3 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -82,7 +82,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, # Special case of e = 3 if num_stages == 3 - a_unknown = [0.25] + a_unknown = [0.25] dt_opt = 42.0 # TODO! This is a placeholder value else # Calculate coefficients of the stability polynomial in monomial form diff --git a/test/test_unit.jl b/test/test_unit.jl index 607631d2537..92ed2f23799 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1706,16 +1706,16 @@ end println(ode_algorithm.a_matrix) # Value in CI differs slightly from what I get locally @test isapprox(ode_algorithm.a_matrix, [0.19258805209433105 0.007411947905668948 - 0.28723273300165075 0.012767266998349255 - 0.38017685928843065 0.0198231407115694 - 0.4706744386325171 0.029325561367482902 - 0.5575742010881195 0.04242579891188053 - 0.6390910444606461 0.060908955539353826 - 0.7124869884931394 0.08751301150686068 - 0.7736366314117405 0.12636336858825947 - 0.8161317899892583 0.18386821001074174 - 0.7532715707531655 0.2467284292468345 - 0.31168210731170864 0.18831789268829138], atol = 1e-13) + 0.28723273300165075 0.012767266998349255 + 0.38017685928843065 0.0198231407115694 + 0.4706744386325171 0.029325561367482902 + 0.5575742010881195 0.04242579891188053 + 0.6390910444606461 0.060908955539353826 + 0.7124869884931394 0.08751301150686068 + 0.7736366314117405 0.12636336858825947 + 0.8161317899892583 0.18386821001074174 + 0.7532715707531655 0.2467284292468345 + 0.31168210731170864 0.18831789268829138], atol = 1e-13) end @testset "Sutherlands Law" begin From cda3c840fbcfb30d2a6a3dafa404a012c2f1e595 Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 25 Jun 2024 18:01:18 +0200 Subject: [PATCH 052/160] change the keyword according to the error in the test pipeline and edit some values to match the test pipeline --- ext/TrixiConvexECOSExt.jl | 2 +- test/test_structured_1d.jl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/TrixiConvexECOSExt.jl b/ext/TrixiConvexECOSExt.jl index fac127699ce..948dbf103cd 100644 --- a/ext/TrixiConvexECOSExt.jl +++ b/ext/TrixiConvexECOSExt.jl @@ -136,7 +136,7 @@ function Trixi.bisect_stability_polynomial(consistency_order, num_eig_vals, "reltol_inacc" => 5e-5, "nitref" => 9, "maxit" => 100, - "verbose" => 3); silent_solver = true) + "verbose" => 3); silent = true) abs_p = problem.optval diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index 279febbd5b9..283ab40ed7b 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -60,8 +60,8 @@ end @trixi_testset "elixir_burgers_perk3.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_perk3.jl"), - l2=[8.120426320528704e-8], - linf=[4.906376875890572e-7], + l2=[8.12194103e-08], + linf=[4.90725569e-07], atol=1.0e-6) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) From 84f6a6d78f30a1a0866a1ea143a16c836b8c0288 Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 25 Jun 2024 18:10:35 +0200 Subject: [PATCH 053/160] remove unused import --- ext/TrixiNLsolveExt.jl | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 0e0cfba338b..ba15bb913cd 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -9,16 +9,11 @@ else using ..NLsolve: nlsolve end -# Use other necessary libraries -using LinearAlgebra: norm - using Random: seed! -# Use functions and additional symbols that are not exported -using Trixi: Trixi, PairedExplicitRK3_butcher_tableau_objective_function, @muladd - -# Use functions that are to be extended -using Trixi: Trixi, solve_a_unknown! +# Use functions that are to be extended and additional symbols that are not exported +using Trixi: Trixi, solve_a_unknown!, PairedExplicitRK3_butcher_tableau_objective_function, + @muladd # By default, Julia/LLVM does not use fused multiply-add operations (FMAs). # Since these FMAs can increase the performance of many numerical algorithms, From 144bfa1d712f6586cf62d677da1f23f0572c9173 Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 25 Jun 2024 18:14:49 +0200 Subject: [PATCH 054/160] fix test values in misc --- test/test_unit.jl | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/test/test_unit.jl b/test/test_unit.jl index 92ed2f23799..1c61fa6ce7f 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1705,17 +1705,17 @@ end #TODO: adjust this value according to the result in the test pipeline println(ode_algorithm.a_matrix) # Value in CI differs slightly from what I get locally @test isapprox(ode_algorithm.a_matrix, - [0.19258805209433105 0.007411947905668948 - 0.28723273300165075 0.012767266998349255 - 0.38017685928843065 0.0198231407115694 - 0.4706744386325171 0.029325561367482902 - 0.5575742010881195 0.04242579891188053 - 0.6390910444606461 0.060908955539353826 - 0.7124869884931394 0.08751301150686068 - 0.7736366314117405 0.12636336858825947 - 0.8161317899892583 0.18386821001074174 - 0.7532715707531655 0.2467284292468345 - 0.31168210731170864 0.18831789268829138], atol = 1e-13) + [0.19258815209175084 0.007411847908249183 + 0.287232921421498 0.012767078578501994 + 0.38017716660879974 0.019822833391200292 + 0.4706748922245802 0.029325107775419784 + 0.5575748091858802 0.042425190814119815 + 0.6390917624593604 0.06090823754063958 + 0.712487669254592 0.08751233074540807 + 0.7736370088751211 0.1263629911248789 + 0.816131548721476 0.18386845127852405 + 0.7532704353232954 0.24672956467670462 + 0.3116823911691762 0.18831760883082385], atol = 1e-13) end @testset "Sutherlands Law" begin From 6e53ad216c16deb123b38b42ae6f478d8f2bb62b Mon Sep 17 00:00:00 2001 From: Warisa Date: Wed, 26 Jun 2024 18:33:32 +0200 Subject: [PATCH 055/160] add max iteration --- ext/TrixiNLsolveExt.jl | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index ba15bb913cd..79084e30a0c 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -27,7 +27,7 @@ using Trixi: Trixi, solve_a_unknown!, PairedExplicitRK3_butcher_tableau_objectiv # For details, see Proposition 3.2, Equation (3.3) from # Hairer, Wanner: Solving Ordinary Differential Equations 2 function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; - verbose) + verbose, max_iter = 100000) is_sol_valid = false # Define the objective_function @@ -40,7 +40,7 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; seed!(5555) - while !is_sol_valid + for _ in 1:max_iter # Due to the nature of the nonlinear solver, different initial guesses can lead to # small numerical differences in the solution. # To ensure consistency and reproducibility of results across runs, we use @@ -58,12 +58,16 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; is_sol_valid = all(x -> !isnan(x) && x >= 0, a_unknown) && all(x -> !isnan(x) && x >= 0, c[3:end] .- a_unknown) - if verbose && !is_sol_valid - println("Solution invalid. Restart the process of solving non-linear system of equations again.") + if is_sol_valid + return a_unknown + else + if verbose + println("Solution invalid. Restart the process of solving non-linear system of equations again.") + end end end - return a_unknown + error("Maximum number of iterations ($max_iter) reached. Cannot find valid sets of coefficients.") end end # @muladd From a34d412fa48ce96941996f29eda1a661c41f0ac0 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Wed, 26 Jun 2024 19:04:11 +0200 Subject: [PATCH 056/160] Update ext/TrixiNLsolveExt.jl Co-authored-by: Daniel Doehring --- ext/TrixiNLsolveExt.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 79084e30a0c..b5707f8f6a8 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -9,6 +9,8 @@ else using ..NLsolve: nlsolve end +# We use a random initialization of the nonlinear solver. +# To make the tests reproducible, we need to seed the RNG using Random: seed! # Use functions that are to be extended and additional symbols that are not exported From a65cdb8d48327b3eedec3f1573d1b2ffa2ae196c Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Fri, 5 Jul 2024 12:04:45 +0200 Subject: [PATCH 057/160] Apply suggestions from code review --- examples/structured_1d_dgsem/elixir_burgers_perk3.jl | 2 +- .../paired_explicit_runge_kutta/methods_PERK3.jl | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl index d93d3d0fbb2..ec2c8169cac 100644 --- a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl +++ b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl @@ -4,7 +4,7 @@ using OrdinaryDiffEq using Trixi ############################################################################### -# semidiscretization of the (inviscid) Burgers' equation +# semidiscretization of the (inviscid) Burgers equation equations = InviscidBurgersEquation1D() diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 4562d0fc8b3..7693b7f9dee 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -13,7 +13,6 @@ function compute_c_coeffs(num_stages, cS2) # Last timesteps as for SSPRK33, see motivation in # https://doi.org/10.48550/arXiv.2403.05144 - c[num_stages - 1] = 1 c[num_stages] = 0.5 @@ -33,7 +32,7 @@ function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_sta c_ts = compute_c_coeffs(num_stages, cS2) # ts = timestep # For explicit methods, a_{1,1} = 0 and a_{2,1} = c_2 (Butcher's condition) a_coeff = [0.0, c_ts[2], a_unknown...] - # Equality Constraint array that ensures that the stability polynomial computed from + # Equality constraint array that ensures that the stability polynomial computed from # the to-be-constructed Butcher-Tableau matches the monomial coefficients of the # optimized stability polynomial. # For details, see Chapter4.3, Proposition 3.2, Equation (3.3) from @@ -167,8 +166,8 @@ end - `cS2` (`Float64`, optional): Value of c in the Butcher tableau at c_{s-2}, when s is the number of stages, default is 1.0. -The following structures and methods provide a implementation of -the third-order paired explicit Runge-Kutta method +The following structures and methods provide an implementation of +the third-order paired explicit Runge-Kutta (P-ERK) method optimized for a certain simulation setup (PDE, IC & BC, Riemann Solver, DG Solver). The original paper is - Nasab, Vermeire (2022) From 6d2fc6db2f6211c45fd65822c5a3613c2f17027c Mon Sep 17 00:00:00 2001 From: Warisa Date: Fri, 5 Jul 2024 15:17:21 +0200 Subject: [PATCH 058/160] remove the allocating part of is_sol_valid --- ext/TrixiNLsolveExt.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index b5707f8f6a8..571eb1377eb 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -58,7 +58,8 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; # Check if the values a[i, i-1] >= 0.0 (which stem from the nonlinear solver) # and also c[i] - a[i, i-1] >= 0.0 since all coefficients should be non-negative is_sol_valid = all(x -> !isnan(x) && x >= 0, a_unknown) && - all(x -> !isnan(x) && x >= 0, c[3:end] .- a_unknown) + all(!isnan(c[i] - a_unknown[i - 2]) && + c[i] - a_unknown[i - 2] >= 0 for i in eachindex(c) if i > 2) if is_sol_valid return a_unknown From e95fe976f35c78704b01f9ae3855df6d2aa20996 Mon Sep 17 00:00:00 2001 From: Warisa Date: Fri, 5 Jul 2024 15:38:38 +0200 Subject: [PATCH 059/160] removing dt_opt and update test values --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 11 +++++------ test/test_structured_1d.jl | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 7693b7f9dee..d42713e409b 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -82,7 +82,6 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, # Special case of e = 3 if num_stages == 3 a_unknown = [0.25] - dt_opt = 42.0 # TODO! This is a placeholder value else # Calculate coefficients of the stability polynomial in monomial form consistency_order = 3 @@ -91,11 +90,11 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, num_eig_vals, eig_vals = filter_eig_vals(eig_vals; verbose) - monomial_coeffs, dt_opt = bisect_stability_polynomial(consistency_order, - num_eig_vals, num_stages, - dtmax, - dteps, - eig_vals; verbose) + monomial_coeffs, _ = bisect_stability_polynomial(consistency_order, + num_eig_vals, num_stages, + dtmax, + dteps, + eig_vals; verbose) monomial_coeffs = undo_normalization!(monomial_coeffs, consistency_order, num_stages) diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index 283ab40ed7b..53b4c75444a 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -60,8 +60,8 @@ end @trixi_testset "elixir_burgers_perk3.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_perk3.jl"), - l2=[8.12194103e-08], - linf=[4.90725569e-07], + l2=[8.120426534092787e-8], + linf=[4.906376900315479e-7], atol=1.0e-6) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) From c61187c7fb744203bb6eb4b736db1b11b579239e Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Fri, 5 Jul 2024 16:32:20 +0200 Subject: [PATCH 060/160] Update NEWS.md Co-authored-by: Daniel Doehring --- NEWS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index d27ec29cebb..b13f756c1b3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -16,8 +16,8 @@ for human readability. method with [Convex.jl](https://github.com/jump-dev/Convex.jl) and [ECOS.jl](https://github.com/jump-dev/ECOS.jl) ([#1908]) - Add subcell limiting support for `StructuredMesh` ([#1946]). - New time integrator `PairedExplicitRK3`, implementing the third-order paired explicit Runge-Kutta - method with [Convex.jl](https://github.com/jump-dev/Convex.jl), [ECOS.jl](https://github.com/jump-dev/ECOS.jl) - , and [NLsolve.jl](https://github.com/JuliaNLSolvers/NLsolve.jl) ([TBD]) + method with [Convex.jl](https://github.com/jump-dev/Convex.jl), [ECOS.jl](https://github.com/jump-dev/ECOS.jl), + and [NLsolve.jl](https://github.com/JuliaNLSolvers/NLsolve.jl) ([TBD]) ## Changes when updating to v0.7 from v0.6.x From 2fc30857d254ef66a020135dcbb9117f84c597c7 Mon Sep 17 00:00:00 2001 From: Warisa Date: Fri, 5 Jul 2024 16:48:32 +0200 Subject: [PATCH 061/160] update cfl number for the simulation --- examples/structured_1d_dgsem/elixir_burgers_perk3.jl | 2 +- test/test_structured_1d.jl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl index ec2c8169cac..59f49921e2e 100644 --- a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl +++ b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl @@ -35,7 +35,7 @@ analysis_callback = AnalysisCallback(semi, interval = analysis_interval) alive_callback = AliveCallback(analysis_interval = analysis_interval) -stepsize_callback = StepsizeCallback() +stepsize_callback = StepsizeCallback(cfl = 3.713) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index 53b4c75444a..883f1b12fad 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -60,8 +60,8 @@ end @trixi_testset "elixir_burgers_perk3.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_perk3.jl"), - l2=[8.120426534092787e-8], - linf=[4.906376900315479e-7], + l2=[6.4744366559817754e-6], + linf=[4.357450084224723e-5], atol=1.0e-6) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) From bd55f1d478c3e9c1dc917c94c0e23e42f6a727a5 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Fri, 5 Jul 2024 16:53:35 +0200 Subject: [PATCH 062/160] Update examples/structured_1d_dgsem/elixir_burgers_perk3.jl Co-authored-by: Daniel Doehring --- examples/structured_1d_dgsem/elixir_burgers_perk3.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl index 59f49921e2e..6f74bb1d982 100644 --- a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl +++ b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl @@ -35,7 +35,7 @@ analysis_callback = AnalysisCallback(semi, interval = analysis_interval) alive_callback = AliveCallback(analysis_interval = analysis_interval) -stepsize_callback = StepsizeCallback(cfl = 3.713) +stepsize_callback = StepsizeCallback(cfl = 3.7) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, From 8d08b87d63a3bf2d55553e960d3601c5af85d236 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Fri, 5 Jul 2024 16:54:27 +0200 Subject: [PATCH 063/160] Update src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl Co-authored-by: Daniel Doehring --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index d42713e409b..d50f8f1bf0e 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -92,8 +92,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, monomial_coeffs, _ = bisect_stability_polynomial(consistency_order, num_eig_vals, num_stages, - dtmax, - dteps, + dtmax, dteps, eig_vals; verbose) monomial_coeffs = undo_normalization!(monomial_coeffs, consistency_order, num_stages) From c5c00bceb2991bfc459b357f7da0125e822f770d Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Fri, 5 Jul 2024 16:54:34 +0200 Subject: [PATCH 064/160] Update src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl Co-authored-by: Daniel Doehring --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index d50f8f1bf0e..a04d5ce1997 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -46,7 +46,7 @@ function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_sta term1 *= a_coeff[num_stage_evals - 1 - j] term2 *= a_coeff[num_stage_evals - j] end - term1 *= c_ts[num_stages - 2 - i] * 1 / 6 # 1/ 6 = b_{S-1} + term1 *= c_ts[num_stages - 2 - i] * 1 / 6 # 1 / 6 = b_{S-1} term2 *= c_ts[num_stages - 1 - i] * 2 / 3 # 2 / 3 = b_S c_eq[i] = monomial_coeffs[i] - (term1 + term2) From 6fa86477c29a252171270c17c859f13351ebe087 Mon Sep 17 00:00:00 2001 From: Warisa Date: Fri, 5 Jul 2024 17:02:39 +0200 Subject: [PATCH 065/160] change from a_stages_stages.txt to a_stages.txt --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 5 ++--- test/test_unit.jl | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index d42713e409b..111a2902d20 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -129,8 +129,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, a_matrix[:, 1] = c[3:end] path_a_coeffs = joinpath(base_path_a_coeffs, - "a_" * string(num_stages) * "_" * string(num_stages) * - ".txt") + "a_" * string(num_stages) * ".txt") @assert isfile(path_a_coeffs) "Couldn't find file" a_coeffs = readdlm(path_a_coeffs, Float64) @@ -156,7 +155,7 @@ end - `num_stages` (`Int`): Number of stages in the PERK method. - `base_path_a_coeffs` (`AbstractString`): Path to a file containing some coefficients in the A-matrix in the Butcher tableau of the Runge Kutta method. - The matrix should be stored in a text file at `joinpath(base_path_a_coeffs, "a_$(num_stages)_.$(num_stages)txt")` and separated by line breaks. + The matrix should be stored in a text file at `joinpath(base_path_a_coeffs, "a_$(num_stages).txt")` and separated by line breaks. - `tspan`: Time span of the simulation. - `semi` (`AbstractSemidiscretization`): Semidiscretization setup. - `eig_vals` (`Vector{ComplexF64}`): Eigenvalues of the Jacobian of the right-hand side (rhs) of the ODEProblem after the diff --git a/test/test_unit.jl b/test/test_unit.jl index 1c61fa6ce7f..65b2bde4f5b 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1681,7 +1681,7 @@ end @testset "PERK Single p3 Constructors" begin path_coeff_file = mktempdir() Trixi.download("https://gist.githubusercontent.com/warisa-r/0796db36abcd5abe735ac7eebf41b973/raw/32889062fd5dcf7f450748f4f5f0797c8155a18d/a_8_8.txt", - joinpath(path_coeff_file, "a_8_8.txt")) + joinpath(path_coeff_file, "a_8.txt")) ode_algorithm = Trixi.PairedExplicitRK3(8, path_coeff_file) From 88c92e210771fa9b7b9331558f4c08b3426800bb Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 8 Jul 2024 17:49:04 +0200 Subject: [PATCH 066/160] fixed step size should work with save solution now --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 1c36f5e3700..ca549e744ab 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -221,8 +221,9 @@ mutable struct PairedExplicitRK3Integrator{RealT <: Real, uType, Params, Sol, F, du::uType u_tmp::uType t::RealT + tdir::RealT dt::RealT # current time step - dtcache::RealT # ignored + dtcache::RealT # manually set time step iter::Int # current number of time steps (iteration) p::Params # will be the semidiscretization from Trixi sol::Sol # faked @@ -230,6 +231,8 @@ mutable struct PairedExplicitRK3Integrator{RealT <: Real, uType, Params, Sol, F, alg::Alg # This is our own class written above; Abbreviation for ALGorithm opts::PairedExplicitRKOptions finalstep::Bool # added for convenience + dtchangeable::Bool + force_stepfail::Bool # PairedExplicitRK stages: k1::uType k_higher::uType @@ -246,15 +249,16 @@ function init(ode::ODEProblem, alg::PairedExplicitRK3; k_higher = zero(u0) t0 = first(ode.tspan) + tdir = sign(ode.tspan[end] - ode.tspan[1]) iter = 0 - integrator = PairedExplicitRK3Integrator(u0, du, u_tmp, t0, dt, zero(dt), iter, + integrator = PairedExplicitRK3Integrator(u0, du, u_tmp, t0, tdir, dt, dt, iter, ode.p, (prob = ode,), ode.f, alg, PairedExplicitRKOptions(callback, ode.tspan; kwargs...), - false, + false, true, false, k1, k_higher) # initialize callbacks @@ -306,6 +310,8 @@ function step!(integrator::PairedExplicitRK3Integrator) error("time step size `dt` is NaN") end + modify_dt_for_tstops!(integrator) + # 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) From 71f2841a1abb0c2078f74b32380e2015fafa23e1 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Tue, 9 Jul 2024 19:34:35 +0200 Subject: [PATCH 067/160] Update examples/structured_1d_dgsem/elixir_burgers_perk3.jl Co-authored-by: Daniel Doehring --- examples/structured_1d_dgsem/elixir_burgers_perk3.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl index 6f74bb1d982..cc3ee92d53c 100644 --- a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl +++ b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl @@ -44,6 +44,7 @@ callbacks = CallbackSet(summary_callback, ############################################################################### # run the simulation +# Optimize 8-stage, third order P-ERK scheme for this semidiscretization ode_algorithm = Trixi.PairedExplicitRK3(8, tspan, semi) sol = Trixi.solve(ode, ode_algorithm, From 739b54b430599a5738b6b62b51a9a712d6555fba Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 9 Jul 2024 19:39:08 +0200 Subject: [PATCH 068/160] add save solution to the example --- examples/structured_1d_dgsem/elixir_burgers_perk3.jl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl index cc3ee92d53c..832968acabd 100644 --- a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl +++ b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl @@ -35,10 +35,15 @@ analysis_callback = AnalysisCallback(semi, interval = analysis_interval) alive_callback = AliveCallback(analysis_interval = analysis_interval) +save_solution = SaveSolutionCallback(dt = 0.1, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + stepsize_callback = StepsizeCallback(cfl = 3.7) callbacks = CallbackSet(summary_callback, - analysis_callback, alive_callback, + analysis_callback, alive_callback, save_solution, stepsize_callback) ############################################################################### From 995107b2db330522da75a0af516244665de45f2a Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 9 Jul 2024 19:56:58 +0200 Subject: [PATCH 069/160] update test to be compatible with save_solution --- test/test_structured_1d.jl | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index 883f1b12fad..034604f7788 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -60,8 +60,8 @@ end @trixi_testset "elixir_burgers_perk3.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_perk3.jl"), - l2=[6.4744366559817754e-6], - linf=[4.357450084224723e-5], + l2=[4.12066275835687e-6], + linf=[2.538190787615413e-5], atol=1.0e-6) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) @@ -73,6 +73,25 @@ end end end +# Testing the third-order paired explicit Runge-Kutta (PERK) method without stepsize callback +@trixi_testset "elixir_burgers_perk3.jl(fixed time step)" begin + @test_trixi_include( dt=2.0e-3, + tspan=(0.0, 2.0), + save_solution=SaveSolutionCallback(dt = 0.1 + 1.0e-8), + callbacks=CallbackSet(summary_callback, save_solution, + analysis_callback, alive_callback), + l2=[5.725141913990915e-7], + linf=[3.4298598041715422e-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.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov.jl"), l2=[3.67478226e-01, 3.49491179e-01, 8.08910759e-01], From 640c7f642ccd859d9c801f6d85d17f37906b58ae Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 9 Jul 2024 20:02:04 +0200 Subject: [PATCH 070/160] move comment regarding seed upwards --- ext/TrixiNLsolveExt.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 571eb1377eb..74f3e442da0 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -40,13 +40,14 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; c_s2) end + # To ensure consistency and reproducibility of results across runs, we use + # a seeded random initial guess. seed!(5555) for _ in 1:max_iter # Due to the nature of the nonlinear solver, different initial guesses can lead to # small numerical differences in the solution. - # To ensure consistency and reproducibility of results across runs, we use - # a seeded random initial guess. + x0 = 0.1 .* rand(num_stages - 2) sol = nlsolve(objective_function, x0, method = :trust_region, From e92330557c3dc0898dbef5ed398cdb90e65a868e Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 9 Jul 2024 20:10:43 +0200 Subject: [PATCH 071/160] Revert "Correct the logic of step!" only the part that meddles with methods_PERK2 --- .../methods_PERK2.jl | 4 +- .../methods_PERK3.jl | 109 +++++++++--------- 2 files changed, 57 insertions(+), 56 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK2.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK2.jl index 1d9680153e6..b3b917dc18d 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK2.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK2.jl @@ -273,10 +273,10 @@ function solve(ode::ODEProblem, alg::PairedExplicitRK2; integrator = init(ode, alg, dt = dt, callback = callback; kwargs...) # Start actual solve - solve!(integrator) + solve_steps!(integrator) end -function solve!(integrator::PairedExplicitRK2Integrator) +function solve_steps!(integrator::PairedExplicitRK2Integrator) @unpack prob = integrator.sol integrator.finalstep = false diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index ca549e744ab..cc1acc617bc 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -312,62 +312,62 @@ function step!(integrator::PairedExplicitRK3Integrator) modify_dt_for_tstops!(integrator) - # 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 - - @trixi_timeit timer() "Paired Explicit Runge-Kutta ODE integration step" begin - # k1 - integrator.f(integrator.du, integrator.u, prob.p, integrator.t) - @threaded for i in eachindex(integrator.du) - integrator.k1[i] = integrator.du[i] * integrator.dt + # 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 - # Construct current state - @threaded for i in eachindex(integrator.du) - integrator.u_tmp[i] = integrator.u[i] + alg.c[2] * integrator.k1[i] - end - # k2 - integrator.f(integrator.du, integrator.u_tmp, prob.p, - integrator.t + alg.c[2] * integrator.dt) + @trixi_timeit timer() "Paired Explicit Runge-Kutta ODE integration step" begin + # k1 + integrator.f(integrator.du, integrator.u, prob.p, integrator.t) + @threaded for i in eachindex(integrator.du) + integrator.k1[i] = integrator.du[i] * integrator.dt + end + + # Construct current state + @threaded for i in eachindex(integrator.du) + integrator.u_tmp[i] = integrator.u[i] + alg.c[2] * integrator.k1[i] + end + # k2 + integrator.f(integrator.du, integrator.u_tmp, prob.p, + integrator.t + alg.c[2] * integrator.dt) @threaded for i in eachindex(integrator.du) integrator.k_higher[i] = integrator.du[i] * integrator.dt end - # Higher stages - for stage in 3:(alg.num_stages - 1) - # Construct current state - @threaded for i in eachindex(integrator.du) - integrator.u_tmp[i] = integrator.u[i] + - alg.a_matrix[stage - 2, 1] * - integrator.k1[i] + - alg.a_matrix[stage - 2, 2] * - integrator.k_higher[i] - end + # Higher stages + for stage in 3:(alg.num_stages - 1) + # Construct current state + @threaded for i in eachindex(integrator.du) + integrator.u_tmp[i] = integrator.u[i] + + alg.a_matrix[stage - 2, 1] * + integrator.k1[i] + + alg.a_matrix[stage - 2, 2] * + integrator.k_higher[i] + end - integrator.f(integrator.du, integrator.u_tmp, prob.p, - integrator.t + alg.c[stage] * integrator.dt) + integrator.f(integrator.du, integrator.u_tmp, prob.p, + integrator.t + alg.c[stage] * integrator.dt) @threaded for i in eachindex(integrator.du) integrator.k_higher[i] = integrator.du[i] * integrator.dt end end - # Last stage - @threaded for i in eachindex(integrator.du) - integrator.u_tmp[i] = integrator.u[i] + - alg.a_matrix[alg.num_stages - 2, 1] * - integrator.k1[i] + - alg.a_matrix[alg.num_stages - 2, 2] * - integrator.k_higher[i] - end + # Last stage + @threaded for i in eachindex(integrator.du) + integrator.u_tmp[i] = integrator.u[i] + + alg.a_matrix[alg.num_stages - 2, 1] * + integrator.k1[i] + + alg.a_matrix[alg.num_stages - 2, 2] * + integrator.k_higher[i] + end - integrator.f(integrator.du, integrator.u_tmp, prob.p, - integrator.t + alg.c[alg.num_stages] * integrator.dt) + integrator.f(integrator.du, integrator.u_tmp, prob.p, + integrator.t + alg.c[alg.num_stages] * integrator.dt) @threaded for i in eachindex(integrator.u) # "Own" PairedExplicitRK based on SSPRK33. @@ -378,23 +378,24 @@ function step!(integrator::PairedExplicitRK3Integrator) end end # PairedExplicitRK step timer - integrator.iter += 1 - integrator.t += integrator.dt + 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) + # 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 - end - # respect maximum number of iterations - if integrator.iter >= integrator.opts.maxiters && !integrator.finalstep - @warn "Interrupted. Larger maxiters is needed." - terminate!(integrator) - end + # respect maximum number of iterations + if integrator.iter >= integrator.opts.maxiters && !integrator.finalstep + @warn "Interrupted. Larger maxiters is needed." + terminate!(integrator) + end + end # "main loop" timer end # used for AMR (Adaptive Mesh Refinement) From f3f4e254085378271a4d47fcd2d9883ea7cbc396 Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 9 Jul 2024 20:12:48 +0200 Subject: [PATCH 072/160] correct methods_PERK3 --- .../methods_PERK3.jl | 109 +++++++++--------- 1 file changed, 54 insertions(+), 55 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index cc1acc617bc..ca549e744ab 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -312,62 +312,62 @@ function step!(integrator::PairedExplicitRK3Integrator) modify_dt_for_tstops!(integrator) - # 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 + # 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 - @trixi_timeit timer() "Paired Explicit Runge-Kutta ODE integration step" begin - # k1 - integrator.f(integrator.du, integrator.u, prob.p, integrator.t) - @threaded for i in eachindex(integrator.du) - integrator.k1[i] = integrator.du[i] * integrator.dt - end + @trixi_timeit timer() "Paired Explicit Runge-Kutta ODE integration step" begin + # k1 + integrator.f(integrator.du, integrator.u, prob.p, integrator.t) + @threaded for i in eachindex(integrator.du) + integrator.k1[i] = integrator.du[i] * integrator.dt + end - # Construct current state - @threaded for i in eachindex(integrator.du) - integrator.u_tmp[i] = integrator.u[i] + alg.c[2] * integrator.k1[i] - end - # k2 - integrator.f(integrator.du, integrator.u_tmp, prob.p, - integrator.t + alg.c[2] * integrator.dt) + # Construct current state + @threaded for i in eachindex(integrator.du) + integrator.u_tmp[i] = integrator.u[i] + alg.c[2] * integrator.k1[i] + end + # k2 + integrator.f(integrator.du, integrator.u_tmp, prob.p, + integrator.t + alg.c[2] * integrator.dt) @threaded for i in eachindex(integrator.du) integrator.k_higher[i] = integrator.du[i] * integrator.dt end - # Higher stages - for stage in 3:(alg.num_stages - 1) - # Construct current state - @threaded for i in eachindex(integrator.du) - integrator.u_tmp[i] = integrator.u[i] + - alg.a_matrix[stage - 2, 1] * - integrator.k1[i] + - alg.a_matrix[stage - 2, 2] * - integrator.k_higher[i] - end + # Higher stages + for stage in 3:(alg.num_stages - 1) + # Construct current state + @threaded for i in eachindex(integrator.du) + integrator.u_tmp[i] = integrator.u[i] + + alg.a_matrix[stage - 2, 1] * + integrator.k1[i] + + alg.a_matrix[stage - 2, 2] * + integrator.k_higher[i] + end - integrator.f(integrator.du, integrator.u_tmp, prob.p, - integrator.t + alg.c[stage] * integrator.dt) + integrator.f(integrator.du, integrator.u_tmp, prob.p, + integrator.t + alg.c[stage] * integrator.dt) @threaded for i in eachindex(integrator.du) integrator.k_higher[i] = integrator.du[i] * integrator.dt end end - # Last stage - @threaded for i in eachindex(integrator.du) - integrator.u_tmp[i] = integrator.u[i] + - alg.a_matrix[alg.num_stages - 2, 1] * - integrator.k1[i] + - alg.a_matrix[alg.num_stages - 2, 2] * - integrator.k_higher[i] - end + # Last stage + @threaded for i in eachindex(integrator.du) + integrator.u_tmp[i] = integrator.u[i] + + alg.a_matrix[alg.num_stages - 2, 1] * + integrator.k1[i] + + alg.a_matrix[alg.num_stages - 2, 2] * + integrator.k_higher[i] + end - integrator.f(integrator.du, integrator.u_tmp, prob.p, - integrator.t + alg.c[alg.num_stages] * integrator.dt) + integrator.f(integrator.du, integrator.u_tmp, prob.p, + integrator.t + alg.c[alg.num_stages] * integrator.dt) @threaded for i in eachindex(integrator.u) # "Own" PairedExplicitRK based on SSPRK33. @@ -378,24 +378,23 @@ function step!(integrator::PairedExplicitRK3Integrator) end end # PairedExplicitRK step timer - integrator.iter += 1 - integrator.t += integrator.dt + 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 + # 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 # "main loop" timer + # respect maximum number of iterations + if integrator.iter >= integrator.opts.maxiters && !integrator.finalstep + @warn "Interrupted. Larger maxiters is needed." + terminate!(integrator) + end end # used for AMR (Adaptive Mesh Refinement) From a6addd71a5095dfeeafa4511b5d63f3863bdd99d Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 9 Jul 2024 20:16:03 +0200 Subject: [PATCH 073/160] move is_sol_valid closer to the for loop --- ext/TrixiNLsolveExt.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 74f3e442da0..731d31da18c 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -30,7 +30,6 @@ using Trixi: Trixi, solve_a_unknown!, PairedExplicitRK3_butcher_tableau_objectiv # Hairer, Wanner: Solving Ordinary Differential Equations 2 function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; verbose, max_iter = 100000) - is_sol_valid = false # Define the objective_function function objective_function(x) @@ -44,6 +43,8 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; # a seeded random initial guess. seed!(5555) + is_sol_valid = false + for _ in 1:max_iter # Due to the nature of the nonlinear solver, different initial guesses can lead to # small numerical differences in the solution. From 87c6cae97e30f898b0cbb8bc46579902a0d6ef05 Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 9 Jul 2024 20:17:52 +0200 Subject: [PATCH 074/160] fmt --- ext/TrixiNLsolveExt.jl | 2 +- test/test_structured_1d.jl | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 731d31da18c..27e7a714caa 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -48,7 +48,7 @@ function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; for _ in 1:max_iter # Due to the nature of the nonlinear solver, different initial guesses can lead to # small numerical differences in the solution. - + x0 = 0.1 .* rand(num_stages - 2) sol = nlsolve(objective_function, x0, method = :trust_region, diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index 034604f7788..3f6a3a2e551 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -75,13 +75,13 @@ end # Testing the third-order paired explicit Runge-Kutta (PERK) method without stepsize callback @trixi_testset "elixir_burgers_perk3.jl(fixed time step)" begin - @test_trixi_include( dt=2.0e-3, - tspan=(0.0, 2.0), - save_solution=SaveSolutionCallback(dt = 0.1 + 1.0e-8), - callbacks=CallbackSet(summary_callback, save_solution, - analysis_callback, alive_callback), - l2=[5.725141913990915e-7], - linf=[3.4298598041715422e-6]) + @test_trixi_include(dt=2.0e-3, + tspan=(0.0, 2.0), + save_solution=SaveSolutionCallback(dt = 0.1 + 1.0e-8), + callbacks=CallbackSet(summary_callback, save_solution, + analysis_callback, alive_callback), + l2=[5.725141913990915e-7], + linf=[3.4298598041715422e-6]) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let From 0d642fb33f4b19a0be360af7279848701eb599e2 Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 9 Jul 2024 20:35:11 +0200 Subject: [PATCH 075/160] Revert some random changes in other test unit --- test/test_structured_1d.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index 3f6a3a2e551..35d402ed73a 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -47,7 +47,7 @@ end @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_shockcapturing.jl"), l2=[0.08015029105233593], linf=[0.610709468736576], - atol=1.0e-12) + atol=1.0e-5) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let From d602a959cf420fbd2d4cf573834a300161bec682 Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 9 Jul 2024 20:36:18 +0200 Subject: [PATCH 076/160] add tolerance to the test --- test/test_structured_1d.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index 35d402ed73a..6acbc3ccb09 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -81,7 +81,8 @@ end callbacks=CallbackSet(summary_callback, save_solution, analysis_callback, alive_callback), l2=[5.725141913990915e-7], - linf=[3.4298598041715422e-6]) + linf=[3.4298598041715422e-6], + atol=1.0e-6) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let From bc358e455f5baf24734374bc9884096a808c9e94 Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 9 Jul 2024 20:45:04 +0200 Subject: [PATCH 077/160] modify functions so that they are also compatible with PERK3 --- .../paired_explicit_runge_kutta/methods_PERK2.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK2.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK2.jl index ddcc1b365be..6abf1cbaa9e 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK2.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK2.jl @@ -233,11 +233,11 @@ mutable struct PairedExplicitRK2Integrator{RealT <: Real, uType, Params, Sol, F, end """ - add_tstop!(integrator::PairedExplicitRK2Integrator, t) + add_tstop!(integrator::AbstractPairedExplicitRKSingleIntegrator, 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::PairedExplicitRK2Integrator, t) +function add_tstop!(integrator::AbstractPairedExplicitRKSingleIntegrator, 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. @@ -248,8 +248,8 @@ function add_tstop!(integrator::PairedExplicitRK2Integrator, t) push!(integrator.opts.tstops, integrator.tdir * t) end -has_tstop(integrator::PairedExplicitRK2Integrator) = !isempty(integrator.opts.tstops) -first_tstop(integrator::PairedExplicitRK2Integrator) = first(integrator.opts.tstops) +has_tstop(integrator::AbstractPairedExplicitRKSingleIntegrator) = !isempty(integrator.opts.tstops) +first_tstop(integrator::AbstractPairedExplicitRKSingleIntegrator) = first(integrator.opts.tstops) # Forward integrator.stats.naccept to integrator.iter (see GitHub PR#771) function Base.getproperty(integrator::PairedExplicitRK, field::Symbol) From 10d712697dafe26720888ac8de91fc0b5dc9632c Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 9 Jul 2024 21:02:06 +0200 Subject: [PATCH 078/160] change function's name to be more descriptive --- ext/TrixiConvexECOSExt.jl | 2 +- ext/TrixiNLsolveExt.jl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/TrixiConvexECOSExt.jl b/ext/TrixiConvexECOSExt.jl index 8251fe3eed9..0a5b4c44c5d 100644 --- a/ext/TrixiConvexECOSExt.jl +++ b/ext/TrixiConvexECOSExt.jl @@ -136,7 +136,7 @@ function Trixi.bisect_stability_polynomial(consistency_order, num_eig_vals, "reltol_inacc" => 5e-5, "nitref" => 9, "maxit" => 100, - "verbose" => 3); silent = true) + "verbose" => 3); silent_solver = true) abs_p = problem.optval diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 27e7a714caa..4b4a5a2dc56 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -14,7 +14,7 @@ end using Random: seed! # Use functions that are to be extended and additional symbols that are not exported -using Trixi: Trixi, solve_a_unknown!, PairedExplicitRK3_butcher_tableau_objective_function, +using Trixi: Trixi, solve_a_butcher_coeffs_unknown!, PairedExplicitRK3_butcher_tableau_objective_function, @muladd # By default, Julia/LLVM does not use fused multiply-add operations (FMAs). @@ -28,7 +28,7 @@ using Trixi: Trixi, solve_a_unknown!, PairedExplicitRK3_butcher_tableau_objectiv # non-linear equations that arise from the relation of the stability polynomial to the Butcher tableau. # For details, see Proposition 3.2, Equation (3.3) from # Hairer, Wanner: Solving Ordinary Differential Equations 2 -function Trixi.solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; +function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; verbose, max_iter = 100000) # Define the objective_function From 75de0888ec61a39e6bf4dde15e4879153d0f28ad Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 9 Jul 2024 21:02:49 +0200 Subject: [PATCH 079/160] change function's name to be more descriptive in all files --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 2 +- .../paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index ca549e744ab..0cc472ba330 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -100,7 +100,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, # Solve the nonlinear system of equations from monomial coefficient and # Butcher array abscissae c to find Butcher matrix A # This function is extended in TrixiNLsolveExt.jl - a_unknown = solve_a_unknown!(a_unknown, num_stages, monomial_coeffs, cS2, c; + a_unknown = solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_coeffs, cS2, c; verbose) end # Fill A-matrix in P-ERK style diff --git a/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl b/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl index cc48c3ca458..8f8cacadd79 100644 --- a/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl +++ b/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl @@ -14,5 +14,5 @@ include("polynomial_optimizer.jl") # Add definitions of functions related to polynomial optimization by NLsolve here # such that hey can be exported from Trixi.jl and extended in the TrixiConvexECOSExt package # extension or by the NLsolve-specific code loaded by Requires.jl -function solve_a_unknown! end +function solve_a_butcher_coeffs_unknown! end end # @muladd From 58fabb79e1f6dada4cf645f975e13d8596ef1071 Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 9 Jul 2024 21:03:40 +0200 Subject: [PATCH 080/160] Revert irrelevent change in TrixiConvexECOSExt.jl --- ext/TrixiConvexECOSExt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/TrixiConvexECOSExt.jl b/ext/TrixiConvexECOSExt.jl index 0a5b4c44c5d..8251fe3eed9 100644 --- a/ext/TrixiConvexECOSExt.jl +++ b/ext/TrixiConvexECOSExt.jl @@ -136,7 +136,7 @@ function Trixi.bisect_stability_polynomial(consistency_order, num_eig_vals, "reltol_inacc" => 5e-5, "nitref" => 9, "maxit" => 100, - "verbose" => 3); silent_solver = true) + "verbose" => 3); silent = true) abs_p = problem.optval From 40dd61029713968bb00cba3a3f9ae66df4a783bd Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 9 Jul 2024 21:05:52 +0200 Subject: [PATCH 081/160] add PR number to NEWS.md --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index b089b716505..fdc234ab883 100644 --- a/NEWS.md +++ b/NEWS.md @@ -31,7 +31,7 @@ for human readability. - Add subcell limiting support for `StructuredMesh` ([#1946]). - New time integrator `PairedExplicitRK3`, implementing the third-order paired explicit Runge-Kutta method with [Convex.jl](https://github.com/jump-dev/Convex.jl), [ECOS.jl](https://github.com/jump-dev/ECOS.jl), - and [NLsolve.jl](https://github.com/JuliaNLSolvers/NLsolve.jl) ([TBD]) + and [NLsolve.jl](https://github.com/JuliaNLSolvers/NLsolve.jl) ([#2008]) ## Changes when updating to v0.7 from v0.6.x From c104ff2efaf585b80904cf4baff99fa7287961c9 Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 9 Jul 2024 21:09:20 +0200 Subject: [PATCH 082/160] fmt --- ext/TrixiNLsolveExt.jl | 8 +++++--- .../paired_explicit_runge_kutta/methods_PERK3.jl | 5 +++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 4b4a5a2dc56..0766f8ed5e0 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -14,7 +14,8 @@ end using Random: seed! # Use functions that are to be extended and additional symbols that are not exported -using Trixi: Trixi, solve_a_butcher_coeffs_unknown!, PairedExplicitRK3_butcher_tableau_objective_function, +using Trixi: Trixi, solve_a_butcher_coeffs_unknown!, + PairedExplicitRK3_butcher_tableau_objective_function, @muladd # By default, Julia/LLVM does not use fused multiply-add operations (FMAs). @@ -28,8 +29,9 @@ using Trixi: Trixi, solve_a_butcher_coeffs_unknown!, PairedExplicitRK3_butcher_t # non-linear equations that arise from the relation of the stability polynomial to the Butcher tableau. # For details, see Proposition 3.2, Equation (3.3) from # Hairer, Wanner: Solving Ordinary Differential Equations 2 -function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; - verbose, max_iter = 100000) +function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_coeffs, + c_s2, c; + verbose, max_iter = 100000) # Define the objective_function function objective_function(x) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 0cc472ba330..4e1a3b54ef1 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -100,8 +100,9 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, # Solve the nonlinear system of equations from monomial coefficient and # Butcher array abscissae c to find Butcher matrix A # This function is extended in TrixiNLsolveExt.jl - a_unknown = solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_coeffs, cS2, c; - verbose) + a_unknown = solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, + monomial_coeffs, cS2, c; + verbose) end # Fill A-matrix in P-ERK style a_matrix = zeros(num_stages - 2, 2) From 76487b5d7f4a3153559a8f4cc4625a2cd9592624 Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 9 Jul 2024 21:31:05 +0200 Subject: [PATCH 083/160] change from using Random to StableRNGs --- Project.toml | 4 ++-- ext/TrixiNLsolveExt.jl | 6 +++--- test/Project.toml | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Project.toml b/Project.toml index 1d397335704..d931fc8b82d 100644 --- a/Project.toml +++ b/Project.toml @@ -28,13 +28,13 @@ Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" Preferences = "21216c6a-2e73-6563-6e65-726566657250" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" Requires = "ae029012-a4dd-5104-9daa-d747884805df" SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" SimpleUnPack = "ce78b400-467f-4804-87d8-8f486da07d0a" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3" StartUpDG = "472ebc20-7c99-4d4b-9470-8fde4e9faa0f" Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" StaticArrayInterface = "0d7ed370-da01-4f52-bd93-41d350b8b718" @@ -90,13 +90,13 @@ Polyester = "0.7.10" PrecompileTools = "1.1" Preferences = "1.3" Printf = "1" -Random = "1" RecipesBase = "1.1" Reexport = "1.0" Requires = "1.1" SciMLBase = "1.90, 2" SimpleUnPack = "1.1" SparseArrays = "1" +StableRNGs = "1.0.2" StartUpDG = "0.17.7" Static = "0.8.7" StaticArrayInterface = "1.4" diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 0766f8ed5e0..60f00941158 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -11,7 +11,7 @@ end # We use a random initialization of the nonlinear solver. # To make the tests reproducible, we need to seed the RNG -using Random: seed! +using StableRNGs: StableRNG, rand # Use functions that are to be extended and additional symbols that are not exported using Trixi: Trixi, solve_a_butcher_coeffs_unknown!, @@ -43,7 +43,7 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_c # To ensure consistency and reproducibility of results across runs, we use # a seeded random initial guess. - seed!(5555) + rng = StableRNG(555) is_sol_valid = false @@ -51,7 +51,7 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_c # Due to the nature of the nonlinear solver, different initial guesses can lead to # small numerical differences in the solution. - x0 = 0.1 .* rand(num_stages - 2) + x0 = 0.1 .* rand(rng, num_stages - 2) sol = nlsolve(objective_function, x0, method = :trust_region, ftol = 4e-16, # Enforce objective up to machine precision diff --git a/test/Project.toml b/test/Project.toml index 84d35d6ca26..f8bcff947c0 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -15,6 +15,7 @@ OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] @@ -34,6 +35,7 @@ OrdinaryDiffEq = "6.49.1" Plots = "1.19" Printf = "1" Random = "1" +StableRNGs = "1.0.2" Test = "1" [preferences.OrdinaryDiffEq] From ecbb0ffc95d08daf19eb85762ac1432014d52b69 Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 9 Jul 2024 22:40:00 +0200 Subject: [PATCH 084/160] fix the value in unit test --- test/test_unit.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/test_unit.jl b/test/test_unit.jl index b71c0130cbe..06580e322d5 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1724,16 +1724,16 @@ end #TODO: adjust this value according to the result in the test pipeline println(ode_algorithm.a_matrix) # Value in CI differs slightly from what I get locally @test isapprox(ode_algorithm.a_matrix, - [0.19258815209175084 0.007411847908249183 - 0.287232921421498 0.012767078578501994 - 0.38017716660879974 0.019822833391200292 - 0.4706748922245802 0.029325107775419784 - 0.5575748091858802 0.042425190814119815 - 0.6390917624593604 0.06090823754063958 + [0.19156094079581354 0.008439059204186486 + 0.2872329213106948 0.01276707868930521 + 0.3801771666087999 0.019822833391200098 + 0.4706748922245802 0.02932510777541978 + 0.5575748091858802 0.04242519081411982 + 0.6390917624593604 0.06090823754063957 0.712487669254592 0.08751233074540807 0.7736370088751211 0.1263629911248789 - 0.816131548721476 0.18386845127852405 - 0.7532704353232954 0.24672956467670462 + 0.8161315487214759 0.1838684512785241 + 0.7532704353232954 0.24672956467670457 0.3116823911691762 0.18831760883082385], atol = 1e-13) end From bcadd5a5087bd3924891787f68779a52afe99279 Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 9 Jul 2024 22:40:40 +0200 Subject: [PATCH 085/160] remove prints --- test/test_unit.jl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/test_unit.jl b/test/test_unit.jl index 06580e322d5..07e8cc836d4 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1704,8 +1704,6 @@ end ode_algorithm = Trixi.PairedExplicitRK3(8, path_coeff_file) - #TODO: adjust this value according to the result in the test pipeline - println(ode_algorithm.a_matrix) # Value in CI differs slightly from what I get locally @test isapprox(ode_algorithm.a_matrix, [0.3355167784195604 0.06448322158043965 0.4965349205803965 0.10346507941960345 @@ -1721,8 +1719,6 @@ end tspan = (0.0, 1.0) ode_algorithm = Trixi.PairedExplicitRK3(13, tspan, vec(eig_vals)) - #TODO: adjust this value according to the result in the test pipeline - println(ode_algorithm.a_matrix) # Value in CI differs slightly from what I get locally @test isapprox(ode_algorithm.a_matrix, [0.19156094079581354 0.008439059204186486 0.2872329213106948 0.01276707868930521 From 47e52d0985c35359981035cf3ac1e41b39825d11 Mon Sep 17 00:00:00 2001 From: Warisa Date: Wed, 10 Jul 2024 11:57:13 +0200 Subject: [PATCH 086/160] minor comment correction --- ext/TrixiNLsolveExt.jl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 60f00941158..4f0ad2a3fd1 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -1,4 +1,4 @@ -# Package extension for adding Convex-based features to Trixi.jl +# Package extension for adding NLsolve-based features to Trixi.jl module TrixiNLsolveExt # Required for coefficient optimization in P-ERK scheme integrators @@ -14,9 +14,8 @@ end using StableRNGs: StableRNG, rand # Use functions that are to be extended and additional symbols that are not exported -using Trixi: Trixi, solve_a_butcher_coeffs_unknown!, - PairedExplicitRK3_butcher_tableau_objective_function, - @muladd +using Trixi: Trixi, PairedExplicitRK3_butcher_tableau_objective_function, + solve_a_butcher_coeffs_unknown!, @muladd # By default, Julia/LLVM does not use fused multiply-add operations (FMAs). # Since these FMAs can increase the performance of many numerical algorithms, From 98264575195ecabacb926c8750e0f01fc30a5ea2 Mon Sep 17 00:00:00 2001 From: Warisa Date: Wed, 10 Jul 2024 12:04:15 +0200 Subject: [PATCH 087/160] attempt to fix the error at fixed time step --- test/test_structured_1d.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index 6acbc3ccb09..35d402ed73a 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -81,8 +81,7 @@ end callbacks=CallbackSet(summary_callback, save_solution, analysis_callback, alive_callback), l2=[5.725141913990915e-7], - linf=[3.4298598041715422e-6], - atol=1.0e-6) + linf=[3.4298598041715422e-6]) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let From d66b241bcdacb83b814d3549ba1ea061adc41e27 Mon Sep 17 00:00:00 2001 From: Warisa Date: Wed, 10 Jul 2024 20:19:59 +0200 Subject: [PATCH 088/160] add the missing clause to test set --- test/test_structured_1d.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index 35d402ed73a..5ad71f7b5b9 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -75,7 +75,8 @@ end # Testing the third-order paired explicit Runge-Kutta (PERK) method without stepsize callback @trixi_testset "elixir_burgers_perk3.jl(fixed time step)" begin - @test_trixi_include(dt=2.0e-3, + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_perk3.jl"), + dt=2.0e-3, tspan=(0.0, 2.0), save_solution=SaveSolutionCallback(dt = 0.1 + 1.0e-8), callbacks=CallbackSet(summary_callback, save_solution, From d405551c28ffe0ebc1ef9ca6eddfcef2d7a4736f Mon Sep 17 00:00:00 2001 From: Warisa Date: Wed, 10 Jul 2024 20:30:49 +0200 Subject: [PATCH 089/160] adjust allocation values in test of perk3 --- test/test_structured_1d.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index 5ad71f7b5b9..8745116e3c5 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -69,7 +69,7 @@ end t = 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)) < 8000 end end @@ -89,7 +89,7 @@ end t = 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)) < 8000 end end From f07066859f754f62e46a70b41df0c2cb28102d4e Mon Sep 17 00:00:00 2001 From: Warisa Date: Wed, 10 Jul 2024 21:15:15 +0200 Subject: [PATCH 090/160] update test value --- test/test_structured_1d.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index 8745116e3c5..ff682f3ea5d 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -81,8 +81,8 @@ end save_solution=SaveSolutionCallback(dt = 0.1 + 1.0e-8), callbacks=CallbackSet(summary_callback, save_solution, analysis_callback, alive_callback), - l2=[5.725141913990915e-7], - linf=[3.4298598041715422e-6]) + l2=[5.726144786001842e-7], + linf=[3.430730019182704e-6]) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let From 5746b5f8c9edc0d2b23bf2b436f06aeb07d43842 Mon Sep 17 00:00:00 2001 From: Warisa Date: Thu, 11 Jul 2024 19:37:17 +0200 Subject: [PATCH 091/160] move objective function to the extension --- ext/TrixiNLsolveExt.jl | 58 ++++++++++++++++--- .../methods_PERK3.jl | 44 -------------- 2 files changed, 51 insertions(+), 51 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 4f0ad2a3fd1..c64e0ceed8b 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -1,7 +1,8 @@ # Package extension for adding NLsolve-based features to Trixi.jl module TrixiNLsolveExt -# Required for coefficient optimization in P-ERK scheme integrators +# Required for finding coefficients in Butcher tableau in the third order of +# P-ERK scheme integrators if isdefined(Base, :get_extension) using NLsolve: nlsolve else @@ -14,8 +15,7 @@ end using StableRNGs: StableRNG, rand # Use functions that are to be extended and additional symbols that are not exported -using Trixi: Trixi, PairedExplicitRK3_butcher_tableau_objective_function, - solve_a_butcher_coeffs_unknown!, @muladd +using Trixi: Trixi, solve_a_butcher_coeffs_unknown!, compute_c_coeffs, @muladd # By default, Julia/LLVM does not use fused multiply-add operations (FMAs). # Since these FMAs can increase the performance of many numerical algorithms, @@ -24,6 +24,50 @@ using Trixi: Trixi, PairedExplicitRK3_butcher_tableau_objective_function, @muladd begin #! format: noindent +# Compute residuals for nonlinear equations to match a stability polynomial with given coefficients, +# in order to find A-matrix in the Butcher-Tableau +function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_stages, + num_stage_evals, + monomial_coeffs, cS2) + c_ts = Trixi.compute_c_coeffs(num_stages, cS2) # ts = timestep + # For explicit methods, a_{1,1} = 0 and a_{2,1} = c_2 (Butcher's condition) + a_coeff = [0.0, c_ts[2], a_unknown...] + # Equality constraint array that ensures that the stability polynomial computed from + # the to-be-constructed Butcher-Tableau matches the monomial coefficients of the + # optimized stability polynomial. + # For details, see Chapter4.3, Proposition 3.2, Equation (3.3) from + # Hairer, Wanner: Solving Ordinary Differential Equations 2 + c_eq = zeros(num_stage_evals - 2) # Add equality constraint that cS2 is equal to 1 + # Lower-order terms: Two summands present + for i in 1:(num_stage_evals - 4) + term1 = a_coeff[num_stage_evals - 1] + term2 = a_coeff[num_stage_evals] + for j in 1:i + term1 *= a_coeff[num_stage_evals - 1 - j] + term2 *= a_coeff[num_stage_evals - j] + end + term1 *= c_ts[num_stages - 2 - i] * 1 / 6 # 1 / 6 = b_{S-1} + term2 *= c_ts[num_stages - 1 - i] * 2 / 3 # 2 / 3 = b_S + + c_eq[i] = monomial_coeffs[i] - (term1 + term2) + end + + # Highest coefficient: Only one term present + i = num_stage_evals - 3 + term2 = a_coeff[num_stage_evals] + for j in 1:i + term2 *= a_coeff[num_stage_evals - j] + end + term2 *= c_ts[num_stages - 1 - i] * 2 / 3 # 2 / 3 = b_S + + c_eq[i] = monomial_coeffs[i] - term2 + # Third-order consistency condition (Cf. eq. (27) from https://doi.org/10.1016/j.jcp.2022.111470 + c_eq[num_stage_evals - 2] = 1 - 4 * a_coeff[num_stage_evals] - + a_coeff[num_stage_evals - 1] + + return c_eq +end + # Find the values of the a_{i, i-1} in the Butcher tableau matrix A by solving a system of # non-linear equations that arise from the relation of the stability polynomial to the Butcher tableau. # For details, see Proposition 3.2, Equation (3.3) from @@ -34,10 +78,10 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_c # Define the objective_function function objective_function(x) - return Trixi.PairedExplicitRK3_butcher_tableau_objective_function(x, num_stages, - num_stages, - monomial_coeffs, - c_s2) + return PairedExplicitRK3_butcher_tableau_objective_function(x, num_stages, + num_stages, + monomial_coeffs, + c_s2) end # To ensure consistency and reproducibility of results across runs, we use diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 4e1a3b54ef1..cedcd06a9b1 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -24,50 +24,6 @@ function compute_c_coeffs(num_stages, cS2) return c end -# Compute residuals for nonlinear equations to match a stability polynomial with given coefficients, -# in order to find A-matrix in the Butcher-Tableau -function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_stages, - num_stage_evals, - monomial_coeffs, cS2) - c_ts = compute_c_coeffs(num_stages, cS2) # ts = timestep - # For explicit methods, a_{1,1} = 0 and a_{2,1} = c_2 (Butcher's condition) - a_coeff = [0.0, c_ts[2], a_unknown...] - # Equality constraint array that ensures that the stability polynomial computed from - # the to-be-constructed Butcher-Tableau matches the monomial coefficients of the - # optimized stability polynomial. - # For details, see Chapter4.3, Proposition 3.2, Equation (3.3) from - # Hairer, Wanner: Solving Ordinary Differential Equations 2 - c_eq = zeros(num_stage_evals - 2) # Add equality constraint that cS2 is equal to 1 - # Lower-order terms: Two summands present - for i in 1:(num_stage_evals - 4) - term1 = a_coeff[num_stage_evals - 1] - term2 = a_coeff[num_stage_evals] - for j in 1:i - term1 *= a_coeff[num_stage_evals - 1 - j] - term2 *= a_coeff[num_stage_evals - j] - end - term1 *= c_ts[num_stages - 2 - i] * 1 / 6 # 1 / 6 = b_{S-1} - term2 *= c_ts[num_stages - 1 - i] * 2 / 3 # 2 / 3 = b_S - - c_eq[i] = monomial_coeffs[i] - (term1 + term2) - end - - # Highest coefficient: Only one term present - i = num_stage_evals - 3 - term2 = a_coeff[num_stage_evals] - for j in 1:i - term2 *= a_coeff[num_stage_evals - j] - end - term2 *= c_ts[num_stages - 1 - i] * 2 / 3 # 2 / 3 = b_S - - c_eq[i] = monomial_coeffs[i] - term2 - # Third-order consistency condition (Cf. eq. (27) from https://doi.org/10.1016/j.jcp.2022.111470 - c_eq[num_stage_evals - 2] = 1 - 4 * a_coeff[num_stage_evals] - - a_coeff[num_stage_evals - 1] - - return c_eq -end - # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 # using a list of eigenvalues function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, From b87592ec25559ffdb892050b7f2401dfa1c068eb Mon Sep 17 00:00:00 2001 From: Warisa Date: Fri, 12 Jul 2024 11:53:10 +0200 Subject: [PATCH 092/160] minor fix with compute_c_coeffs --- ext/TrixiNLsolveExt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index c64e0ceed8b..e172074edbf 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -29,7 +29,7 @@ using Trixi: Trixi, solve_a_butcher_coeffs_unknown!, compute_c_coeffs, @muladd function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_stages, num_stage_evals, monomial_coeffs, cS2) - c_ts = Trixi.compute_c_coeffs(num_stages, cS2) # ts = timestep + c_ts = compute_c_coeffs(num_stages, cS2) # ts = timestep # For explicit methods, a_{1,1} = 0 and a_{2,1} = c_2 (Butcher's condition) a_coeff = [0.0, c_ts[2], a_unknown...] # Equality constraint array that ensures that the stability polynomial computed from From 24cbde6b84065a0b2fd1d0606e709ee905a86230 Mon Sep 17 00:00:00 2001 From: Warisa Date: Fri, 12 Jul 2024 14:26:21 +0200 Subject: [PATCH 093/160] remove explicit import of solve_a_unknown from line 18 --- ext/TrixiNLsolveExt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index e172074edbf..0241d5e67fe 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -15,7 +15,7 @@ end using StableRNGs: StableRNG, rand # Use functions that are to be extended and additional symbols that are not exported -using Trixi: Trixi, solve_a_butcher_coeffs_unknown!, compute_c_coeffs, @muladd +using Trixi: Trixi, compute_c_coeffs, @muladd # By default, Julia/LLVM does not use fused multiply-add operations (FMAs). # Since these FMAs can increase the performance of many numerical algorithms, From a083ac013ac6843cec594ddae4a4c52abf11956e Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Mon, 15 Jul 2024 12:10:52 +0200 Subject: [PATCH 094/160] Apply suggestions from code review --- ext/TrixiNLsolveExt.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 0241d5e67fe..d2c8ac03b59 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -88,6 +88,7 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_c # a seeded random initial guess. rng = StableRNG(555) + # Flag for criteria going beyond satisfaction of non-linear equations is_sol_valid = false for _ in 1:max_iter @@ -100,7 +101,7 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_c ftol = 4e-16, # Enforce objective up to machine precision iterations = 10^4, xtol = 1e-13) - a_unknown = sol.zero + a_unknown = sol.zero # Retrieve solution (root = zero) # Check if the values a[i, i-1] >= 0.0 (which stem from the nonlinear solver) # and also c[i] - a[i, i-1] >= 0.0 since all coefficients should be non-negative From fe26ef182d98e852baa2db9eb44d2266c0981b8c Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 15 Jul 2024 14:39:31 +0200 Subject: [PATCH 095/160] document why additional packages are loaded --- examples/structured_1d_dgsem/elixir_burgers_perk3.jl | 6 ++++++ examples/tree_1d_dgsem/elixir_advection_perk2.jl | 3 +++ 2 files changed, 9 insertions(+) diff --git a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl index 832968acabd..4d031db7ae1 100644 --- a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl +++ b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl @@ -1,5 +1,11 @@ +# Convex and ECOS are imported because they are used for finding the optimal time step and optimal +# monomial coefficients in the stability polynomial of P-ERK time integrators. using Convex, ECOS + +# NLsolve is imported to solve the system of nonlinear equations to find a coefficients +# in the Butcher tableau in the third order P-ERK time integrator. using NLsolve + using OrdinaryDiffEq using Trixi diff --git a/examples/tree_1d_dgsem/elixir_advection_perk2.jl b/examples/tree_1d_dgsem/elixir_advection_perk2.jl index 7db461a079e..68befbcfe82 100644 --- a/examples/tree_1d_dgsem/elixir_advection_perk2.jl +++ b/examples/tree_1d_dgsem/elixir_advection_perk2.jl @@ -1,5 +1,8 @@ +# Convex and ECOS are imported because they are used for finding the optimal time step and optimal +# monomial coefficients in the stability polynomial of P-ERK time integrators. using Convex, ECOS + using OrdinaryDiffEq using Trixi From 339eae2c4b9eb5b98cb4cf7bfd50a3f325bd44c7 Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 16 Jul 2024 09:29:55 +0200 Subject: [PATCH 096/160] correct docstring --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index cedcd06a9b1..f17fd3f8b96 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -104,7 +104,7 @@ end cS2 = 1.0) PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; verbose = false, cS2 = 1.0) - PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; + PairedExplicitRK3(num_stages, tspan, eig_vals::Vector{ComplexF64}; verbose = false, cS2 = 1.0) Parameters: @@ -151,7 +151,7 @@ end # Constructor that computes Butcher matrix A coefficients from a semidiscretization function PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; - verbose = false, cS2 = 1) + verbose = false, cS2 = 1.0) eig_vals = eigvals(jacobian_ad_forward(semi)) return PairedExplicitRK3(num_stages, tspan, eig_vals; verbose, cS2) @@ -159,7 +159,7 @@ end # Constructor that calculates the coefficients with polynomial optimizer from a list of eigenvalues function PairedExplicitRK3(num_stages, tspan, eig_vals::Vector{ComplexF64}; - verbose = false, cS2 = 1) + verbose = false, cS2 = 1.0) a_matrix, c = compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, eig_vals; From 1a0bf58ab278247516e40db5391d3c601d8b3084 Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 16 Jul 2024 17:06:13 +0200 Subject: [PATCH 097/160] use Float32 --- ext/TrixiNLsolveExt.jl | 10 ++++----- .../methods_PERK3.jl | 22 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index d2c8ac03b59..aea077e5898 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -31,7 +31,7 @@ function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_sta monomial_coeffs, cS2) c_ts = compute_c_coeffs(num_stages, cS2) # ts = timestep # For explicit methods, a_{1,1} = 0 and a_{2,1} = c_2 (Butcher's condition) - a_coeff = [0.0, c_ts[2], a_unknown...] + a_coeff = [0.0f0, c_ts[2], a_unknown...] # Equality constraint array that ensures that the stability polynomial computed from # the to-be-constructed Butcher-Tableau matches the monomial coefficients of the # optimized stability polynomial. @@ -62,7 +62,7 @@ function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_sta c_eq[i] = monomial_coeffs[i] - term2 # Third-order consistency condition (Cf. eq. (27) from https://doi.org/10.1016/j.jcp.2022.111470 - c_eq[num_stage_evals - 2] = 1 - 4 * a_coeff[num_stage_evals] - + c_eq[num_stage_evals - 2] = 1.0f0 - 4.0f0 * a_coeff[num_stage_evals] - a_coeff[num_stage_evals - 1] return c_eq @@ -95,11 +95,11 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_c # Due to the nature of the nonlinear solver, different initial guesses can lead to # small numerical differences in the solution. - x0 = 0.1 .* rand(rng, num_stages - 2) + x0 = 0.1f0 .* rand(rng, num_stages - 2) sol = nlsolve(objective_function, x0, method = :trust_region, - ftol = 4e-16, # Enforce objective up to machine precision - iterations = 10^4, xtol = 1e-13) + ftol = 4.0f-16, # Enforce objective up to machine precision + iterations = 10^4, xtol = 1.0f-13) a_unknown = sol.zero # Retrieve solution (root = zero) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index f17fd3f8b96..89e5c4cfa3a 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -13,8 +13,8 @@ function compute_c_coeffs(num_stages, cS2) # Last timesteps as for SSPRK33, see motivation in # https://doi.org/10.48550/arXiv.2403.05144 - c[num_stages - 1] = 1 - c[num_stages] = 0.5 + c[num_stages - 1] = 1.0f0 + c[num_stages] = 0.5f0 # Linear increasing timestep for remainder for i in 2:(num_stages - 2) @@ -37,12 +37,12 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, # Special case of e = 3 if num_stages == 3 - a_unknown = [0.25] + a_unknown = [0.25f0] else # Calculate coefficients of the stability polynomial in monomial form consistency_order = 3 dtmax = tspan[2] - tspan[1] - dteps = 1e-9 + dteps = 1.0f-9 num_eig_vals, eig_vals = filter_eig_vals(eig_vals; verbose) @@ -101,11 +101,11 @@ end @doc raw""" PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString; - cS2 = 1.0) + cS2 = 1.0f0) PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; - verbose = false, cS2 = 1.0) + verbose = false, cS2 = 1.0f0) PairedExplicitRK3(num_stages, tspan, eig_vals::Vector{ComplexF64}; - verbose = false, cS2 = 1.0) + verbose = false, cS2 = 1.0f0) Parameters: - `num_stages` (`Int`): Number of stages in the PERK method. @@ -118,7 +118,7 @@ end equation has been semidiscretized. - `verbose` (`Bool`, optional): Verbosity flag, default is false. - `cS2` (`Float64`, optional): Value of c in the Butcher tableau at c_{s-2}, when - s is the number of stages, default is 1.0. + s is the number of stages, default is 1.0f0. The following structures and methods provide an implementation of the third-order paired explicit Runge-Kutta (P-ERK) method @@ -141,7 +141,7 @@ end # struct PairedExplicitRK3 # Constructor for previously computed A Coeffs function PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString; - cS2 = 1.0) + cS2 = 1.0f0) a_matrix, c = compute_PairedExplicitRK3_butcher_tableau(num_stages, base_path_a_coeffs; cS2) @@ -151,7 +151,7 @@ end # Constructor that computes Butcher matrix A coefficients from a semidiscretization function PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; - verbose = false, cS2 = 1.0) + verbose = false, cS2 = 1.0f0) eig_vals = eigvals(jacobian_ad_forward(semi)) return PairedExplicitRK3(num_stages, tspan, eig_vals; verbose, cS2) @@ -159,7 +159,7 @@ end # Constructor that calculates the coefficients with polynomial optimizer from a list of eigenvalues function PairedExplicitRK3(num_stages, tspan, eig_vals::Vector{ComplexF64}; - verbose = false, cS2 = 1.0) + verbose = false, cS2 = 1.0f0) a_matrix, c = compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, eig_vals; From 6d95ec6af375660104ec470fd6668f22e1662f20 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Wed, 17 Jul 2024 08:39:27 +0200 Subject: [PATCH 098/160] Update ext/TrixiNLsolveExt.jl Co-authored-by: Hendrik Ranocha --- ext/TrixiNLsolveExt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index aea077e5898..ac6759f984b 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -62,7 +62,7 @@ function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_sta c_eq[i] = monomial_coeffs[i] - term2 # Third-order consistency condition (Cf. eq. (27) from https://doi.org/10.1016/j.jcp.2022.111470 - c_eq[num_stage_evals - 2] = 1.0f0 - 4.0f0 * a_coeff[num_stage_evals] - + c_eq[num_stage_evals - 2] = 1 - 4 * a_coeff[num_stage_evals] - a_coeff[num_stage_evals - 1] return c_eq From 485a2a70082d70c10be49551b09d4e3dfc77abd1 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Wed, 17 Jul 2024 08:39:35 +0200 Subject: [PATCH 099/160] Update ext/TrixiNLsolveExt.jl Co-authored-by: Hendrik Ranocha --- ext/TrixiNLsolveExt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index ac6759f984b..2ac419d4272 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -95,7 +95,7 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_c # Due to the nature of the nonlinear solver, different initial guesses can lead to # small numerical differences in the solution. - x0 = 0.1f0 .* rand(rng, num_stages - 2) + x0 = convert(RealT, 0.1) .* rand(rng, RealT, num_stages - 2) sol = nlsolve(objective_function, x0, method = :trust_region, ftol = 4.0f-16, # Enforce objective up to machine precision From f8731c17be11233810b689dcfaf86ae00984476c Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Wed, 17 Jul 2024 08:39:42 +0200 Subject: [PATCH 100/160] Update ext/TrixiNLsolveExt.jl Co-authored-by: Hendrik Ranocha --- ext/TrixiNLsolveExt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 2ac419d4272..e9fc555aeba 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -31,7 +31,7 @@ function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_sta monomial_coeffs, cS2) c_ts = compute_c_coeffs(num_stages, cS2) # ts = timestep # For explicit methods, a_{1,1} = 0 and a_{2,1} = c_2 (Butcher's condition) - a_coeff = [0.0f0, c_ts[2], a_unknown...] + a_coeff = [0, c_ts[2], a_unknown...] # Equality constraint array that ensures that the stability polynomial computed from # the to-be-constructed Butcher-Tableau matches the monomial coefficients of the # optimized stability polynomial. From 3faf2cc1a562b74873e0c2e406b6110b8f1a0219 Mon Sep 17 00:00:00 2001 From: Warisa Date: Wed, 17 Jul 2024 16:06:33 +0200 Subject: [PATCH 101/160] change some Flot32 back to the way they originally were --- ext/TrixiNLsolveExt.jl | 4 ++-- .../paired_explicit_runge_kutta/methods_PERK3.jl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index e9fc555aeba..7a8df058319 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -98,8 +98,8 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_c x0 = convert(RealT, 0.1) .* rand(rng, RealT, num_stages - 2) sol = nlsolve(objective_function, x0, method = :trust_region, - ftol = 4.0f-16, # Enforce objective up to machine precision - iterations = 10^4, xtol = 1.0f-13) + ftol = 4.0e-16, # Enforce objective up to machine precision + iterations = 10^4, xtol = 1.0e-13) a_unknown = sol.zero # Retrieve solution (root = zero) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 89e5c4cfa3a..c93e95819ee 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -37,7 +37,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, # Special case of e = 3 if num_stages == 3 - a_unknown = [0.25f0] + a_unknown = [0.25] else # Calculate coefficients of the stability polynomial in monomial form consistency_order = 3 From 339f43eefae4818a8afa83ebacb34f297a013fd3 Mon Sep 17 00:00:00 2001 From: Warisa Date: Wed, 17 Jul 2024 20:14:46 +0200 Subject: [PATCH 102/160] add line that get the type that a_unknown should be --- ext/TrixiNLsolveExt.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 7a8df058319..435e2f87d36 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -84,6 +84,9 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_c c_s2) end + # RealT is determined as the type of the first element in monomial_coeffs to ensure type consistency + RealT = typeof(monomial_coeffs[1]) + # To ensure consistency and reproducibility of results across runs, we use # a seeded random initial guess. rng = StableRNG(555) From ad47a2fda0bda1c99738e89e0306819d2c1807b4 Mon Sep 17 00:00:00 2001 From: Warisa Date: Wed, 17 Jul 2024 21:44:10 +0200 Subject: [PATCH 103/160] due to some the change of type, print out some values of a_matrix that changes slighly from the original value (error value in other tests still remain the same) --- test/test_unit.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test_unit.jl b/test/test_unit.jl index 90341dbc7fb..116f32a0621 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1710,6 +1710,7 @@ end ode_algorithm = Trixi.PairedExplicitRK3(8, path_coeff_file) + println(ode_algorithm.a_matrix) @test isapprox(ode_algorithm.a_matrix, [0.3355167784195604 0.06448322158043965 0.4965349205803965 0.10346507941960345 @@ -1725,6 +1726,7 @@ end tspan = (0.0, 1.0) ode_algorithm = Trixi.PairedExplicitRK3(13, tspan, vec(eig_vals)) + println(ode_algorithm.a_matrix) @test isapprox(ode_algorithm.a_matrix, [0.19156094079581354 0.008439059204186486 0.2872329213106948 0.01276707868930521 From 29743017252a6dfb732a3be8a344ed6a24b4d518 Mon Sep 17 00:00:00 2001 From: Warisa Date: Wed, 17 Jul 2024 23:17:41 +0200 Subject: [PATCH 104/160] update test values --- test/test_unit.jl | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/test/test_unit.jl b/test/test_unit.jl index 116f32a0621..befad58aa7f 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1710,11 +1710,10 @@ end ode_algorithm = Trixi.PairedExplicitRK3(8, path_coeff_file) - println(ode_algorithm.a_matrix) @test isapprox(ode_algorithm.a_matrix, - [0.3355167784195604 0.06448322158043965 - 0.4965349205803965 0.10346507941960345 - 0.6496890792935297 0.15031092070647037 + [0.33551678438002486 0.06448322158043965 + 0.49653494442225443 0.10346507941960345 + 0.6496890912144586 0.15031092070647037 0.789172498521197 0.21082750147880308 0.7522972036571336 0.2477027963428664 0.31192569908571666 0.18807430091428337], atol = 1e-13) @@ -1726,18 +1725,17 @@ end tspan = (0.0, 1.0) ode_algorithm = Trixi.PairedExplicitRK3(13, tspan, vec(eig_vals)) - println(ode_algorithm.a_matrix) @test isapprox(ode_algorithm.a_matrix, - [0.19156094079581354 0.008439059204186486 - 0.2872329213106948 0.01276707868930521 - 0.3801771666087999 0.019822833391200098 - 0.4706748922245802 0.02932510777541978 - 0.5575748091858802 0.04242519081411982 - 0.6390917624593604 0.06090823754063957 - 0.712487669254592 0.08751233074540807 - 0.7736370088751211 0.1263629911248789 - 0.8161315487214759 0.1838684512785241 - 0.7532704353232954 0.24672956467670457 + [0.19258815508201277 0.00741184789821947 + 0.2872329330253629 0.01276707889556606 + 0.3801771730615694 0.01982283289889509 + 0.4706748926615584 0.02932510733844162 + 0.5575748313419124 0.04242519249994544 + 0.6390917539959684 0.06090823408310269 + 0.7124876783811593 0.08751233353976957 + 0.7736369902636945 0.12636298589444758 + 0.8161315438506253 0.18386845614937472 + 0.7532704353232954 0.24672956467670462 0.3116823911691762 0.18831760883082385], atol = 1e-13) end From 3023dc2c07c46a8d0fb6d003eca0293b660a1927 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Sat, 27 Jul 2024 11:13:25 +0200 Subject: [PATCH 105/160] Update src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index c93e95819ee..fcd0762c014 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -108,7 +108,7 @@ end verbose = false, cS2 = 1.0f0) Parameters: - - `num_stages` (`Int`): Number of stages in the PERK method. + - `num_stages` (`Int`): Number of stages in the paired explicit Runge-Kutta (P-ERK) method. - `base_path_a_coeffs` (`AbstractString`): Path to a file containing some coefficients in the A-matrix in the Butcher tableau of the Runge Kutta method. The matrix should be stored in a text file at `joinpath(base_path_a_coeffs, "a_$(num_stages).txt")` and separated by line breaks. From 3071c4824cc0ce0738cb48b2242c8db4211fc0df Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Sat, 27 Jul 2024 11:16:27 +0200 Subject: [PATCH 106/160] Update src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index fcd0762c014..6a54959aab5 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -170,7 +170,7 @@ 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. +# which are used in Trixi.jl. mutable struct PairedExplicitRK3Integrator{RealT <: Real, uType, Params, Sol, F, Alg, PairedExplicitRKOptions} <: AbstractPairedExplicitRKSingleIntegrator From 6454c469f4a17bdc706700dbec3df3e5c97eb831 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Sat, 27 Jul 2024 15:17:28 +0200 Subject: [PATCH 107/160] Apply suggestions from code review Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 6a54959aab5..b06f22f5e76 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -87,7 +87,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, path_a_coeffs = joinpath(base_path_a_coeffs, "a_" * string(num_stages) * ".txt") - @assert isfile(path_a_coeffs) "Couldn't find file" + @assert isfile(path_a_coeffs) "Couldn't find file $path_a_coeffs" a_coeffs = readdlm(path_a_coeffs, Float64) num_a_coeffs = size(a_coeffs, 1) From f325f991628a253964fe45cd12c598ba9f2face1 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Sat, 27 Jul 2024 15:28:55 +0200 Subject: [PATCH 108/160] Update src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index b06f22f5e76..da582bb5954 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -221,7 +221,7 @@ function init(ode::ODEProblem, alg::PairedExplicitRK3; # initialize callbacks if callback isa CallbackSet for cb in callback.continuous_callbacks - error("unsupported") + error("Continuous callbacks are unsupported with paired explicit Runge-Kutta methods.") end for cb in callback.discrete_callbacks cb.initialize(cb, integrator.u, integrator.t, integrator) From 8334c75b5512c01daeb33671a32e43bc16881d77 Mon Sep 17 00:00:00 2001 From: Warisa Date: Sat, 27 Jul 2024 16:00:05 +0200 Subject: [PATCH 109/160] allocate c_eq once per solve_a_unknown is called --- ext/TrixiNLsolveExt.jl | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 435e2f87d36..745348f1517 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -28,7 +28,8 @@ using Trixi: Trixi, compute_c_coeffs, @muladd # in order to find A-matrix in the Butcher-Tableau function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_stages, num_stage_evals, - monomial_coeffs, cS2) + monomial_coeffs, c_eq, + cS2) c_ts = compute_c_coeffs(num_stages, cS2) # ts = timestep # For explicit methods, a_{1,1} = 0 and a_{2,1} = c_2 (Butcher's condition) a_coeff = [0, c_ts[2], a_unknown...] @@ -37,7 +38,7 @@ function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_sta # optimized stability polynomial. # For details, see Chapter4.3, Proposition 3.2, Equation (3.3) from # Hairer, Wanner: Solving Ordinary Differential Equations 2 - c_eq = zeros(num_stage_evals - 2) # Add equality constraint that cS2 is equal to 1 + # Lower-order terms: Two summands present for i in 1:(num_stage_evals - 4) term1 = a_coeff[num_stage_evals - 1] @@ -76,11 +77,17 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_c c_s2, c; verbose, max_iter = 100000) + # c_eq is a vector initialized with zeros with length num_stages - 2. + # It is used to store the coefficients of the non-linear equations arise from the relation of + # the coefficients of the stability polynomial and the coefficients of the Butcher tableau. + c_eq = zeros(num_stages - 2) + # Define the objective_function function objective_function(x) return PairedExplicitRK3_butcher_tableau_objective_function(x, num_stages, num_stages, monomial_coeffs, + c_eq, c_s2) end From b309ca5b6ca0eb1cc4d8b9cb471af7c9b2e7b72a Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Sat, 27 Jul 2024 21:44:32 +0200 Subject: [PATCH 110/160] Update ext/TrixiNLsolveExt.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> --- ext/TrixiNLsolveExt.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 745348f1517..61121badc01 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -26,9 +26,9 @@ using Trixi: Trixi, compute_c_coeffs, @muladd # Compute residuals for nonlinear equations to match a stability polynomial with given coefficients, # in order to find A-matrix in the Butcher-Tableau -function PairedExplicitRK3_butcher_tableau_objective_function(a_unknown, num_stages, +function PairedExplicitRK3_butcher_tableau_objective_function!(c_eq, a_unknown, num_stages, num_stage_evals, - monomial_coeffs, c_eq, + monomial_coeffs, cS2) c_ts = compute_c_coeffs(num_stages, cS2) # ts = timestep # For explicit methods, a_{1,1} = 0 and a_{2,1} = c_2 (Butcher's condition) From 08733ba5f1be6e1b3b433ed50f0c06a83e64b483 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Sat, 27 Jul 2024 21:44:39 +0200 Subject: [PATCH 111/160] Update ext/TrixiNLsolveExt.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> --- ext/TrixiNLsolveExt.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 61121badc01..c4576b57984 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -83,11 +83,10 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_c c_eq = zeros(num_stages - 2) # Define the objective_function - function objective_function(x) - return PairedExplicitRK3_butcher_tableau_objective_function(x, num_stages, + function objective_function!(c_eq, x) + return PairedExplicitRK3_butcher_tableau_objective_function!(c_eq, x, num_stages, num_stages, monomial_coeffs, - c_eq, c_s2) end From 01bc7574a60a83a85e30aab5590cf0a76fd3066c Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Sat, 27 Jul 2024 21:44:48 +0200 Subject: [PATCH 112/160] Update ext/TrixiNLsolveExt.jl Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> --- ext/TrixiNLsolveExt.jl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index c4576b57984..08c5ed7b5b3 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -77,10 +77,6 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_c c_s2, c; verbose, max_iter = 100000) - # c_eq is a vector initialized with zeros with length num_stages - 2. - # It is used to store the coefficients of the non-linear equations arise from the relation of - # the coefficients of the stability polynomial and the coefficients of the Butcher tableau. - c_eq = zeros(num_stages - 2) # Define the objective_function function objective_function!(c_eq, x) From 33bdcb8e8ff56f40748740953a3ecb795fd6cacf Mon Sep 17 00:00:00 2001 From: Warisa Date: Sat, 27 Jul 2024 21:48:54 +0200 Subject: [PATCH 113/160] minor fix regarding recent changes witjh c_eq --- ext/TrixiNLsolveExt.jl | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 08c5ed7b5b3..66933b7e5d2 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -26,10 +26,11 @@ using Trixi: Trixi, compute_c_coeffs, @muladd # Compute residuals for nonlinear equations to match a stability polynomial with given coefficients, # in order to find A-matrix in the Butcher-Tableau -function PairedExplicitRK3_butcher_tableau_objective_function!(c_eq, a_unknown, num_stages, - num_stage_evals, - monomial_coeffs, - cS2) +function PairedExplicitRK3_butcher_tableau_objective_function!(c_eq, a_unknown, + num_stages, + num_stage_evals, + monomial_coeffs, + cS2) c_ts = compute_c_coeffs(num_stages, cS2) # ts = timestep # For explicit methods, a_{1,1} = 0 and a_{2,1} = c_2 (Butcher's condition) a_coeff = [0, c_ts[2], a_unknown...] @@ -65,8 +66,6 @@ function PairedExplicitRK3_butcher_tableau_objective_function!(c_eq, a_unknown, # Third-order consistency condition (Cf. eq. (27) from https://doi.org/10.1016/j.jcp.2022.111470 c_eq[num_stage_evals - 2] = 1 - 4 * a_coeff[num_stage_evals] - a_coeff[num_stage_evals - 1] - - return c_eq end # Find the values of the a_{i, i-1} in the Butcher tableau matrix A by solving a system of @@ -77,13 +76,13 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_c c_s2, c; verbose, max_iter = 100000) - # Define the objective_function function objective_function!(c_eq, x) - return PairedExplicitRK3_butcher_tableau_objective_function!(c_eq, x, num_stages, - num_stages, - monomial_coeffs, - c_s2) + return PairedExplicitRK3_butcher_tableau_objective_function!(c_eq, x, + num_stages, + num_stages, + monomial_coeffs, + c_s2) end # RealT is determined as the type of the first element in monomial_coeffs to ensure type consistency @@ -102,7 +101,7 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_c x0 = convert(RealT, 0.1) .* rand(rng, RealT, num_stages - 2) - sol = nlsolve(objective_function, x0, method = :trust_region, + sol = nlsolve(objective_function!, x0, method = :trust_region, ftol = 4.0e-16, # Enforce objective up to machine precision iterations = 10^4, xtol = 1.0e-13) From ff7ec1a1d82277d24a2a4d052ddf7a8f1b831f50 Mon Sep 17 00:00:00 2001 From: Warisa Date: Sat, 27 Jul 2024 22:31:47 +0200 Subject: [PATCH 114/160] adjust a constructor to get num stages from reading the files directly --- .../methods_PERK3.jl | 38 ++++++++----------- test/test_unit.jl | 13 ++++--- 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index da582bb5954..a6c395966d4 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -71,36 +71,30 @@ end # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 # using provided values of coefficients a in A-matrix of Butcher tableau -function compute_PairedExplicitRK3_butcher_tableau(num_stages, - base_path_a_coeffs::AbstractString; +function compute_PairedExplicitRK3_butcher_tableau(path_a_coeffs::AbstractString; cS2) + @assert isfile(path_a_coeffs) "Couldn't find file $path_a_coeffs" + a_coeffs = readdlm(path_a_coeffs, Float64) + num_a_coeffs = size(a_coeffs, 1) + + # + 2 Since the first entry of A is always zero (explicit method) and the second is given by c_2 (consistency) + num_stages = num_a_coeffs + 2 # Initialize array of c c = compute_c_coeffs(num_stages, cS2) - # - 2 Since First entry of A is always zero (explicit method) and second is given by c_2 (consistency) - a_coeffs_max = num_stages - 2 - - a_matrix = zeros(a_coeffs_max, 2) + a_matrix = zeros(num_a_coeffs, 2) a_matrix[:, 1] = c[3:end] - path_a_coeffs = joinpath(base_path_a_coeffs, - "a_" * string(num_stages) * ".txt") - - @assert isfile(path_a_coeffs) "Couldn't find file $path_a_coeffs" - a_coeffs = readdlm(path_a_coeffs, Float64) - num_a_coeffs = size(a_coeffs, 1) - - @assert num_a_coeffs == a_coeffs_max # Fill A-matrix in P-ERK style a_matrix[:, 1] -= a_coeffs a_matrix[:, 2] = a_coeffs - return a_matrix, c + return num_stages, a_matrix, c end @doc raw""" - PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString; + PairedExplicitRK3(path_a_coeffs::AbstractString; cS2 = 1.0f0) PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; verbose = false, cS2 = 1.0f0) @@ -108,10 +102,9 @@ end verbose = false, cS2 = 1.0f0) Parameters: - - `num_stages` (`Int`): Number of stages in the paired explicit Runge-Kutta (P-ERK) method. - - `base_path_a_coeffs` (`AbstractString`): Path to a file containing some coefficients in the A-matrix in + - `path_a_coeffs` (`AbstractString`): Path to a file containing some coefficients in the A-matrix in the Butcher tableau of the Runge Kutta method. - The matrix should be stored in a text file at `joinpath(base_path_a_coeffs, "a_$(num_stages).txt")` and separated by line breaks. + - `num_stages` (`Int`): Number of stages in the paired explicit Runge-Kutta (P-ERK) method. - `tspan`: Time span of the simulation. - `semi` (`AbstractSemidiscretization`): Semidiscretization setup. - `eig_vals` (`Vector{ComplexF64}`): Eigenvalues of the Jacobian of the right-hand side (rhs) of the ODEProblem after the @@ -140,11 +133,10 @@ mutable struct PairedExplicitRK3 <: AbstractPairedExplicitRKSingle end # struct PairedExplicitRK3 # Constructor for previously computed A Coeffs -function PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString; +function PairedExplicitRK3(path_a_coeffs::AbstractString; cS2 = 1.0f0) - a_matrix, c = compute_PairedExplicitRK3_butcher_tableau(num_stages, - base_path_a_coeffs; - cS2) + num_stages, a_matrix, c = compute_PairedExplicitRK3_butcher_tableau(path_a_coeffs; + cS2) return PairedExplicitRK3(num_stages, a_matrix, c) end diff --git a/test/test_unit.jl b/test/test_unit.jl index befad58aa7f..84ffed77f95 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1704,11 +1704,13 @@ end end @testset "PERK Single p3 Constructors" begin - path_coeff_file = mktempdir() + base_path_coeff_file = mktempdir() + + path_a_coeffs = joinpath(base_path_coeff_file, "a_8.txt") Trixi.download("https://gist.githubusercontent.com/warisa-r/0796db36abcd5abe735ac7eebf41b973/raw/32889062fd5dcf7f450748f4f5f0797c8155a18d/a_8_8.txt", - joinpath(path_coeff_file, "a_8.txt")) + path_a_coeffs) - ode_algorithm = Trixi.PairedExplicitRK3(8, path_coeff_file) + ode_algorithm = Trixi.PairedExplicitRK3(path_a_coeffs) @test isapprox(ode_algorithm.a_matrix, [0.33551678438002486 0.06448322158043965 @@ -1718,10 +1720,11 @@ end 0.7522972036571336 0.2477027963428664 0.31192569908571666 0.18807430091428337], atol = 1e-13) + path_spectrum = joinpath(base_path_coeff_file, "spectrum.txt") Trixi.download("https://gist.githubusercontent.com/warisa-r/8d93f6a3ae0635e13b9f51ee32ab7fff/raw/54dc5b14be9288e186b745facb5bbcb04d1476f8/EigenvalueList_Refined2.txt", - joinpath(path_coeff_file, "spectrum.txt")) + path_spectrum) - eig_vals = readdlm(joinpath(path_coeff_file, "spectrum.txt"), ComplexF64) + eig_vals = readdlm(path_spectrum, ComplexF64) tspan = (0.0, 1.0) ode_algorithm = Trixi.PairedExplicitRK3(13, tspan, vec(eig_vals)) From fd05aff653bba7629241d5f396b609b71f4d8d3e Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 29 Jul 2024 09:03:45 +0200 Subject: [PATCH 115/160] Revert "adjust a constructor to get num stages from reading the files directly" since it is breaking --- .../methods_PERK3.jl | 38 +++++++++++-------- test/test_unit.jl | 13 +++---- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index a6c395966d4..da582bb5954 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -71,30 +71,36 @@ end # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 # using provided values of coefficients a in A-matrix of Butcher tableau -function compute_PairedExplicitRK3_butcher_tableau(path_a_coeffs::AbstractString; +function compute_PairedExplicitRK3_butcher_tableau(num_stages, + base_path_a_coeffs::AbstractString; cS2) - @assert isfile(path_a_coeffs) "Couldn't find file $path_a_coeffs" - a_coeffs = readdlm(path_a_coeffs, Float64) - num_a_coeffs = size(a_coeffs, 1) - - # + 2 Since the first entry of A is always zero (explicit method) and the second is given by c_2 (consistency) - num_stages = num_a_coeffs + 2 # Initialize array of c c = compute_c_coeffs(num_stages, cS2) - a_matrix = zeros(num_a_coeffs, 2) + # - 2 Since First entry of A is always zero (explicit method) and second is given by c_2 (consistency) + a_coeffs_max = num_stages - 2 + + a_matrix = zeros(a_coeffs_max, 2) a_matrix[:, 1] = c[3:end] + path_a_coeffs = joinpath(base_path_a_coeffs, + "a_" * string(num_stages) * ".txt") + + @assert isfile(path_a_coeffs) "Couldn't find file $path_a_coeffs" + a_coeffs = readdlm(path_a_coeffs, Float64) + num_a_coeffs = size(a_coeffs, 1) + + @assert num_a_coeffs == a_coeffs_max # Fill A-matrix in P-ERK style a_matrix[:, 1] -= a_coeffs a_matrix[:, 2] = a_coeffs - return num_stages, a_matrix, c + return a_matrix, c end @doc raw""" - PairedExplicitRK3(path_a_coeffs::AbstractString; + PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString; cS2 = 1.0f0) PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; verbose = false, cS2 = 1.0f0) @@ -102,9 +108,10 @@ end verbose = false, cS2 = 1.0f0) Parameters: - - `path_a_coeffs` (`AbstractString`): Path to a file containing some coefficients in the A-matrix in - the Butcher tableau of the Runge Kutta method. - `num_stages` (`Int`): Number of stages in the paired explicit Runge-Kutta (P-ERK) method. + - `base_path_a_coeffs` (`AbstractString`): Path to a file containing some coefficients in the A-matrix in + the Butcher tableau of the Runge Kutta method. + The matrix should be stored in a text file at `joinpath(base_path_a_coeffs, "a_$(num_stages).txt")` and separated by line breaks. - `tspan`: Time span of the simulation. - `semi` (`AbstractSemidiscretization`): Semidiscretization setup. - `eig_vals` (`Vector{ComplexF64}`): Eigenvalues of the Jacobian of the right-hand side (rhs) of the ODEProblem after the @@ -133,10 +140,11 @@ mutable struct PairedExplicitRK3 <: AbstractPairedExplicitRKSingle end # struct PairedExplicitRK3 # Constructor for previously computed A Coeffs -function PairedExplicitRK3(path_a_coeffs::AbstractString; +function PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString; cS2 = 1.0f0) - num_stages, a_matrix, c = compute_PairedExplicitRK3_butcher_tableau(path_a_coeffs; - cS2) + a_matrix, c = compute_PairedExplicitRK3_butcher_tableau(num_stages, + base_path_a_coeffs; + cS2) return PairedExplicitRK3(num_stages, a_matrix, c) end diff --git a/test/test_unit.jl b/test/test_unit.jl index 84ffed77f95..befad58aa7f 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1704,13 +1704,11 @@ end end @testset "PERK Single p3 Constructors" begin - base_path_coeff_file = mktempdir() - - path_a_coeffs = joinpath(base_path_coeff_file, "a_8.txt") + path_coeff_file = mktempdir() Trixi.download("https://gist.githubusercontent.com/warisa-r/0796db36abcd5abe735ac7eebf41b973/raw/32889062fd5dcf7f450748f4f5f0797c8155a18d/a_8_8.txt", - path_a_coeffs) + joinpath(path_coeff_file, "a_8.txt")) - ode_algorithm = Trixi.PairedExplicitRK3(path_a_coeffs) + ode_algorithm = Trixi.PairedExplicitRK3(8, path_coeff_file) @test isapprox(ode_algorithm.a_matrix, [0.33551678438002486 0.06448322158043965 @@ -1720,11 +1718,10 @@ end 0.7522972036571336 0.2477027963428664 0.31192569908571666 0.18807430091428337], atol = 1e-13) - path_spectrum = joinpath(base_path_coeff_file, "spectrum.txt") Trixi.download("https://gist.githubusercontent.com/warisa-r/8d93f6a3ae0635e13b9f51ee32ab7fff/raw/54dc5b14be9288e186b745facb5bbcb04d1476f8/EigenvalueList_Refined2.txt", - path_spectrum) + joinpath(path_coeff_file, "spectrum.txt")) - eig_vals = readdlm(path_spectrum, ComplexF64) + eig_vals = readdlm(joinpath(path_coeff_file, "spectrum.txt"), ComplexF64) tspan = (0.0, 1.0) ode_algorithm = Trixi.PairedExplicitRK3(13, tspan, vec(eig_vals)) From 582dd870d22deca7a8c156abc7723a5987e8b1fd Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 29 Jul 2024 09:50:20 +0200 Subject: [PATCH 116/160] Update TrixiNLsolveExt.jl to use forward autodiff in solve_a_butcher_coeffs_unknown! function --- ext/TrixiNLsolveExt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 66933b7e5d2..4de8feb25a4 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -103,7 +103,7 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_c sol = nlsolve(objective_function!, x0, method = :trust_region, ftol = 4.0e-16, # Enforce objective up to machine precision - iterations = 10^4, xtol = 1.0e-13) + iterations = 10^4, xtol = 1.0e-13, autodiff = :forward) a_unknown = sol.zero # Retrieve solution (root = zero) From 859bf371a679112a9400f61db083fd9ec7c3bfba Mon Sep 17 00:00:00 2001 From: Daniel Doehring Date: Tue, 13 Aug 2024 17:59:07 +0200 Subject: [PATCH 117/160] Apply suggestions from code review --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index da582bb5954..f069ec81005 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -11,8 +11,8 @@ using DelimitedFiles: readdlm function compute_c_coeffs(num_stages, cS2) c = zeros(num_stages) - # Last timesteps as for SSPRK33, see motivation in - # https://doi.org/10.48550/arXiv.2403.05144 + # Last timesteps as for SSPRK33, see motivation in Section 3.3 of + # https://doi.org/10.1016/j.jcp.2024.113223 c[num_stages - 1] = 1.0f0 c[num_stages] = 0.5f0 @@ -130,7 +130,7 @@ Third-order Paired Explicit Runge-Kutta schemes for stiff systems of equations While the changes to SSPRK33 base-scheme are described in - Doehring, Schlottke-Lakemper, Gassner, Torrilhon (2024) Multirate Time-Integration based on Dynamic ODE Partitioning through Adaptively Refined Meshes for Compressible Fluid Dynamics -[Arxiv: 10.48550/arXiv.2403.05144](https://doi.org/10.48550/arXiv.2403.05144) +[DOI: 10.1016/j.jcp.2024.113223](https://doi.org/10.1016/j.jcp.2024.113223) """ mutable struct PairedExplicitRK3 <: AbstractPairedExplicitRKSingle const num_stages::Int # S From 55418447f7101eea724fb6bfca7286021f1437d7 Mon Sep 17 00:00:00 2001 From: Daniel_Doehring Date: Wed, 14 Aug 2024 10:25:31 +0200 Subject: [PATCH 118/160] Slight modifications a values --- test/test_unit.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test_unit.jl b/test/test_unit.jl index befad58aa7f..bc149dc715a 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1726,15 +1726,15 @@ end ode_algorithm = Trixi.PairedExplicitRK3(13, tspan, vec(eig_vals)) @test isapprox(ode_algorithm.a_matrix, - [0.19258815508201277 0.00741184789821947 - 0.2872329330253629 0.01276707889556606 - 0.3801771730615694 0.01982283289889509 + [0.19258815508348048 0.007411847896751755 + 0.28723293302534425 0.012767078895584727 + 0.38017717306156973 0.01982283289889476 0.4706748926615584 0.02932510733844162 0.5575748313419124 0.04242519249994544 0.6390917539959684 0.06090823408310269 0.7124876783811593 0.08751233353976957 0.7736369902636945 0.12636298589444758 - 0.8161315438506253 0.18386845614937472 + 0.8161315438506253 0.18386845614937475 0.7532704353232954 0.24672956467670462 0.3116823911691762 0.18831760883082385], atol = 1e-13) end From a50a4e07519149cd6d28c71eb4eabe690d68ba9f Mon Sep 17 00:00:00 2001 From: Warisa Date: Thu, 10 Oct 2024 19:50:19 +0200 Subject: [PATCH 119/160] add cfl number calculation for PERK3 --- .../elixir_burgers_perk3_optimal_cfl.jl | 69 +++++++++++++++++++ .../methods_PERK3.jl | 28 ++++---- test/test_structured_1d.jl | 16 +++++ test/test_unit.jl | 2 +- 4 files changed, 101 insertions(+), 14 deletions(-) create mode 100644 examples/structured_1d_dgsem/elixir_burgers_perk3_optimal_cfl.jl diff --git a/examples/structured_1d_dgsem/elixir_burgers_perk3_optimal_cfl.jl b/examples/structured_1d_dgsem/elixir_burgers_perk3_optimal_cfl.jl new file mode 100644 index 00000000000..b59543fbfd3 --- /dev/null +++ b/examples/structured_1d_dgsem/elixir_burgers_perk3_optimal_cfl.jl @@ -0,0 +1,69 @@ +# Convex and ECOS are imported because they are used for finding the optimal time step and optimal +# monomial coefficients in the stability polynomial of P-ERK time integrators. +using Convex, ECOS + +# NLsolve is imported to solve the system of nonlinear equations to find a coefficients +# in the Butcher tableau in the third order P-ERK time integrator. +using NLsolve + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the (inviscid) Burgers equation + +equations = InviscidBurgersEquation1D() + +initial_condition = initial_condition_convergence_test + +# 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) + +coordinates_min = (0.0,) # minimum coordinate +coordinates_max = (1.0,) # maximum coordinate +cells_per_dimension = (64,) + +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, 2.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(dt = 0.1, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +# Construct second order paired explicit Runge-Kutta method with 8 stages for given simulation setup. +# Pass `tspan` to calculate maximum time step allowed for the bisection algorithm used +# in calculating the polynomial coefficients in the ODE algorithm. +ode_algorithm = Trixi.PairedExplicitRK3(8, tspan, semi) + +cfl_number = Trixi.calculate_cfl(ode_algorithm, ode) +# For non-linear problems, the CFL number should be reduced by a safety factor +stepsize_callback = StepsizeCallback(cfl = 0.85 * cfl_number) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, save_solution, + stepsize_callback) + +############################################################################### +# run the simulation +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); + +# Print the timer summary +summary_callback() diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index f069ec81005..6f0a9a96296 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -46,10 +46,10 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, num_eig_vals, eig_vals = filter_eig_vals(eig_vals; verbose) - monomial_coeffs, _ = bisect_stability_polynomial(consistency_order, - num_eig_vals, num_stages, - dtmax, dteps, - eig_vals; verbose) + monomial_coeffs, dt_opt = bisect_stability_polynomial(consistency_order, + num_eig_vals, num_stages, + dtmax, dteps, + eig_vals; verbose) monomial_coeffs = undo_normalization!(monomial_coeffs, consistency_order, num_stages) @@ -66,7 +66,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, a_matrix[:, 1] -= a_unknown a_matrix[:, 2] = a_unknown - return a_matrix, c + return a_matrix, c, dt_opt end # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 @@ -100,7 +100,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, end @doc raw""" - PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString; + PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString, dt_opt; cS2 = 1.0f0) PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; verbose = false, cS2 = 1.0f0) @@ -112,6 +112,7 @@ end - `base_path_a_coeffs` (`AbstractString`): Path to a file containing some coefficients in the A-matrix in the Butcher tableau of the Runge Kutta method. The matrix should be stored in a text file at `joinpath(base_path_a_coeffs, "a_$(num_stages).txt")` and separated by line breaks. + - `dt_opt` (`Float64`): Optimal time step size for the simulation setup. - `tspan`: Time span of the simulation. - `semi` (`AbstractSemidiscretization`): Semidiscretization setup. - `eig_vals` (`Vector{ComplexF64}`): Eigenvalues of the Jacobian of the right-hand side (rhs) of the ODEProblem after the @@ -137,16 +138,17 @@ mutable struct PairedExplicitRK3 <: AbstractPairedExplicitRKSingle a_matrix::Matrix{Float64} c::Vector{Float64} + dt_opt::Float64 end # struct PairedExplicitRK3 # Constructor for previously computed A Coeffs -function PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString; +function PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString, dt_opt; cS2 = 1.0f0) a_matrix, c = compute_PairedExplicitRK3_butcher_tableau(num_stages, base_path_a_coeffs; cS2) - return PairedExplicitRK3(num_stages, a_matrix, c) + return PairedExplicitRK3(num_stages, a_matrix, c, dt_opt) end # Constructor that computes Butcher matrix A coefficients from a semidiscretization @@ -160,11 +162,11 @@ end # Constructor that calculates the coefficients with polynomial optimizer from a list of eigenvalues function PairedExplicitRK3(num_stages, tspan, eig_vals::Vector{ComplexF64}; verbose = false, cS2 = 1.0f0) - a_matrix, c = compute_PairedExplicitRK3_butcher_tableau(num_stages, - tspan, - eig_vals; - verbose, cS2) - return PairedExplicitRK3(num_stages, a_matrix, c) + a_matrix, c, dt_opt = compute_PairedExplicitRK3_butcher_tableau(num_stages, + tspan, + eig_vals; + verbose, cS2) + return PairedExplicitRK3(num_stages, a_matrix, c, dt_opt) end # This struct is needed to fake https://github.com/SciML/OrdinaryDiffEq.jl/blob/0c2048a502101647ac35faabd80da8a5645beac7/src/integrators/type.jl#L77 diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index 8943762d231..094f1c4f698 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -73,6 +73,22 @@ end end end +# Testing the third-order paired explicit Runge-Kutta (PERK) method with its optimal CFL number +@trixi_testset "elixir_burgers_perk3_optimal_cfl.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_perk3_optimal_cfl.jl"), + l2=[4.12066275835687e-6], #TODO: fix this values to match the ones in CI + linf=[2.538190787615413e-5], + atol=1.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)) < 8000 + end +end + # Testing the third-order paired explicit Runge-Kutta (PERK) method without stepsize callback @trixi_testset "elixir_burgers_perk3.jl(fixed time step)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_perk3.jl"), diff --git a/test/test_unit.jl b/test/test_unit.jl index eefb412cc93..e4d2ff24d92 100644 --- a/test/test_unit.jl +++ b/test/test_unit.jl @@ -1708,7 +1708,7 @@ end Trixi.download("https://gist.githubusercontent.com/warisa-r/0796db36abcd5abe735ac7eebf41b973/raw/32889062fd5dcf7f450748f4f5f0797c8155a18d/a_8_8.txt", joinpath(path_coeff_file, "a_8.txt")) - ode_algorithm = Trixi.PairedExplicitRK3(8, path_coeff_file) + ode_algorithm = Trixi.PairedExplicitRK3(8, path_coeff_file, 42) # dummy optimal time step (dt_opt plays no role in determining `a_matrix`) @test isapprox(ode_algorithm.a_matrix, [0.33551678438002486 0.06448322158043965 From 0d9e66445c22e048d0547f7209a0000a96423f6f Mon Sep 17 00:00:00 2001 From: Warisa Date: Thu, 10 Oct 2024 20:28:40 +0200 Subject: [PATCH 120/160] update CI values --- test/test_structured_1d.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_structured_1d.jl b/test/test_structured_1d.jl index 094f1c4f698..6bc4b9ccab6 100644 --- a/test/test_structured_1d.jl +++ b/test/test_structured_1d.jl @@ -76,8 +76,8 @@ end # Testing the third-order paired explicit Runge-Kutta (PERK) method with its optimal CFL number @trixi_testset "elixir_burgers_perk3_optimal_cfl.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_burgers_perk3_optimal_cfl.jl"), - l2=[4.12066275835687e-6], #TODO: fix this values to match the ones in CI - linf=[2.538190787615413e-5], + l2=[3.8156922097242205e-6], + linf=[2.1962957979626552e-5], atol=1.0e-6) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) From 71cf293818dffed6134070dc03271ba722aa4af2 Mon Sep 17 00:00:00 2001 From: Warisa Date: Sat, 12 Oct 2024 09:36:31 +0200 Subject: [PATCH 121/160] remove the example without cfl calculation --- .../elixir_burgers_perk3.jl | 13 ++-- .../elixir_burgers_perk3_optimal_cfl.jl | 69 ------------------- 2 files changed, 8 insertions(+), 74 deletions(-) delete mode 100644 examples/structured_1d_dgsem/elixir_burgers_perk3_optimal_cfl.jl diff --git a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl index 4d031db7ae1..b59543fbfd3 100644 --- a/examples/structured_1d_dgsem/elixir_burgers_perk3.jl +++ b/examples/structured_1d_dgsem/elixir_burgers_perk3.jl @@ -46,7 +46,14 @@ save_solution = SaveSolutionCallback(dt = 0.1, save_final_solution = true, solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl = 3.7) +# Construct second order paired explicit Runge-Kutta method with 8 stages for given simulation setup. +# Pass `tspan` to calculate maximum time step allowed for the bisection algorithm used +# in calculating the polynomial coefficients in the ODE algorithm. +ode_algorithm = Trixi.PairedExplicitRK3(8, tspan, semi) + +cfl_number = Trixi.calculate_cfl(ode_algorithm, ode) +# For non-linear problems, the CFL number should be reduced by a safety factor +stepsize_callback = StepsizeCallback(cfl = 0.85 * cfl_number) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, @@ -54,10 +61,6 @@ callbacks = CallbackSet(summary_callback, ############################################################################### # run the simulation - -# Optimize 8-stage, third order P-ERK scheme for this semidiscretization -ode_algorithm = Trixi.PairedExplicitRK3(8, tspan, semi) - 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); diff --git a/examples/structured_1d_dgsem/elixir_burgers_perk3_optimal_cfl.jl b/examples/structured_1d_dgsem/elixir_burgers_perk3_optimal_cfl.jl deleted file mode 100644 index b59543fbfd3..00000000000 --- a/examples/structured_1d_dgsem/elixir_burgers_perk3_optimal_cfl.jl +++ /dev/null @@ -1,69 +0,0 @@ -# Convex and ECOS are imported because they are used for finding the optimal time step and optimal -# monomial coefficients in the stability polynomial of P-ERK time integrators. -using Convex, ECOS - -# NLsolve is imported to solve the system of nonlinear equations to find a coefficients -# in the Butcher tableau in the third order P-ERK time integrator. -using NLsolve - -using OrdinaryDiffEq -using Trixi - -############################################################################### -# semidiscretization of the (inviscid) Burgers equation - -equations = InviscidBurgersEquation1D() - -initial_condition = initial_condition_convergence_test - -# 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) - -coordinates_min = (0.0,) # minimum coordinate -coordinates_max = (1.0,) # maximum coordinate -cells_per_dimension = (64,) - -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, 2.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(dt = 0.1, - save_initial_solution = true, - save_final_solution = true, - solution_variables = cons2prim) - -# Construct second order paired explicit Runge-Kutta method with 8 stages for given simulation setup. -# Pass `tspan` to calculate maximum time step allowed for the bisection algorithm used -# in calculating the polynomial coefficients in the ODE algorithm. -ode_algorithm = Trixi.PairedExplicitRK3(8, tspan, semi) - -cfl_number = Trixi.calculate_cfl(ode_algorithm, ode) -# For non-linear problems, the CFL number should be reduced by a safety factor -stepsize_callback = StepsizeCallback(cfl = 0.85 * cfl_number) - -callbacks = CallbackSet(summary_callback, - analysis_callback, alive_callback, save_solution, - stepsize_callback) - -############################################################################### -# run the simulation -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); - -# Print the timer summary -summary_callback() From 995e228eb8f8196776705cdc32487542c7e8764e Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Sat, 12 Oct 2024 10:10:47 +0200 Subject: [PATCH 122/160] Apply suggestions from code review Co-authored-by: Daniel Doehring --- ext/TrixiNLsolveExt.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 4de8feb25a4..b7d91dda64f 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -37,7 +37,7 @@ function PairedExplicitRK3_butcher_tableau_objective_function!(c_eq, a_unknown, # Equality constraint array that ensures that the stability polynomial computed from # the to-be-constructed Butcher-Tableau matches the monomial coefficients of the # optimized stability polynomial. - # For details, see Chapter4.3, Proposition 3.2, Equation (3.3) from + # For details, see Chapter 4.3, Proposition 3.2, Equation (3.3) from # Hairer, Wanner: Solving Ordinary Differential Equations 2 # Lower-order terms: Two summands present @@ -109,6 +109,7 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_c # Check if the values a[i, i-1] >= 0.0 (which stem from the nonlinear solver) # and also c[i] - a[i, i-1] >= 0.0 since all coefficients should be non-negative + # to avoid downwinding of numerical fluxes. is_sol_valid = all(x -> !isnan(x) && x >= 0, a_unknown) && all(!isnan(c[i] - a_unknown[i - 2]) && c[i] - a_unknown[i - 2] >= 0 for i in eachindex(c) if i > 2) From 109bad9902183faf2d199655722bfcc965652dc2 Mon Sep 17 00:00:00 2001 From: Warisa Roongaraya <81345089+warisa-r@users.noreply.github.com> Date: Sat, 12 Oct 2024 10:11:40 +0200 Subject: [PATCH 123/160] Update src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl Co-authored-by: Daniel Doehring --- .../paired_explicit_runge_kutta/methods_PERK3.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 6f0a9a96296..17a841c7ac3 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -37,7 +37,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, # Special case of e = 3 if num_stages == 3 - a_unknown = [0.25] + a_unknown = [0.25] # Use classic SSPRK33 (Shu-Osher) Butcher Tableau else # Calculate coefficients of the stability polynomial in monomial form consistency_order = 3 From 5b6edb00279d6af987e693ffde37f2491cdb4cb2 Mon Sep 17 00:00:00 2001 From: Warisa Date: Sat, 12 Oct 2024 10:14:07 +0200 Subject: [PATCH 124/160] add DOI to a reference in TrixiNLsolveExt --- ext/TrixiNLsolveExt.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index b7d91dda64f..51dfd7843a8 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -39,6 +39,7 @@ function PairedExplicitRK3_butcher_tableau_objective_function!(c_eq, a_unknown, # optimized stability polynomial. # For details, see Chapter 4.3, Proposition 3.2, Equation (3.3) from # Hairer, Wanner: Solving Ordinary Differential Equations 2 + # DOI: 10.1007/978-3-662-09947-6 # Lower-order terms: Two summands present for i in 1:(num_stage_evals - 4) From 325b2bc6a18eafb2f7d2435e933c0286c2bc1222 Mon Sep 17 00:00:00 2001 From: Warisa Date: Sat, 12 Oct 2024 12:24:00 +0200 Subject: [PATCH 125/160] add a copy of PERK3 to work on with testing values of b --- .../methods_embedded_PERK3.jl | 368 ++++++++++++++++++ 1 file changed, 368 insertions(+) create mode 100644 src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl new file mode 100644 index 00000000000..17a841c7ac3 --- /dev/null +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -0,0 +1,368 @@ +# 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. +using DelimitedFiles: readdlm + +@muladd begin +#! format: noindent + +# Initialize Butcher array abscissae c for PairedExplicitRK3 based on SSPRK33 base method +function compute_c_coeffs(num_stages, cS2) + c = zeros(num_stages) + + # Last timesteps as for SSPRK33, see motivation in Section 3.3 of + # https://doi.org/10.1016/j.jcp.2024.113223 + c[num_stages - 1] = 1.0f0 + c[num_stages] = 0.5f0 + + # Linear increasing timestep for remainder + for i in 2:(num_stages - 2) + c[i] = cS2 * (i - 1) / (num_stages - 3) + end + + return c +end + +# Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 +# using a list of eigenvalues +function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, + eig_vals::Vector{ComplexF64}; + verbose = false, cS2) + # Initialize array of c + c = compute_c_coeffs(num_stages, cS2) + + # Initialize the array of our solution + a_unknown = zeros(num_stages - 2) + + # Special case of e = 3 + if num_stages == 3 + a_unknown = [0.25] # Use classic SSPRK33 (Shu-Osher) Butcher Tableau + else + # Calculate coefficients of the stability polynomial in monomial form + consistency_order = 3 + dtmax = tspan[2] - tspan[1] + dteps = 1.0f-9 + + num_eig_vals, eig_vals = filter_eig_vals(eig_vals; verbose) + + monomial_coeffs, dt_opt = bisect_stability_polynomial(consistency_order, + num_eig_vals, num_stages, + dtmax, dteps, + eig_vals; verbose) + monomial_coeffs = undo_normalization!(monomial_coeffs, consistency_order, + num_stages) + + # Solve the nonlinear system of equations from monomial coefficient and + # Butcher array abscissae c to find Butcher matrix A + # This function is extended in TrixiNLsolveExt.jl + a_unknown = solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, + monomial_coeffs, cS2, c; + verbose) + end + # Fill A-matrix in P-ERK style + a_matrix = zeros(num_stages - 2, 2) + a_matrix[:, 1] = c[3:end] + a_matrix[:, 1] -= a_unknown + a_matrix[:, 2] = a_unknown + + return a_matrix, c, dt_opt +end + +# Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 +# using provided values of coefficients a in A-matrix of Butcher tableau +function compute_PairedExplicitRK3_butcher_tableau(num_stages, + base_path_a_coeffs::AbstractString; + cS2) + + # Initialize array of c + c = compute_c_coeffs(num_stages, cS2) + + # - 2 Since First entry of A is always zero (explicit method) and second is given by c_2 (consistency) + a_coeffs_max = num_stages - 2 + + a_matrix = zeros(a_coeffs_max, 2) + a_matrix[:, 1] = c[3:end] + + path_a_coeffs = joinpath(base_path_a_coeffs, + "a_" * string(num_stages) * ".txt") + + @assert isfile(path_a_coeffs) "Couldn't find file $path_a_coeffs" + a_coeffs = readdlm(path_a_coeffs, Float64) + num_a_coeffs = size(a_coeffs, 1) + + @assert num_a_coeffs == a_coeffs_max + # Fill A-matrix in P-ERK style + a_matrix[:, 1] -= a_coeffs + a_matrix[:, 2] = a_coeffs + + return a_matrix, c +end + +@doc raw""" + PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString, dt_opt; + cS2 = 1.0f0) + PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; + verbose = false, cS2 = 1.0f0) + PairedExplicitRK3(num_stages, tspan, eig_vals::Vector{ComplexF64}; + verbose = false, cS2 = 1.0f0) + + Parameters: + - `num_stages` (`Int`): Number of stages in the paired explicit Runge-Kutta (P-ERK) method. + - `base_path_a_coeffs` (`AbstractString`): Path to a file containing some coefficients in the A-matrix in + the Butcher tableau of the Runge Kutta method. + The matrix should be stored in a text file at `joinpath(base_path_a_coeffs, "a_$(num_stages).txt")` and separated by line breaks. + - `dt_opt` (`Float64`): Optimal time step size for the simulation setup. + - `tspan`: Time span of the simulation. + - `semi` (`AbstractSemidiscretization`): Semidiscretization setup. + - `eig_vals` (`Vector{ComplexF64}`): Eigenvalues of the Jacobian of the right-hand side (rhs) of the ODEProblem after the + equation has been semidiscretized. + - `verbose` (`Bool`, optional): Verbosity flag, default is false. + - `cS2` (`Float64`, optional): Value of c in the Butcher tableau at c_{s-2}, when + s is the number of stages, default is 1.0f0. + +The following structures and methods provide an implementation of +the third-order paired explicit Runge-Kutta (P-ERK) method +optimized for a certain simulation setup (PDE, IC & BC, Riemann Solver, DG Solver). +The original paper is +- Nasab, Vermeire (2022) +Third-order Paired Explicit Runge-Kutta schemes for stiff systems of equations +[DOI: 10.1016/j.jcp.2022.111470](https://doi.org/10.1016/j.jcp.2022.111470) +While the changes to SSPRK33 base-scheme are described in +- Doehring, Schlottke-Lakemper, Gassner, Torrilhon (2024) +Multirate Time-Integration based on Dynamic ODE Partitioning through Adaptively Refined Meshes for Compressible Fluid Dynamics +[DOI: 10.1016/j.jcp.2024.113223](https://doi.org/10.1016/j.jcp.2024.113223) +""" +mutable struct PairedExplicitRK3 <: AbstractPairedExplicitRKSingle + const num_stages::Int # S + + a_matrix::Matrix{Float64} + c::Vector{Float64} + dt_opt::Float64 +end # struct PairedExplicitRK3 + +# Constructor for previously computed A Coeffs +function PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString, dt_opt; + cS2 = 1.0f0) + a_matrix, c = compute_PairedExplicitRK3_butcher_tableau(num_stages, + base_path_a_coeffs; + cS2) + + return PairedExplicitRK3(num_stages, a_matrix, c, dt_opt) +end + +# Constructor that computes Butcher matrix A coefficients from a semidiscretization +function PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; + verbose = false, cS2 = 1.0f0) + eig_vals = eigvals(jacobian_ad_forward(semi)) + + return PairedExplicitRK3(num_stages, tspan, eig_vals; verbose, cS2) +end + +# Constructor that calculates the coefficients with polynomial optimizer from a list of eigenvalues +function PairedExplicitRK3(num_stages, tspan, eig_vals::Vector{ComplexF64}; + verbose = false, cS2 = 1.0f0) + a_matrix, c, dt_opt = compute_PairedExplicitRK3_butcher_tableau(num_stages, + tspan, + eig_vals; + verbose, cS2) + return PairedExplicitRK3(num_stages, a_matrix, c, dt_opt) +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.jl. +mutable struct PairedExplicitRK3Integrator{RealT <: Real, uType, Params, Sol, F, Alg, + PairedExplicitRKOptions} <: + AbstractPairedExplicitRKSingleIntegrator + u::uType + du::uType + u_tmp::uType + t::RealT + tdir::RealT + dt::RealT # current time step + dtcache::RealT # manually set time step + iter::Int # current number of time steps (iteration) + p::Params # will be the semidiscretization from Trixi + sol::Sol # faked + f::F + alg::Alg # This is our own class written above; Abbreviation for ALGorithm + opts::PairedExplicitRKOptions + finalstep::Bool # added for convenience + dtchangeable::Bool + force_stepfail::Bool + # PairedExplicitRK stages: + k1::uType + k_higher::uType +end + +function init(ode::ODEProblem, alg::PairedExplicitRK3; + dt, callback = nothing, kwargs...) + u0 = copy(ode.u0) + du = zero(u0) + u_tmp = zero(u0) + + # PairedExplicitRK stages + k1 = zero(u0) + k_higher = zero(u0) + + t0 = first(ode.tspan) + tdir = sign(ode.tspan[end] - ode.tspan[1]) + iter = 0 + + integrator = PairedExplicitRK3Integrator(u0, du, u_tmp, t0, tdir, dt, dt, iter, + ode.p, + (prob = ode,), ode.f, alg, + PairedExplicitRKOptions(callback, + ode.tspan; + kwargs...), + false, true, false, + k1, k_higher) + + # initialize callbacks + if callback isa CallbackSet + for cb in callback.continuous_callbacks + error("Continuous callbacks are unsupported with paired explicit Runge-Kutta methods.") + end + for cb in callback.discrete_callbacks + cb.initialize(cb, integrator.u, integrator.t, integrator) + end + elseif !isnothing(callback) + error("unsupported") + end + + return integrator +end + +# Fakes `solve`: https://diffeq.sciml.ai/v6.8/basics/overview/#Solving-the-Problems-1 +function solve(ode::ODEProblem, alg::PairedExplicitRK3; + dt, callback = nothing, kwargs...) + integrator = init(ode, alg, dt = dt, callback = callback; kwargs...) + + # Start actual solve + solve!(integrator) +end + +function solve!(integrator::PairedExplicitRK3Integrator) + @unpack prob = integrator.sol + + integrator.finalstep = false + + @trixi_timeit timer() "main loop" while !integrator.finalstep + step!(integrator) + end # "main loop" timer + + return TimeIntegratorSolution((first(prob.tspan), integrator.t), + (prob.u0, integrator.u), + integrator.sol.prob) +end + +function step!(integrator::PairedExplicitRK3Integrator) + @unpack prob = integrator.sol + @unpack alg = integrator + t_end = last(prob.tspan) + callbacks = integrator.opts.callback + + @assert !integrator.finalstep + if isnan(integrator.dt) + error("time step size `dt` is NaN") + end + + modify_dt_for_tstops!(integrator) + + # 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 + + @trixi_timeit timer() "Paired Explicit Runge-Kutta ODE integration step" begin + # k1 + integrator.f(integrator.du, integrator.u, prob.p, integrator.t) + @threaded for i in eachindex(integrator.du) + integrator.k1[i] = integrator.du[i] * integrator.dt + end + + # Construct current state + @threaded for i in eachindex(integrator.du) + integrator.u_tmp[i] = integrator.u[i] + alg.c[2] * integrator.k1[i] + end + # k2 + integrator.f(integrator.du, integrator.u_tmp, prob.p, + integrator.t + alg.c[2] * integrator.dt) + + @threaded for i in eachindex(integrator.du) + integrator.k_higher[i] = integrator.du[i] * integrator.dt + end + + # Higher stages + for stage in 3:(alg.num_stages - 1) + # Construct current state + @threaded for i in eachindex(integrator.du) + integrator.u_tmp[i] = integrator.u[i] + + alg.a_matrix[stage - 2, 1] * + integrator.k1[i] + + alg.a_matrix[stage - 2, 2] * + integrator.k_higher[i] + end + + integrator.f(integrator.du, integrator.u_tmp, prob.p, + integrator.t + alg.c[stage] * integrator.dt) + + @threaded for i in eachindex(integrator.du) + integrator.k_higher[i] = integrator.du[i] * integrator.dt + end + end + + # Last stage + @threaded for i in eachindex(integrator.du) + integrator.u_tmp[i] = integrator.u[i] + + alg.a_matrix[alg.num_stages - 2, 1] * + integrator.k1[i] + + alg.a_matrix[alg.num_stages - 2, 2] * + integrator.k_higher[i] + end + + integrator.f(integrator.du, integrator.u_tmp, prob.p, + integrator.t + alg.c[alg.num_stages] * integrator.dt) + + @threaded for i in eachindex(integrator.u) + # "Own" PairedExplicitRK based on SSPRK33. + # Note that 'k_higher' carries the values of K_{S-1} + # and that we construct 'K_S' "in-place" from 'integrator.du' + integrator.u[i] += (integrator.k1[i] + integrator.k_higher[i] + + 4.0 * integrator.du[i] * integrator.dt) / 6.0 + end + end # PairedExplicitRK step timer + + 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 + +# used for AMR (Adaptive Mesh Refinement) +function Base.resize!(integrator::PairedExplicitRK3Integrator, new_size) + resize!(integrator.u, new_size) + resize!(integrator.du, new_size) + resize!(integrator.u_tmp, new_size) + + resize!(integrator.k1, new_size) + resize!(integrator.k_higher, new_size) +end +end # @muladd From ce321accc2c82113c1ceaa70c220e7b9279bdfe9 Mon Sep 17 00:00:00 2001 From: Warisa Date: Sat, 12 Oct 2024 19:50:34 +0200 Subject: [PATCH 126/160] some first edits for the embedded scheme --- .../methods_embedded_PERK3.jl | 108 ++++++++++-------- 1 file changed, 59 insertions(+), 49 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index 17a841c7ac3..81c3da2232b 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -7,26 +7,9 @@ using DelimitedFiles: readdlm @muladd begin #! format: noindent -# Initialize Butcher array abscissae c for PairedExplicitRK3 based on SSPRK33 base method -function compute_c_coeffs(num_stages, cS2) - c = zeros(num_stages) - - # Last timesteps as for SSPRK33, see motivation in Section 3.3 of - # https://doi.org/10.1016/j.jcp.2024.113223 - c[num_stages - 1] = 1.0f0 - c[num_stages] = 0.5f0 - - # Linear increasing timestep for remainder - for i in 2:(num_stages - 2) - c[i] = cS2 * (i - 1) / (num_stages - 3) - end - - return c -end - # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 # using a list of eigenvalues -function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, +function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, tspan, eig_vals::Vector{ComplexF64}; verbose = false, cS2) # Initialize array of c @@ -71,7 +54,7 @@ end # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 # using provided values of coefficients a in A-matrix of Butcher tableau -function compute_PairedExplicitRK3_butcher_tableau(num_stages, +function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, base_path_a_coeffs::AbstractString; cS2) @@ -81,6 +64,8 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, # - 2 Since First entry of A is always zero (explicit method) and second is given by c_2 (consistency) a_coeffs_max = num_stages - 2 + b = zeros(num_stages) + a_matrix = zeros(a_coeffs_max, 2) a_matrix[:, 1] = c[3:end] @@ -96,15 +81,15 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, a_matrix[:, 1] -= a_coeffs a_matrix[:, 2] = a_coeffs - return a_matrix, c + return a_matrix, b, c end @doc raw""" - PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString, dt_opt; + EmbeddedPairedRK3(num_stages, base_path_a_coeffs::AbstractString, dt_opt; cS2 = 1.0f0) - PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; + EmbeddedPairedRK3(num_stages, tspan, semi::AbstractSemidiscretization; verbose = false, cS2 = 1.0f0) - PairedExplicitRK3(num_stages, tspan, eig_vals::Vector{ComplexF64}; + EmbeddedPairedRK3(num_stages, tspan, eig_vals::Vector{ComplexF64}; verbose = false, cS2 = 1.0f0) Parameters: @@ -133,47 +118,49 @@ While the changes to SSPRK33 base-scheme are described in Multirate Time-Integration based on Dynamic ODE Partitioning through Adaptively Refined Meshes for Compressible Fluid Dynamics [DOI: 10.1016/j.jcp.2024.113223](https://doi.org/10.1016/j.jcp.2024.113223) """ -mutable struct PairedExplicitRK3 <: AbstractPairedExplicitRKSingle +mutable struct EmbeddedPairedRK3 <: AbstractPairedExplicitRKSingle const num_stages::Int # S + const num_stage_evals::Int # e a_matrix::Matrix{Float64} + b::Vector{Float64} c::Vector{Float64} dt_opt::Float64 -end # struct PairedExplicitRK3 +end # struct EmbeddedPairedRK3 # Constructor for previously computed A Coeffs -function PairedExplicitRK3(num_stages, base_path_a_coeffs::AbstractString, dt_opt; +function EmbeddedPairedRK3(num_stages, num_stage_evals, base_path_a_coeffs::AbstractString, dt_opt; cS2 = 1.0f0) - a_matrix, c = compute_PairedExplicitRK3_butcher_tableau(num_stages, + a_matrix, b, c = compute_EmbeddedPairedRK3_butcher_tableau(num_stages, base_path_a_coeffs; cS2) - return PairedExplicitRK3(num_stages, a_matrix, c, dt_opt) + return EmbeddedPairedRK3(num_stages, num_stage_evals, a_matrix, b, c, dt_opt) end # Constructor that computes Butcher matrix A coefficients from a semidiscretization -function PairedExplicitRK3(num_stages, tspan, semi::AbstractSemidiscretization; +function EmbeddedPairedRK3(num_stages, num_stage_evals, tspan, semi::AbstractSemidiscretization; verbose = false, cS2 = 1.0f0) eig_vals = eigvals(jacobian_ad_forward(semi)) - return PairedExplicitRK3(num_stages, tspan, eig_vals; verbose, cS2) + return EmbeddedPairedRK3(num_stages, num_stage_evals, tspan, eig_vals; verbose, cS2) end # Constructor that calculates the coefficients with polynomial optimizer from a list of eigenvalues -function PairedExplicitRK3(num_stages, tspan, eig_vals::Vector{ComplexF64}; +function EmbeddedPairedRK3(num_stages, num_stage_evals, tspan, eig_vals::Vector{ComplexF64}; verbose = false, cS2 = 1.0f0) - a_matrix, c, dt_opt = compute_PairedExplicitRK3_butcher_tableau(num_stages, + a_matrix, b, c, dt_opt = compute_EmbeddedPairedRK3_butcher_tableau(num_stages, tspan, eig_vals; verbose, cS2) - return PairedExplicitRK3(num_stages, a_matrix, c, dt_opt) + return EmbeddedPairedRK3(num_stages, num_stage_evals, a_matrix, b, c, dt_opt) 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.jl. -mutable struct PairedExplicitRK3Integrator{RealT <: Real, uType, Params, Sol, F, Alg, +mutable struct EmbeddedPairedRK3Integrator{RealT <: Real, uType, Params, Sol, F, Alg, PairedExplicitRKOptions} <: AbstractPairedExplicitRKSingleIntegrator u::uType @@ -197,7 +184,7 @@ mutable struct PairedExplicitRK3Integrator{RealT <: Real, uType, Params, Sol, F, k_higher::uType end -function init(ode::ODEProblem, alg::PairedExplicitRK3; +function init(ode::ODEProblem, alg::EmbeddedPairedRK3; dt, callback = nothing, kwargs...) u0 = copy(ode.u0) du = zero(u0) @@ -205,13 +192,13 @@ function init(ode::ODEProblem, alg::PairedExplicitRK3; # PairedExplicitRK stages k1 = zero(u0) - k_higher = zero(u0) + k_higher = zero(u0, alg.num_stage_evals - 2) t0 = first(ode.tspan) tdir = sign(ode.tspan[end] - ode.tspan[1]) iter = 0 - integrator = PairedExplicitRK3Integrator(u0, du, u_tmp, t0, tdir, dt, dt, iter, + integrator = EmbeddedPairedRK3Integrator(u0, du, u_tmp, t0, tdir, dt, dt, iter, ode.p, (prob = ode,), ode.f, alg, PairedExplicitRKOptions(callback, @@ -236,7 +223,7 @@ function init(ode::ODEProblem, alg::PairedExplicitRK3; end # Fakes `solve`: https://diffeq.sciml.ai/v6.8/basics/overview/#Solving-the-Problems-1 -function solve(ode::ODEProblem, alg::PairedExplicitRK3; +function solve(ode::ODEProblem, alg::EmbeddedPairedRK3; dt, callback = nothing, kwargs...) integrator = init(ode, alg, dt = dt, callback = callback; kwargs...) @@ -244,7 +231,7 @@ function solve(ode::ODEProblem, alg::PairedExplicitRK3; solve!(integrator) end -function solve!(integrator::PairedExplicitRK3Integrator) +function solve!(integrator::EmbeddedPairedRK3Integrator) @unpack prob = integrator.sol integrator.finalstep = false @@ -258,7 +245,7 @@ function solve!(integrator::PairedExplicitRK3Integrator) integrator.sol.prob) end -function step!(integrator::PairedExplicitRK3Integrator) +function step!(integrator::EmbeddedPairedRK3Integrator) @unpack prob = integrator.sol @unpack alg = integrator t_end = last(prob.tspan) @@ -297,8 +284,8 @@ function step!(integrator::PairedExplicitRK3Integrator) integrator.k_higher[i] = integrator.du[i] * integrator.dt end - # Higher stages - for stage in 3:(alg.num_stages - 1) + # Higher stages where the weight of b in the butcher tableau is zero + for stage in 3:(alg.num_stages - alg.num_stage_evals + 1) # Construct current state @threaded for i in eachindex(integrator.du) integrator.u_tmp[i] = integrator.u[i] + @@ -316,6 +303,31 @@ function step!(integrator::PairedExplicitRK3Integrator) end end + # Higher stages where the weight of b in the butcher tableau is non-zero + for stage in (alg.num_stages - alg.num_stage_evals + 2):(alg.num_stages -1) + # Construct current state + @threaded for i in eachindex(integrator.du) + integrator.u_tmp[i] = integrator.u[i] + + alg.a_matrix[stage - 2, 1] * + integrator.k1[i] + + alg.a_matrix[stage - 2, 2] * + integrator.k_higher[i] + end + + integrator.f(integrator.du, integrator.u_tmp, prob.p, + integrator.t + alg.c[stage] * integrator.dt) + + @threaded for i in eachindex(integrator.du) + integrator.k_higher[i] = integrator.du[i] * integrator.dt + end + + @threaded for i in eachindex(integrator.u) + integrator.u[i] += integrator.k_higher[i] * alg.b[stage - alg.num_stages + alg.num_stage_evals - 1] + end + end + + #TODO: Check if commenting this is equal to not commenting + #= # Last stage @threaded for i in eachindex(integrator.du) integrator.u_tmp[i] = integrator.u[i] + @@ -324,16 +336,14 @@ function step!(integrator::PairedExplicitRK3Integrator) alg.a_matrix[alg.num_stages - 2, 2] * integrator.k_higher[i] end + integrator.f(integrator.du, integrator.u_tmp, prob.p, integrator.t + alg.c[alg.num_stages] * integrator.dt) - + =# @threaded for i in eachindex(integrator.u) - # "Own" PairedExplicitRK based on SSPRK33. - # Note that 'k_higher' carries the values of K_{S-1} - # and that we construct 'K_S' "in-place" from 'integrator.du' - integrator.u[i] += (integrator.k1[i] + integrator.k_higher[i] + - 4.0 * integrator.du[i] * integrator.dt) / 6.0 + # add the contribution of the first stage + integrator.u[i] += (1 - sum(alg.b)) * integrator.k1[i] end end # PairedExplicitRK step timer @@ -357,7 +367,7 @@ function step!(integrator::PairedExplicitRK3Integrator) end # used for AMR (Adaptive Mesh Refinement) -function Base.resize!(integrator::PairedExplicitRK3Integrator, new_size) +function Base.resize!(integrator::EmbeddedPairedRK3Integrator, new_size) resize!(integrator.u, new_size) resize!(integrator.du, new_size) resize!(integrator.u_tmp, new_size) From 38d98a5a09e9557810ea1ec01483d06bc0cfd2ba Mon Sep 17 00:00:00 2001 From: Warisa Date: Sat, 12 Oct 2024 20:57:53 +0200 Subject: [PATCH 127/160] add weak dep stuff --- Project.toml | 4 ++ ext/TrixiConvexClarabelExt.jl | 38 +++++++++++++++++++ src/Trixi.jl | 3 ++ .../methods_embedded_PERK3.jl | 13 +++++-- .../paired_explicit_runge_kutta.jl | 2 + 5 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 ext/TrixiConvexClarabelExt.jl diff --git a/Project.toml b/Project.toml index 63febf9c65c..9c70f134850 100644 --- a/Project.toml +++ b/Project.toml @@ -53,18 +53,21 @@ TrixiBase = "9a0f1c46-06d5-4909-a5a3-ce25d3fa3284" UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [weakdeps] +Clarabel = "61c947e1-3e6d-4ee4-985a-eec8c727bd6e" Convex = "f65535da-76fb-5f13-bab9-19810c17039a" ECOS = "e2685f51-7e38-5353-a97d-a921fd2c8199" Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" [extensions] +TrixiConvexClarabelExt = ["Convex", "Clarabel"] TrixiConvexECOSExt = ["Convex", "ECOS"] TrixiMakieExt = "Makie" TrixiNLsolveExt = "NLsolve" [compat] Accessors = "0.1.12" +Clarabel = "0.9.0" CodeTracking = "1.0.5" ConstructionBase = "1.3" Convex = "0.16" @@ -118,6 +121,7 @@ UUIDs = "1.6" julia = "1.8" [extras] +Clarabel = "61c947e1-3e6d-4ee4-985a-eec8c727bd6e" Convex = "f65535da-76fb-5f13-bab9-19810c17039a" ECOS = "e2685f51-7e38-5353-a97d-a921fd2c8199" Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" diff --git a/ext/TrixiConvexClarabelExt.jl b/ext/TrixiConvexClarabelExt.jl new file mode 100644 index 00000000000..12f5f2525ae --- /dev/null +++ b/ext/TrixiConvexClarabelExt.jl @@ -0,0 +1,38 @@ +# Package extension for adding Convex-based features to Trixi.jl +module TrixiConvexClarabelExt + +# Required for coefficient optimization in P-ERK scheme integrators +if isdefined(Base, :get_extension) + using Convex: MOI, solve!, Variable, minimize, evaluate + using Clarabel: Optimizer +else + # Until Julia v1.9 is the minimum required version for Trixi.jl, we still support Requires.jl + using ..Convex: MOI, solve!, Variable, minimize, evaluate + using ..Clarabel: Optimizer +end + +# Use functions that are to be extended and additional symbols that are not exported +using Trixi: Trixi, @muladd + +# 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 + +# New version of stability polynomial of the embedded scheme +function stability_polynomials() + #TODO: Implement the stability polynomial of the embedded scheme +end + +function bisect_stability_polynomial() + #TODO: Implement the bisect_stability_polynomial function. This should either be called by the function below or be implemented there(better). + # the names of the functions here just correspond with the original code better +end + +function Trixi.solve_b_butcher_coeffs_unknown(num_stages, a_matrix, c, dt_opt,eig_vals; verbose) + +end +end # @muladd + +end # module TrixiConvexClarabelExt diff --git a/src/Trixi.jl b/src/Trixi.jl index d51c25d9c9a..6bfd6a17a59 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -317,6 +317,9 @@ function __init__() @require ECOS="e2685f51-7e38-5353-a97d-a921fd2c8199" begin include("../ext/TrixiConvexECOSExt.jl") end + @require Clarabel="61c947e1-3e6d-4ee4-985a-eec8c727bd6e" begin + include("../ext/TrixiConvexClarabelExt.jl") + end end end diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index 81c3da2232b..97a63c74e88 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -9,7 +9,7 @@ using DelimitedFiles: readdlm # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 # using a list of eigenvalues -function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, tspan, +function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, tspan, eig_vals::Vector{ComplexF64}; verbose = false, cS2) # Initialize array of c @@ -39,7 +39,7 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, tspan, # Solve the nonlinear system of equations from monomial coefficient and # Butcher array abscissae c to find Butcher matrix A # This function is extended in TrixiNLsolveExt.jl - a_unknown = solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, + a_unknown = solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, num_stage_evals, #TODO: We have to change this in TrixiNLsolveExt.jl (add one more argument to it) but for PERK3 let num_stages = num_stages_evals -> in the PERK3 file monomial_coeffs, cS2, c; verbose) end @@ -49,7 +49,10 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, tspan, a_matrix[:, 1] -= a_unknown a_matrix[:, 2] = a_unknown - return a_matrix, c, dt_opt + b_opt = solve_b_butcher_coeffs_unknown(num_stages, a_matrix, c, dt_opt, + eig_vals; verbose) #TODO: define and overload this function in TrixiConvexClarabelExt + + return a_matrix, c, b_opt, dt_opt end # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 @@ -64,6 +67,7 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, # - 2 Since First entry of A is always zero (explicit method) and second is given by c_2 (consistency) a_coeffs_max = num_stages - 2 + #TODO: Read the values from the file b = zeros(num_stages) a_matrix = zeros(a_coeffs_max, 2) @@ -131,6 +135,7 @@ end # struct EmbeddedPairedRK3 # Constructor for previously computed A Coeffs function EmbeddedPairedRK3(num_stages, num_stage_evals, base_path_a_coeffs::AbstractString, dt_opt; cS2 = 1.0f0) + #TODO: Update this constructor to have num_stage_evals as well a_matrix, b, c = compute_EmbeddedPairedRK3_butcher_tableau(num_stages, base_path_a_coeffs; cS2) @@ -149,7 +154,7 @@ end # Constructor that calculates the coefficients with polynomial optimizer from a list of eigenvalues function EmbeddedPairedRK3(num_stages, num_stage_evals, tspan, eig_vals::Vector{ComplexF64}; verbose = false, cS2 = 1.0f0) - a_matrix, b, c, dt_opt = compute_EmbeddedPairedRK3_butcher_tableau(num_stages, + a_matrix, b, c, dt_opt = compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, tspan, eig_vals; verbose, cS2) diff --git a/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl b/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl index 8f8cacadd79..00b164b87d3 100644 --- a/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl +++ b/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl @@ -8,6 +8,7 @@ # Basic implementation of the second-order paired explicit Runge-Kutta (PERK) method include("methods_PERK2.jl") include("methods_PERK3.jl") +include("methods_embedded_PERK3.jl") # Define all of the functions necessary for polynomial optimizations include("polynomial_optimizer.jl") @@ -15,4 +16,5 @@ include("polynomial_optimizer.jl") # such that hey can be exported from Trixi.jl and extended in the TrixiConvexECOSExt package # extension or by the NLsolve-specific code loaded by Requires.jl function solve_a_butcher_coeffs_unknown! end +function solve_b_butcher_coeffs_unknown end end # @muladd From 7fb103a30fc9e9d05106ca99dc9df117e13d391b Mon Sep 17 00:00:00 2001 From: Warisa Date: Sat, 12 Oct 2024 21:24:02 +0200 Subject: [PATCH 128/160] add a couple of TODOs --- ext/TrixiConvexClarabelExt.jl | 2 +- ext/TrixiNLsolveExt.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/TrixiConvexClarabelExt.jl b/ext/TrixiConvexClarabelExt.jl index 12f5f2525ae..5bfc991e626 100644 --- a/ext/TrixiConvexClarabelExt.jl +++ b/ext/TrixiConvexClarabelExt.jl @@ -31,7 +31,7 @@ function bisect_stability_polynomial() end function Trixi.solve_b_butcher_coeffs_unknown(num_stages, a_matrix, c, dt_opt,eig_vals; verbose) - + #TODO: Implement this end end # @muladd diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 51dfd7843a8..5177c72dcba 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -75,7 +75,7 @@ end # Hairer, Wanner: Solving Ordinary Differential Equations 2 function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_coeffs, c_s2, c; - verbose, max_iter = 100000) + verbose, max_iter = 100000) #TODO: Add an argument of num_stage_evals here # Define the objective_function function objective_function!(c_eq, x) From 9953bc200b0e8466f7b55d478c4667defa0c89c2 Mon Sep 17 00:00:00 2001 From: Warisa Date: Sun, 13 Oct 2024 09:29:07 +0200 Subject: [PATCH 129/160] move the code of b solver from OptRungeKutta to Trixi --- ext/TrixiConvexClarabelExt.jl | 143 ++++++++++++++++++++++++++++++++-- 1 file changed, 135 insertions(+), 8 deletions(-) diff --git a/ext/TrixiConvexClarabelExt.jl b/ext/TrixiConvexClarabelExt.jl index 5bfc991e626..babf8245b21 100644 --- a/ext/TrixiConvexClarabelExt.jl +++ b/ext/TrixiConvexClarabelExt.jl @@ -19,19 +19,146 @@ using Trixi: Trixi, @muladd # we need to opt-in explicitly. # See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. @muladd begin +#! format: noindent # New version of stability polynomial of the embedded scheme -function stability_polynomials() - #TODO: Implement the stability polynomial of the embedded scheme -end +# Compute stability polynomials for paired explicit Runge-Kutta up to specified consistency +# order(p = 2), including contributions from free coefficients for higher orders, and +# return the maximum absolute value +function stability_polynomials!(pnoms, + num_stages_embedded, num_stage_evals_embedded, + normalized_powered_eigvals_scaled, + a, b, c) + + # Construct a full b coefficient vector #TODO: is there a way to not do this and just use b directly? + b_coeff = [1 - sum(b), zeros(Float64, num_stages_embedded - num_stage_evals_embedded)..., b..., 0] + num_eig_vals = length(pnoms) + + # Initialize with 1 + z + for i in 1:num_eig_vals + pnoms[i] = 1.0 + normalized_powered_eigvals_scaled[i, 1] + end + # z^2: b^T * c + #pnoms += dot(b, c) * normalized_powered_eigvals_scaled[:, 2] + pnoms += 0.5 * normalized_powered_eigvals_scaled[:, 2] -function bisect_stability_polynomial() - #TODO: Implement the bisect_stability_polynomial function. This should either be called by the function below or be implemented there(better). - # the names of the functions here just correspond with the original code better + # Contribution from free coefficients + for i in 3:num_stage_evals_embedded + sum = 0.0 + for j in (i + num_stages_embedded - num_stage_evals_embedded):num_stages_embedded + prod = 1.0 + for k in (3 + j - i):j + prod *= a[k] + end + sum += prod * b_coeff[j] * c[j - i + 2] + end + pnoms += sum * normalized_powered_eigvals_scaled[:, i] + end + + # For optimization only the maximum is relevant + return maximum(abs(pnoms)) end -function Trixi.solve_b_butcher_coeffs_unknown(num_stages, a_matrix, c, dt_opt,eig_vals; verbose) - #TODO: Implement this +function Trixi.solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, + num_stages, num_stage_evals, + num_stages_embedded, + num_stage_evals_embedded, + a_unknown, c, dtmax, dteps) + dtmin = 0.0 + dt = -1.0 + abs_p = -1.0 + + # Construct a full a coefficient vector + a = zeros(num_stages) + num_a_unknown = length(a_unknown) + + for i = 1:num_a_unknown + a[num_stages - i + 1] = a_unknown[num_a_unknown - i + 1] + end + + # Construct stability polynomial for each eigenvalue + pnoms = ones(Complex{Float64}, num_eig_vals, 1) + + # There are e - 2 free variables for the stability polynomial of the embedded scheme + b = Variable(num_stage_evals - 2) + + normalized_powered_eigvals = zeros(Complex{Float64}, num_eig_vals, num_stage_evals) + + for j in 1:num_stage_evals + #fac_j = factorial(j) + for i in 1:num_eig_vals + #normalized_powered_eigvals[i, j] = eig_vals[i]^j / fac_j + # Try first without factorial normalization + normalized_powered_eigvals[i, j] = eig_vals[i]^j + end + end + + normalized_powered_eigvals_scaled = similar(normalized_powered_eigvals) + + # Bisection on timestep + while dtmax - dtmin > dteps + dt = 0.5 * (dtmax + dtmin) + + # Compute stability polynomial for current timestep + for k in 1:num_stage_evals + dt_k = dt^k + for i in 1:num_eig_vals + normalized_powered_eigvals_scaled[i, k] = dt_k * + normalized_powered_eigvals[i, + k] + end + end + + # Second-order constraint + # Since c[1] is always 0 we can ignore the contribution of b[1] and only account for the ones from other non-zero entries of b + constraints = [b >= 0, + 2 * dot(b, c[(num_stages - num_stage_evals + 2):(num_stages - 1)]) == 1.0] + + # Use last optimal values for b in (potentially) next iteration + problem = minimize(stability_polynomials!(pnoms, + num_stages_embedded, + num_stage_evals_embedded, + normalized_powered_eigvals_scaled, + a, b, c), constraints) + + #= + solve!(problem, + # Parameters taken from default values for EiCOS + Convex.MOI.OptimizerWithAttributes(ECOS.Optimizer, "b" => 0.99, + "delta" => 2e-7, + "feastol" => 1e-9, + "abstol" => 1e-9, + "reltol" => 1e-9, + "feastol_inacc" => 1e-4, + "abstol_inacc" => 5e-5, + "reltol_inacc" => 5e-5, + "nitref" => 9, + "maxit" => 100, + "verbose" => 3); silent_solver = false) + =# + + solve!(problem, + Convex.MOI.OptimizerWithAttributes(Clarabel.Optimizer, + "tol_feas" => 1e-12); + silent_solver = false) + + abs_p = problem.optval + + if abs_p < 1 + dtmin = dt + else + dtmax = dt + end + end + + b_opt = evaluate(b) + + # Catch case S = 3 (only one opt. variable) + if isa(b_opt, Number) + b_opt = [b_opt] + end + + return b_opt, dt end end # @muladd From f30d533e9274d6f71ba8e2095373d24c625962c9 Mon Sep 17 00:00:00 2001 From: Warisa Date: Sun, 13 Oct 2024 09:33:59 +0200 Subject: [PATCH 130/160] small comment and minor format fix --- ext/TrixiConvexClarabelExt.jl | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/ext/TrixiConvexClarabelExt.jl b/ext/TrixiConvexClarabelExt.jl index babf8245b21..175c2e74810 100644 --- a/ext/TrixiConvexClarabelExt.jl +++ b/ext/TrixiConvexClarabelExt.jl @@ -21,17 +21,22 @@ using Trixi: Trixi, @muladd @muladd begin #! format: noindent -# New version of stability polynomial of the embedded scheme -# Compute stability polynomials for paired explicit Runge-Kutta up to specified consistency -# order(p = 2), including contributions from free coefficients for higher orders, and -# return the maximum absolute value -function stability_polynomials!(pnoms, - num_stages_embedded, num_stage_evals_embedded, - normalized_powered_eigvals_scaled, - a, b, c) +# Compute new version of stability polynomial of the embedded scheme for paired explicit Runge-Kutta +# up to specified consistency order(p = 2), including contributions from free coefficients for higher +# orders, and return the maximum absolute value +function embedded_scheme_stability_polynomials!(pnoms, + num_stages_embedded, + num_stage_evals_embedded, + normalized_powered_eigvals_scaled, + a, b, c) # Construct a full b coefficient vector #TODO: is there a way to not do this and just use b directly? - b_coeff = [1 - sum(b), zeros(Float64, num_stages_embedded - num_stage_evals_embedded)..., b..., 0] + b_coeff = [ + 1 - sum(b), + zeros(Float64, num_stages_embedded - num_stage_evals_embedded)..., + b..., + 0 + ] num_eig_vals = length(pnoms) # Initialize with 1 + z @@ -72,7 +77,7 @@ function Trixi.solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, a = zeros(num_stages) num_a_unknown = length(a_unknown) - for i = 1:num_a_unknown + for i in 1:num_a_unknown a[num_stages - i + 1] = a_unknown[num_a_unknown - i + 1] end @@ -115,11 +120,11 @@ function Trixi.solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, 2 * dot(b, c[(num_stages - num_stage_evals + 2):(num_stages - 1)]) == 1.0] # Use last optimal values for b in (potentially) next iteration - problem = minimize(stability_polynomials!(pnoms, - num_stages_embedded, - num_stage_evals_embedded, - normalized_powered_eigvals_scaled, - a, b, c), constraints) + problem = minimize(embedded_scheme_stability_polynomials!(pnoms, + num_stages_embedded, + num_stage_evals_embedded, + normalized_powered_eigvals_scaled, + a, b, c), constraints) #= solve!(problem, From 23a838c04768677a291b95fde6146b71fe56c413 Mon Sep 17 00:00:00 2001 From: Warisa Date: Sun, 13 Oct 2024 09:38:39 +0200 Subject: [PATCH 131/160] we do not have to store e-2 k when we increment k for every stage that b != 0 --- .../paired_explicit_runge_kutta/methods_embedded_PERK3.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index 97a63c74e88..f426b66d631 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -197,7 +197,7 @@ function init(ode::ODEProblem, alg::EmbeddedPairedRK3; # PairedExplicitRK stages k1 = zero(u0) - k_higher = zero(u0, alg.num_stage_evals - 2) + k_higher = zero(u0) t0 = first(ode.tspan) tdir = sign(ode.tspan[end] - ode.tspan[1]) From e7a6ee1faba65411a640f8cf573ecc96410cb99a Mon Sep 17 00:00:00 2001 From: Warisa Date: Sun, 13 Oct 2024 09:48:07 +0200 Subject: [PATCH 132/160] - add an extra argument to solve_a_butcher_coeffs_unknown! so that e can be varied. - modify solve_a_butcher_coeffs_unknown! in methods_PERK3.jl to match the change --- ext/TrixiNLsolveExt.jl | 6 +++--- .../paired_explicit_runge_kutta/methods_PERK3.jl | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 5177c72dcba..3db0e057f12 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -73,15 +73,15 @@ end # non-linear equations that arise from the relation of the stability polynomial to the Butcher tableau. # For details, see Proposition 3.2, Equation (3.3) from # Hairer, Wanner: Solving Ordinary Differential Equations 2 -function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, monomial_coeffs, +function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, num_stage_evals, monomial_coeffs, c_s2, c; - verbose, max_iter = 100000) #TODO: Add an argument of num_stage_evals here + verbose, max_iter = 100000) # Define the objective_function function objective_function!(c_eq, x) return PairedExplicitRK3_butcher_tableau_objective_function!(c_eq, x, num_stages, - num_stages, + num_stage_evals, monomial_coeffs, c_s2) end diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl index 17a841c7ac3..0e7dfcc69b9 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_PERK3.jl @@ -56,7 +56,7 @@ function compute_PairedExplicitRK3_butcher_tableau(num_stages, tspan, # Solve the nonlinear system of equations from monomial coefficient and # Butcher array abscissae c to find Butcher matrix A # This function is extended in TrixiNLsolveExt.jl - a_unknown = solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, + a_unknown = solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, num_stages, monomial_coeffs, cS2, c; verbose) end From d7d7146998472f69397d00eb508728cb91a09647 Mon Sep 17 00:00:00 2001 From: Warisa Date: Sun, 13 Oct 2024 09:50:48 +0200 Subject: [PATCH 133/160] fmt --- .../methods_embedded_PERK3.jl | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index f426b66d631..c5700606076 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -39,7 +39,8 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, # Solve the nonlinear system of equations from monomial coefficient and # Butcher array abscissae c to find Butcher matrix A # This function is extended in TrixiNLsolveExt.jl - a_unknown = solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, num_stage_evals, #TODO: We have to change this in TrixiNLsolveExt.jl (add one more argument to it) but for PERK3 let num_stages = num_stages_evals -> in the PERK3 file + a_unknown = solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, + num_stage_evals, monomial_coeffs, cS2, c; verbose) end @@ -133,18 +134,20 @@ mutable struct EmbeddedPairedRK3 <: AbstractPairedExplicitRKSingle end # struct EmbeddedPairedRK3 # Constructor for previously computed A Coeffs -function EmbeddedPairedRK3(num_stages, num_stage_evals, base_path_a_coeffs::AbstractString, dt_opt; +function EmbeddedPairedRK3(num_stages, num_stage_evals, + base_path_a_coeffs::AbstractString, dt_opt; cS2 = 1.0f0) #TODO: Update this constructor to have num_stage_evals as well a_matrix, b, c = compute_EmbeddedPairedRK3_butcher_tableau(num_stages, - base_path_a_coeffs; - cS2) + base_path_a_coeffs; + cS2) return EmbeddedPairedRK3(num_stages, num_stage_evals, a_matrix, b, c, dt_opt) end # Constructor that computes Butcher matrix A coefficients from a semidiscretization -function EmbeddedPairedRK3(num_stages, num_stage_evals, tspan, semi::AbstractSemidiscretization; +function EmbeddedPairedRK3(num_stages, num_stage_evals, tspan, + semi::AbstractSemidiscretization; verbose = false, cS2 = 1.0f0) eig_vals = eigvals(jacobian_ad_forward(semi)) @@ -152,12 +155,14 @@ function EmbeddedPairedRK3(num_stages, num_stage_evals, tspan, semi::AbstractSem end # Constructor that calculates the coefficients with polynomial optimizer from a list of eigenvalues -function EmbeddedPairedRK3(num_stages, num_stage_evals, tspan, eig_vals::Vector{ComplexF64}; +function EmbeddedPairedRK3(num_stages, num_stage_evals, tspan, + eig_vals::Vector{ComplexF64}; verbose = false, cS2 = 1.0f0) - a_matrix, b, c, dt_opt = compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, - tspan, - eig_vals; - verbose, cS2) + a_matrix, b, c, dt_opt = compute_EmbeddedPairedRK3_butcher_tableau(num_stages, + num_stage_evals, + tspan, + eig_vals; + verbose, cS2) return EmbeddedPairedRK3(num_stages, num_stage_evals, a_matrix, b, c, dt_opt) end @@ -309,7 +314,7 @@ function step!(integrator::EmbeddedPairedRK3Integrator) end # Higher stages where the weight of b in the butcher tableau is non-zero - for stage in (alg.num_stages - alg.num_stage_evals + 2):(alg.num_stages -1) + for stage in (alg.num_stages - alg.num_stage_evals + 2):(alg.num_stages - 1) # Construct current state @threaded for i in eachindex(integrator.du) integrator.u_tmp[i] = integrator.u[i] + @@ -327,9 +332,10 @@ function step!(integrator::EmbeddedPairedRK3Integrator) end @threaded for i in eachindex(integrator.u) - integrator.u[i] += integrator.k_higher[i] * alg.b[stage - alg.num_stages + alg.num_stage_evals - 1] + integrator.u[i] += integrator.k_higher[i] * + alg.b[stage - alg.num_stages + alg.num_stage_evals - 1] end - end + end #TODO: Check if commenting this is equal to not commenting #= @@ -341,7 +347,6 @@ function step!(integrator::EmbeddedPairedRK3Integrator) alg.a_matrix[alg.num_stages - 2, 2] * integrator.k_higher[i] end - integrator.f(integrator.du, integrator.u_tmp, prob.p, integrator.t + alg.c[alg.num_stages] * integrator.dt) From da60e8803b6a756ffb3e27da89d3ab01665c485d Mon Sep 17 00:00:00 2001 From: Warisa Date: Sun, 13 Oct 2024 09:59:49 +0200 Subject: [PATCH 134/160] add an example and fix solve_b_butcher coeffs unknown --- .../elixir_advection_embedded_perk3.jl | 75 +++++++++++++++++++ .../methods_embedded_PERK3.jl | 7 +- 2 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl diff --git a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl new file mode 100644 index 00000000000..b534332a8f9 --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl @@ -0,0 +1,75 @@ + +# Convex and ECOS are imported because they are used for finding the optimal time step and optimal +# monomial coefficients in the stability polynomial of P-ERK time integrators. +using Convex, ECOS + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear advection equation + +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) + +coordinates_min = -1.0 # minimum 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 + +# 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 20.0 +tspan = (0.0, 20.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 StepsizeCallback handles the re-calculation of the maximum Δt after each time step +stepsize_callback = StepsizeCallback(cfl = 2.5) + +alive_callback = AliveCallback(alive_interval = analysis_interval) + +save_solution = SaveSolutionCallback(dt = 0.1, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +# Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver +callbacks = CallbackSet(summary_callback, + alive_callback, + save_solution, + analysis_callback, + stepsize_callback) + +############################################################################### +# run the simulation + +# Construct second order paired explicit Runge-Kutta method with 6 stages for given simulation setup. +# Pass `tspan` to calculate maximum time step allowed for the bisection algorithm used +# in calculating the polynomial coefficients in the ODE algorithm. +ode_algorithm = Trixi.EmbeddedPairedRK3(6, tspan, semi) + +sol = Trixi.solve(ode, ode_algorithm, + dt = 1.0, # Manual time step value, will be overwritten by the stepsize_callback when it is specified. + save_everystep = false, callback = callbacks); + +# Print the timer summary +summary_callback() diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index c5700606076..98739dbb5fd 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -50,8 +50,11 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, a_matrix[:, 1] -= a_unknown a_matrix[:, 2] = a_unknown - b_opt = solve_b_butcher_coeffs_unknown(num_stages, a_matrix, c, dt_opt, - eig_vals; verbose) #TODO: define and overload this function in TrixiConvexClarabelExt + b_opt = solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, + num_stages, num_stage_evals, + num_stages_embedded, + num_stage_evals_embedded, + a_unknown, c, dtmax, dteps) return a_matrix, c, b_opt, dt_opt end From 22bfc6c0c17d7e5ed15bad081522efc42665590f Mon Sep 17 00:00:00 2001 From: Warisa Date: Sun, 13 Oct 2024 21:57:24 +0200 Subject: [PATCH 135/160] minor bug fix that makes everything runs without error. Not done with fixing the logic of the integrator stage constructions --- .../elixir_advection_embedded_perk3.jl | 4 +- ext/TrixiConvexClarabelExt.jl | 6 +- ext/TrixiConvexECOSExt.jl | 2 +- .../methods_embedded_PERK3.jl | 59 ++++++++++--------- 4 files changed, 38 insertions(+), 33 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl index b534332a8f9..b1a1800b201 100644 --- a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl +++ b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl @@ -1,7 +1,7 @@ # Convex and ECOS are imported because they are used for finding the optimal time step and optimal # monomial coefficients in the stability polynomial of P-ERK time integrators. -using Convex, ECOS +using Convex, ECOS, Clarabel using OrdinaryDiffEq using Trixi @@ -65,7 +65,7 @@ callbacks = CallbackSet(summary_callback, # Construct second order paired explicit Runge-Kutta method with 6 stages for given simulation setup. # Pass `tspan` to calculate maximum time step allowed for the bisection algorithm used # in calculating the polynomial coefficients in the ODE algorithm. -ode_algorithm = Trixi.EmbeddedPairedRK3(6, tspan, semi) +ode_algorithm = Trixi.EmbeddedPairedRK3(8, 6, tspan, semi) sol = Trixi.solve(ode, ode_algorithm, dt = 1.0, # Manual time step value, will be overwritten by the stepsize_callback when it is specified. diff --git a/ext/TrixiConvexClarabelExt.jl b/ext/TrixiConvexClarabelExt.jl index 175c2e74810..ff51b05bec9 100644 --- a/ext/TrixiConvexClarabelExt.jl +++ b/ext/TrixiConvexClarabelExt.jl @@ -3,7 +3,7 @@ module TrixiConvexClarabelExt # Required for coefficient optimization in P-ERK scheme integrators if isdefined(Base, :get_extension) - using Convex: MOI, solve!, Variable, minimize, evaluate + using Convex: MOI, solve!, Variable, minimize, evaluate, dot using Clarabel: Optimizer else # Until Julia v1.9 is the minimum required version for Trixi.jl, we still support Requires.jl @@ -143,8 +143,8 @@ function Trixi.solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, =# solve!(problem, - Convex.MOI.OptimizerWithAttributes(Clarabel.Optimizer, - "tol_feas" => 1e-12); + MOI.OptimizerWithAttributes(Optimizer, + "tol_feas" => 1e-12); silent_solver = false) abs_p = problem.optval diff --git a/ext/TrixiConvexECOSExt.jl b/ext/TrixiConvexECOSExt.jl index 8251fe3eed9..0a5b4c44c5d 100644 --- a/ext/TrixiConvexECOSExt.jl +++ b/ext/TrixiConvexECOSExt.jl @@ -136,7 +136,7 @@ function Trixi.bisect_stability_polynomial(consistency_order, num_eig_vals, "reltol_inacc" => 5e-5, "nitref" => 9, "maxit" => 100, - "verbose" => 3); silent = true) + "verbose" => 3); silent_solver = true) abs_p = problem.optval diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index 98739dbb5fd..3d63134aa6e 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -50,13 +50,15 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, a_matrix[:, 1] -= a_unknown a_matrix[:, 2] = a_unknown - b_opt = solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, + + #TODO: something wrong when s = e + b, _ = solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, num_stages, num_stage_evals, - num_stages_embedded, - num_stage_evals_embedded, + num_stages - 1, # num_stages_embedded = num_stages - 1 + num_stage_evals - 1, # num_stage_evals_embedded = num_stage_evals - 1 a_unknown, c, dtmax, dteps) - return a_matrix, c, b_opt, dt_opt + return a_matrix, b, c, dt_opt end # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 @@ -140,7 +142,7 @@ end # struct EmbeddedPairedRK3 function EmbeddedPairedRK3(num_stages, num_stage_evals, base_path_a_coeffs::AbstractString, dt_opt; cS2 = 1.0f0) - #TODO: Update this constructor to have num_stage_evals as well + #TODO: Update this constructor to have num_stage_evals as well and also return correct things a_matrix, b, c = compute_EmbeddedPairedRK3_butcher_tableau(num_stages, base_path_a_coeffs; cS2) @@ -285,43 +287,46 @@ function step!(integrator::EmbeddedPairedRK3Integrator) integrator.k1[i] = integrator.du[i] * integrator.dt end - # Construct current state - @threaded for i in eachindex(integrator.du) - integrator.u_tmp[i] = integrator.u[i] + alg.c[2] * integrator.k1[i] - end - # k2 - integrator.f(integrator.du, integrator.u_tmp, prob.p, - integrator.t + alg.c[2] * integrator.dt) - - @threaded for i in eachindex(integrator.du) - integrator.k_higher[i] = integrator.du[i] * integrator.dt - end - # Higher stages where the weight of b in the butcher tableau is zero - for stage in 3:(alg.num_stages - alg.num_stage_evals + 1) + for stage in 2:alg.num_stage_evals - 1 # Construct current state @threaded for i in eachindex(integrator.du) - integrator.u_tmp[i] = integrator.u[i] + - alg.a_matrix[stage - 2, 1] * - integrator.k1[i] + - alg.a_matrix[stage - 2, 2] * - integrator.k_higher[i] + integrator.u_tmp[i] = integrator.u[i] + alg.c[stage] * integrator.k1[i] end integrator.f(integrator.du, integrator.u_tmp, prob.p, - integrator.t + alg.c[stage] * integrator.dt) + integrator.t + alg.c[stage] * integrator.dt) @threaded for i in eachindex(integrator.du) integrator.k_higher[i] = integrator.du[i] * integrator.dt end end - # Higher stages where the weight of b in the butcher tableau is non-zero - for stage in (alg.num_stages - alg.num_stage_evals + 2):(alg.num_stages - 1) + # k_e (k at posoition num_stage_evals) + + # Construct current state + @threaded for i in eachindex(integrator.du) + integrator.u_tmp[i] = integrator.u[i] + alg.c[stage] * integrator.k1[i] + end + + integrator.f(integrator.du, integrator.u_tmp, prob.p, + integrator.t + alg.c[stage] * integrator.dt) + + @threaded for i in eachindex(integrator.du) + integrator.k_higher[i] = integrator.du[i] * integrator.dt + end + + @threaded for i in eachindex(integrator.u) + integrator.u[i] += integrator.k_higher[i] * + alg.b[1] + end + + # Higher stages after num_stage_evals where b is non-zero + for stage in alg.num_stage_evals + 1:(alg.num_stages - 1) # Construct current state @threaded for i in eachindex(integrator.du) integrator.u_tmp[i] = integrator.u[i] + - alg.a_matrix[stage - 2, 1] * + alg.a_matrix[stage - 2, 1] * #TODO: work on the indexing here and below integrator.k1[i] + alg.a_matrix[stage - 2, 2] * integrator.k_higher[i] From 96a7bf88836a84f62abb2c50d597b1e1c9ec02f9 Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 14 Oct 2024 18:40:22 +0200 Subject: [PATCH 136/160] obvious bug fix --- ext/TrixiNLsolveExt.jl | 6 ++--- .../methods_embedded_PERK3.jl | 27 +++++++++---------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 3db0e057f12..4516bdcf744 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -100,7 +100,7 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, num_stage_ # Due to the nature of the nonlinear solver, different initial guesses can lead to # small numerical differences in the solution. - x0 = convert(RealT, 0.1) .* rand(rng, RealT, num_stages - 2) + x0 = convert(RealT, 0.1) .* rand(rng, RealT, num_stage_evals - 2) sol = nlsolve(objective_function!, x0, method = :trust_region, ftol = 4.0e-16, # Enforce objective up to machine precision @@ -112,8 +112,8 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, num_stage_ # and also c[i] - a[i, i-1] >= 0.0 since all coefficients should be non-negative # to avoid downwinding of numerical fluxes. is_sol_valid = all(x -> !isnan(x) && x >= 0, a_unknown) && - all(!isnan(c[i] - a_unknown[i - 2]) && - c[i] - a_unknown[i - 2] >= 0 for i in eachindex(c) if i > 2) + all(!isnan(c[i] - a_unknown[i - num_stage_evals]) && + c[i] - a_unknown[i - num_stage_evals] >= 0 for i in eachindex(c) if i > num_stage_evals) if is_sol_valid return a_unknown diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index 3d63134aa6e..6540aced755 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -16,10 +16,10 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, c = compute_c_coeffs(num_stages, cS2) # Initialize the array of our solution - a_unknown = zeros(num_stages - 2) + a_unknown = zeros(num_stage_evals - 2) # Special case of e = 3 - if num_stages == 3 + if num_stage_evals == 3 a_unknown = [0.25] # Use classic SSPRK33 (Shu-Osher) Butcher Tableau else # Calculate coefficients of the stability polynomial in monomial form @@ -45,8 +45,8 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, verbose) end # Fill A-matrix in P-ERK style - a_matrix = zeros(num_stages - 2, 2) - a_matrix[:, 1] = c[3:end] + a_matrix = zeros(num_stage_evals - 2, 2) + a_matrix[:, 1] = c[num_stages - num_stage_evals + 3:end] # issue a_matrix[:, 1] -= a_unknown a_matrix[:, 2] = a_unknown @@ -303,14 +303,13 @@ function step!(integrator::EmbeddedPairedRK3Integrator) end # k_e (k at posoition num_stage_evals) - # Construct current state @threaded for i in eachindex(integrator.du) - integrator.u_tmp[i] = integrator.u[i] + alg.c[stage] * integrator.k1[i] + integrator.u_tmp[i] = integrator.u[i] + alg.c[alg.num_stage_evals] * integrator.k1[i] end integrator.f(integrator.du, integrator.u_tmp, prob.p, - integrator.t + alg.c[stage] * integrator.dt) + integrator.t + alg.c[alg.num_stage_evals] * integrator.dt) @threaded for i in eachindex(integrator.du) integrator.k_higher[i] = integrator.du[i] * integrator.dt @@ -326,9 +325,9 @@ function step!(integrator::EmbeddedPairedRK3Integrator) # Construct current state @threaded for i in eachindex(integrator.du) integrator.u_tmp[i] = integrator.u[i] + - alg.a_matrix[stage - 2, 1] * #TODO: work on the indexing here and below + alg.a_matrix[stage - alg.num_stage_evals, 1] integrator.k1[i] + - alg.a_matrix[stage - 2, 2] * + alg.a_matrix[stage - alg.num_stage_evals, 2] * integrator.k_higher[i] end @@ -341,24 +340,22 @@ function step!(integrator::EmbeddedPairedRK3Integrator) @threaded for i in eachindex(integrator.u) integrator.u[i] += integrator.k_higher[i] * - alg.b[stage - alg.num_stages + alg.num_stage_evals - 1] + alg.b[stage - alg.num_stage_evals + 1] end end - #TODO: Check if commenting this is equal to not commenting - #= # Last stage @threaded for i in eachindex(integrator.du) integrator.u_tmp[i] = integrator.u[i] + - alg.a_matrix[alg.num_stages - 2, 1] * + alg.a_matrix[alg.num_stages - alg.num_stage_evals - 1, 1] * integrator.k1[i] + - alg.a_matrix[alg.num_stages - 2, 2] * + alg.a_matrix[alg.num_stages - alg.num_stage_evals - 1, 2] * integrator.k_higher[i] end integrator.f(integrator.du, integrator.u_tmp, prob.p, integrator.t + alg.c[alg.num_stages] * integrator.dt) - =# + @threaded for i in eachindex(integrator.u) # add the contribution of the first stage integrator.u[i] += (1 - sum(alg.b)) * integrator.k1[i] From 6a526f03b2f65c944e5651614f582a2acddb896e Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 14 Oct 2024 19:04:11 +0200 Subject: [PATCH 137/160] fix obvious bug further --- examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl | 2 +- .../paired_explicit_runge_kutta/methods_embedded_PERK3.jl | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl index b1a1800b201..55fe1288016 100644 --- a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl +++ b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl @@ -65,7 +65,7 @@ callbacks = CallbackSet(summary_callback, # Construct second order paired explicit Runge-Kutta method with 6 stages for given simulation setup. # Pass `tspan` to calculate maximum time step allowed for the bisection algorithm used # in calculating the polynomial coefficients in the ODE algorithm. -ode_algorithm = Trixi.EmbeddedPairedRK3(8, 6, tspan, semi) +ode_algorithm = Trixi.EmbeddedPairedRK3(10, 8, tspan, semi) sol = Trixi.solve(ode, ode_algorithm, dt = 1.0, # Manual time step value, will be overwritten by the stepsize_callback when it is specified. diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index 6540aced755..48248af9e1b 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -325,12 +325,12 @@ function step!(integrator::EmbeddedPairedRK3Integrator) # Construct current state @threaded for i in eachindex(integrator.du) integrator.u_tmp[i] = integrator.u[i] + - alg.a_matrix[stage - alg.num_stage_evals, 1] + alg.a_matrix[stage - alg.num_stage_evals, 1] * integrator.k1[i] + alg.a_matrix[stage - alg.num_stage_evals, 2] * integrator.k_higher[i] end - + integrator.f(integrator.du, integrator.u_tmp, prob.p, integrator.t + alg.c[stage] * integrator.dt) @@ -347,9 +347,9 @@ function step!(integrator::EmbeddedPairedRK3Integrator) # Last stage @threaded for i in eachindex(integrator.du) integrator.u_tmp[i] = integrator.u[i] + - alg.a_matrix[alg.num_stages - alg.num_stage_evals - 1, 1] * + alg.a_matrix[alg.num_stage_evals - 2, 1] * integrator.k1[i] + - alg.a_matrix[alg.num_stages - alg.num_stage_evals - 1, 2] * + alg.a_matrix[alg.num_stage_evals - 2, 2] * integrator.k_higher[i] end From 0c0d5324ac361ac66d6a942732ea063c131d19c2 Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 14 Oct 2024 19:22:04 +0200 Subject: [PATCH 138/160] minor change --- .../paired_explicit_runge_kutta/methods_embedded_PERK3.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index 48248af9e1b..be6648d89fc 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -58,6 +58,7 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, num_stage_evals - 1, # num_stage_evals_embedded = num_stage_evals - 1 a_unknown, c, dtmax, dteps) + return a_matrix, b, c, dt_opt end From 5208689ad2d7edfb34579ab9a3d1e6290902dc49 Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 14 Oct 2024 19:57:34 +0200 Subject: [PATCH 139/160] minor change and also print out the result --- .../tree_1d_dgsem/elixir_advection_embedded_perk3.jl | 12 +++++++++++- ext/TrixiConvexClarabelExt.jl | 2 +- .../methods_embedded_PERK3.jl | 9 +++++---- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl index 55fe1288016..d915ee1318a 100644 --- a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl +++ b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl @@ -65,7 +65,7 @@ callbacks = CallbackSet(summary_callback, # Construct second order paired explicit Runge-Kutta method with 6 stages for given simulation setup. # Pass `tspan` to calculate maximum time step allowed for the bisection algorithm used # in calculating the polynomial coefficients in the ODE algorithm. -ode_algorithm = Trixi.EmbeddedPairedRK3(10, 8, tspan, semi) +ode_algorithm = Trixi.EmbeddedPairedRK3(10, 7, tspan, semi) sol = Trixi.solve(ode, ode_algorithm, dt = 1.0, # Manual time step value, will be overwritten by the stepsize_callback when it is specified. @@ -73,3 +73,13 @@ sol = Trixi.solve(ode, ode_algorithm, # Print the timer summary summary_callback() + +function construct_b_vector(b_unknown, num_stages_embedded, num_stage_evals_embedded) + # Construct the b vector + b = [1 - sum(b_unknown), zeros(Float64, num_stages_embedded - num_stage_evals_embedded)..., b_unknown..., 0] + return b +end + +b = construct_b_vector(ode_algorithm.b, ode_algorithm.num_stages - 1, ode_algorithm.num_stage_evals - 1) +println("dot(b, c) = ", dot(b, ode_algorithm.c)) +println("sum(b) = ", sum(b)) \ No newline at end of file diff --git a/ext/TrixiConvexClarabelExt.jl b/ext/TrixiConvexClarabelExt.jl index ff51b05bec9..40e484d038c 100644 --- a/ext/TrixiConvexClarabelExt.jl +++ b/ext/TrixiConvexClarabelExt.jl @@ -116,7 +116,7 @@ function Trixi.solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, # Second-order constraint # Since c[1] is always 0 we can ignore the contribution of b[1] and only account for the ones from other non-zero entries of b - constraints = [b >= 0, + constraints = [b > 0, 2 * dot(b, c[(num_stages - num_stage_evals + 2):(num_stages - 1)]) == 1.0] # Use last optimal values for b in (potentially) next iteration diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index be6648d89fc..e969761d58b 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -288,6 +288,11 @@ function step!(integrator::EmbeddedPairedRK3Integrator) integrator.k1[i] = integrator.du[i] * integrator.dt end + @threaded for i in eachindex(integrator.u) + # add the contribution of the first stage + integrator.u[i] += (1 - sum(alg.b)) * integrator.k1[i] + end + # Higher stages where the weight of b in the butcher tableau is zero for stage in 2:alg.num_stage_evals - 1 # Construct current state @@ -357,10 +362,6 @@ function step!(integrator::EmbeddedPairedRK3Integrator) integrator.f(integrator.du, integrator.u_tmp, prob.p, integrator.t + alg.c[alg.num_stages] * integrator.dt) - @threaded for i in eachindex(integrator.u) - # add the contribution of the first stage - integrator.u[i] += (1 - sum(alg.b)) * integrator.k1[i] - end end # PairedExplicitRK step timer integrator.iter += 1 From e08f3e9d7c91730c1800c1f18e417ee4ecd58d26 Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 14 Oct 2024 19:58:46 +0200 Subject: [PATCH 140/160] change cfl number and now result is fine yayy --- examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl index d915ee1318a..bffd4eba375 100644 --- a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl +++ b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl @@ -43,7 +43,7 @@ analysis_interval = 100 analysis_callback = AnalysisCallback(semi, interval = analysis_interval) # The StepsizeCallback handles the re-calculation of the maximum Δt after each time step -stepsize_callback = StepsizeCallback(cfl = 2.5) +stepsize_callback = StepsizeCallback(cfl = 1.0) alive_callback = AliveCallback(alive_interval = analysis_interval) From 7fd60c77b82e16af2b9fc13ea38718a861dc8a96 Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 14 Oct 2024 20:04:49 +0200 Subject: [PATCH 141/160] change cfl number --- examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl index bffd4eba375..a7f5eb19f06 100644 --- a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl +++ b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl @@ -43,7 +43,7 @@ analysis_interval = 100 analysis_callback = AnalysisCallback(semi, interval = analysis_interval) # The StepsizeCallback handles the re-calculation of the maximum Δt after each time step -stepsize_callback = StepsizeCallback(cfl = 1.0) +stepsize_callback = StepsizeCallback(cfl = 1.5) alive_callback = AliveCallback(alive_interval = analysis_interval) From 9d56c93a046cc6e8b9cc212144ba51e95c978a7f Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 14 Oct 2024 20:45:54 +0200 Subject: [PATCH 142/160] change dt_opt to be that of b_opt and add a new example --- ...lixir_euler_source_terms_embedded_perk3.jl | 66 +++++++++++++++++++ .../elixir_advection_embedded_perk3.jl | 16 +++-- .../methods_embedded_PERK3.jl | 4 +- 3 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl diff --git a/examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl b/examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl new file mode 100644 index 00000000000..145eab169d8 --- /dev/null +++ b/examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl @@ -0,0 +1,66 @@ +# The same setup as tree_1d_dgsem/elixir_euler_source_terms.jl +# to verify the StructuredMesh implementation against TreeMesh +using Convex, ECOS, Clarabel +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleEulerEquations1D(1.4) + +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) + +coordinates_min = (0.0,) +coordinates_max = (2.0,) +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) + +############################################################################### +# 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) + + +ode_algorithm = Trixi.EmbeddedPairedRK3(10, 7, tspan, semi) +cfl_number = Trixi.calculate_cfl(ode_algorithm, ode) + +stepsize_callback = StepsizeCallback(cfl = 0.5) + +callbacks = CallbackSet(summary_callback, + alive_callback, + save_solution, + analysis_callback, + stepsize_callback) + +############################################################################### +# run the simulation + +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); +summary_callback() # print the timer summary +println("cfl_number = ", cfl_number) \ No newline at end of file diff --git a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl index a7f5eb19f06..46a2d1e7fe7 100644 --- a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl +++ b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl @@ -43,7 +43,7 @@ analysis_interval = 100 analysis_callback = AnalysisCallback(semi, interval = analysis_interval) # The StepsizeCallback handles the re-calculation of the maximum Δt after each time step -stepsize_callback = StepsizeCallback(cfl = 1.5) + alive_callback = AliveCallback(alive_interval = analysis_interval) @@ -53,11 +53,7 @@ save_solution = SaveSolutionCallback(dt = 0.1, solution_variables = cons2prim) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver -callbacks = CallbackSet(summary_callback, - alive_callback, - save_solution, - analysis_callback, - stepsize_callback) + ############################################################################### # run the simulation @@ -66,6 +62,14 @@ callbacks = CallbackSet(summary_callback, # Pass `tspan` to calculate maximum time step allowed for the bisection algorithm used # in calculating the polynomial coefficients in the ODE algorithm. ode_algorithm = Trixi.EmbeddedPairedRK3(10, 7, tspan, semi) +cfl_number = Trixi.calculate_cfl(ode_algorithm, ode) +stepsize_callback = StepsizeCallback(cfl = cfl_number) + +callbacks = CallbackSet(summary_callback, + alive_callback, + save_solution, + analysis_callback, + stepsize_callback) sol = Trixi.solve(ode, ode_algorithm, dt = 1.0, # Manual time step value, will be overwritten by the stepsize_callback when it is specified. diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index e969761d58b..ecee2455a95 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -52,14 +52,14 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, #TODO: something wrong when s = e - b, _ = solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, + b, dt_opt_b = solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, num_stages, num_stage_evals, num_stages - 1, # num_stages_embedded = num_stages - 1 num_stage_evals - 1, # num_stage_evals_embedded = num_stage_evals - 1 a_unknown, c, dtmax, dteps) - return a_matrix, b, c, dt_opt + return a_matrix, b, c, dt_opt_b end # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 From 0bce052e7fc5220e437d67c7977255cc314801e4 Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 14 Oct 2024 22:06:22 +0200 Subject: [PATCH 143/160] fix the logic of the integrator found from bound error when lower evaluation stage number is input --- .../elixir_euler_source_terms_embedded_perk3.jl | 5 +++-- .../elixir_advection_embedded_perk3.jl | 16 +++++++++------- ext/TrixiNLsolveExt.jl | 4 ++-- .../methods_embedded_PERK3.jl | 16 ++++++++-------- 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl b/examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl index 145eab169d8..c07296df888 100644 --- a/examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl +++ b/examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl @@ -45,10 +45,11 @@ save_solution = SaveSolutionCallback(interval = 100, solution_variables = cons2prim) -ode_algorithm = Trixi.EmbeddedPairedRK3(10, 7, tspan, semi) +ode_algorithm = Trixi.EmbeddedPairedRK3(10, 6, tspan, semi) cfl_number = Trixi.calculate_cfl(ode_algorithm, ode) -stepsize_callback = StepsizeCallback(cfl = 0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) # Warisa: This number is extremely small in contrast the other one from optimizing A + # I've tried using cfl of 0.5 and the error is very similar. callbacks = CallbackSet(summary_callback, alive_callback, diff --git a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl index 46a2d1e7fe7..178534d58b5 100644 --- a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl +++ b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl @@ -54,16 +54,16 @@ save_solution = SaveSolutionCallback(dt = 0.1, # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver - -############################################################################### -# run the simulation - -# Construct second order paired explicit Runge-Kutta method with 6 stages for given simulation setup. +# Construct embedded order paired explicit Runge-Kutta method with 10 stages and 7 evaluation stages for given simulation setup. # Pass `tspan` to calculate maximum time step allowed for the bisection algorithm used # in calculating the polynomial coefficients in the ODE algorithm. -ode_algorithm = Trixi.EmbeddedPairedRK3(10, 7, tspan, semi) +ode_algorithm = Trixi.EmbeddedPairedRK3(10, 6, tspan, semi) + +# Calculate the CFL number for the given ODE algorithm and ODE problem (cfl_number calculate from dt_opt of the optimization of +# b values in the Butcher tableau of the ODE algorithm). cfl_number = Trixi.calculate_cfl(ode_algorithm, ode) -stepsize_callback = StepsizeCallback(cfl = cfl_number) +stepsize_callback = StepsizeCallback(cfl = cfl_number) # Warisa: This number is very small in contrast the other one from optimizing A + # I've tried using cfl of 1.5 and the error is very similar. callbacks = CallbackSet(summary_callback, alive_callback, @@ -71,6 +71,8 @@ callbacks = CallbackSet(summary_callback, analysis_callback, stepsize_callback) +############################################################################### +# run the simulation sol = Trixi.solve(ode, ode_algorithm, dt = 1.0, # Manual time step value, will be overwritten by the stepsize_callback when it is specified. save_everystep = false, callback = callbacks); diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 4516bdcf744..ac97fedf469 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -112,8 +112,8 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, num_stage_ # and also c[i] - a[i, i-1] >= 0.0 since all coefficients should be non-negative # to avoid downwinding of numerical fluxes. is_sol_valid = all(x -> !isnan(x) && x >= 0, a_unknown) && - all(!isnan(c[i] - a_unknown[i - num_stage_evals]) && - c[i] - a_unknown[i - num_stage_evals] >= 0 for i in eachindex(c) if i > num_stage_evals) + all(!isnan(c[i] - a_unknown[i - num_stages + num_stage_evals - 2]) && + c[i] - a_unknown[i - num_stages + num_stage_evals - 2] >= 0 for i in eachindex(c) if i > num_stages - num_stage_evals + 2) if is_sol_valid return a_unknown diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index ecee2455a95..f850720ef84 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -294,7 +294,7 @@ function step!(integrator::EmbeddedPairedRK3Integrator) end # Higher stages where the weight of b in the butcher tableau is zero - for stage in 2:alg.num_stage_evals - 1 + for stage in 2:alg.num_stages - alg.num_stage_evals + 1 # Construct current state @threaded for i in eachindex(integrator.du) integrator.u_tmp[i] = integrator.u[i] + alg.c[stage] * integrator.k1[i] @@ -308,14 +308,14 @@ function step!(integrator::EmbeddedPairedRK3Integrator) end end - # k_e (k at posoition num_stage_evals) + # k_(s-e+2) # Construct current state @threaded for i in eachindex(integrator.du) - integrator.u_tmp[i] = integrator.u[i] + alg.c[alg.num_stage_evals] * integrator.k1[i] + integrator.u_tmp[i] = integrator.u[i] + alg.c[alg.num_stages - alg.num_stage_evals + 2] * integrator.k1[i] end integrator.f(integrator.du, integrator.u_tmp, prob.p, - integrator.t + alg.c[alg.num_stage_evals] * integrator.dt) + integrator.t + alg.c[alg.num_stages - alg.num_stage_evals + 2] * integrator.dt) @threaded for i in eachindex(integrator.du) integrator.k_higher[i] = integrator.du[i] * integrator.dt @@ -327,13 +327,13 @@ function step!(integrator::EmbeddedPairedRK3Integrator) end # Higher stages after num_stage_evals where b is non-zero - for stage in alg.num_stage_evals + 1:(alg.num_stages - 1) + for stage in alg.num_stages - alg.num_stage_evals + 3:(alg.num_stages - 1) # Construct current state @threaded for i in eachindex(integrator.du) integrator.u_tmp[i] = integrator.u[i] + - alg.a_matrix[stage - alg.num_stage_evals, 1] * + alg.a_matrix[stage - alg.num_stages + alg.num_stage_evals - 2, 1] * integrator.k1[i] + - alg.a_matrix[stage - alg.num_stage_evals, 2] * + alg.a_matrix[stage - alg.num_stages + alg.num_stage_evals - 2, 2] * integrator.k_higher[i] end @@ -346,7 +346,7 @@ function step!(integrator::EmbeddedPairedRK3Integrator) @threaded for i in eachindex(integrator.u) integrator.u[i] += integrator.k_higher[i] * - alg.b[stage - alg.num_stage_evals + 1] + alg.b[stage - alg.num_stages + alg.num_stage_evals - 1] end end From 44ea471bc5d25bb1365d22f9e47b87d14b8079ab Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 14 Oct 2024 22:46:03 +0200 Subject: [PATCH 144/160] add some comments --- ...lixir_euler_source_terms_embedded_perk3.jl | 16 ++++++- .../elixir_advection_embedded_perk3.jl | 3 +- .../methods_embedded_PERK3.jl | 44 +++++++++++-------- 3 files changed, 42 insertions(+), 21 deletions(-) diff --git a/examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl b/examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl index c07296df888..c3eb657eaad 100644 --- a/examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl +++ b/examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl @@ -44,7 +44,9 @@ save_solution = SaveSolutionCallback(interval = 100, save_final_solution = true, solution_variables = cons2prim) - +# Construct embedded order paired explicit Runge-Kutta method with 10 stages and 6 evaluation stages for given simulation setup. +# Pass `tspan` to calculate maximum time step allowed for the bisection algorithm used +# in calculating the polynomial coefficients in the ODE algorithm. ode_algorithm = Trixi.EmbeddedPairedRK3(10, 6, tspan, semi) cfl_number = Trixi.calculate_cfl(ode_algorithm, ode) @@ -64,4 +66,16 @@ 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); summary_callback() # print the timer summary + +# Some function defined so that I can check if the second order condition is met. This will be removed later. +function construct_b_vector(b_unknown, num_stages_embedded, num_stage_evals_embedded) + # Construct the b vector + b = [1 - sum(b_unknown), zeros(Float64, num_stages_embedded - num_stage_evals_embedded)..., b_unknown..., 0] + return b +end + +b = construct_b_vector(ode_algorithm.b, ode_algorithm.num_stages - 1, ode_algorithm.num_stage_evals - 1) +println("dot(b, c) = ", dot(b, ode_algorithm.c)) +println("sum(b) = ", sum(b)) + println("cfl_number = ", cfl_number) \ No newline at end of file diff --git a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl index 178534d58b5..9b8d02c1198 100644 --- a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl +++ b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl @@ -62,7 +62,7 @@ ode_algorithm = Trixi.EmbeddedPairedRK3(10, 6, tspan, semi) # Calculate the CFL number for the given ODE algorithm and ODE problem (cfl_number calculate from dt_opt of the optimization of # b values in the Butcher tableau of the ODE algorithm). cfl_number = Trixi.calculate_cfl(ode_algorithm, ode) -stepsize_callback = StepsizeCallback(cfl = cfl_number) # Warisa: This number is very small in contrast the other one from optimizing A +stepsize_callback = StepsizeCallback(cfl = cfl_number) # Warisa: This number is quite small in contrast the other one from optimizing A # I've tried using cfl of 1.5 and the error is very similar. callbacks = CallbackSet(summary_callback, @@ -80,6 +80,7 @@ sol = Trixi.solve(ode, ode_algorithm, # Print the timer summary summary_callback() +# Some function defined so that I can check if the second order condition is met. This will be removed later. function construct_b_vector(b_unknown, num_stages_embedded, num_stage_evals_embedded) # Construct the b vector b = [1 - sum(b_unknown), zeros(Float64, num_stages_embedded - num_stage_evals_embedded)..., b_unknown..., 0] diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index f850720ef84..e0731477152 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -51,7 +51,7 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, a_matrix[:, 2] = a_unknown - #TODO: something wrong when s = e + # Find the optimal b coeffficient from the Butcher tableau and its time step b, dt_opt_b = solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, num_stages, num_stage_evals, num_stages - 1, # num_stages_embedded = num_stages - 1 @@ -59,44 +59,51 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, a_unknown, c, dtmax, dteps) - return a_matrix, b, c, dt_opt_b + return a_matrix, b, c, dt_opt_b # Return the optimal time step from the b coefficients for testing purposes end # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 # using provided values of coefficients a in A-matrix of Butcher tableau -function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, - base_path_a_coeffs::AbstractString; +function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, + base_path_coeffs::AbstractString; cS2) # Initialize array of c c = compute_c_coeffs(num_stages, cS2) # - 2 Since First entry of A is always zero (explicit method) and second is given by c_2 (consistency) - a_coeffs_max = num_stages - 2 + coeffs_max = num_stage_evals - 2 - #TODO: Read the values from the file - b = zeros(num_stages) - - a_matrix = zeros(a_coeffs_max, 2) + a_matrix = zeros(coeffs_max, 2) a_matrix[:, 1] = c[3:end] - path_a_coeffs = joinpath(base_path_a_coeffs, - "a_" * string(num_stages) * ".txt") + b = zeros(coeffs_max) + + path_a_coeffs = joinpath(base_path_coeffs, + "a_" * string(num_stages) * "_" * string(num_stage_evals) * ".txt") + + path_b_coeffs = joinpath(base_path_coeffs, + "b_" * string(num_stages) * "_" * string(num_stage_evals) * ".txt") @assert isfile(path_a_coeffs) "Couldn't find file $path_a_coeffs" a_coeffs = readdlm(path_a_coeffs, Float64) num_a_coeffs = size(a_coeffs, 1) - @assert num_a_coeffs == a_coeffs_max + @assert num_a_coeffs == coeffs_max # Fill A-matrix in P-ERK style a_matrix[:, 1] -= a_coeffs a_matrix[:, 2] = a_coeffs + @assert isfile(path_b_coeffs) "Couldn't find file $path_b_coeffs" + b = readdlm(path_b_coeffs, Float64) + num_b_coeffs = size(b, 1) + @assert num_b_coeffs == coeffs_max + return a_matrix, b, c end @doc raw""" - EmbeddedPairedRK3(num_stages, base_path_a_coeffs::AbstractString, dt_opt; + EmbeddedPairedRK3(num_stages, base_path_coeffs::AbstractString, dt_opt; cS2 = 1.0f0) EmbeddedPairedRK3(num_stages, tspan, semi::AbstractSemidiscretization; verbose = false, cS2 = 1.0f0) @@ -105,8 +112,8 @@ end Parameters: - `num_stages` (`Int`): Number of stages in the paired explicit Runge-Kutta (P-ERK) method. - - `base_path_a_coeffs` (`AbstractString`): Path to a file containing some coefficients in the A-matrix in - the Butcher tableau of the Runge Kutta method. + - `base_path_coeffs` (`AbstractString`): Path to a file containing some coefficients in the A-matrix and a file constaining + in some coefficients in the b vector of the Butcher tableau of the Runge Kutta method. The matrix should be stored in a text file at `joinpath(base_path_a_coeffs, "a_$(num_stages).txt")` and separated by line breaks. - `dt_opt` (`Float64`): Optimal time step size for the simulation setup. - `tspan`: Time span of the simulation. @@ -141,11 +148,10 @@ end # struct EmbeddedPairedRK3 # Constructor for previously computed A Coeffs function EmbeddedPairedRK3(num_stages, num_stage_evals, - base_path_a_coeffs::AbstractString, dt_opt; + base_path_coeffs::AbstractString, dt_opt; cS2 = 1.0f0) - #TODO: Update this constructor to have num_stage_evals as well and also return correct things - a_matrix, b, c = compute_EmbeddedPairedRK3_butcher_tableau(num_stages, - base_path_a_coeffs; + a_matrix, b, c = compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, + base_path_coeffs; cS2) return EmbeddedPairedRK3(num_stages, num_stage_evals, a_matrix, b, c, dt_opt) From 810a0a14ab11249bf60881b4d1f733eb2607bded Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 14 Oct 2024 22:49:23 +0200 Subject: [PATCH 145/160] fmt --- ...lixir_euler_source_terms_embedded_perk3.jl | 20 ++++++--- .../elixir_advection_embedded_perk3.jl | 15 ++++--- ext/TrixiNLsolveExt.jl | 10 +++-- .../methods_embedded_PERK3.jl | 43 +++++++++++-------- 4 files changed, 54 insertions(+), 34 deletions(-) diff --git a/examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl b/examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl index c3eb657eaad..28b93a83b8f 100644 --- a/examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl +++ b/examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl @@ -51,8 +51,8 @@ ode_algorithm = Trixi.EmbeddedPairedRK3(10, 6, tspan, semi) cfl_number = Trixi.calculate_cfl(ode_algorithm, ode) stepsize_callback = StepsizeCallback(cfl = 0.5) # Warisa: This number is extremely small in contrast the other one from optimizing A - # I've tried using cfl of 0.5 and the error is very similar. - +# I've tried using cfl of 0.5 and the error is very similar. + callbacks = CallbackSet(summary_callback, alive_callback, save_solution, @@ -63,19 +63,25 @@ callbacks = CallbackSet(summary_callback, # run the simulation 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 # Some function defined so that I can check if the second order condition is met. This will be removed later. function construct_b_vector(b_unknown, num_stages_embedded, num_stage_evals_embedded) # Construct the b vector - b = [1 - sum(b_unknown), zeros(Float64, num_stages_embedded - num_stage_evals_embedded)..., b_unknown..., 0] + b = [ + 1 - sum(b_unknown), + zeros(Float64, num_stages_embedded - num_stage_evals_embedded)..., + b_unknown..., + 0 + ] return b end -b = construct_b_vector(ode_algorithm.b, ode_algorithm.num_stages - 1, ode_algorithm.num_stage_evals - 1) +b = construct_b_vector(ode_algorithm.b, ode_algorithm.num_stages - 1, + ode_algorithm.num_stage_evals - 1) println("dot(b, c) = ", dot(b, ode_algorithm.c)) println("sum(b) = ", sum(b)) -println("cfl_number = ", cfl_number) \ No newline at end of file +println("cfl_number = ", cfl_number) diff --git a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl index 9b8d02c1198..6e280ba0916 100644 --- a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl +++ b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl @@ -44,7 +44,6 @@ analysis_callback = AnalysisCallback(semi, interval = analysis_interval) # The StepsizeCallback handles the re-calculation of the maximum Δt after each time step - alive_callback = AliveCallback(alive_interval = analysis_interval) save_solution = SaveSolutionCallback(dt = 0.1, @@ -63,7 +62,7 @@ ode_algorithm = Trixi.EmbeddedPairedRK3(10, 6, tspan, semi) # b values in the Butcher tableau of the ODE algorithm). cfl_number = Trixi.calculate_cfl(ode_algorithm, ode) stepsize_callback = StepsizeCallback(cfl = cfl_number) # Warisa: This number is quite small in contrast the other one from optimizing A - # I've tried using cfl of 1.5 and the error is very similar. +# I've tried using cfl of 1.5 and the error is very similar. callbacks = CallbackSet(summary_callback, alive_callback, @@ -83,10 +82,16 @@ summary_callback() # Some function defined so that I can check if the second order condition is met. This will be removed later. function construct_b_vector(b_unknown, num_stages_embedded, num_stage_evals_embedded) # Construct the b vector - b = [1 - sum(b_unknown), zeros(Float64, num_stages_embedded - num_stage_evals_embedded)..., b_unknown..., 0] + b = [ + 1 - sum(b_unknown), + zeros(Float64, num_stages_embedded - num_stage_evals_embedded)..., + b_unknown..., + 0 + ] return b end -b = construct_b_vector(ode_algorithm.b, ode_algorithm.num_stages - 1, ode_algorithm.num_stage_evals - 1) +b = construct_b_vector(ode_algorithm.b, ode_algorithm.num_stages - 1, + ode_algorithm.num_stage_evals - 1) println("dot(b, c) = ", dot(b, ode_algorithm.c)) -println("sum(b) = ", sum(b)) \ No newline at end of file +println("sum(b) = ", sum(b)) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index ac97fedf469..b7f1394bf3e 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -73,7 +73,8 @@ end # non-linear equations that arise from the relation of the stability polynomial to the Butcher tableau. # For details, see Proposition 3.2, Equation (3.3) from # Hairer, Wanner: Solving Ordinary Differential Equations 2 -function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, num_stage_evals, monomial_coeffs, +function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, num_stage_evals, + monomial_coeffs, c_s2, c; verbose, max_iter = 100000) @@ -112,8 +113,11 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, num_stage_ # and also c[i] - a[i, i-1] >= 0.0 since all coefficients should be non-negative # to avoid downwinding of numerical fluxes. is_sol_valid = all(x -> !isnan(x) && x >= 0, a_unknown) && - all(!isnan(c[i] - a_unknown[i - num_stages + num_stage_evals - 2]) && - c[i] - a_unknown[i - num_stages + num_stage_evals - 2] >= 0 for i in eachindex(c) if i > num_stages - num_stage_evals + 2) + all(!isnan(c[i] - + a_unknown[i - num_stages + num_stage_evals - 2]) && + c[i] - a_unknown[i - num_stages + num_stage_evals - 2] >= 0 + for i in eachindex(c) + if i > num_stages - num_stage_evals + 2) if is_sol_valid return a_unknown diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index e0731477152..f0e7ed823a3 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -46,18 +46,16 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, end # Fill A-matrix in P-ERK style a_matrix = zeros(num_stage_evals - 2, 2) - a_matrix[:, 1] = c[num_stages - num_stage_evals + 3:end] # issue + a_matrix[:, 1] = c[(num_stages - num_stage_evals + 3):end] # issue a_matrix[:, 1] -= a_unknown a_matrix[:, 2] = a_unknown - # Find the optimal b coeffficient from the Butcher tableau and its time step b, dt_opt_b = solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, - num_stages, num_stage_evals, - num_stages - 1, # num_stages_embedded = num_stages - 1 - num_stage_evals - 1, # num_stage_evals_embedded = num_stage_evals - 1 - a_unknown, c, dtmax, dteps) - + num_stages, num_stage_evals, + num_stages - 1, # num_stages_embedded = num_stages - 1 + num_stage_evals - 1, # num_stage_evals_embedded = num_stage_evals - 1 + a_unknown, c, dtmax, dteps) return a_matrix, b, c, dt_opt_b # Return the optimal time step from the b coefficients for testing purposes end @@ -80,10 +78,12 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, b = zeros(coeffs_max) path_a_coeffs = joinpath(base_path_coeffs, - "a_" * string(num_stages) * "_" * string(num_stage_evals) * ".txt") + "a_" * string(num_stages) * "_" * string(num_stage_evals) * + ".txt") path_b_coeffs = joinpath(base_path_coeffs, - "b_" * string(num_stages) * "_" * string(num_stage_evals) * ".txt") + "b_" * string(num_stages) * "_" * string(num_stage_evals) * + ".txt") @assert isfile(path_a_coeffs) "Couldn't find file $path_a_coeffs" a_coeffs = readdlm(path_a_coeffs, Float64) @@ -150,7 +150,8 @@ end # struct EmbeddedPairedRK3 function EmbeddedPairedRK3(num_stages, num_stage_evals, base_path_coeffs::AbstractString, dt_opt; cS2 = 1.0f0) - a_matrix, b, c = compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, + a_matrix, b, c = compute_EmbeddedPairedRK3_butcher_tableau(num_stages, + num_stage_evals, base_path_coeffs; cS2) @@ -300,14 +301,14 @@ function step!(integrator::EmbeddedPairedRK3Integrator) end # Higher stages where the weight of b in the butcher tableau is zero - for stage in 2:alg.num_stages - alg.num_stage_evals + 1 + for stage in 2:(alg.num_stages - alg.num_stage_evals + 1) # Construct current state @threaded for i in eachindex(integrator.du) integrator.u_tmp[i] = integrator.u[i] + alg.c[stage] * integrator.k1[i] end integrator.f(integrator.du, integrator.u_tmp, prob.p, - integrator.t + alg.c[stage] * integrator.dt) + integrator.t + alg.c[stage] * integrator.dt) @threaded for i in eachindex(integrator.du) integrator.k_higher[i] = integrator.du[i] * integrator.dt @@ -317,11 +318,14 @@ function step!(integrator::EmbeddedPairedRK3Integrator) # k_(s-e+2) # Construct current state @threaded for i in eachindex(integrator.du) - integrator.u_tmp[i] = integrator.u[i] + alg.c[alg.num_stages - alg.num_stage_evals + 2] * integrator.k1[i] + integrator.u_tmp[i] = integrator.u[i] + + alg.c[alg.num_stages - alg.num_stage_evals + 2] * + integrator.k1[i] end integrator.f(integrator.du, integrator.u_tmp, prob.p, - integrator.t + alg.c[alg.num_stages - alg.num_stage_evals + 2] * integrator.dt) + integrator.t + + alg.c[alg.num_stages - alg.num_stage_evals + 2] * integrator.dt) @threaded for i in eachindex(integrator.du) integrator.k_higher[i] = integrator.du[i] * integrator.dt @@ -333,16 +337,18 @@ function step!(integrator::EmbeddedPairedRK3Integrator) end # Higher stages after num_stage_evals where b is non-zero - for stage in alg.num_stages - alg.num_stage_evals + 3:(alg.num_stages - 1) + for stage in (alg.num_stages - alg.num_stage_evals + 3):(alg.num_stages - 1) # Construct current state @threaded for i in eachindex(integrator.du) integrator.u_tmp[i] = integrator.u[i] + - alg.a_matrix[stage - alg.num_stages + alg.num_stage_evals - 2, 1] * + alg.a_matrix[stage - alg.num_stages + alg.num_stage_evals - 2, + 1] * integrator.k1[i] + - alg.a_matrix[stage - alg.num_stages + alg.num_stage_evals - 2, 2] * + alg.a_matrix[stage - alg.num_stages + alg.num_stage_evals - 2, + 2] * integrator.k_higher[i] end - + integrator.f(integrator.du, integrator.u_tmp, prob.p, integrator.t + alg.c[stage] * integrator.dt) @@ -367,7 +373,6 @@ function step!(integrator::EmbeddedPairedRK3Integrator) integrator.f(integrator.du, integrator.u_tmp, prob.p, integrator.t + alg.c[alg.num_stages] * integrator.dt) - end # PairedExplicitRK step timer integrator.iter += 1 From 7cce9b6c71a950ce47f275549bff80da80423b6d Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 14 Oct 2024 22:50:26 +0200 Subject: [PATCH 146/160] change back to silent instead of silent_solver --- ext/TrixiConvexClarabelExt.jl | 2 +- ext/TrixiConvexECOSExt.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/TrixiConvexClarabelExt.jl b/ext/TrixiConvexClarabelExt.jl index 40e484d038c..3da405603e3 100644 --- a/ext/TrixiConvexClarabelExt.jl +++ b/ext/TrixiConvexClarabelExt.jl @@ -145,7 +145,7 @@ function Trixi.solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, solve!(problem, MOI.OptimizerWithAttributes(Optimizer, "tol_feas" => 1e-12); - silent_solver = false) + silent = false) abs_p = problem.optval diff --git a/ext/TrixiConvexECOSExt.jl b/ext/TrixiConvexECOSExt.jl index 0a5b4c44c5d..8251fe3eed9 100644 --- a/ext/TrixiConvexECOSExt.jl +++ b/ext/TrixiConvexECOSExt.jl @@ -136,7 +136,7 @@ function Trixi.bisect_stability_polynomial(consistency_order, num_eig_vals, "reltol_inacc" => 5e-5, "nitref" => 9, "maxit" => 100, - "verbose" => 3); silent_solver = true) + "verbose" => 3); silent = true) abs_p = problem.optval From e21e19973bf553e1245eeccd993e7a78a39d316e Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 14 Oct 2024 23:13:00 +0200 Subject: [PATCH 147/160] try some other s and e for euler's case --- .../elixir_euler_source_terms_embedded_perk3.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl b/examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl index 28b93a83b8f..a30089b68c5 100644 --- a/examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl +++ b/examples/structured_1d_dgsem/elixir_euler_source_terms_embedded_perk3.jl @@ -47,7 +47,7 @@ save_solution = SaveSolutionCallback(interval = 100, # Construct embedded order paired explicit Runge-Kutta method with 10 stages and 6 evaluation stages for given simulation setup. # Pass `tspan` to calculate maximum time step allowed for the bisection algorithm used # in calculating the polynomial coefficients in the ODE algorithm. -ode_algorithm = Trixi.EmbeddedPairedRK3(10, 6, tspan, semi) +ode_algorithm = Trixi.EmbeddedPairedRK3(10, 7, tspan, semi) cfl_number = Trixi.calculate_cfl(ode_algorithm, ode) stepsize_callback = StepsizeCallback(cfl = 0.5) # Warisa: This number is extremely small in contrast the other one from optimizing A From c0e0ded8adc302b1cacc9b6bcacf11d490fba634 Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 15 Oct 2024 16:19:32 +0200 Subject: [PATCH 148/160] correct some spelling --- .../paired_explicit_runge_kutta/methods_embedded_PERK3.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index f0e7ed823a3..1809a4c6092 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -112,7 +112,7 @@ end Parameters: - `num_stages` (`Int`): Number of stages in the paired explicit Runge-Kutta (P-ERK) method. - - `base_path_coeffs` (`AbstractString`): Path to a file containing some coefficients in the A-matrix and a file constaining + - `base_path_coeffs` (`AbstractString`): Path to a file containing some coefficients in the A-matrix and a file containing in some coefficients in the b vector of the Butcher tableau of the Runge Kutta method. The matrix should be stored in a text file at `joinpath(base_path_a_coeffs, "a_$(num_stages).txt")` and separated by line breaks. - `dt_opt` (`Float64`): Optimal time step size for the simulation setup. From 280ddf1ad52a278d0073983b8acaea1b3c90e142 Mon Sep 17 00:00:00 2001 From: Warisa Date: Thu, 17 Oct 2024 20:06:12 +0200 Subject: [PATCH 149/160] include normalization --- ext/TrixiConvexClarabelExt.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/TrixiConvexClarabelExt.jl b/ext/TrixiConvexClarabelExt.jl index 3da405603e3..edeb5e8bc18 100644 --- a/ext/TrixiConvexClarabelExt.jl +++ b/ext/TrixiConvexClarabelExt.jl @@ -90,11 +90,11 @@ function Trixi.solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, normalized_powered_eigvals = zeros(Complex{Float64}, num_eig_vals, num_stage_evals) for j in 1:num_stage_evals - #fac_j = factorial(j) + fac_j = factorial(j) for i in 1:num_eig_vals - #normalized_powered_eigvals[i, j] = eig_vals[i]^j / fac_j + normalized_powered_eigvals[i, j] = eig_vals[i]^j / fac_j # Try first without factorial normalization - normalized_powered_eigvals[i, j] = eig_vals[i]^j + #normalized_powered_eigvals[i, j] = eig_vals[i]^j end end @@ -145,7 +145,7 @@ function Trixi.solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, solve!(problem, MOI.OptimizerWithAttributes(Optimizer, "tol_feas" => 1e-12); - silent = false) + silent_solver = true) abs_p = problem.optval From bd9496922fd987b2d52b7e65e95bad99328f719b Mon Sep 17 00:00:00 2001 From: Warisa Date: Thu, 17 Oct 2024 21:27:28 +0200 Subject: [PATCH 150/160] fix some bug with normalized_powered_eigvals allocation and loop --- ext/TrixiConvexClarabelExt.jl | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/ext/TrixiConvexClarabelExt.jl b/ext/TrixiConvexClarabelExt.jl index edeb5e8bc18..b7487d111ee 100644 --- a/ext/TrixiConvexClarabelExt.jl +++ b/ext/TrixiConvexClarabelExt.jl @@ -87,14 +87,14 @@ function Trixi.solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, # There are e - 2 free variables for the stability polynomial of the embedded scheme b = Variable(num_stage_evals - 2) - normalized_powered_eigvals = zeros(Complex{Float64}, num_eig_vals, num_stage_evals) + normalized_powered_eigvals = zeros(Complex{Float64}, num_eig_vals, num_stage_evals-1) - for j in 1:num_stage_evals - fac_j = factorial(j) + for j in 1:num_stage_evals-1 + #fac_j = factorial(j) for i in 1:num_eig_vals - normalized_powered_eigvals[i, j] = eig_vals[i]^j / fac_j + #normalized_powered_eigvals[i, j] = eig_vals[i]^j / fac_j # Try first without factorial normalization - #normalized_powered_eigvals[i, j] = eig_vals[i]^j + normalized_powered_eigvals[i, j] = eig_vals[i]^j end end @@ -105,7 +105,7 @@ function Trixi.solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, dt = 0.5 * (dtmax + dtmin) # Compute stability polynomial for current timestep - for k in 1:num_stage_evals + for k in 1:num_stage_evals-1 dt_k = dt^k for i in 1:num_eig_vals normalized_powered_eigvals_scaled[i, k] = dt_k * @@ -116,7 +116,7 @@ function Trixi.solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, # Second-order constraint # Since c[1] is always 0 we can ignore the contribution of b[1] and only account for the ones from other non-zero entries of b - constraints = [b > 0, + constraints = [b >= 0, 2 * dot(b, c[(num_stages - num_stage_evals + 2):(num_stages - 1)]) == 1.0] # Use last optimal values for b in (potentially) next iteration @@ -126,10 +126,10 @@ function Trixi.solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, normalized_powered_eigvals_scaled, a, b, c), constraints) - #= + #= solve!(problem, # Parameters taken from default values for EiCOS - Convex.MOI.OptimizerWithAttributes(ECOS.Optimizer, "b" => 0.99, + MOI.OptimizerWithAttributes(Optimizer, "b" => 0.99, "delta" => 2e-7, "feastol" => 1e-9, "abstol" => 1e-9, @@ -139,14 +139,17 @@ function Trixi.solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, "reltol_inacc" => 5e-5, "nitref" => 9, "maxit" => 100, - "verbose" => 3); silent_solver = false) + "verbose" => 3); silent_solver = true) =# + solve!(problem, MOI.OptimizerWithAttributes(Optimizer, - "tol_feas" => 1e-12); + "tol_feas" => 1e-4); silent_solver = true) - + + print("dt: ", dt, "\n") + print("Problem value: ", problem.optval, "\n") abs_p = problem.optval if abs_p < 1 From 3b028680e68d6b84a06553434d270eb84c8394b8 Mon Sep 17 00:00:00 2001 From: Warisa Date: Thu, 17 Oct 2024 21:28:05 +0200 Subject: [PATCH 151/160] since now dt_opt doesnt exist. Just use cfl of constant as a makeshift wavlue --- .../elixir_advection_embedded_perk3.jl | 10 +++++++--- .../methods_embedded_PERK3.jl | 17 +++++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl index 6e280ba0916..0d1135ff4cd 100644 --- a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl +++ b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl @@ -56,12 +56,12 @@ save_solution = SaveSolutionCallback(dt = 0.1, # Construct embedded order paired explicit Runge-Kutta method with 10 stages and 7 evaluation stages for given simulation setup. # Pass `tspan` to calculate maximum time step allowed for the bisection algorithm used # in calculating the polynomial coefficients in the ODE algorithm. -ode_algorithm = Trixi.EmbeddedPairedRK3(10, 6, tspan, semi) +ode_algorithm = Trixi.EmbeddedPairedRK3(10, 10, tspan, semi) # Calculate the CFL number for the given ODE algorithm and ODE problem (cfl_number calculate from dt_opt of the optimization of # b values in the Butcher tableau of the ODE algorithm). -cfl_number = Trixi.calculate_cfl(ode_algorithm, ode) -stepsize_callback = StepsizeCallback(cfl = cfl_number) # Warisa: This number is quite small in contrast the other one from optimizing A +#cfl_number = Trixi.calculate_cfl(ode_algorithm, ode) +stepsize_callback = StepsizeCallback(cfl = 0.75) # Warisa: This number is quite small in contrast the other one from optimizing A # I've tried using cfl of 1.5 and the error is very similar. callbacks = CallbackSet(summary_callback, @@ -95,3 +95,7 @@ b = construct_b_vector(ode_algorithm.b, ode_algorithm.num_stages - 1, ode_algorithm.num_stage_evals - 1) println("dot(b, c) = ", dot(b, ode_algorithm.c)) println("sum(b) = ", sum(b)) + +println("dt_opt_a = ", ode_algorithm.dt_opt_a) +println("dt_opt_b = ", ode_algorithm.dt_opt_b) +println("ratio = ", ode_algorithm.dt_opt_b / ode_algorithm.dt_opt_a * 100) \ No newline at end of file diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index 1809a4c6092..e9a64bd4c19 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -29,7 +29,7 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, num_eig_vals, eig_vals = filter_eig_vals(eig_vals; verbose) - monomial_coeffs, dt_opt = bisect_stability_polynomial(consistency_order, + monomial_coeffs, dt_opt_a = bisect_stability_polynomial(consistency_order, num_eig_vals, num_stages, dtmax, dteps, eig_vals; verbose) @@ -46,7 +46,7 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, end # Fill A-matrix in P-ERK style a_matrix = zeros(num_stage_evals - 2, 2) - a_matrix[:, 1] = c[(num_stages - num_stage_evals + 3):end] # issue + a_matrix[:, 1] = c[(num_stages - num_stage_evals + 3):end] a_matrix[:, 1] -= a_unknown a_matrix[:, 2] = a_unknown @@ -57,7 +57,7 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, num_stage_evals - 1, # num_stage_evals_embedded = num_stage_evals - 1 a_unknown, c, dtmax, dteps) - return a_matrix, b, c, dt_opt_b # Return the optimal time step from the b coefficients for testing purposes + return a_matrix, b, c, dt_opt_a, dt_opt_b # Return the optimal time step from the b coefficients for testing purposes end # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 @@ -143,19 +143,20 @@ mutable struct EmbeddedPairedRK3 <: AbstractPairedExplicitRKSingle a_matrix::Matrix{Float64} b::Vector{Float64} c::Vector{Float64} - dt_opt::Float64 + dt_opt_a::Float64 + dt_opt_b::Float64 end # struct EmbeddedPairedRK3 # Constructor for previously computed A Coeffs function EmbeddedPairedRK3(num_stages, num_stage_evals, - base_path_coeffs::AbstractString, dt_opt; + base_path_coeffs::AbstractString, dt_opt_a, dt_opt_b; cS2 = 1.0f0) a_matrix, b, c = compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, base_path_coeffs; cS2) - return EmbeddedPairedRK3(num_stages, num_stage_evals, a_matrix, b, c, dt_opt) + return EmbeddedPairedRK3(num_stages, num_stage_evals, a_matrix, b, c, dt_opt_a, dt_opt_b) end # Constructor that computes Butcher matrix A coefficients from a semidiscretization @@ -171,12 +172,12 @@ end function EmbeddedPairedRK3(num_stages, num_stage_evals, tspan, eig_vals::Vector{ComplexF64}; verbose = false, cS2 = 1.0f0) - a_matrix, b, c, dt_opt = compute_EmbeddedPairedRK3_butcher_tableau(num_stages, + a_matrix, b, c, dt_opt_a, dt_opt_b = compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, tspan, eig_vals; verbose, cS2) - return EmbeddedPairedRK3(num_stages, num_stage_evals, a_matrix, b, c, dt_opt) + return EmbeddedPairedRK3(num_stages, num_stage_evals, a_matrix, b, c, dt_opt_a, dt_opt_b) end # This struct is needed to fake https://github.com/SciML/OrdinaryDiffEq.jl/blob/0c2048a502101647ac35faabd80da8a5645beac7/src/integrators/type.jl#L77 From 92a1f8499b9e6aa2b5010de0bda580665e7731fc Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 21 Oct 2024 20:49:21 +0200 Subject: [PATCH 152/160] change up the approach to the problem --- .../elixir_advection_embedded_perk3.jl | 4 +- ext/TrixiConvexClarabelExt.jl | 2 +- ext/TrixiConvexECOSExt.jl | 2 +- ext/TrixiNLsolveExt.jl | 83 +++++++++++++++++++ .../methods_embedded_PERK3.jl | 30 +++++-- .../paired_explicit_runge_kutta.jl | 2 +- 6 files changed, 109 insertions(+), 14 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl index 0d1135ff4cd..74a6ba74fb2 100644 --- a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl +++ b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl @@ -1,7 +1,7 @@ # Convex and ECOS are imported because they are used for finding the optimal time step and optimal # monomial coefficients in the stability polynomial of P-ERK time integrators. -using Convex, ECOS, Clarabel +using Convex, ECOS using OrdinaryDiffEq using Trixi @@ -56,7 +56,7 @@ save_solution = SaveSolutionCallback(dt = 0.1, # Construct embedded order paired explicit Runge-Kutta method with 10 stages and 7 evaluation stages for given simulation setup. # Pass `tspan` to calculate maximum time step allowed for the bisection algorithm used # in calculating the polynomial coefficients in the ODE algorithm. -ode_algorithm = Trixi.EmbeddedPairedRK3(10, 10, tspan, semi) +ode_algorithm = Trixi.EmbeddedPairedRK3(10, 6, tspan, semi) # Calculate the CFL number for the given ODE algorithm and ODE problem (cfl_number calculate from dt_opt of the optimization of # b values in the Butcher tableau of the ODE algorithm). diff --git a/ext/TrixiConvexClarabelExt.jl b/ext/TrixiConvexClarabelExt.jl index b7487d111ee..bedc05031f7 100644 --- a/ext/TrixiConvexClarabelExt.jl +++ b/ext/TrixiConvexClarabelExt.jl @@ -64,7 +64,7 @@ function embedded_scheme_stability_polynomials!(pnoms, return maximum(abs(pnoms)) end -function Trixi.solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, +function solve_b_butcher_coeffs_unknown_new(num_eig_vals, eig_vals, num_stages, num_stage_evals, num_stages_embedded, num_stage_evals_embedded, diff --git a/ext/TrixiConvexECOSExt.jl b/ext/TrixiConvexECOSExt.jl index 8251fe3eed9..0a5b4c44c5d 100644 --- a/ext/TrixiConvexECOSExt.jl +++ b/ext/TrixiConvexECOSExt.jl @@ -136,7 +136,7 @@ function Trixi.bisect_stability_polynomial(consistency_order, num_eig_vals, "reltol_inacc" => 5e-5, "nitref" => 9, "maxit" => 100, - "verbose" => 3); silent = true) + "verbose" => 3); silent_solver = true) abs_p = problem.optval diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index b7f1394bf3e..fca975db3ba 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -10,6 +10,9 @@ else using ..NLsolve: nlsolve end +# Use other necessary libraries for the dot product in finding b_unknown +using LinearAlgebra: dot + # We use a random initialization of the nonlinear solver. # To make the tests reproducible, we need to seed the RNG using StableRNGs: StableRNG, rand @@ -69,6 +72,43 @@ function PairedExplicitRK3_butcher_tableau_objective_function!(c_eq, a_unknown, a_coeff[num_stage_evals - 1] end +function EmbeddedPairedExplicitRK3_butcher_tableau_objective_function!(b_eq, x, + num_stages, + num_stage_evals, + embedded_monomial_coeffs, + c, a) + + # Construct a full b coefficient vector + b_coeff = [ + 1 - sum(x), + zeros(Float64, num_stages - num_stage_evals)..., + x..., + 0 + ] + + b_eq_count = 0 + + #TODO: check the logic of this loop cos b is getting absurdly large + for i in 3:num_stage_evals-1 + sum = 0.0 + for j in (i + num_stages - num_stage_evals):num_stages-1 + prod = 1.0 + for k in (3 + j - i):j + prod *= a[k] + end + sum += prod * b_coeff[j] * c[j - i + 2] + end + b_eq[i-2] = embedded_monomial_coeffs[i-2] - sum + b_eq_count += 1 + end + + # TODO: there is a more efficient way to compute the dot product for sure... + b_eq[num_stage_evals-2] = 0.5 - dot(b_coeff, c) + b_eq_count += 1 + + println("b_eq_count: ", b_eq_count) # Debugging +end + # Find the values of the a_{i, i-1} in the Butcher tableau matrix A by solving a system of # non-linear equations that arise from the relation of the stability polynomial to the Butcher tableau. # For details, see Proposition 3.2, Equation (3.3) from @@ -130,6 +170,49 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, num_stage_ error("Maximum number of iterations ($max_iter) reached. Cannot find valid sets of coefficients.") end + +function Trixi.solve_b_butcher_coeffs_unknown!(b_unknown, num_stages, num_stage_evals, embedded_monomial_coeffs, c, a_unknown; + verbose, max_iter = 100000) + + # Construct a full a coefficient vector + a = zeros(num_stages) + num_a_unknown = length(a_unknown) + + for i in 1:num_a_unknown + a[num_stages - i + 1] = a_unknown[num_a_unknown - i + 1] + end + + # Define the objective_function + function embedded_scheme_objective_function!(b_eq, x) + return EmbeddedPairedExplicitRK3_butcher_tableau_objective_function!(b_eq, x, + num_stages, + num_stage_evals, + embedded_monomial_coeffs, + c, a) + end + + # RealT is determined as the type of the first element in monomial_coeffs to ensure type consistency + RealT = typeof(embedded_monomial_coeffs[1]) + + # To ensure consistency and reproducibility of results across runs, we use + # a seeded random initial guess. + rng = StableRNG(55555) + + # Due to the nature of the nonlinear solver, different initial guesses can lead to + # small numerical differences in the solution. + + # There is e-2 free variables of b of the embedded scheme + x0 = convert(RealT, 0.1) .* rand(rng, RealT, num_stage_evals - 2) + + sol = nlsolve(embedded_scheme_objective_function!, x0, method = :newton, + ftol = 4.0e-16, # Enforce objective up to machine precision + iterations = 10^4, xtol = 1.0e-13, autodiff = :forward) + + b_unknown = sol.zero # Retrieve solution (root = zero) + + + return b_unknown +end end # @muladd end # module TrixiNLsolveExt diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index e9a64bd4c19..2fb6d118f3a 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -17,6 +17,7 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, # Initialize the array of our solution a_unknown = zeros(num_stage_evals - 2) + b_unknown = zeros(num_stage_evals - 2) # Special case of e = 3 if num_stage_evals == 3 @@ -30,11 +31,18 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, num_eig_vals, eig_vals = filter_eig_vals(eig_vals; verbose) monomial_coeffs, dt_opt_a = bisect_stability_polynomial(consistency_order, - num_eig_vals, num_stages, + num_eig_vals, num_stage_evals, dtmax, dteps, eig_vals; verbose) monomial_coeffs = undo_normalization!(monomial_coeffs, consistency_order, - num_stages) + num_stage_evals) + + embedded_monomial_coeffs, dt_opt_b = bisect_stability_polynomial(consistency_order-1, + num_eig_vals, num_stage_evals-1, + dtmax, dteps, + eig_vals; verbose) + + embedded_monomial_coeffs = undo_normalization!(embedded_monomial_coeffs, consistency_order, num_stage_evals-1) # Solve the nonlinear system of equations from monomial coefficient and # Butcher array abscissae c to find Butcher matrix A @@ -43,6 +51,17 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, num_stage_evals, monomial_coeffs, cS2, c; verbose) + + println("dt_opt_b = ", dt_opt_b) + + b_unknown = Trixi.solve_b_butcher_coeffs_unknown!(b_unknown, num_stages, num_stage_evals, embedded_monomial_coeffs, c, a_unknown; verbose) + + println("Embedded monomial after normalization: ", embedded_monomial_coeffs) + println("This is b_unknown = ",b_unknown) + println("dt_opt_a = ", dt_opt_a) + + + error("Stability polynomial optimization process is complete.") end # Fill A-matrix in P-ERK style a_matrix = zeros(num_stage_evals - 2, 2) @@ -50,13 +69,6 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, a_matrix[:, 1] -= a_unknown a_matrix[:, 2] = a_unknown - # Find the optimal b coeffficient from the Butcher tableau and its time step - b, dt_opt_b = solve_b_butcher_coeffs_unknown(num_eig_vals, eig_vals, - num_stages, num_stage_evals, - num_stages - 1, # num_stages_embedded = num_stages - 1 - num_stage_evals - 1, # num_stage_evals_embedded = num_stage_evals - 1 - a_unknown, c, dtmax, dteps) - return a_matrix, b, c, dt_opt_a, dt_opt_b # Return the optimal time step from the b coefficients for testing purposes end diff --git a/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl b/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl index 00b164b87d3..52d2d307db7 100644 --- a/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl +++ b/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl @@ -16,5 +16,5 @@ include("polynomial_optimizer.jl") # such that hey can be exported from Trixi.jl and extended in the TrixiConvexECOSExt package # extension or by the NLsolve-specific code loaded by Requires.jl function solve_a_butcher_coeffs_unknown! end -function solve_b_butcher_coeffs_unknown end +function solve_b_butcher_coeffs_unknown! end end # @muladd From 2ef2e0acb277e20589460d28e57045dc013f1957 Mon Sep 17 00:00:00 2001 From: Warisa Date: Mon, 21 Oct 2024 21:11:48 +0200 Subject: [PATCH 153/160] something wrong with b values... will have to reconstruct that part again from the stability polynomial in TrixiNLsolveExt --- ext/TrixiNLsolveExt.jl | 31 +++++++++++++------ .../methods_embedded_PERK3.jl | 7 ++--- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index fca975db3ba..319134e3700 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -86,19 +86,23 @@ function EmbeddedPairedExplicitRK3_butcher_tableau_objective_function!(b_eq, x, 0 ] + println("Length of b_coeff") + println(length(b_coeff)) # Debugging + b_eq_count = 0 #TODO: check the logic of this loop cos b is getting absurdly large for i in 3:num_stage_evals-1 sum = 0.0 + fac_i = factorial(i) for j in (i + num_stages - num_stage_evals):num_stages-1 prod = 1.0 for k in (3 + j - i):j prod *= a[k] end - sum += prod * b_coeff[j] * c[j - i + 2] + sum += prod * b_coeff[j] * c[j - i + 2] end - b_eq[i-2] = embedded_monomial_coeffs[i-2] - sum + b_eq[i-2] = embedded_monomial_coeffs[i-2] - sum * fac_i b_eq_count += 1 end @@ -174,6 +178,8 @@ end function Trixi.solve_b_butcher_coeffs_unknown!(b_unknown, num_stages, num_stage_evals, embedded_monomial_coeffs, c, a_unknown; verbose, max_iter = 100000) + verbose = true + # Construct a full a coefficient vector a = zeros(num_stages) num_a_unknown = length(a_unknown) @@ -201,17 +207,22 @@ function Trixi.solve_b_butcher_coeffs_unknown!(b_unknown, num_stages, num_stage_ # Due to the nature of the nonlinear solver, different initial guesses can lead to # small numerical differences in the solution. - # There is e-2 free variables of b of the embedded scheme - x0 = convert(RealT, 0.1) .* rand(rng, RealT, num_stage_evals - 2) + for _ in 1:max_iter + + # There is e-2 free variables of b of the embedded scheme + x0 = convert(RealT, 0.1) .* rand(rng, RealT, num_stage_evals - 2) + + sol = nlsolve(embedded_scheme_objective_function!, x0, method = :trust_region, + ftol = 4.0e-16, # Enforce objective up to machine precision + iterations = 10^4, xtol = 1.0e-13, autodiff = :forward) - sol = nlsolve(embedded_scheme_objective_function!, x0, method = :newton, - ftol = 4.0e-16, # Enforce objective up to machine precision - iterations = 10^4, xtol = 1.0e-13, autodiff = :forward) + b_unknown = sol.zero # Retrieve solution (root = zero) - b_unknown = sol.zero # Retrieve solution (root = zero) + is_sol_valid = all(x -> !isnan(x) && x >= 0, b_unknown) && (sum(b_unknown) <= 1.0) - - return b_unknown + return b_unknown + + end end end # @muladd diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index 2fb6d118f3a..0b00b1bf364 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -17,7 +17,7 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, # Initialize the array of our solution a_unknown = zeros(num_stage_evals - 2) - b_unknown = zeros(num_stage_evals - 2) + b = zeros(num_stage_evals - 2) # Special case of e = 3 if num_stage_evals == 3 @@ -54,14 +54,13 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, println("dt_opt_b = ", dt_opt_b) - b_unknown = Trixi.solve_b_butcher_coeffs_unknown!(b_unknown, num_stages, num_stage_evals, embedded_monomial_coeffs, c, a_unknown; verbose) + b = Trixi.solve_b_butcher_coeffs_unknown!(b, num_stages, num_stage_evals, embedded_monomial_coeffs, c, a_unknown; verbose) println("Embedded monomial after normalization: ", embedded_monomial_coeffs) - println("This is b_unknown = ",b_unknown) println("dt_opt_a = ", dt_opt_a) - error("Stability polynomial optimization process is complete.") + #error("Stability polynomial optimization process is complete.") end # Fill A-matrix in P-ERK style a_matrix = zeros(num_stage_evals - 2, 2) From 753531e6a16c02f215cce02de41bb5e1a4b636eb Mon Sep 17 00:00:00 2001 From: Warisa Date: Thu, 24 Oct 2024 22:49:44 +0200 Subject: [PATCH 154/160] got negative b but equations are set up now --- .../elixir_advection_embedded_perk3.jl | 8 +-- .../methods_embedded_PERK3.jl | 54 ++++++++++++++++--- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl index 74a6ba74fb2..0221817e1cf 100644 --- a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl +++ b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl @@ -56,12 +56,12 @@ save_solution = SaveSolutionCallback(dt = 0.1, # Construct embedded order paired explicit Runge-Kutta method with 10 stages and 7 evaluation stages for given simulation setup. # Pass `tspan` to calculate maximum time step allowed for the bisection algorithm used # in calculating the polynomial coefficients in the ODE algorithm. -ode_algorithm = Trixi.EmbeddedPairedRK3(10, 6, tspan, semi) +ode_algorithm = Trixi.EmbeddedPairedRK3(16, 5, tspan, semi) # Calculate the CFL number for the given ODE algorithm and ODE problem (cfl_number calculate from dt_opt of the optimization of # b values in the Butcher tableau of the ODE algorithm). #cfl_number = Trixi.calculate_cfl(ode_algorithm, ode) -stepsize_callback = StepsizeCallback(cfl = 0.75) # Warisa: This number is quite small in contrast the other one from optimizing A +stepsize_callback = StepsizeCallback() # Warisa: This number is quite small in contrast the other one from optimizing A # I've tried using cfl of 1.5 and the error is very similar. callbacks = CallbackSet(summary_callback, @@ -83,9 +83,9 @@ summary_callback() function construct_b_vector(b_unknown, num_stages_embedded, num_stage_evals_embedded) # Construct the b vector b = [ - 1 - sum(b_unknown), + b_unknown[1], zeros(Float64, num_stages_embedded - num_stage_evals_embedded)..., - b_unknown..., + b_unknown[2:end]..., 0 ] return b diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index 0b00b1bf364..d859014d712 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -7,6 +7,45 @@ using DelimitedFiles: readdlm @muladd begin #! format: noindent +function compute_b_embedded_coeffs(num_stage_evals, num_stages, embedded_monomial_coeffs, a_unknown, c) + # Different scheme for c? + + A = zeros(num_stage_evals - 1, num_stage_evals - 1) + b_embedded = zeros(num_stage_evals - 1) + rhs = [1, 1/2, embedded_monomial_coeffs...] + + # sum(b) = 1 + A[1, :] .= 1 + + # The second order constraint: dot(b,c) = 1/2 + for i in 2:num_stage_evals - 1 + A[2, i] = c[num_stages - num_stage_evals + i] + end + + # Fill the A matrix + for i in 3:(num_stage_evals - 1) + # z^i + for j in i: (num_stage_evals - 1) + println("i = ", i, ", j = ", j) + println("[num_stages - num_stage_evals + j - 1] = ", num_stages - num_stage_evals + j - 1) + A[i,j] = c[num_stages - num_stage_evals + j - 1] + # number of times a_unknown should be multiplied in each power of z + for k in 1: i-2 + # so we want to get from a[k] * ... i-2 times (1 time is already accounted for by c-coeff) + # j-1 - k + 1 = j - k + println("a_unknown at index: ", j - k) + A[i, j] *= a_unknown[j - k] # a[k] is in the same stage as b[k-1] -> since we also store b_1 + end + end + #rhs[i] /= factorial(i) + end + + display(A) + + b_embedded = A \ rhs + return b_embedded +end + # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 # using a list of eigenvalues function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, tspan, @@ -42,7 +81,7 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, dtmax, dteps, eig_vals; verbose) - embedded_monomial_coeffs = undo_normalization!(embedded_monomial_coeffs, consistency_order, num_stage_evals-1) + embedded_monomial_coeffs = undo_normalization!(embedded_monomial_coeffs, consistency_order-1, num_stage_evals-1) # Solve the nonlinear system of equations from monomial coefficient and # Butcher array abscissae c to find Butcher matrix A @@ -54,13 +93,14 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, println("dt_opt_b = ", dt_opt_b) - b = Trixi.solve_b_butcher_coeffs_unknown!(b, num_stages, num_stage_evals, embedded_monomial_coeffs, c, a_unknown; verbose) + b = compute_b_embedded_coeffs(num_stage_evals, num_stages, embedded_monomial_coeffs, a_unknown, c) + println("b: ", b) println("Embedded monomial after normalization: ", embedded_monomial_coeffs) println("dt_opt_a = ", dt_opt_a) - #error("Stability polynomial optimization process is complete.") + #error("b found.") end # Fill A-matrix in P-ERK style a_matrix = zeros(num_stage_evals - 2, 2) @@ -309,7 +349,7 @@ function step!(integrator::EmbeddedPairedRK3Integrator) @threaded for i in eachindex(integrator.u) # add the contribution of the first stage - integrator.u[i] += (1 - sum(alg.b)) * integrator.k1[i] + integrator.u[i] += alg.b[1] * integrator.k1[i] end # Higher stages where the weight of b in the butcher tableau is zero @@ -345,7 +385,7 @@ function step!(integrator::EmbeddedPairedRK3Integrator) @threaded for i in eachindex(integrator.u) integrator.u[i] += integrator.k_higher[i] * - alg.b[1] + alg.b[2] end # Higher stages after num_stage_evals where b is non-zero @@ -370,10 +410,11 @@ function step!(integrator::EmbeddedPairedRK3Integrator) @threaded for i in eachindex(integrator.u) integrator.u[i] += integrator.k_higher[i] * - alg.b[stage - alg.num_stages + alg.num_stage_evals - 1] + alg.b[stage - alg.num_stages + alg.num_stage_evals] end end + # Last stage @threaded for i in eachindex(integrator.du) integrator.u_tmp[i] = integrator.u[i] + @@ -382,6 +423,7 @@ function step!(integrator::EmbeddedPairedRK3Integrator) alg.a_matrix[alg.num_stage_evals - 2, 2] * integrator.k_higher[i] end + integrator.f(integrator.du, integrator.u_tmp, prob.p, integrator.t + alg.c[alg.num_stages] * integrator.dt) From b2358e5a3cddd20fbbece88e68a7ca05fae3a670 Mon Sep 17 00:00:00 2001 From: Warisa Date: Fri, 25 Oct 2024 20:52:37 +0200 Subject: [PATCH 155/160] Finally some positive b --- .../elixir_advection_embedded_perk3.jl | 7 ++- ext/TrixiConvexECOSExt.jl | 59 ++++++++++++++++++- ext/TrixiNLsolveExt.jl | 50 ---------------- .../methods_embedded_PERK3.jl | 21 ++++++- .../paired_explicit_runge_kutta.jl | 2 +- 5 files changed, 81 insertions(+), 58 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl index 0221817e1cf..61e202f6984 100644 --- a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl +++ b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl @@ -56,7 +56,7 @@ save_solution = SaveSolutionCallback(dt = 0.1, # Construct embedded order paired explicit Runge-Kutta method with 10 stages and 7 evaluation stages for given simulation setup. # Pass `tspan` to calculate maximum time step allowed for the bisection algorithm used # in calculating the polynomial coefficients in the ODE algorithm. -ode_algorithm = Trixi.EmbeddedPairedRK3(16, 5, tspan, semi) +ode_algorithm = Trixi.EmbeddedPairedRK3(10, 7, tspan, semi) # Calculate the CFL number for the given ODE algorithm and ODE problem (cfl_number calculate from dt_opt of the optimization of # b values in the Butcher tableau of the ODE algorithm). @@ -79,6 +79,9 @@ sol = Trixi.solve(ode, ode_algorithm, # Print the timer summary summary_callback() +ode_algorithm.b + + # Some function defined so that I can check if the second order condition is met. This will be removed later. function construct_b_vector(b_unknown, num_stages_embedded, num_stage_evals_embedded) # Construct the b vector @@ -98,4 +101,4 @@ println("sum(b) = ", sum(b)) println("dt_opt_a = ", ode_algorithm.dt_opt_a) println("dt_opt_b = ", ode_algorithm.dt_opt_b) -println("ratio = ", ode_algorithm.dt_opt_b / ode_algorithm.dt_opt_a * 100) \ No newline at end of file +println("ratio = ", ode_algorithm.dt_opt_b / ode_algorithm.dt_opt_a * 100) diff --git a/ext/TrixiConvexECOSExt.jl b/ext/TrixiConvexECOSExt.jl index 0a5b4c44c5d..518eaa6c14f 100644 --- a/ext/TrixiConvexECOSExt.jl +++ b/ext/TrixiConvexECOSExt.jl @@ -3,11 +3,11 @@ module TrixiConvexECOSExt # Required for coefficient optimization in P-ERK scheme integrators if isdefined(Base, :get_extension) - using Convex: MOI, solve!, Variable, minimize, evaluate + using Convex: MOI, solve!, Variable, minimize, evaluate, sumsquares using ECOS: Optimizer else # Until Julia v1.9 is the minimum required version for Trixi.jl, we still support Requires.jl - using ..Convex: MOI, solve!, Variable, minimize, evaluate + using ..Convex: MOI, solve!, Variable, minimize, evaluate, sumsquares using ..ECOS: Optimizer end @@ -15,7 +15,7 @@ end using LinearAlgebra: eigvals # Use functions that are to be extended and additional symbols that are not exported -using Trixi: Trixi, undo_normalization!, bisect_stability_polynomial, @muladd +using Trixi: Trixi, undo_normalization!, bisect_stability_polynomial, compute_b_embedded_coeffs, @muladd # By default, Julia/LLVM does not use fused multiply-add operations (FMAs). # Since these FMAs can increase the performance of many numerical algorithms, @@ -160,6 +160,59 @@ function Trixi.bisect_stability_polynomial(consistency_order, num_eig_vals, return gamma_opt, dt end + +function Trixi.compute_b_embedded_coeffs(num_stage_evals, num_stages, embedded_monomial_coeffs, a_unknown, c) + + A = zeros(num_stage_evals-1, num_stage_evals) + rhs = [1, 1/2, embedded_monomial_coeffs...] + + # Define the variables + b_embedded = Variable(num_stage_evals) # the unknown coefficients we want to solve for + + # Initialize A matrix for the constraints + A[1, :] .= 1 # sum(b) = 1 constraint row + for i in 1:num_stage_evals-1 + A[2, i+1] = c[num_stages - num_stage_evals + i] # second order constraint: dot(b, c) = 1/2 + end + + # Fill the A matrix with other constraints based on monomial coefficients + for i in 3:(num_stage_evals-1) + for j in i+1:num_stage_evals + A[i, j] = c[num_stages - num_stage_evals + j - 2] + for k in 1:i-2 + A[i, j] *= a_unknown[j - 1 - k] # recursive dependence on `a_unknown` + end + end + end + + println("A matrix of finding b") + display(A) + + # Set up weights to prioritize the first two constraints + weights = [2, 2, ones(num_stage_evals-3)...] # Heavier weight for the first two rows + weighted_residual = weights .* (A * b_embedded - rhs) # Element-wise multiplication for weighting + + # Set up the objective to minimize the weighted norm of the difference + problem = minimize(sumsquares(weighted_residual), [b_embedded >= 0]) + + solve!(problem, # Parameters taken from default values for EiCOS + MOI.OptimizerWithAttributes(Optimizer, "gamma" => 0.99, + "delta" => 2e-7, + "feastol" => 1e-9, + "abstol" => 1e-9, + "reltol" => 1e-9, + "feastol_inacc" => 1e-7, + "abstol_inacc" => 5e-6, + "reltol_inacc" => 5e-7, + "nitref" => 9, + "maxit" => 1000000, + "verbose" => 3); silent_solver = true) + + + ot = problem.optval + println("Optimal value of the objective function: ", ot) + return evaluate(b_embedded) +end end # @muladd end # module TrixiConvexECOSExt diff --git a/ext/TrixiNLsolveExt.jl b/ext/TrixiNLsolveExt.jl index 319134e3700..ded4e7e281a 100644 --- a/ext/TrixiNLsolveExt.jl +++ b/ext/TrixiNLsolveExt.jl @@ -174,56 +174,6 @@ function Trixi.solve_a_butcher_coeffs_unknown!(a_unknown, num_stages, num_stage_ error("Maximum number of iterations ($max_iter) reached. Cannot find valid sets of coefficients.") end - -function Trixi.solve_b_butcher_coeffs_unknown!(b_unknown, num_stages, num_stage_evals, embedded_monomial_coeffs, c, a_unknown; - verbose, max_iter = 100000) - - verbose = true - - # Construct a full a coefficient vector - a = zeros(num_stages) - num_a_unknown = length(a_unknown) - - for i in 1:num_a_unknown - a[num_stages - i + 1] = a_unknown[num_a_unknown - i + 1] - end - - # Define the objective_function - function embedded_scheme_objective_function!(b_eq, x) - return EmbeddedPairedExplicitRK3_butcher_tableau_objective_function!(b_eq, x, - num_stages, - num_stage_evals, - embedded_monomial_coeffs, - c, a) - end - - # RealT is determined as the type of the first element in monomial_coeffs to ensure type consistency - RealT = typeof(embedded_monomial_coeffs[1]) - - # To ensure consistency and reproducibility of results across runs, we use - # a seeded random initial guess. - rng = StableRNG(55555) - - # Due to the nature of the nonlinear solver, different initial guesses can lead to - # small numerical differences in the solution. - - for _ in 1:max_iter - - # There is e-2 free variables of b of the embedded scheme - x0 = convert(RealT, 0.1) .* rand(rng, RealT, num_stage_evals - 2) - - sol = nlsolve(embedded_scheme_objective_function!, x0, method = :trust_region, - ftol = 4.0e-16, # Enforce objective up to machine precision - iterations = 10^4, xtol = 1.0e-13, autodiff = :forward) - - b_unknown = sol.zero # Retrieve solution (root = zero) - - is_sol_valid = all(x -> !isnan(x) && x >= 0, b_unknown) && (sum(b_unknown) <= 1.0) - - return b_unknown - - end -end end # @muladd end # module TrixiNLsolveExt diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index d859014d712..f29c1cffee3 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -7,8 +7,8 @@ using DelimitedFiles: readdlm @muladd begin #! format: noindent +#= function compute_b_embedded_coeffs(num_stage_evals, num_stages, embedded_monomial_coeffs, a_unknown, c) - # Different scheme for c? A = zeros(num_stage_evals - 1, num_stage_evals - 1) b_embedded = zeros(num_stage_evals - 1) @@ -45,6 +45,19 @@ function compute_b_embedded_coeffs(num_stage_evals, num_stages, embedded_monomia b_embedded = A \ rhs return b_embedded end +=# + +# Some function defined so that I can check if the second order condition is met. This will be removed later. +function construct_b_vector(b_unknown, num_stages_embedded, num_stage_evals_embedded) + # Construct the b vector + b = [ + b_unknown[1], + zeros(Float64, num_stages_embedded - num_stage_evals_embedded-1)..., + b_unknown[2:end]..., + 0 + ] + return b +end # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 # using a list of eigenvalues @@ -94,13 +107,17 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, println("dt_opt_b = ", dt_opt_b) b = compute_b_embedded_coeffs(num_stage_evals, num_stages, embedded_monomial_coeffs, a_unknown, c) + + b_full = construct_b_vector(b, num_stages - 1, num_stage_evals - 1) + println("dot(b, c) = ", dot(b_full, c)) + println("sum(b) = ", sum(b_full)) println("b: ", b) println("Embedded monomial after normalization: ", embedded_monomial_coeffs) println("dt_opt_a = ", dt_opt_a) - #error("b found.") + error("b found.") end # Fill A-matrix in P-ERK style a_matrix = zeros(num_stage_evals - 2, 2) diff --git a/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl b/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl index 52d2d307db7..af396cb3ae7 100644 --- a/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl +++ b/src/time_integration/paired_explicit_runge_kutta/paired_explicit_runge_kutta.jl @@ -16,5 +16,5 @@ include("polynomial_optimizer.jl") # such that hey can be exported from Trixi.jl and extended in the TrixiConvexECOSExt package # extension or by the NLsolve-specific code loaded by Requires.jl function solve_a_butcher_coeffs_unknown! end -function solve_b_butcher_coeffs_unknown! end +function compute_b_embedded_coeffs end end # @muladd From 2af55dd94c40dad4f5654cc64ee14fc166de167c Mon Sep 17 00:00:00 2001 From: Warisa Date: Fri, 25 Oct 2024 21:25:12 +0200 Subject: [PATCH 156/160] change with the integrator --- .../elixir_advection_embedded_perk3.jl | 4 +- .../methods_embedded_PERK3.jl | 39 ++++++++++--------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl index 61e202f6984..0f90ea22199 100644 --- a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl +++ b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl @@ -56,12 +56,12 @@ save_solution = SaveSolutionCallback(dt = 0.1, # Construct embedded order paired explicit Runge-Kutta method with 10 stages and 7 evaluation stages for given simulation setup. # Pass `tspan` to calculate maximum time step allowed for the bisection algorithm used # in calculating the polynomial coefficients in the ODE algorithm. -ode_algorithm = Trixi.EmbeddedPairedRK3(10, 7, tspan, semi) +ode_algorithm = Trixi.EmbeddedPairedRK3(10, 9, tspan, semi) # Calculate the CFL number for the given ODE algorithm and ODE problem (cfl_number calculate from dt_opt of the optimization of # b values in the Butcher tableau of the ODE algorithm). #cfl_number = Trixi.calculate_cfl(ode_algorithm, ode) -stepsize_callback = StepsizeCallback() # Warisa: This number is quite small in contrast the other one from optimizing A +stepsize_callback = StepsizeCallback() # I've tried using cfl of 1.5 and the error is very similar. callbacks = CallbackSet(summary_callback, diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index f29c1cffee3..1f145fb76cb 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -117,7 +117,7 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, println("dt_opt_a = ", dt_opt_a) - error("b found.") + #error("b found.") end # Fill A-matrix in P-ERK style a_matrix = zeros(num_stage_evals - 2, 2) @@ -370,7 +370,7 @@ function step!(integrator::EmbeddedPairedRK3Integrator) end # Higher stages where the weight of b in the butcher tableau is zero - for stage in 2:(alg.num_stages - alg.num_stage_evals + 1) + for stage in 2:(alg.num_stages - alg.num_stage_evals) # Construct current state @threaded for i in eachindex(integrator.du) integrator.u_tmp[i] = integrator.u[i] + alg.c[stage] * integrator.k1[i] @@ -384,25 +384,28 @@ function step!(integrator::EmbeddedPairedRK3Integrator) end end - # k_(s-e+2) + # #k_(s-e+1) and k_(s-e+2) # Construct current state - @threaded for i in eachindex(integrator.du) - integrator.u_tmp[i] = integrator.u[i] + - alg.c[alg.num_stages - alg.num_stage_evals + 2] * - integrator.k1[i] - end - integrator.f(integrator.du, integrator.u_tmp, prob.p, - integrator.t + - alg.c[alg.num_stages - alg.num_stage_evals + 2] * integrator.dt) + for j in 1:2 + @threaded for i in eachindex(integrator.du) + integrator.u_tmp[i] = integrator.u[i] + + alg.c[alg.num_stages - alg.num_stage_evals + 2] * + integrator.k1[i] + end - @threaded for i in eachindex(integrator.du) - integrator.k_higher[i] = integrator.du[i] * integrator.dt - end + integrator.f(integrator.du, integrator.u_tmp, prob.p, + integrator.t + + alg.c[alg.num_stages - alg.num_stage_evals + j] * integrator.dt) - @threaded for i in eachindex(integrator.u) - integrator.u[i] += integrator.k_higher[i] * - alg.b[2] + @threaded for i in eachindex(integrator.du) + integrator.k_higher[i] = integrator.du[i] * integrator.dt + end + + @threaded for i in eachindex(integrator.u) + integrator.u[i] += integrator.k_higher[i] * + alg.b[j+1] + end end # Higher stages after num_stage_evals where b is non-zero @@ -427,7 +430,7 @@ function step!(integrator::EmbeddedPairedRK3Integrator) @threaded for i in eachindex(integrator.u) integrator.u[i] += integrator.k_higher[i] * - alg.b[stage - alg.num_stages + alg.num_stage_evals] + alg.b[stage - alg.num_stages + alg.num_stage_evals+1] end end From 6360b8d66e9163d55534eef1e3bc14e27e7f8792 Mon Sep 17 00:00:00 2001 From: Warisa Date: Fri, 25 Oct 2024 21:25:48 +0200 Subject: [PATCH 157/160] remove some comments and unneeded file --- .../elixir_advection_embedded_perk3.jl | 25 --- ext/TrixiConvexClarabelExt.jl | 173 ------------------ 2 files changed, 198 deletions(-) delete mode 100644 ext/TrixiConvexClarabelExt.jl diff --git a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl index 0f90ea22199..dc1ab1c3516 100644 --- a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl +++ b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl @@ -62,7 +62,6 @@ ode_algorithm = Trixi.EmbeddedPairedRK3(10, 9, tspan, semi) # b values in the Butcher tableau of the ODE algorithm). #cfl_number = Trixi.calculate_cfl(ode_algorithm, ode) stepsize_callback = StepsizeCallback() -# I've tried using cfl of 1.5 and the error is very similar. callbacks = CallbackSet(summary_callback, alive_callback, @@ -78,27 +77,3 @@ sol = Trixi.solve(ode, ode_algorithm, # Print the timer summary summary_callback() - -ode_algorithm.b - - -# Some function defined so that I can check if the second order condition is met. This will be removed later. -function construct_b_vector(b_unknown, num_stages_embedded, num_stage_evals_embedded) - # Construct the b vector - b = [ - b_unknown[1], - zeros(Float64, num_stages_embedded - num_stage_evals_embedded)..., - b_unknown[2:end]..., - 0 - ] - return b -end - -b = construct_b_vector(ode_algorithm.b, ode_algorithm.num_stages - 1, - ode_algorithm.num_stage_evals - 1) -println("dot(b, c) = ", dot(b, ode_algorithm.c)) -println("sum(b) = ", sum(b)) - -println("dt_opt_a = ", ode_algorithm.dt_opt_a) -println("dt_opt_b = ", ode_algorithm.dt_opt_b) -println("ratio = ", ode_algorithm.dt_opt_b / ode_algorithm.dt_opt_a * 100) diff --git a/ext/TrixiConvexClarabelExt.jl b/ext/TrixiConvexClarabelExt.jl deleted file mode 100644 index bedc05031f7..00000000000 --- a/ext/TrixiConvexClarabelExt.jl +++ /dev/null @@ -1,173 +0,0 @@ -# Package extension for adding Convex-based features to Trixi.jl -module TrixiConvexClarabelExt - -# Required for coefficient optimization in P-ERK scheme integrators -if isdefined(Base, :get_extension) - using Convex: MOI, solve!, Variable, minimize, evaluate, dot - using Clarabel: Optimizer -else - # Until Julia v1.9 is the minimum required version for Trixi.jl, we still support Requires.jl - using ..Convex: MOI, solve!, Variable, minimize, evaluate - using ..Clarabel: Optimizer -end - -# Use functions that are to be extended and additional symbols that are not exported -using Trixi: Trixi, @muladd - -# 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 - -# Compute new version of stability polynomial of the embedded scheme for paired explicit Runge-Kutta -# up to specified consistency order(p = 2), including contributions from free coefficients for higher -# orders, and return the maximum absolute value -function embedded_scheme_stability_polynomials!(pnoms, - num_stages_embedded, - num_stage_evals_embedded, - normalized_powered_eigvals_scaled, - a, b, c) - - # Construct a full b coefficient vector #TODO: is there a way to not do this and just use b directly? - b_coeff = [ - 1 - sum(b), - zeros(Float64, num_stages_embedded - num_stage_evals_embedded)..., - b..., - 0 - ] - num_eig_vals = length(pnoms) - - # Initialize with 1 + z - for i in 1:num_eig_vals - pnoms[i] = 1.0 + normalized_powered_eigvals_scaled[i, 1] - end - # z^2: b^T * c - #pnoms += dot(b, c) * normalized_powered_eigvals_scaled[:, 2] - pnoms += 0.5 * normalized_powered_eigvals_scaled[:, 2] - - # Contribution from free coefficients - for i in 3:num_stage_evals_embedded - sum = 0.0 - for j in (i + num_stages_embedded - num_stage_evals_embedded):num_stages_embedded - prod = 1.0 - for k in (3 + j - i):j - prod *= a[k] - end - sum += prod * b_coeff[j] * c[j - i + 2] - end - pnoms += sum * normalized_powered_eigvals_scaled[:, i] - end - - # For optimization only the maximum is relevant - return maximum(abs(pnoms)) -end - -function solve_b_butcher_coeffs_unknown_new(num_eig_vals, eig_vals, - num_stages, num_stage_evals, - num_stages_embedded, - num_stage_evals_embedded, - a_unknown, c, dtmax, dteps) - dtmin = 0.0 - dt = -1.0 - abs_p = -1.0 - - # Construct a full a coefficient vector - a = zeros(num_stages) - num_a_unknown = length(a_unknown) - - for i in 1:num_a_unknown - a[num_stages - i + 1] = a_unknown[num_a_unknown - i + 1] - end - - # Construct stability polynomial for each eigenvalue - pnoms = ones(Complex{Float64}, num_eig_vals, 1) - - # There are e - 2 free variables for the stability polynomial of the embedded scheme - b = Variable(num_stage_evals - 2) - - normalized_powered_eigvals = zeros(Complex{Float64}, num_eig_vals, num_stage_evals-1) - - for j in 1:num_stage_evals-1 - #fac_j = factorial(j) - for i in 1:num_eig_vals - #normalized_powered_eigvals[i, j] = eig_vals[i]^j / fac_j - # Try first without factorial normalization - normalized_powered_eigvals[i, j] = eig_vals[i]^j - end - end - - normalized_powered_eigvals_scaled = similar(normalized_powered_eigvals) - - # Bisection on timestep - while dtmax - dtmin > dteps - dt = 0.5 * (dtmax + dtmin) - - # Compute stability polynomial for current timestep - for k in 1:num_stage_evals-1 - dt_k = dt^k - for i in 1:num_eig_vals - normalized_powered_eigvals_scaled[i, k] = dt_k * - normalized_powered_eigvals[i, - k] - end - end - - # Second-order constraint - # Since c[1] is always 0 we can ignore the contribution of b[1] and only account for the ones from other non-zero entries of b - constraints = [b >= 0, - 2 * dot(b, c[(num_stages - num_stage_evals + 2):(num_stages - 1)]) == 1.0] - - # Use last optimal values for b in (potentially) next iteration - problem = minimize(embedded_scheme_stability_polynomials!(pnoms, - num_stages_embedded, - num_stage_evals_embedded, - normalized_powered_eigvals_scaled, - a, b, c), constraints) - - #= - solve!(problem, - # Parameters taken from default values for EiCOS - MOI.OptimizerWithAttributes(Optimizer, "b" => 0.99, - "delta" => 2e-7, - "feastol" => 1e-9, - "abstol" => 1e-9, - "reltol" => 1e-9, - "feastol_inacc" => 1e-4, - "abstol_inacc" => 5e-5, - "reltol_inacc" => 5e-5, - "nitref" => 9, - "maxit" => 100, - "verbose" => 3); silent_solver = true) - =# - - - solve!(problem, - MOI.OptimizerWithAttributes(Optimizer, - "tol_feas" => 1e-4); - silent_solver = true) - - print("dt: ", dt, "\n") - print("Problem value: ", problem.optval, "\n") - abs_p = problem.optval - - if abs_p < 1 - dtmin = dt - else - dtmax = dt - end - end - - b_opt = evaluate(b) - - # Catch case S = 3 (only one opt. variable) - if isa(b_opt, Number) - b_opt = [b_opt] - end - - return b_opt, dt -end -end # @muladd - -end # module TrixiConvexClarabelExt From aee9697f1447465ee012838d405d2a685f19332f Mon Sep 17 00:00:00 2001 From: Warisa Date: Tue, 29 Oct 2024 13:38:11 +0100 Subject: [PATCH 158/160] some changes. Set constraint to b positive --- .../elixir_advection_embedded_perk3.jl | 2 +- ext/TrixiConvexECOSExt.jl | 136 +++++++++++++++++- .../methods_embedded_PERK3.jl | 54 +------ 3 files changed, 142 insertions(+), 50 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl index 0221817e1cf..60f812b3e54 100644 --- a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl +++ b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl @@ -56,7 +56,7 @@ save_solution = SaveSolutionCallback(dt = 0.1, # Construct embedded order paired explicit Runge-Kutta method with 10 stages and 7 evaluation stages for given simulation setup. # Pass `tspan` to calculate maximum time step allowed for the bisection algorithm used # in calculating the polynomial coefficients in the ODE algorithm. -ode_algorithm = Trixi.EmbeddedPairedRK3(16, 5, tspan, semi) +ode_algorithm = Trixi.EmbeddedPairedRK3(16, 11, tspan, semi) # Calculate the CFL number for the given ODE algorithm and ODE problem (cfl_number calculate from dt_opt of the optimization of # b values in the Butcher tableau of the ODE algorithm). diff --git a/ext/TrixiConvexECOSExt.jl b/ext/TrixiConvexECOSExt.jl index 0a5b4c44c5d..c63a767f038 100644 --- a/ext/TrixiConvexECOSExt.jl +++ b/ext/TrixiConvexECOSExt.jl @@ -15,7 +15,7 @@ end using LinearAlgebra: eigvals # Use functions that are to be extended and additional symbols that are not exported -using Trixi: Trixi, undo_normalization!, bisect_stability_polynomial, @muladd +using Trixi: Trixi, undo_normalization!, bisect_stability_polynomial, solve_b_embedded, @muladd # By default, Julia/LLVM does not use fused multiply-add operations (FMAs). # Since these FMAs can increase the performance of many numerical algorithms, @@ -160,6 +160,140 @@ function Trixi.bisect_stability_polynomial(consistency_order, num_eig_vals, return gamma_opt, dt end + +function compute_b_embedded_coeffs(num_stage_evals, num_stages, embedded_monomial_coeffs, a_unknown, c) + + A = zeros(num_stage_evals - 1, num_stage_evals - 1) + b_embedded = zeros(num_stage_evals - 1) + rhs = [1, 1/2, embedded_monomial_coeffs...] # Cast embedded_monomial_coeffs to Float64 if needed + + # sum(b) = 1 + A[1, :] .= 1 + + # The second order constraint: dot(b,c) = 1/2 + for i in 2:num_stage_evals - 1 + A[2, i] = c[num_stages - num_stage_evals + i] + end + + # Fill the A matrix + for i in 3:(num_stage_evals - 1) + # z^i + for j in i: (num_stage_evals - 1) + println("i = ", i, ", j = ", j) + println("[num_stages - num_stage_evals + j - 1] = ", num_stages - num_stage_evals + j - 1) + A[i,j] = c[num_stages - num_stage_evals + j - 1] + # number of times a_unknown should be multiplied in each power of z + for k in 1: i-2 + # so we want to get from a[k] * ... i-2 times (1 time is already accounted for by c-coeff) + # j-1 - k + 1 = j - k + println("a_unknown at index: ", j - k) + A[i, j] *= a_unknown[j - k] # a[k] is in the same stage as b[k-1] -> since we also store b_1 + end + end + rhs[i] /= factorial(i) + end + + A_inv = inv(A) + + b_embedded = A_inv * rhs + + return b_embedded +end + +#TODO: Add an optimization of the embedded scheme that subject the b solved from the set of gamme to be + +# the same as the b from the original scheme. This will be done by using the same optimization as the normal scheme but with cosntraint and the function +# that will be used to construct the b vector from the gamma vector. +function Trixi.solve_b_embedded(consistency_order, num_eig_vals, num_stage_evals, num_stages, + dtmax, dteps, eig_vals, a_unknown, c; + verbose = false) + dtmin = 0.0 + dt = -1.0 + abs_p = -1.0 + consistency_order_embedded = consistency_order - 1 + + num_stage_evals_embedded = num_stage_evals -1 + + # Construct stability polynomial for each eigenvalue + pnoms = ones(Complex{Float64}, num_eig_vals, 1) + + # Init datastructure for monomial coefficients + gamma = Variable(num_stage_evals_embedded - consistency_order_embedded) + + normalized_powered_eigvals = zeros(Complex{Float64}, num_eig_vals, num_stage_evals_embedded) + + for j in 1:num_stage_evals_embedded + fac_j = factorial(j) + for i in 1:num_eig_vals + normalized_powered_eigvals[i, j] = eig_vals[i]^j / fac_j + end + end + + normalized_powered_eigvals_scaled = similar(normalized_powered_eigvals) + + if verbose + println("Start optimization of stability polynomial \n") + end + + # Bisection on timestep + while dtmax - dtmin > dteps + dt = 0.5 * (dtmax + dtmin) + + # Compute stability polynomial for current timestep + for k in 1:num_stage_evals_embedded + dt_k = dt^k + for i in 1:num_eig_vals + normalized_powered_eigvals_scaled[i, k] = dt_k * + normalized_powered_eigvals[i, + k] + end + end + + constraint = compute_b_embedded_coeffs(num_stage_evals, num_stages, gamma, a_unknown, c).>= -1e-5 + + # Use last optimal values for gamma in (potentially) next iteration + problem = minimize(stability_polynomials!(pnoms, consistency_order_embedded, + num_stage_evals_embedded, + normalized_powered_eigvals_scaled, + gamma), constraint) + + solve!(problem, + # Parameters taken from default values for EiCOS + MOI.OptimizerWithAttributes(Optimizer, "gamma" => 0.99, + "delta" => 2e-7, + "feastol" => 1e-9, + "abstol" => 1e-9, + "reltol" => 1e-9, + "feastol_inacc" => 1e-4, + "abstol_inacc" => 5e-5, + "reltol_inacc" => 5e-5, + "nitref" => 9, + "maxit" => 100, + "verbose" => 3); silent_solver = true) + + abs_p = problem.optval + + if abs_p < 1 + dtmin = dt + else + dtmax = dt + end + end + + if verbose + println("Concluded stability polynomial optimization \n") + end + + gamma_opt = evaluate(gamma) + + # Catch case S = 3 (only one opt. variable) + if isa(gamma_opt, Number) + gamma_opt = [gamma_opt] + end + + b_embedded = compute_b_embedded_coeffs(num_stage_evals, num_stages, gamma_opt, a_unknown, c) + + return b_embedded, dt +end end # @muladd end # module TrixiConvexECOSExt diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index d859014d712..f1a59eb4459 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -7,44 +7,8 @@ using DelimitedFiles: readdlm @muladd begin #! format: noindent -function compute_b_embedded_coeffs(num_stage_evals, num_stages, embedded_monomial_coeffs, a_unknown, c) - # Different scheme for c? - - A = zeros(num_stage_evals - 1, num_stage_evals - 1) - b_embedded = zeros(num_stage_evals - 1) - rhs = [1, 1/2, embedded_monomial_coeffs...] - - # sum(b) = 1 - A[1, :] .= 1 - - # The second order constraint: dot(b,c) = 1/2 - for i in 2:num_stage_evals - 1 - A[2, i] = c[num_stages - num_stage_evals + i] - end - - # Fill the A matrix - for i in 3:(num_stage_evals - 1) - # z^i - for j in i: (num_stage_evals - 1) - println("i = ", i, ", j = ", j) - println("[num_stages - num_stage_evals + j - 1] = ", num_stages - num_stage_evals + j - 1) - A[i,j] = c[num_stages - num_stage_evals + j - 1] - # number of times a_unknown should be multiplied in each power of z - for k in 1: i-2 - # so we want to get from a[k] * ... i-2 times (1 time is already accounted for by c-coeff) - # j-1 - k + 1 = j - k - println("a_unknown at index: ", j - k) - A[i, j] *= a_unknown[j - k] # a[k] is in the same stage as b[k-1] -> since we also store b_1 - end - end - #rhs[i] /= factorial(i) - end - - display(A) - - b_embedded = A \ rhs - return b_embedded -end +# To be overwritten in TrixiConvexECOSExt.jl +function solve_b_embedded end # Compute the Butcher tableau for a paired explicit Runge-Kutta method order 3 # using a list of eigenvalues @@ -76,13 +40,6 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, monomial_coeffs = undo_normalization!(monomial_coeffs, consistency_order, num_stage_evals) - embedded_monomial_coeffs, dt_opt_b = bisect_stability_polynomial(consistency_order-1, - num_eig_vals, num_stage_evals-1, - dtmax, dteps, - eig_vals; verbose) - - embedded_monomial_coeffs = undo_normalization!(embedded_monomial_coeffs, consistency_order-1, num_stage_evals-1) - # Solve the nonlinear system of equations from monomial coefficient and # Butcher array abscissae c to find Butcher matrix A # This function is extended in TrixiNLsolveExt.jl @@ -91,12 +48,13 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, monomial_coeffs, cS2, c; verbose) - println("dt_opt_b = ", dt_opt_b) + b, dt_opt_b = solve_b_embedded(consistency_order, num_eig_vals, num_stage_evals, num_stages, + dtmax, dteps, eig_vals, a_unknown, c; + verbose = true) - b = compute_b_embedded_coeffs(num_stage_evals, num_stages, embedded_monomial_coeffs, a_unknown, c) + println("dt_opt_b = ", dt_opt_b) println("b: ", b) - println("Embedded monomial after normalization: ", embedded_monomial_coeffs) println("dt_opt_a = ", dt_opt_a) From 3e8b9810021ddbb4bf096cf2531832c1ec069faa Mon Sep 17 00:00:00 2001 From: Warisa Date: Fri, 1 Nov 2024 10:38:43 +0100 Subject: [PATCH 159/160] seeing whether e-2 produce a substantial time step --- .../elixir_advection_embedded_perk3.jl | 2 +- ext/TrixiConvexECOSExt.jl | 1 - .../methods_embedded_PERK3.jl | 21 +++++++++++++++---- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl index 7b305bb2308..c15912e77c8 100644 --- a/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl +++ b/examples/tree_1d_dgsem/elixir_advection_embedded_perk3.jl @@ -56,7 +56,7 @@ save_solution = SaveSolutionCallback(dt = 0.1, # Construct embedded order paired explicit Runge-Kutta method with 10 stages and 7 evaluation stages for given simulation setup. # Pass `tspan` to calculate maximum time step allowed for the bisection algorithm used # in calculating the polynomial coefficients in the ODE algorithm. -ode_algorithm = Trixi.EmbeddedPairedRK3(16, 5, tspan, semi) +ode_algorithm = Trixi.EmbeddedPairedRK3(16, 16, tspan, semi) # Calculate the CFL number for the given ODE algorithm and ODE problem (cfl_number calculate from dt_opt of the optimization of # b values in the Butcher tableau of the ODE algorithm). diff --git a/ext/TrixiConvexECOSExt.jl b/ext/TrixiConvexECOSExt.jl index 544438da871..a9f443c8d6e 100644 --- a/ext/TrixiConvexECOSExt.jl +++ b/ext/TrixiConvexECOSExt.jl @@ -16,7 +16,6 @@ using LinearAlgebra: eigvals # Use functions that are to be extended and additional symbols that are not exported using Trixi: Trixi, undo_normalization!, bisect_stability_polynomial, solve_b_embedded, @muladd -using Trixi: Trixi, undo_normalization!, bisect_stability_polynomial, compute_b_embedded_coeffs, @muladd # 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/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index 6a592493d49..3c76063cc1b 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -7,6 +7,8 @@ using DelimitedFiles: readdlm @muladd begin #! format: noindent +function solve_b_embedded end + #= function compute_b_embedded_coeffs(num_stage_evals, num_stages, embedded_monomial_coeffs, a_unknown, c) @@ -97,11 +99,22 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, monomial_coeffs, cS2, c; verbose) - b, dt_opt_b = solve_b_embedded(consistency_order, num_eig_vals, num_stage_evals, num_stages, - dtmax, dteps, eig_vals, a_unknown, c; - verbose = true) + monomial_coeffs_embedded, dt_opt_b = bisect_stability_polynomial(consistency_order-1, + num_eig_vals, num_stage_evals-2, + dtmax, dteps, + eig_vals; verbose) + #b, dt_opt_b = solve_b_embedded(consistency_order, num_eig_vals, num_stage_evals, num_stages, + #dtmax, dteps, eig_vals, a_unknown, c; + #verbose = true) println("dt_opt_b = ", dt_opt_b) + println("dt_opt_a = ", dt_opt_a) + + # Calculate and print the percentage difference + percentage_difference = (dt_opt_b / dt_opt_a) * 100 + println("Percentage difference (dt_opt_b / dt_opt_a * 100) = ", percentage_difference) + + error("dt_opt_b found.") b = compute_b_embedded_coeffs(num_stage_evals, num_stages, embedded_monomial_coeffs, a_unknown, c) @@ -113,7 +126,7 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, println("dt_opt_a = ", dt_opt_a) - #error("b found.") + error("b found.") end # Fill A-matrix in P-ERK style a_matrix = zeros(num_stage_evals - 2, 2) From d19ce67f8bd628560a5aae25d9041ac7a78e1e31 Mon Sep 17 00:00:00 2001 From: Warisa Date: Fri, 1 Nov 2024 18:14:22 +0100 Subject: [PATCH 160/160] revert this to original intention --- .../paired_explicit_runge_kutta/methods_embedded_PERK3.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl index 3c76063cc1b..30465675c95 100644 --- a/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl +++ b/src/time_integration/paired_explicit_runge_kutta/methods_embedded_PERK3.jl @@ -54,7 +54,7 @@ function construct_b_vector(b_unknown, num_stages_embedded, num_stage_evals_embe # Construct the b vector b = [ b_unknown[1], - zeros(Float64, num_stages_embedded - num_stage_evals_embedded-1)..., + zeros(Float64, num_stages_embedded - num_stage_evals_embedded)..., b_unknown[2:end]..., 0 ] @@ -71,7 +71,7 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, # Initialize the array of our solution a_unknown = zeros(num_stage_evals - 2) - b = zeros(num_stage_evals - 2) + b = zeros(num_stage_evals - 1) # Special case of e = 3 if num_stage_evals == 3 @@ -100,7 +100,7 @@ function compute_EmbeddedPairedRK3_butcher_tableau(num_stages, num_stage_evals, verbose) monomial_coeffs_embedded, dt_opt_b = bisect_stability_polynomial(consistency_order-1, - num_eig_vals, num_stage_evals-2, + num_eig_vals, num_stage_evals-1, dtmax, dteps, eig_vals; verbose) #b, dt_opt_b = solve_b_embedded(consistency_order, num_eig_vals, num_stage_evals, num_stages,