-
Notifications
You must be signed in to change notification settings - Fork 1
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
Add cubed sphere test cases #199
base: main
Are you sure you want to change the base?
Changes from 95 commits
d5ecc49
72709e5
71ba4bf
9c83b05
5b3960b
3e31f4a
2d45c62
92d817a
530f5cc
c7d38d4
ba00c6f
cdf6e5e
aa6d8c7
cf43795
dda491a
35513ac
bf0b732
b864850
9430f2d
5956a78
ccd23fc
1be73d9
584a674
7c82c90
d1850a7
fd103d9
6170610
94cc1c7
7dbb2c6
7906080
ff6ac54
dfea9e4
017e166
f534175
8b6a81f
f96436b
b76ca70
37b88a1
95ba0cc
44ffad8
b40a2a1
e4d6901
66ee664
3f665f0
3a0387b
49394c7
9bc76b4
110219d
ade7e73
6627b97
2550872
211de01
08daf22
e7ab9eb
6672d9c
e48dcb2
00e4914
312e979
a175a04
d5fd61f
4449a82
0a359b1
0351ea9
7b654a4
41ab02a
6bda669
a8c573e
5a33b95
378dc90
8c36455
f28d802
d95de39
492d1c4
272a0a2
9e36f4e
c6ec30a
b866b8b
ac1b653
58444f3
5f02f44
218cd91
47a2e4c
8bd1b23
85f882c
49fa815
5cf1aec
8ccad7b
5599568
142e6a2
8794de7
b7bd4c4
5f5fe48
f341561
889f990
63ece7a
90312a1
b379e50
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 | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -15,6 +15,43 @@ using LinearAlgebra | |||||||||||||||||||||||||||
using LibTrixi | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
# Callable struct holding vectors with source terms | ||||||||||||||||||||||||||||
struct SourceTerm | ||||||||||||||||||||||||||||
nnodesdim::Int | ||||||||||||||||||||||||||||
registry::LibTrixiDataRegistry | ||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
# We overwrite Trixi.jl's internal method here such that it calls source_terms with indices | ||||||||||||||||||||||||||||
function Trixi.calc_sources!(du, u, t, source_terms::SourceTerm, | ||||||||||||||||||||||||||||
equations::CompressibleEulerEquations3D, dg::DG, cache) | ||||||||||||||||||||||||||||
@unpack node_coordinates = cache.elements | ||||||||||||||||||||||||||||
Trixi.@threaded for element in eachelement(dg, cache) | ||||||||||||||||||||||||||||
for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg) | ||||||||||||||||||||||||||||
u_local = Trixi.get_node_vars(u, equations, dg, i, j, k, element) | ||||||||||||||||||||||||||||
du_local = source_terms(u_local, i, j, k, element, t, equations) | ||||||||||||||||||||||||||||
#x_local = Trixi.get_node_coords(node_coordinates, equations, dg, | ||||||||||||||||||||||||||||
# i, j, k, element) | ||||||||||||||||||||||||||||
#du_local_ref = source_terms_baroclinic_instability(u_local, x_local, t, | ||||||||||||||||||||||||||||
# equations) | ||||||||||||||||||||||||||||
Trixi.add_to_node_vars!(du, du_local, equations, dg, i, j, k, element) | ||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||
return nothing | ||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
@inline function (source::SourceTerm)(u, i, j, k, element, t, | ||||||||||||||||||||||||||||
equations::CompressibleEulerEquations3D) | ||||||||||||||||||||||||||||
@unpack nnodesdim = source | ||||||||||||||||||||||||||||
index_global = (element-1) * nnodesdim^3 + (k-1) * nnodesdim^2 + (j-1) * nnodesdim + i | ||||||||||||||||||||||||||||
du2::Vector{Float64} = source.registry[1] | ||||||||||||||||||||||||||||
du3::Vector{Float64} = source.registry[2] | ||||||||||||||||||||||||||||
du4::Vector{Float64} = source.registry[3] | ||||||||||||||||||||||||||||
du5::Vector{Float64} = source.registry[4] | ||||||||||||||||||||||||||||
return SVector(zero(eltype(u)), du2[index_global], du3[index_global], | ||||||||||||||||||||||||||||
du4[index_global], du5[index_global]) | ||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
# Initial condition for an idealized baroclinic instability test | ||||||||||||||||||||||||||||
# https://doi.org/10.1002/qj.2241, Section 3.2 and Appendix A | ||||||||||||||||||||||||||||
function initial_condition_baroclinic_instability(x, t, | ||||||||||||||||||||||||||||
|
@@ -193,38 +230,51 @@ end | |||||||||||||||||||||||||||
# The function to create the simulation state needs to be named `init_simstate` | ||||||||||||||||||||||||||||
function init_simstate() | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
############################################################################### | ||||||||||||||||||||||||||||
# Setup for the baroclinic instability test | ||||||||||||||||||||||||||||
# compressible euler equations | ||||||||||||||||||||||||||||
gamma = 1.4 | ||||||||||||||||||||||||||||
equations = CompressibleEulerEquations3D(gamma) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
############################################################################### | ||||||||||||||||||||||||||||
# semidiscretization of the problem | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
# setup of the problem | ||||||||||||||||||||||||||||
initial_condition = initial_condition_baroclinic_instability | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
boundary_conditions = Dict(:inside => boundary_condition_slip_wall, | ||||||||||||||||||||||||||||
:outside => boundary_condition_slip_wall) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
# This is a good estimate for the speed of sound in this example. | ||||||||||||||||||||||||||||
# Other values between 300 and 400 should work as well. | ||||||||||||||||||||||||||||
# estimate for the speed of sound | ||||||||||||||||||||||||||||
surface_flux = FluxLMARS(340) | ||||||||||||||||||||||||||||
volume_flux = flux_kennedy_gruber | ||||||||||||||||||||||||||||
solver = DGSEM(polydeg = 5, surface_flux = surface_flux, | ||||||||||||||||||||||||||||
volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
trees_per_cube_face = (16, 8) | ||||||||||||||||||||||||||||
mesh = Trixi.P4estMeshCubedSphere(trees_per_cube_face..., 6.371229e6, 30000.0, | ||||||||||||||||||||||||||||
polydeg = 5, initial_refinement_level = 0) | ||||||||||||||||||||||||||||
# for nice results, use 4 and 8 here | ||||||||||||||||||||||||||||
lat_lon_levels = 2 | ||||||||||||||||||||||||||||
layers = 4 | ||||||||||||||||||||||||||||
mesh = Trixi.T8codeMeshCubedSphere(lat_lon_levels, layers, 6.371229e6, 30000.0, | ||||||||||||||||||||||||||||
polydeg = 5, initial_refinement_level = 0) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
# create the data registry and three vectors for the source terms | ||||||||||||||||||||||||||||
benegee marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||
registry = LibTrixiDataRegistry(undef, 4) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
nnodesdim = Trixi.nnodes(solver) | ||||||||||||||||||||||||||||
nnodes = nnodesdim^3 | ||||||||||||||||||||||||||||
nelements = Trixi.ncells(mesh) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
# provide some data because calc_sources! will already be called during initialization | ||||||||||||||||||||||||||||
zero_data = zeros(Float64, nelements*nnodes) | ||||||||||||||||||||||||||||
registry[1] = zero_data | ||||||||||||||||||||||||||||
registry[2] = zero_data | ||||||||||||||||||||||||||||
registry[3] = zero_data | ||||||||||||||||||||||||||||
registry[4] = zero_data | ||||||||||||||||||||||||||||
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 current implementation does not seem correct. All entries of I see that they will be overwritten later again. However, my feeling is that it would be better to make sure that this is not accidentally considered a valid implementation:
Suggested change
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. As a side note, I am starting to wonder if storage for source terms should maybe live on the Trixi.jl side instead of the C side. This goes against previous statements I made, and I wouldn't change it now before we have gathered more experience with it. However, it seems to me that it is overly convoluted this way, especially since it's effectively Trixi.jl that needs and controls the memory, not the C side 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. True! I now allocate separate arrays to avoid confusion. 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 argument for memory management on C side was that some large software frameworks have their own storage pool and would like to use it. |
||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
source_term_data_registry = SourceTerm(nnodesdim, registry) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, | ||||||||||||||||||||||||||||
source_terms = source_terms_baroclinic_instability, | ||||||||||||||||||||||||||||
source_terms = source_term_data_registry, | ||||||||||||||||||||||||||||
boundary_conditions = boundary_conditions) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
############################################################################### | ||||||||||||||||||||||||||||
# ODE solvers, callbacks etc. | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
tspan = (0.0, 12 * 24 * 60 * 60.0) # time in seconds for 12 days# | ||||||||||||||||||||||||||||
# for nice results, use 10 days | ||||||||||||||||||||||||||||
days = 0.02 | ||||||||||||||||||||||||||||
tspan = (0.0, days * 24 * 60 * 60.0) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
ode = semidiscretize(semi, tspan) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
|
@@ -235,33 +285,24 @@ function init_simstate() | |||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
alive_callback = AliveCallback(analysis_interval = analysis_interval) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
save_solution = SaveSolutionCallback(interval = 5000, | ||||||||||||||||||||||||||||
save_solution = SaveSolutionCallback(interval = 500, | ||||||||||||||||||||||||||||
save_initial_solution = true, | ||||||||||||||||||||||||||||
save_final_solution = true, | ||||||||||||||||||||||||||||
solution_variables = cons2prim, | ||||||||||||||||||||||||||||
output_directory = "out_baroclinic",) | ||||||||||||||||||||||||||||
output_directory = "out_baroclinic") | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
callbacks = CallbackSet(summary_callback, | ||||||||||||||||||||||||||||
analysis_callback, | ||||||||||||||||||||||||||||
alive_callback, | ||||||||||||||||||||||||||||
save_solution) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
############################################################################### | ||||||||||||||||||||||||||||
# create the time integrator | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
# OrdinaryDiffEq's `integrator` | ||||||||||||||||||||||||||||
# Use a Runge-Kutta method with automatic (error based) time step size control | ||||||||||||||||||||||||||||
integrator = init(ode, RDPK3SpFSAL49(); | ||||||||||||||||||||||||||||
# use a Runge-Kutta method with automatic (error based) time step size control | ||||||||||||||||||||||||||||
integrator = init(ode, RDPK3SpFSAL49(thread = OrdinaryDiffEq.False()); | ||||||||||||||||||||||||||||
abstol = 1.0e-6, reltol = 1.0e-6, | ||||||||||||||||||||||||||||
ode_default_options()..., | ||||||||||||||||||||||||||||
callback = callbacks, | ||||||||||||||||||||||||||||
maxiters=5e5); | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
############################################################################### | ||||||||||||||||||||||||||||
# Create simulation state | ||||||||||||||||||||||||||||
ode_default_options()..., callback = callbacks, maxiters=1e7); | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
simstate = SimulationState(semi, integrator) | ||||||||||||||||||||||||||||
# create simulation state | ||||||||||||||||||||||||||||
simstate = SimulationState(semi, integrator, registry) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
return simstate | ||||||||||||||||||||||||||||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
# A manufactured solution of a circular wind with constant angular velocity | ||
# on a planetary-sized cubed sphere mesh with a blob detected by AMR | ||
# | ||
# Note that this libelixir is based on an elixir by Erik Faulhaber for Trixi.jl | ||
# Source: https://github.com/trixi-framework/Trixi.jl/blob/main/examples/p4est_3d_dgsem/elixir_euler_circular_wind_nonconforming.jl | ||
|
||
using OrdinaryDiffEq | ||
using Trixi | ||
using LinearAlgebra | ||
using LibTrixi | ||
|
||
|
||
function initial_condition_circular_wind(x, t, equations::CompressibleEulerEquations3D) | ||
radius_earth = 6.371229e6 | ||
lambda, phi, r = cart_to_sphere(x) | ||
|
||
p = 1e5 | ||
v1 = -10 * x[2] / radius_earth | ||
v2 = 10 * x[1] / radius_earth | ||
v3 = 0.0 | ||
rho = 1.0 + 0.1 * exp(-50 * ((lambda-1.0)^2/2.0 + (phi-0.4)^2)) + | ||
0.08 * exp(-100 * ((lambda-0.8)^2/4.0 + (phi-0.5)^2)) | ||
|
||
return prim2cons(SVector(rho, v1, v2, v3, p), equations) | ||
end | ||
|
||
@inline function source_terms_circular_wind(u, x, t, | ||
equations::CompressibleEulerEquations3D) | ||
radius_earth = 6.371229e6 | ||
rho = u[1] | ||
|
||
du1 = 0.0 | ||
du2 = -rho * (10 / radius_earth) * (10 * x[1] / radius_earth) | ||
du3 = -rho * (10 / radius_earth) * (10 * x[2] / radius_earth) | ||
du4 = 0.0 | ||
du5 = 0.0 | ||
|
||
return SVector(du1, du2, du3, du4, du5) | ||
end | ||
|
||
function cart_to_sphere(x) | ||
r = norm(x) | ||
lambda = atan(x[2], x[1]) | ||
if lambda < 0 | ||
lambda += 2 * pi | ||
end | ||
phi = asin(x[3] / r) | ||
|
||
return lambda, phi, r | ||
end | ||
|
||
|
||
# The function to create the simulation state needs to be named `init_simstate` | ||
function init_simstate() | ||
|
||
# compressible Euler equations | ||
gamma = 1.4 | ||
equations = CompressibleEulerEquations3D(gamma) | ||
|
||
# setup of the problem | ||
initial_condition = initial_condition_circular_wind | ||
|
||
boundary_conditions = Dict(:inside => boundary_condition_slip_wall, | ||
:outside => boundary_condition_slip_wall) | ||
|
||
# estimate for speed of sound | ||
surface_flux = FluxLMARS(374) | ||
solver = DGSEM(polydeg = 3, surface_flux = surface_flux) | ||
|
||
# increase trees_per_cube_face to 4 to get nicer results | ||
lat_lon_levels = 2 | ||
layers = 1 | ||
mesh = Trixi.T8codeMeshCubedSphere(lat_lon_levels, layers, 6.371229e6, 30000.0, | ||
polydeg = 3, initial_refinement_level = 0) | ||
|
||
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, | ||
source_terms = source_terms_circular_wind, | ||
boundary_conditions = boundary_conditions) | ||
|
||
# increase number of days | ||
days = 0.1 | ||
tspan = (0.0, days * 24 * 60 * 60.0) | ||
|
||
ode = semidiscretize(semi, tspan) | ||
|
||
summary_callback = SummaryCallback() | ||
|
||
analysis_interval = 5000 | ||
analysis_callback = AnalysisCallback(semi, interval = analysis_interval) | ||
|
||
alive_callback = AliveCallback(analysis_interval = analysis_interval) | ||
|
||
save_solution = SaveSolutionCallback(interval = 2000, | ||
save_initial_solution = true, | ||
save_final_solution = true, | ||
solution_variables = cons2prim, | ||
output_directory = "out_tracer") | ||
|
||
amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first), | ||
base_level = 0, | ||
med_level = 1, med_threshold = 1.004, | ||
max_level = 3, max_threshold = 1.11) | ||
|
||
amr_callback = AMRCallback(semi, amr_controller, | ||
interval = 2000, | ||
adapt_initial_condition = true, | ||
adapt_initial_condition_only_refine = true) | ||
|
||
callbacks = CallbackSet(summary_callback, | ||
analysis_callback, | ||
alive_callback, | ||
amr_callback, | ||
save_solution) | ||
|
||
# use a Runge-Kutta method with automatic (error based) time step size control | ||
integrator = init(ode, RDPK3SpFSAL49(thread = OrdinaryDiffEq.False()); | ||
abstol = 1.0e-6, reltol = 1.0e-6, | ||
ode_default_options()..., callback = callbacks, maxiters=1e7); | ||
|
||
# create simulation state | ||
simstate = SimulationState(semi, integrator) | ||
|
||
return simstate | ||
end |
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.
Why?
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.
Good catch!
At some point I ran t8code elixirs also with PC, but not anymore.
Removed this line.