-
Couldn't load subscription status.
- Fork 131
Adaptive Volume Integral #2601
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
base: main
Are you sure you want to change the base?
Adaptive Volume Integral #2601
Changes from 42 commits
f355e1b
552d717
3ca63fc
147e896
2eec5d8
8e9949b
d823ff5
7bc660a
fc0347a
724335a
3166699
c0b1f0b
9876f85
dde3c81
6ec9287
a96827b
004adba
7409fdb
0bec762
e7ae7a2
32e4c75
0a38976
1375fa7
64c123a
0dac510
58db43b
5f885d6
224b84d
eaefcc1
e27d62a
ab8cb7f
a755aa6
7535812
7533ad0
624113c
a618ec5
56ac3ef
a5fb02b
26dc558
80d6754
ebb2e21
257480f
2c35e7f
6b324f7
80b91ca
dd741d7
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,58 @@ | ||
| using OrdinaryDiffEqLowStorageRK | ||
| using Trixi | ||
|
|
||
| ############################################################################### | ||
| # semidiscretization of the compressible Euler equations | ||
| equations = CompressibleEulerEquations1D(1.4) | ||
|
|
||
| initial_condition = initial_condition_weak_blast_wave | ||
|
|
||
| basis = LobattoLegendreBasis(5) | ||
| surface_flux = flux_lax_friedrichs | ||
| # Note: Plain weak form volume integral is still stable for this problem | ||
|
|
||
| volume_integral_fluxdiff = VolumeIntegralFluxDifferencing(flux_ranocha) | ||
|
|
||
| # Standard Flux-Differencing volume integral, roughly twice as expensive as the adaptive one | ||
| #solver = DGSEM(basis, surface_flux, volume_integral_fluxdiff) | ||
|
|
||
| indicator = IndicatorEntropyViolation(basis; threshold = 1e-6) | ||
| volume_integral = VolumeIntegralAdaptive(indicator; | ||
| volume_integral_default = VolumeIntegralWeakForm(), | ||
| volume_integral_stabilized = volume_integral_fluxdiff) | ||
|
|
||
| solver = DGSEM(basis, surface_flux, volume_integral) | ||
|
|
||
| coordinates_min = (-2.0,) | ||
| coordinates_max = (2.0,) | ||
| mesh = TreeMesh(coordinates_min, coordinates_max, | ||
| initial_refinement_level = 8, | ||
| n_cells_max = 10_000) | ||
|
|
||
| semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) | ||
|
|
||
| ############################################################################### | ||
| # ODE solvers, callbacks etc. | ||
|
|
||
| tspan = (0.0, 1.0) | ||
| ode = semidiscretize(semi, tspan) | ||
|
|
||
| summary_callback = SummaryCallback() | ||
|
|
||
| analysis_interval = 100 | ||
| analysis_callback = AnalysisCallback(semi, interval = analysis_interval) | ||
|
|
||
| alive_callback = AliveCallback(analysis_interval = analysis_interval) | ||
|
|
||
| stepsize_callback = StepsizeCallback(cfl = 0.8) | ||
|
|
||
| callbacks = CallbackSet(summary_callback, | ||
| analysis_callback, alive_callback, | ||
| stepsize_callback) | ||
|
|
||
| ############################################################################### | ||
| # run the simulation | ||
|
|
||
| sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false); | ||
| dt = 1.0, | ||
| ode_default_options()..., callback = callbacks); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| using OrdinaryDiffEqLowStorageRK | ||
| using Trixi | ||
|
|
||
| # Warm bubble test case from | ||
| # - Wicker, L. J., and Skamarock, W. C. (1998) | ||
| # A time-splitting scheme for the elastic equations incorporating | ||
| # second-order Runge–Kutta time differencing | ||
| # [DOI: 10.1175/1520-0493(1998)126%3C1992:ATSSFT%3E2.0.CO;2](https://doi.org/10.1175/1520-0493(1998)126%3C1992:ATSSFT%3E2.0.CO;2) | ||
| # See also | ||
| # - Bryan and Fritsch (2002) | ||
| # A Benchmark Simulation for Moist Nonhydrostatic Numerical Models | ||
| # [DOI: 10.1175/1520-0493(2002)130<2917:ABSFMN>2.0.CO;2](https://doi.org/10.1175/1520-0493(2002)130<2917:ABSFMN>2.0.CO;2) | ||
| # - Carpenter, Droegemeier, Woodward, Hane (1990) | ||
| # Application of the Piecewise Parabolic Method (PPM) to | ||
| # Meteorological Modeling | ||
| # [DOI: 10.1175/1520-0493(1990)118<0586:AOTPPM>2.0.CO;2](https://doi.org/10.1175/1520-0493(1990)118<0586:AOTPPM>2.0.CO;2) | ||
| struct WarmBubbleSetup | ||
| # Physical constants | ||
| g::Float64 # gravity of earth | ||
| c_p::Float64 # heat capacity for constant pressure (dry air) | ||
| c_v::Float64 # heat capacity for constant volume (dry air) | ||
| gamma::Float64 # heat capacity ratio (dry air) | ||
|
|
||
| function WarmBubbleSetup(; g = 9.81, c_p = 1004.0, c_v = 717.0, gamma = c_p / c_v) | ||
| new(g, c_p, c_v, gamma) | ||
| end | ||
| end | ||
|
|
||
| # Initial condition | ||
| function (setup::WarmBubbleSetup)(x, t, equations::CompressibleEulerEquations2D) | ||
| RealT = eltype(x) | ||
| @unpack g, c_p, c_v = setup | ||
|
|
||
| # center of perturbation | ||
| center_x = 10000 | ||
| center_z = 2000 | ||
| # radius of perturbation | ||
| radius = 2000 | ||
| # distance of current x to center of perturbation | ||
| r = sqrt((x[1] - center_x)^2 + (x[2] - center_z)^2) | ||
|
|
||
| # perturbation in potential temperature | ||
| potential_temperature_ref = 300 | ||
| potential_temperature_perturbation = zero(RealT) | ||
| if r <= radius | ||
| potential_temperature_perturbation = 2 * cospi(0.5f0 * r / radius)^2 | ||
| end | ||
| potential_temperature = potential_temperature_ref + potential_temperature_perturbation | ||
|
|
||
| # Exner pressure, solves hydrostatic equation for x[2] | ||
| exner = 1 - g / (c_p * potential_temperature) * x[2] | ||
|
|
||
| # pressure | ||
| p_0 = 100_000 # reference pressure | ||
| R = c_p - c_v # gas constant (dry air) | ||
| p = p_0 * exner^(c_p / R) | ||
|
|
||
| # temperature | ||
| T = potential_temperature * exner | ||
|
|
||
| # density | ||
| rho = p / (R * T) | ||
|
|
||
| v1 = 20 | ||
| v2 = 0 | ||
| E = c_v * T + 0.5f0 * (v1^2 + v2^2) | ||
| return SVector(rho, rho * v1, rho * v2, rho * E) | ||
| end | ||
|
|
||
| # Source terms | ||
| @inline function (setup::WarmBubbleSetup)(u, x, t, equations::CompressibleEulerEquations2D) | ||
| @unpack g = setup | ||
| rho, _, rho_v2, _ = u | ||
| return SVector(zero(eltype(u)), zero(eltype(u)), -g * rho, -g * rho_v2) | ||
| end | ||
|
|
||
| ############################################################################### | ||
| # semidiscretization of the compressible Euler equations | ||
| warm_bubble_setup = WarmBubbleSetup() | ||
|
|
||
| equations = CompressibleEulerEquations2D(warm_bubble_setup.gamma) | ||
|
|
||
| boundary_conditions = (x_neg = boundary_condition_periodic, | ||
| x_pos = boundary_condition_periodic, | ||
| y_neg = boundary_condition_slip_wall, | ||
| y_pos = boundary_condition_slip_wall) | ||
|
|
||
| polydeg = 5 | ||
| basis = LobattoLegendreBasis(polydeg) | ||
|
|
||
| # This is a good estimate for the speed of sound in this example. | ||
| # Other values between 300 and 400 should work as well. | ||
| surface_flux = FluxLMARS(340.0) | ||
|
|
||
| volume_flux = flux_kennedy_gruber | ||
|
|
||
| indicator = IndicatorEntropyViolation(basis; threshold = 1e-3) | ||
| volume_integral = VolumeIntegralAdaptive(indicator; | ||
| volume_integral_default = VolumeIntegralWeakForm(), | ||
| volume_integral_stabilized = VolumeIntegralFluxDifferencing(volume_flux)) | ||
|
|
||
| # This would be the standard version | ||
| #volume_integral = VolumeIntegralFluxDifferencing(volume_flux) | ||
|
|
||
| solver = DGSEM(basis, surface_flux, volume_integral) | ||
|
|
||
| coordinates_min = (0.0, -5000.0) | ||
| coordinates_max = (20_000.0, 15_000.0) | ||
|
|
||
| mesh = TreeMesh(coordinates_min, coordinates_max, | ||
| initial_refinement_level = 5, | ||
| n_cells_max = 10_000, | ||
| periodicity = (true, false)) | ||
|
|
||
| semi = SemidiscretizationHyperbolic(mesh, equations, warm_bubble_setup, solver, | ||
| source_terms = warm_bubble_setup, | ||
| boundary_conditions = boundary_conditions) | ||
|
|
||
| ############################################################################### | ||
| # ODE solvers, callbacks etc. | ||
|
|
||
| tspan = (0.0, 1000.0) # seconds | ||
|
|
||
| ode = semidiscretize(semi, tspan) | ||
|
|
||
| summary_callback = SummaryCallback() | ||
|
|
||
| analysis_interval = 10_000 | ||
| analysis_callback = AnalysisCallback(semi, interval = analysis_interval) | ||
|
|
||
| alive_callback = AliveCallback(analysis_interval = analysis_interval) | ||
|
|
||
| save_solution = SaveSolutionCallback(interval = analysis_interval, | ||
| solution_variables = cons2prim) | ||
|
|
||
| stepsize_callback = StepsizeCallback(cfl = 0.8) | ||
|
|
||
| callbacks = CallbackSet(summary_callback, | ||
| analysis_callback, | ||
| alive_callback, | ||
| save_solution, | ||
| stepsize_callback) | ||
|
|
||
| ############################################################################### | ||
| # run the simulation | ||
| sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, thread = Trixi.True()); | ||
| dt = 1.0, # solve needs a value here, will be overwritten by the stepsize_callback | ||
| ode_default_options()..., callback = callbacks); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -177,8 +177,60 @@ function Base.show(io::IO, mime::MIME"text/plain", | |
| end | ||
|
|
||
| function get_element_variables!(element_variables, u, mesh, equations, | ||
| volume_integral::VolumeIntegralShockCapturingHG, dg, | ||
| cache) | ||
| volume_integral::VolumeIntegralShockCapturingHG, | ||
| dg, cache) | ||
| # call the indicator to get up-to-date values for IO | ||
| volume_integral.indicator(u, mesh, equations, dg, cache) | ||
| get_element_variables!(element_variables, volume_integral.indicator, | ||
| volume_integral) | ||
| end | ||
|
|
||
| """ | ||
| VolumeIntegralAdaptive(indicator; | ||
| volume_integral_default = VolumeIntegralWeakForm(), | ||
| volume_integral_stabilized = VolumeIntegralFluxDifferencing(flux_central)) | ||
|
|
||
| Possible combination: [`VolumeIntegralWeakForm`](@ref) and [`VolumeIntegralFluxDifferencing`](@ref). | ||
| TODO: Extend to [`VolumeIntegralWeakForm`](@ref) and [`VolumeIntegralShockCapturingHG`](@ref). | ||
|
Comment on lines
+193
to
+194
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. There are some TODO notes left. How do you want to handle them? 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. This is probably something for the Trixi meeting. The main question is if 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. 👍 |
||
| """ | ||
| struct VolumeIntegralAdaptive{VolumeIntegralDefault, VolumeIntegralStabilized, | ||
| Indicator} <: AbstractVolumeIntegral | ||
| volume_integral_default::VolumeIntegralDefault # Cheap(er) default volume integral to be used in non-critical regions | ||
| volume_integral_stabilized::VolumeIntegralStabilized # More expensive volume integral with stabilizing effect | ||
| indicator::Indicator | ||
| end | ||
|
|
||
| function VolumeIntegralAdaptive(indicator; | ||
| volume_integral_default = VolumeIntegralWeakForm(), | ||
| volume_integral_stabilized = VolumeIntegralFluxDifferencing(flux_central)) | ||
| VolumeIntegralAdaptive{typeof(volume_integral_default), | ||
| typeof(volume_integral_stabilized), | ||
| typeof(indicator)}(volume_integral_default, | ||
| volume_integral_stabilized, | ||
| indicator) | ||
| end | ||
|
|
||
| function Base.show(io::IO, mime::MIME"text/plain", | ||
| integral::VolumeIntegralAdaptive) | ||
| @nospecialize integral # reduce precompilation time | ||
|
|
||
| if get(io, :compact, false) | ||
| show(io, integral) | ||
| else | ||
| summary_header(io, "VolumeIntegralAdaptive") | ||
| summary_line(io, "volume integral default", | ||
| integral.volume_integral_default) | ||
| summary_line(io, "volume integral stabilized", | ||
| integral.volume_integral_stabilized) | ||
| summary_line(io, "indicator", integral.indicator |> typeof |> nameof) | ||
| show(increment_indent(io), mime, integral.indicator) | ||
| summary_footer(io) | ||
| end | ||
| end | ||
|
|
||
| function get_element_variables!(element_variables, u, mesh, equations, | ||
| volume_integral::VolumeIntegralAdaptive, | ||
| dg, cache) | ||
| # call the indicator to get up-to-date values for IO | ||
| volume_integral.indicator(u, mesh, equations, dg, cache) | ||
| get_element_variables!(element_variables, volume_integral.indicator, | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -11,6 +11,13 @@ function create_cache(mesh, equations, | |||||||||
| return NamedTuple() | ||||||||||
| end | ||||||||||
|
|
||||||||||
| function create_cache(mesh, equations, | ||||||||||
| volume_integral::VolumeIntegralAdaptive, dg::DG, uEltype) | ||||||||||
| return create_cache(mesh, equations, | ||||||||||
| volume_integral.volume_integral_stabilized, | ||||||||||
| dg, uEltype) | ||||||||||
| end | ||||||||||
|
|
||||||||||
| # The following `calc_volume_integral!` functions are | ||||||||||
| # dimension and meshtype agnostic, i.e., valid for all 1D, 2D, and 3D meshes. | ||||||||||
|
|
||||||||||
|
|
@@ -79,6 +86,41 @@ function calc_volume_integral!(du, u, mesh, | |||||||||
| return nothing | ||||||||||
| end | ||||||||||
|
|
||||||||||
| function calc_volume_integral!(du, u, mesh, | ||||||||||
| nonconservative_terms, equations, | ||||||||||
| volume_integral::VolumeIntegralAdaptive{VolumeIntegralWeakForm, | ||||||||||
| VolumeIntegralFD, | ||||||||||
| Indicator}, | ||||||||||
| dg::DGSEM, | ||||||||||
| cache) where { | ||||||||||
| VolumeIntegralFD <: | ||||||||||
| VolumeIntegralFluxDifferencing, | ||||||||||
| Indicator <: AbstractIndicator} | ||||||||||
DanielDoehring marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
| @unpack volume_integral_default, volume_integral_stabilized, indicator = volume_integral | ||||||||||
|
|
||||||||||
| # Calculate decision variable | ||||||||||
| decision = @trixi_timeit timer() "integral selector" indicator(u, mesh, equations, | ||||||||||
| dg, cache) | ||||||||||
|
Comment on lines
+102
to
+103
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.
Suggested change
For consistency with the Hennemann-Gassner shock capturing? |
||||||||||
|
|
||||||||||
| @threaded for element in eachelement(dg, cache) | ||||||||||
| stabilized_version = decision[element] | ||||||||||
|
|
||||||||||
| # TODO: Generalize/Dispatch or introduce yet sub-functions of the volume integrals | ||||||||||
|
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. Good question |
||||||||||
| if stabilized_version | ||||||||||
| flux_differencing_kernel!(du, u, element, mesh, | ||||||||||
| nonconservative_terms, equations, | ||||||||||
| volume_integral_stabilized.volume_flux, | ||||||||||
| dg, cache) | ||||||||||
| else | ||||||||||
| weak_form_kernel!(du, u, element, mesh, | ||||||||||
| nonconservative_terms, equations, | ||||||||||
| dg, cache) | ||||||||||
| end | ||||||||||
| end | ||||||||||
|
|
||||||||||
| return nothing | ||||||||||
| end | ||||||||||
|
|
||||||||||
| function calc_volume_integral!(du, u, mesh, | ||||||||||
| have_nonconservative_terms, equations, | ||||||||||
| volume_integral::VolumeIntegralPureLGLFiniteVolume, | ||||||||||
|
|
||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shall we really prove this as default value? Or should we force people to make a reasonable choice?