-
Notifications
You must be signed in to change notification settings - Fork 165
Use Jacobian-free Newton-Krylov for SDIRK time integrators #2505
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 17 commits
c4cbb5a
8a4fdcd
94f250a
2a51e91
16dc218
238afe3
1221c94
3453202
7512dce
57e5989
1ae7504
a1ffd0d
0adb284
b180056
83dce58
41f0b7c
dda0feb
9497f15
da5500b
73ee564
9820f59
8bbf603
fcdfd39
2365682
6409d7c
98012be
178736e
1e8ae90
8a517fe
bb9c185
ae4d19d
d7a4d77
e04e649
add1a0c
e843d3b
476da19
1786907
11a9ac6
16b9951
65ff9f4
bfb58db
18f038c
d8aa14e
2ad186a
38a21b9
1e39b81
e0a38a4
61834b0
f5af542
8b819e6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,171 @@ | ||
| using Trixi | ||
| using OrdinaryDiffEqSDIRK | ||
| using LinearSolve # For Jacobian-free Newton-Krylov (GMRES) solver | ||
| using ADTypes # For automatic differentiation via finite differences | ||
|
|
||
| # This is the classic 1D viscous shock wave problem with analytical solution | ||
| # for a special value of the Prandtl number. | ||
| # The original references are: | ||
| # | ||
| # - R. Becker (1922) | ||
| # Stoßwelle und Detonation. | ||
| # [DOI: 10.1007/BF01329605](https://doi.org/10.1007/BF01329605) | ||
| # | ||
| # English translations: | ||
| # Impact waves and detonation. Part I. | ||
| # https://ntrs.nasa.gov/api/citations/19930090862/downloads/19930090862.pdf | ||
| # Impact waves and detonation. Part II. | ||
| # https://ntrs.nasa.gov/api/citations/19930090863/downloads/19930090863.pdf | ||
| # | ||
| # - M. Morduchow, P. A. Libby (1949) | ||
| # On a Complete Solution of the One-Dimensional Flow Equations | ||
| # of a Viscous, Head-Conducting, Compressible Gas | ||
| # [DOI: 10.2514/8.11882](https://doi.org/10.2514/8.11882) | ||
| # | ||
| # | ||
| # The particular problem considered here is described in | ||
| # - L. G. Margolin, J. M. Reisner, P. M. Jordan (2017) | ||
| # Entropy in self-similar shock profiles | ||
| # [DOI: 10.1016/j.ijnonlinmec.2017.07.003](https://doi.org/10.1016/j.ijnonlinmec.2017.07.003) | ||
|
|
||
| ### Fixed parameters ### | ||
|
|
||
| # Special value for which nonlinear solver can be omitted | ||
| # Corresponds essentially to fixing the Mach number | ||
| alpha = 0.5 | ||
| # We want kappa = cp * mu = mu_bar to ensure constant enthalpy | ||
| prandtl_number() = 3 / 4 | ||
|
|
||
| ### Free choices: ### | ||
| gamma() = 5 / 3 | ||
|
|
||
| # In Margolin et al., the Navier-Stokes equations are given for an | ||
| # isotropic stress tensor τ, i.e., ∇ ⋅ τ = μ Δu | ||
| mu_isotropic() = 0.15 | ||
| mu_bar() = mu_isotropic() / (gamma() - 1) # Re-scaled viscosity | ||
|
|
||
| rho_0() = 1 | ||
| v() = 1 # Shock speed | ||
|
|
||
| domain_length = 4.0 | ||
|
|
||
| ### Derived quantities ### | ||
|
|
||
| Ma() = 2 / sqrt(3 - gamma()) # Mach number for alpha = 0.5 | ||
| c_0() = v() / Ma() # Speed of sound ahead of the shock | ||
|
|
||
| # From constant enthalpy condition | ||
| p_0() = c_0()^2 * rho_0() / gamma() | ||
|
|
||
| l() = mu_bar() / (rho_0() * v()) * 2 * gamma() / (gamma() + 1) # Appropriate length scale | ||
|
|
||
| """ | ||
| initial_condition_viscous_shock(x, t, equations) | ||
|
|
||
| Classic 1D viscous shock wave problem with analytical solution | ||
| for a special value of the Prandtl number. | ||
| The version implemented here is described in | ||
| - L. G. Margolin, J. M. Reisner, P. M. Jordan (2017) | ||
| Entropy in self-similar shock profiles | ||
| [DOI: 10.1016/j.ijnonlinmec.2017.07.003](https://doi.org/10.1016/j.ijnonlinmec.2017.07.003) | ||
| """ | ||
| function initial_condition_viscous_shock(x, t, equations) | ||
| y = x[1] - v() * t # Translated coordinate | ||
|
|
||
| # Coordinate transformation. See eq. (33) in Margolin et al. (2017) | ||
| chi = 2 * exp(y / (2 * l())) | ||
|
|
||
| w = 1 + 1 / (2 * chi^2) * (1 - sqrt(1 + 2 * chi^2)) | ||
|
|
||
| rho = rho_0() / w | ||
| u = v() * (1 - w) | ||
| p = p_0() * 1 / w * (1 + (gamma() - 1) / 2 * Ma()^2 * (1 - w^2)) | ||
|
|
||
| return prim2cons(SVector(rho, u, 0, p), equations) | ||
| end | ||
| initial_condition = initial_condition_viscous_shock | ||
|
|
||
| ############################################################################### | ||
| # semidiscretization of the ideal compressible Navier-Stokes equations | ||
|
|
||
| equations = CompressibleEulerEquations2D(gamma()) | ||
|
|
||
| # Trixi implements the stress tensor in deviatoric form, thus we need to | ||
| # convert the "isotropic viscosity" to the "deviatoric viscosity" | ||
| mu_deviatoric() = mu_bar() * 3 / 4 | ||
| equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu = mu_deviatoric(), | ||
| Prandtl = prandtl_number(), | ||
| gradient_variables = GradientVariablesEntropy()) | ||
|
|
||
| solver = DGSEM(polydeg = 3, surface_flux = flux_hlle) | ||
|
|
||
| coordinates_min = (-domain_length / 2, -domain_length / 2) | ||
| coordinates_max = (domain_length / 2, domain_length / 2) | ||
|
|
||
| trees_per_dimension = (12, 3) | ||
| mesh = P4estMesh(trees_per_dimension, | ||
| polydeg = 3, initial_refinement_level = 0, | ||
| coordinates_min = coordinates_min, coordinates_max = coordinates_max, | ||
| periodicity = (false, true)) | ||
|
|
||
| ### Inviscid boundary conditions ### | ||
|
|
||
| # Prescribe pure influx based on initial conditions | ||
| function boundary_condition_inflow(u_inner, normal_direction::AbstractVector, x, t, | ||
| surface_flux_function, | ||
| equations::CompressibleEulerEquations2D) | ||
| u_cons = initial_condition_viscous_shock(x, t, equations) | ||
| flux = Trixi.flux(u_cons, normal_direction, equations) | ||
|
|
||
| return flux | ||
| end | ||
|
|
||
| boundary_conditions = Dict(:x_neg => boundary_condition_inflow, | ||
| :x_pos => boundary_condition_do_nothing) | ||
|
|
||
| ### Viscous boundary conditions ### | ||
| # For the viscous BCs, we use the known analytical solution | ||
| velocity_bc = NoSlip() do x, t, equations_parabolic | ||
| Trixi.velocity(initial_condition_viscous_shock(x, | ||
| t, | ||
| equations_parabolic), | ||
| equations_parabolic) | ||
| end | ||
|
|
||
| heat_bc = Isothermal() do x, t, equations_parabolic | ||
| Trixi.temperature(initial_condition_viscous_shock(x, | ||
| t, | ||
| equations_parabolic), | ||
| equations_parabolic) | ||
| end | ||
|
|
||
| boundary_condition_parabolic = BoundaryConditionNavierStokesWall(velocity_bc, heat_bc) | ||
|
|
||
| boundary_conditions_parabolic = Dict(:x_neg => boundary_condition_parabolic, | ||
| :x_pos => boundary_condition_parabolic) | ||
|
|
||
| semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), | ||
| initial_condition, solver; | ||
| boundary_conditions = (boundary_conditions, | ||
| boundary_conditions_parabolic)) | ||
|
|
||
| ############################################################################### | ||
| # ODE solvers, callbacks etc. | ||
|
|
||
| tspan = (0.0, 1.0) | ||
| ode = semidiscretize(semi, tspan) | ||
|
|
||
| summary_callback = SummaryCallback() | ||
| alive_callback = AliveCallback(alive_interval = 1) | ||
| analysis_callback = AnalysisCallback(semi, interval = 100) | ||
|
|
||
| callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback) | ||
|
|
||
| ############################################################################### | ||
| # run the simulation | ||
|
|
||
| sol = solve(ode, | ||
| # Use (diagonally) implicit Runge-Kutta method with Jacobian-free (!) Newton-Krylov (GMRES) solver | ||
| # See https://docs.sciml.ai/DiffEqDocs/stable/tutorials/advanced_ode_example/#Using-Jacobian-Free-Newton-Krylov | ||
| KenCarp47(autodiff = AutoFiniteDiff(), linsolve = KrylovJL_GMRES()); | ||
| ode_default_options()..., callback = callbacks) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you please check how the ARKODE methods perform compared to the KenCarp methods implemented in OrdinaryDiffEq.jl?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm the summary callback seems to be not compatible with the more abstract DifferentialEquations options: ERROR: type DEOptions has no field adaptive
Stacktrace:
[1] getproperty
@ ./Base.jl:37 [inlined]
[2] initialize_summary_callback(cb::DiscreteCallback{…}, u::Vector{…}, t::Float64, integrator::Sundials.ARKODEIntegrator{…}; reset_threads::Bool)
@ Trixi ~/git/Trixi.jl/src/callbacks_step/summary.jl:197
[3] initialize_summary_callback
@ ~/git/Trixi.jl/src/callbacks_step/summary.jl:148 [inlined]
[4] initialize
@ ~/git/Trixi.jl/src/callbacks_step/summary.jl:20 [inlined]
[5] initialize!
@ ~/.julia/packages/DiffEqBase/AfBQT/src/callbacks.jl:18 [inlined]
[6] initialize!
@ ~/.julia/packages/DiffEqBase/AfBQT/src/callbacks.jl:7 [inlined]
[7] initialize_callbacks!
@ ~/.julia/packages/Sundials/ixqpi/src/common_interface/solve.jl:1574 [inlined]
[8] initialize_callbacks!(integrator::Sundials.ARKODEIntegrator{…})
@ Sundials ~/.julia/packages/Sundials/ixqpi/src/common_interface/solve.jl:1569
[9] __init(prob::ODEProblem{…}, alg::ARKODE{…}, timeseries::Vector{…}, ts::Vector{…}, ks::Vector{…}; verbose::Bool, callback::CallbackSet{…}, abstol::Float64, reltol::Float64, saveat::Vector{…}, tstops::Vector{…}, d_discontinuities::Vector{…}, maxiters::Int64, dt::Nothing, dtmin::Float64, dtmax::Float64, timeseries_errors::Bool, dense_errors::Bool, save_everystep::Bool, save_idxs::Nothing, dense::Bool, save_on::Bool, save_start::Bool, save_end::Bool, save_timeseries::Nothing, progress::Bool, progress_steps::Int64, progress_name::String, progress_message::typeof(DiffEqBase.ODE_DEFAULT_PROG_MESSAGE), progress_id::Symbol, advance_to_tstop::Bool, stop_at_next_tstop::Bool, userdata::Nothing, alias_u0::Bool, kwargs::@Kwargs{})
@ Sundials ~/.julia/packages/Sundials/ixqpi/src/common_interface/solve.jl:951
[10] __solve(prob::ODEProblem{…}, alg::ARKODE{…}, timeseries::Vector{…}, ts::Vector{…}, ks::Vector{…}, recompile::Type{…}; calculate_error::Bool, kwargs::@Kwargs{…})
@ Sundials ~/.julia/packages/Sundials/ixqpi/src/common_interface/solve.jl:15
[11] __solve (repeats 5 times)
@ ~/.julia/packages/Sundials/ixqpi/src/common_interface/solve.jl:3 [inlined]
[12] solve_call(_prob::ODEProblem{…}, args::ARKODE{…}; merge_callbacks::Bool, kwargshandle::Nothing, kwargs::@Kwargs{…})
@ DiffEqBase ~/.julia/packages/DiffEqBase/AfBQT/src/solve.jl:657
[13] solve_call
@ ~/.julia/packages/DiffEqBase/AfBQT/src/solve.jl:614 [inlined]
[14] #solve_up#45
@ ~/.julia/packages/DiffEqBase/AfBQT/src/solve.jl:1211 [inlined]
[15] solve_up
@ ~/.julia/packages/DiffEqBase/AfBQT/src/solve.jl:1188 [inlined]
[16] #solve#43
@ ~/.julia/packages/DiffEqBase/AfBQT/src/solve.jl:1083 [inlined]
[17] top-level scope
@ ~/git/Trixi.jl/examples/tree_1d_dgsem/elixir_diffusion_ldg_newton_krylov.jl:64
Some type information was truncated. Use `show(err)` to see complete types.for sol = solve(ode,
ARKODE();
ode_default_options()..., callback = callbacks)
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Without callbacks the simulation runs, but usefulness is questionable.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
What do you mean by that? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The error seems to say you're doing something on the non public API, likely something like integrator.opts.adaptive. Sundials cannot be mutated to being non adaptive between steps as it's stepper cannot be non adaptive in general.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Callbacks are somewhat essential for meaningful simulations, right? So what I mean is that unless we rewrite the callbacks to be Sundials-ready, the simulations with sundials are relatively useless. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| using Trixi | ||
| using OrdinaryDiffEqSDIRK | ||
| using LinearSolve # For Jacobian-free Newton-Krylov (GMRES) solver | ||
| using ADTypes # For automatic differentiation via finite differences | ||
|
|
||
| ############################################################################### | ||
| # semidiscretization of the linear (advection) diffusion equation | ||
|
|
||
| advection_velocity = 0.0 # Note: This renders the equation mathematically purely parabolic | ||
| equations = LinearScalarAdvectionEquation1D(advection_velocity) | ||
| diffusivity() = 0.5 | ||
| equations_parabolic = LaplaceDiffusion1D(diffusivity(), equations) | ||
|
|
||
| # surface flux does not matter for pure diffusion problem | ||
| solver = DGSEM(polydeg = 3, surface_flux = flux_central) | ||
|
|
||
| coordinates_min = -convert(Float64, pi) | ||
| coordinates_max = convert(Float64, pi) | ||
|
|
||
| mesh = TreeMesh(coordinates_min, coordinates_max, | ||
| initial_refinement_level = 4, | ||
| n_cells_max = 30_000) | ||
|
|
||
| function initial_condition_pure_diffusion_1d_convergence_test(x, t, | ||
| equation) | ||
| nu = diffusivity() | ||
| c = 0 | ||
| A = 1 | ||
| omega = 1 | ||
| scalar = c + A * sin(omega * sum(x)) * exp(-nu * omega^2 * t) | ||
| return SVector(scalar) | ||
| end | ||
| initial_condition = initial_condition_pure_diffusion_1d_convergence_test | ||
|
|
||
| solver_parabolic = ViscousFormulationLocalDG() | ||
| semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), | ||
| initial_condition, | ||
| solver; solver_parabolic) | ||
|
|
||
| ############################################################################### | ||
| # ODE solvers, callbacks etc. | ||
|
|
||
| tspan = (0.0, 2.0) | ||
| ode = semidiscretize(semi, tspan) | ||
|
|
||
| summary_callback = SummaryCallback() | ||
| analysis_callback = AnalysisCallback(semi, interval = 10) | ||
| alive_callback = AliveCallback(alive_interval = 1) | ||
|
|
||
| callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) | ||
|
|
||
| ############################################################################### | ||
| # run the simulation | ||
|
|
||
| sol = solve(ode, | ||
| # Use (diagonally) implicit Runge-Kutta method with Jacobian-free (!) Newton-Krylov (GMRES) solver | ||
| # See https://docs.sciml.ai/DiffEqDocs/stable/tutorials/advanced_ode_example/#Using-Jacobian-Free-Newton-Krylov | ||
| KenCarp47(autodiff = AutoFiniteDiff(), linsolve = KrylovJL_GMRES()); | ||
| ode_default_options()..., callback = callbacks) |
Uh oh!
There was an error while loading. Please reload this page.