From fd33ffdb3d367fdd8a74157956ee00cd0587f38a Mon Sep 17 00:00:00 2001 From: Daniel_Doehring Date: Sat, 24 Feb 2024 18:21:28 +0100 Subject: [PATCH 1/4] NaNCheckCallback --- .../elixir_hypdiff_nonperiodic.jl | 3 + src/Trixi.jl | 2 +- src/callbacks_step/callbacks_step.jl | 1 + src/callbacks_step/nan.jl | 81 +++++++++++++++++++ src/time_integration/methods_2N.jl | 2 +- src/time_integration/methods_3Sstar.jl | 2 +- 6 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 src/callbacks_step/nan.jl diff --git a/examples/structured_2d_dgsem/elixir_hypdiff_nonperiodic.jl b/examples/structured_2d_dgsem/elixir_hypdiff_nonperiodic.jl index 681b3bd781b..64c5870ceaf 100644 --- a/examples/structured_2d_dgsem/elixir_hypdiff_nonperiodic.jl +++ b/examples/structured_2d_dgsem/elixir_hypdiff_nonperiodic.jl @@ -64,11 +64,14 @@ save_solution = SaveSolutionCallback(interval = 4000, save_final_solution = true, solution_variables = cons2prim) +nan_callback = NaNCallback(analysis_interval = analysis_interval) + stepsize_callback = StepsizeCallback(cfl = 1.9) callbacks = CallbackSet(summary_callback, steady_state_callback, analysis_callback, alive_callback, save_solution, + nan_callback, stepsize_callback) ############################################################################### diff --git a/src/Trixi.jl b/src/Trixi.jl index 5f8cd9cae8e..4f8e23dc521 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -259,7 +259,7 @@ export SemidiscretizationCoupled export SummaryCallback, SteadyStateCallback, AnalysisCallback, AliveCallback, SaveRestartCallback, SaveSolutionCallback, TimeSeriesCallback, VisualizationCallback, AveragingCallback, - AMRCallback, StepsizeCallback, + AMRCallback, StepsizeCallback, NaNCallback, GlmSpeedCallback, LBMCollisionCallback, EulerAcousticsCouplingCallback, TrivialCallback, AnalysisCallbackCoupled diff --git a/src/callbacks_step/callbacks_step.jl b/src/callbacks_step/callbacks_step.jl index 09d197bf225..9ddc74298d7 100644 --- a/src/callbacks_step/callbacks_step.jl +++ b/src/callbacks_step/callbacks_step.jl @@ -53,6 +53,7 @@ include("summary.jl") include("steady_state.jl") include("analysis.jl") include("alive.jl") +include("nan.jl") include("save_restart.jl") include("save_solution.jl") include("time_series.jl") diff --git a/src/callbacks_step/nan.jl b/src/callbacks_step/nan.jl new file mode 100644 index 00000000000..5a3b3162393 --- /dev/null +++ b/src/callbacks_step/nan.jl @@ -0,0 +1,81 @@ +# 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 + +""" + NaNCallback(analysis_interval=0, nan_interval=analysis_interval÷10) + +Callback checking for NaNs in the solution vector `u` every `nan_interval`. +If `analysis_interval ≂̸ 0`, the output is omitted every +`analysis_interval` time steps. +""" +mutable struct NaNCallback + nan_interval::Int + analysis_interval::Int +end + +function NaNCallback(; analysis_interval = 0, + nan_interval = analysis_interval ÷ 10) + nan_callback = NaNCallback(nan_interval, analysis_interval) + + DiscreteCallback(nan_callback, nan_callback, # the first one is the condition, the second the affect! + save_positions = (false, false), + initialize = initialize!) +end + +function Base.show(io::IO, cb::DiscreteCallback{<:Any, <:NaNCallback}) + @nospecialize cb # reduce precompilation time + + nan_callback = cb.affect! + print(io, "NaNCallback(nan_interval=", nan_callback.nan_interval, ")") +end + +function Base.show(io::IO, ::MIME"text/plain", + cb::DiscreteCallback{<:Any, <:NaNCallback}) + @nospecialize cb # reduce precompilation time + + if get(io, :compact, false) + show(io, cb) + else + nan_callback = cb.affect! + + setup = [ + "interval" => nan_callback.nan_interval, + ] + summary_box(io, "NaNCallback", setup) + end +end + +function initialize!(cb::DiscreteCallback{Condition, Affect!}, u, t, + integrator) where {Condition, Affect! <: NaNCallback} + nan_callback = cb.affect! + return nothing +end + +# this method is called to determine whether the callback should be activated +function (nan_callback::NaNCallback)(u, t, integrator) + @unpack nan_interval, analysis_interval = nan_callback + + # With error-based step size control, some steps can be rejected. Thus, + # `integrator.iter >= integrator.stats.naccept` + # (total #steps) (#accepted steps) + # We need to check the number of accepted steps since callbacks are not + # activated after a rejected step. + return nan_interval > 0 && ((integrator.stats.naccept % nan_interval == 0 && + !(integrator.stats.naccept == 0 && integrator.iter > 0) && + (analysis_interval == 0 || + integrator.stats.naccept % analysis_interval != 0)) || + isfinished(integrator)) +end + +# this method is called when the callback is activated +function (nan_callback::NaNCallback)(integrator) + if any(isnan, integrator.u) + error("NaN detected in the solution vector `u` at time $(integrator.t)") + end + return nothing +end +end # @muladd diff --git a/src/time_integration/methods_2N.jl b/src/time_integration/methods_2N.jl index f3b09b01e97..0508ca914d9 100644 --- a/src/time_integration/methods_2N.jl +++ b/src/time_integration/methods_2N.jl @@ -80,7 +80,7 @@ end # which are used in Trixi.jl. mutable struct SimpleIntegrator2N{RealT <: Real, uType, Params, Sol, F, Alg, SimpleIntegrator2NOptions} - u::uType # + u::uType du::uType u_tmp::uType t::RealT diff --git a/src/time_integration/methods_3Sstar.jl b/src/time_integration/methods_3Sstar.jl index 7b70466606c..6434b5d0edd 100644 --- a/src/time_integration/methods_3Sstar.jl +++ b/src/time_integration/methods_3Sstar.jl @@ -146,7 +146,7 @@ end mutable struct SimpleIntegrator3Sstar{RealT <: Real, uType, Params, Sol, F, Alg, SimpleIntegrator3SstarOptions} - u::uType # + u::uType du::uType u_tmp1::uType u_tmp2::uType From 73573608a83268eaecfba13138c477ac367dfc70 Mon Sep 17 00:00:00 2001 From: Daniel_Doehring Date: Sun, 25 Feb 2024 09:19:21 +0100 Subject: [PATCH 2/4] NaNCB for Trixi.solve --- .../tree_1d_dgsem/elixir_hypdiff_harmonic_nonperiodic.jl | 4 +++- examples/tree_2d_dgsem/elixir_advection_timeintegration.jl | 4 +++- .../elixir_euler_blast_wave_sc_subcell_nonperiodic.jl | 4 +++- .../elixir_euler_kelvin_helmholtz_instability_sc_subcell.jl | 4 +++- .../elixir_euler_sedov_blast_wave_sc_subcell.jl | 4 +++- .../tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl | 4 +++- ...eulermulti_shock_bubble_shockcapturing_subcell_minmax.jl | 5 ++++- ...rmulti_shock_bubble_shockcapturing_subcell_positivity.jl | 5 ++++- examples/tree_2d_dgsem/elixir_hypdiff_lax_friedrichs.jl | 4 +++- examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl | 3 +++ examples/tree_3d_dgsem/elixir_hypdiff_lax_friedrichs.jl | 4 +++- examples/tree_3d_dgsem/elixir_hypdiff_nonperiodic.jl | 4 +++- src/callbacks_step/nan.jl | 6 +++++- 13 files changed, 43 insertions(+), 12 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_hypdiff_harmonic_nonperiodic.jl b/examples/tree_1d_dgsem/elixir_hypdiff_harmonic_nonperiodic.jl index b9173ec9f49..8ffc1c326df 100644 --- a/examples/tree_1d_dgsem/elixir_hypdiff_harmonic_nonperiodic.jl +++ b/examples/tree_1d_dgsem/elixir_hypdiff_harmonic_nonperiodic.jl @@ -70,9 +70,11 @@ save_solution = SaveSolutionCallback(interval = 100, stepsize_callback = StepsizeCallback(cfl = 1.75) +nan_callback = NaNCallback(analysis_interval = analysis_interval) + callbacks = CallbackSet(summary_callback, steady_state_callback, analysis_callback, alive_callback, - save_solution, + save_solution, nan_callback, stepsize_callback) ############################################################################### diff --git a/examples/tree_2d_dgsem/elixir_advection_timeintegration.jl b/examples/tree_2d_dgsem/elixir_advection_timeintegration.jl index 06982bb9a27..0acca2a8487 100644 --- a/examples/tree_2d_dgsem/elixir_advection_timeintegration.jl +++ b/examples/tree_2d_dgsem/elixir_advection_timeintegration.jl @@ -49,9 +49,11 @@ amr_callback = AMRCallback(semi, amr_controller, stepsize_callback = StepsizeCallback(cfl = 1.6) +nan_callback = NaNCallback(analysis_interval = analysis_interval) + callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, - save_solution, + save_solution, nan_callback, amr_callback, stepsize_callback) ############################################################################### diff --git a/examples/tree_2d_dgsem/elixir_euler_blast_wave_sc_subcell_nonperiodic.jl b/examples/tree_2d_dgsem/elixir_euler_blast_wave_sc_subcell_nonperiodic.jl index 209aa2ae352..2266e0665cf 100644 --- a/examples/tree_2d_dgsem/elixir_euler_blast_wave_sc_subcell_nonperiodic.jl +++ b/examples/tree_2d_dgsem/elixir_euler_blast_wave_sc_subcell_nonperiodic.jl @@ -77,9 +77,11 @@ save_solution = SaveSolutionCallback(interval = 100, stepsize_callback = StepsizeCallback(cfl = 0.3) +nan_callback = NaNCallback(analysis_interval = analysis_interval) + callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, - save_solution, + save_solution, nan_callback, stepsize_callback) ############################################################################### diff --git a/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_sc_subcell.jl b/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_sc_subcell.jl index 1817672778a..5ca391f917e 100644 --- a/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_sc_subcell.jl +++ b/examples/tree_2d_dgsem/elixir_euler_kelvin_helmholtz_instability_sc_subcell.jl @@ -75,9 +75,11 @@ save_restart = SaveRestartCallback(interval = 1000, stepsize_callback = StepsizeCallback(cfl = 0.7) +nan_callback = NaNCallback(analysis_interval = analysis_interval) + callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, - stepsize_callback, + stepsize_callback, nan_callback, save_restart, save_solution) ############################################################################### diff --git a/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave_sc_subcell.jl b/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave_sc_subcell.jl index c1ba3d96962..439e422bdfd 100644 --- a/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave_sc_subcell.jl +++ b/examples/tree_2d_dgsem/elixir_euler_sedov_blast_wave_sc_subcell.jl @@ -76,9 +76,11 @@ save_solution = SaveSolutionCallback(interval = 1000, stepsize_callback = StepsizeCallback(cfl = 0.6) +nan_callback = NaNCallback(analysis_interval = analysis_interval) + callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, - stepsize_callback, + stepsize_callback, nan_callback, save_solution) ############################################################################### # run the simulation diff --git a/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl b/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl index 44e63a0872e..5d75ca13d96 100644 --- a/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl +++ b/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl @@ -74,9 +74,11 @@ save_solution = SaveSolutionCallback(dt = 0.1, stepsize_callback = StepsizeCallback(cfl = 0.6) +nan_callback = NaNCallback(analysis_interval = analysis_interval) + callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, - save_solution, + save_solution, nan_callback, stepsize_callback) ############################################################################### diff --git a/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_minmax.jl b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_minmax.jl index 4b606502ebe..50263b12bb6 100644 --- a/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_minmax.jl +++ b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_minmax.jl @@ -123,11 +123,14 @@ save_solution = SaveSolutionCallback(interval = 600, stepsize_callback = StepsizeCallback(cfl = 0.5) +nan_callback = NaNCallback(analysis_interval = analysis_interval) + callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, - stepsize_callback) + stepsize_callback, + nan_callback) ############################################################################### # run the simulation diff --git a/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl index 78ff47e255f..73921980a21 100644 --- a/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl +++ b/examples/tree_2d_dgsem/elixir_eulermulti_shock_bubble_shockcapturing_subcell_positivity.jl @@ -124,11 +124,14 @@ save_solution = SaveSolutionCallback(interval = 300, stepsize_callback = StepsizeCallback(cfl = 0.9) +nan_callback = NaNCallback(analysis_interval = analysis_interval) + callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, - stepsize_callback) + stepsize_callback, + nan_callback) ############################################################################### # run the simulation diff --git a/examples/tree_2d_dgsem/elixir_hypdiff_lax_friedrichs.jl b/examples/tree_2d_dgsem/elixir_hypdiff_lax_friedrichs.jl index a1a0397a46c..21326c728ec 100644 --- a/examples/tree_2d_dgsem/elixir_hypdiff_lax_friedrichs.jl +++ b/examples/tree_2d_dgsem/elixir_hypdiff_lax_friedrichs.jl @@ -75,9 +75,11 @@ save_solution = SaveSolutionCallback(interval = 100, stepsize_callback = StepsizeCallback(cfl = 1.2) +nan_callback = NaNCallback(analysis_interval = analysis_interval) + callbacks = CallbackSet(summary_callback, steady_state_callback, analysis_callback, alive_callback, - save_solution, + save_solution, nan_callback, stepsize_callback) ############################################################################### diff --git a/examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl b/examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl index 74d0370647a..59a445737e1 100644 --- a/examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl +++ b/examples/tree_2d_dgsem/elixir_mhd_shockcapturing_subcell.jl @@ -88,6 +88,8 @@ save_solution = SaveSolutionCallback(interval = 100, cfl = 0.4 stepsize_callback = StepsizeCallback(cfl = cfl) +nan_callback = NaNCallback(analysis_interval = analysis_interval) + glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, @@ -95,6 +97,7 @@ callbacks = CallbackSet(summary_callback, alive_callback, save_solution, stepsize_callback, + nan_callback, glm_speed_callback) ############################################################################### diff --git a/examples/tree_3d_dgsem/elixir_hypdiff_lax_friedrichs.jl b/examples/tree_3d_dgsem/elixir_hypdiff_lax_friedrichs.jl index 7bba154a925..d69afaecd95 100644 --- a/examples/tree_3d_dgsem/elixir_hypdiff_lax_friedrichs.jl +++ b/examples/tree_3d_dgsem/elixir_hypdiff_lax_friedrichs.jl @@ -79,9 +79,11 @@ save_solution = SaveSolutionCallback(interval = 100, stepsize_callback = StepsizeCallback(cfl = 2.4) +nan_callback = NaNCallback(analysis_interval = analysis_interval) + callbacks = CallbackSet(summary_callback, steady_state_callback, analysis_callback, alive_callback, - save_solution, + save_solution, nan_callback, stepsize_callback) ############################################################################### diff --git a/examples/tree_3d_dgsem/elixir_hypdiff_nonperiodic.jl b/examples/tree_3d_dgsem/elixir_hypdiff_nonperiodic.jl index 831e01519b6..a9dfc891c1e 100644 --- a/examples/tree_3d_dgsem/elixir_hypdiff_nonperiodic.jl +++ b/examples/tree_3d_dgsem/elixir_hypdiff_nonperiodic.jl @@ -52,9 +52,11 @@ save_solution = SaveSolutionCallback(interval = 100, stepsize_callback = StepsizeCallback(cfl = 1.8) +nan_callback = NaNCallback(analysis_interval = analysis_interval) + callbacks = CallbackSet(summary_callback, steady_state_callback, analysis_callback, alive_callback, - save_solution, + save_solution, nan_callback, stepsize_callback) ############################################################################### diff --git a/src/callbacks_step/nan.jl b/src/callbacks_step/nan.jl index 5a3b3162393..ef683b1ba60 100644 --- a/src/callbacks_step/nan.jl +++ b/src/callbacks_step/nan.jl @@ -9,6 +9,7 @@ NaNCallback(analysis_interval=0, nan_interval=analysis_interval÷10) Callback checking for NaNs in the solution vector `u` every `nan_interval`. +This should be used when using `Trixi.solve` to solve the ODEs. If `analysis_interval ≂̸ 0`, the output is omitted every `analysis_interval` time steps. """ @@ -73,8 +74,11 @@ end # this method is called when the callback is activated function (nan_callback::NaNCallback)(integrator) + @trixi_timeit timer() "NaNCallback" begin if any(isnan, integrator.u) - error("NaN detected in the solution vector `u` at time $(integrator.t)") + error("NaN detected in the solution vector `u`` at time $(integrator.t), + timestep $(integrator.iter)") + end end return nothing end From 110bac7ff759714b334c9b5a4d8c1ca17f7dac17 Mon Sep 17 00:00:00 2001 From: Daniel_Doehring Date: Sun, 25 Feb 2024 09:21:45 +0100 Subject: [PATCH 3/4] docstring --- src/callbacks_step/nan.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/callbacks_step/nan.jl b/src/callbacks_step/nan.jl index ef683b1ba60..69103cd61c0 100644 --- a/src/callbacks_step/nan.jl +++ b/src/callbacks_step/nan.jl @@ -9,9 +9,9 @@ NaNCallback(analysis_interval=0, nan_interval=analysis_interval÷10) Callback checking for NaNs in the solution vector `u` every `nan_interval`. -This should be used when using `Trixi.solve` to solve the ODEs. -If `analysis_interval ≂̸ 0`, the output is omitted every -`analysis_interval` time steps. +This should be used when using `Trixi.solve` to solve the ODEs as the custom +integrators do not come with the `unstable_check` of the DifferentialEquations.jl integrators. +If `analysis_interval ≂̸ 0`, the output is omitted every `analysis_interval` time steps. """ mutable struct NaNCallback nan_interval::Int From 79a6924686798fb79a82023a6745e07e610260fc Mon Sep 17 00:00:00 2001 From: Daniel_Doehring Date: Sun, 25 Feb 2024 09:32:05 +0100 Subject: [PATCH 4/4] fmt --- src/Trixi.jl | 2 +- src/callbacks_step/nan.jl | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Trixi.jl b/src/Trixi.jl index 4f8e23dc521..9caaf935b9b 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -259,7 +259,7 @@ export SemidiscretizationCoupled export SummaryCallback, SteadyStateCallback, AnalysisCallback, AliveCallback, SaveRestartCallback, SaveSolutionCallback, TimeSeriesCallback, VisualizationCallback, AveragingCallback, - AMRCallback, StepsizeCallback, NaNCallback, + AMRCallback, StepsizeCallback, NaNCallback, GlmSpeedCallback, LBMCollisionCallback, EulerAcousticsCouplingCallback, TrivialCallback, AnalysisCallbackCoupled diff --git a/src/callbacks_step/nan.jl b/src/callbacks_step/nan.jl index 69103cd61c0..1a16cd4d913 100644 --- a/src/callbacks_step/nan.jl +++ b/src/callbacks_step/nan.jl @@ -19,7 +19,7 @@ mutable struct NaNCallback end function NaNCallback(; analysis_interval = 0, - nan_interval = analysis_interval ÷ 10) + nan_interval = analysis_interval ÷ 10) nan_callback = NaNCallback(nan_interval, analysis_interval) DiscreteCallback(nan_callback, nan_callback, # the first one is the condition, the second the affect! @@ -75,10 +75,10 @@ end # this method is called when the callback is activated function (nan_callback::NaNCallback)(integrator) @trixi_timeit timer() "NaNCallback" begin - if any(isnan, integrator.u) - error("NaN detected in the solution vector `u`` at time $(integrator.t), - timestep $(integrator.iter)") - end + if any(isnan, integrator.u) + error("NaN detected in the solution vector `u`` at time $(integrator.t), + timestep $(integrator.iter)") + end end return nothing end