Skip to content
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 3D Cartesian Shallow Water Equations #36

Merged
merged 20 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
368b91e
Added curl invariant metrics
amrueda Sep 16, 2024
56a04d0
Fixed specialization of create_cache for semidiscretization_hyperbolic
amrueda Sep 17, 2024
3f78c43
Specialized the computation of the time-step size for 3D equations in…
amrueda Sep 17, 2024
6307055
Updated test results and formatted
amrueda Sep 17, 2024
d39bb66
Added 3D Cartesian Shallow Water equations and entropy-consistent dis…
amrueda Sep 17, 2024
a6c5ec9
Fixed the computation of the metric terms for 2D manifolds in 3D with…
amrueda Sep 17, 2024
e16e866
Added test for 3D Cartesian Shallow Water Equations
amrueda Sep 17, 2024
16b8034
Use Fjordholm flux in EC through correction test to improve coverage
amrueda Sep 17, 2024
a6cd055
Changes to fix the Documenter action
amrueda Sep 17, 2024
111fa45
Fixed equation renderung for documenter and removed max_abs_speed_nai…
amrueda Sep 17, 2024
b13d5c9
Merge branch 'main' into arr/spherical_shallow_water_es
amrueda Nov 4, 2024
37ef0bf
Merge branch 'main' into arr/spherical_shallow_water_es
amrueda Nov 6, 2024
ea64024
Changed name of MetricTermsCurlInvariant to MetricTermsInvariantCurl …
amrueda Nov 6, 2024
23e46bd
Updated test reference results (due to new time-step size routine)
amrueda Nov 6, 2024
8a9ef3d
Moved the Lagrange multiplier functions to shallow_water_3d.jl and im…
amrueda Nov 7, 2024
9ef87f7
Removed the custom rhs routine from the Cartesian spherical shell eli…
amrueda Nov 7, 2024
58aa42b
Apply suggestions from code review
amrueda Nov 8, 2024
9bb4970
Adapted elixirs to new variables that are exported by TrixiAtmo
amrueda Nov 8, 2024
be72d3e
Merge branch 'main' into arr/spherical_shallow_water_es
amrueda Nov 8, 2024
7a42b0f
Format
amrueda Nov 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ version = "0.1.0-DEV"
[deps]
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221"
LoopVectorization = "bdcacae8-1622-11e9-2a5c-532679323890"
NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3"
Expand All @@ -17,6 +18,7 @@ Trixi = "a7f1ee26-1774-49b1-8366-f1abc58fbfcb"
[compat]
LinearAlgebra = "1"
MuladdMacro = "0.2.2"
LoopVectorization = "0.12.118"
NLsolve = "4.5.1"
Reexport = "1.0"
Static = "0.8, 1"
Expand Down
43 changes: 5 additions & 38 deletions examples/elixir_euler_spherical_advection_cartesian.jl
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ end

# Source term function to transform the Euler equations into the linear advection equations with variable advection velocity
function source_terms_convert_to_linear_advection(u, du, x, t,
equations::CompressibleEulerEquations3D)
equations::CompressibleEulerEquations3D,
normal_direction)
v1 = u[2] / u[1]
v2 = u[3] / u[1]
v3 = u[4] / u[1]
Expand All @@ -70,35 +71,6 @@ function source_terms_convert_to_linear_advection(u, du, x, t,
return SVector(0.0, s2, s3, s4, s5)
end

# Custom RHS that applies a source term that depends on du (used to convert the 3D Euler equations into the 3D linear advection
# equations with position-dependent advection speed)
function rhs_semi_custom!(du_ode, u_ode, semi, t)
# Compute standard Trixi RHS
Trixi.rhs!(du_ode, u_ode, semi, t)

# Now apply the custom source term
Trixi.@trixi_timeit Trixi.timer() "custom source term" begin
@unpack solver, equations, cache = semi
@unpack node_coordinates = cache.elements

# Wrap the solution and RHS
u = Trixi.wrap_array(u_ode, semi)
du = Trixi.wrap_array(du_ode, semi)

Trixi.@threaded for element in eachelement(solver, cache)
for j in eachnode(solver), i in eachnode(solver)
u_local = Trixi.get_node_vars(u, equations, solver, i, j, element)
du_local = Trixi.get_node_vars(du, equations, solver, i, j, element)
x_local = Trixi.get_node_coords(node_coordinates, equations, solver,
i, j, element)
source = source_terms_convert_to_linear_advection(u_local, du_local,
x_local, t, equations)
Trixi.add_to_node_vars!(du, source, equations, solver, i, j, element)
end
end
end
end

initial_condition = initial_condition_advection_sphere

element_local_mapping = false
Expand All @@ -108,7 +80,8 @@ mesh = TrixiAtmo.P4estMeshCubedSphere2D(5, 1.0, polydeg = polydeg,
element_local_mapping = element_local_mapping)

# A semidiscretization collects data structures and functions for the spatial discretization
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver)
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver,
source_terms = source_terms_convert_to_linear_advection)

###############################################################################
# ODE solvers, callbacks etc.
Expand All @@ -117,12 +90,6 @@ semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver)
tspan = (0.0, pi)
ode = semidiscretize(semi, tspan)

# Create custom discretization that runs with the custom RHS
ode_semi_custom = ODEProblem(rhs_semi_custom!,
ode.u0,
ode.tspan,
semi)

# At the beginning of the main loop, the SummaryCallback prints a summary of the simulation setup
# and resets the timers
summary_callback = SummaryCallback()
Expand All @@ -148,7 +115,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, save_solution,
# run the simulation

# OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks
sol = solve(ode_semi_custom, CarpenterKennedy2N54(williamson_condition = false),
sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false),
dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback
save_everystep = false, callback = callbacks);

Expand Down
125 changes: 125 additions & 0 deletions examples/elixir_shallowwater_cubed_sphere_shell_EC_correction.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@

using OrdinaryDiffEq
using Trixi

amrueda marked this conversation as resolved.
Show resolved Hide resolved
###############################################################################
# Entropy conservation for the spherical shallow water equations in Cartesian
# form obtained through an entropy correction term

equations = ShallowWaterEquations3D(gravity_constant = 9.81)

# Create DG solver with polynomial degree = 3 and Wintemeyer et al.'s flux as surface flux
polydeg = 3
volume_flux = flux_fjordholm_etal #flux_wintermeyer_etal
surface_flux = flux_fjordholm_etal #flux_wintermeyer_etal #flux_lax_friedrichs
solver = DGSEM(polydeg = polydeg,
surface_flux = surface_flux,
volume_integral = VolumeIntegralFluxDifferencing(volume_flux))

# Initial condition for a Gaussian density profile with constant pressure
# and the velocity of a rotating solid body
function initial_condition_advection_sphere(x, t, equations::ShallowWaterEquations3D)
# Gaussian density
rho = 1.0 + exp(-20 * (x[1]^2 + x[3]^2))

# Spherical coordinates for the point x
if sign(x[2]) == 0.0
signy = 1.0
else
signy = sign(x[2])
end
# Co-latitude
colat = acos(x[3] / sqrt(x[1]^2 + x[2]^2 + x[3]^2))
# Latitude (auxiliary variable)
lat = -colat + 0.5 * pi
# Longitude
r_xy = sqrt(x[1]^2 + x[2]^2)
if r_xy == 0.0
phi = pi / 2
else
phi = signy * acos(x[1] / r_xy)
end

# Compute the velocity of a rotating solid body
# (alpha is the angle between the rotation axis and the polar axis of the spherical coordinate system)
v0 = 1.0 # Velocity at the "equator"
alpha = 0.0 #pi / 4
v_long = v0 * (cos(lat) * cos(alpha) + sin(lat) * cos(phi) * sin(alpha))
v_lat = -v0 * sin(phi) * sin(alpha)

# Transform to Cartesian coordinate system
v1 = -cos(colat) * cos(phi) * v_lat - sin(phi) * v_long
v2 = -cos(colat) * sin(phi) * v_lat + cos(phi) * v_long
v3 = sin(colat) * v_lat

return prim2cons(SVector(rho, v1, v2, v3, 0), equations)
end

# Source term function to apply the entropy correction term and the Lagrange multiplier to the semi-discretization.
# The vector contravariant_normal_vector contains the normal contravariant vectors scaled with the inverse Jacobian.
# The Lagrange multiplier is applied with the vector x, which contains the exact normal direction to the 2D manifold.
function source_terms_entropy_correction(u, du, x, t,
equations::ShallowWaterEquations3D,
contravariant_normal_vector)

# Entropy correction term
s2 = -contravariant_normal_vector[1] * equations.gravity * u[1]^2
s3 = -contravariant_normal_vector[2] * equations.gravity * u[1]^2
s4 = -contravariant_normal_vector[3] * equations.gravity * u[1]^2

new_du = SVector(du[1], du[2] + s2, du[3] + s3, du[4] + s4, du[5])

# Apply Lagrange multipliers using the exact normal vector to the 2D manifold (x)
s = source_terms_lagrange_multiplier(u, new_du, x, t, equations, x)

return SVector(s[1], s[2] + s2, s[3] + s3, s[4] + s4, s[5])
end

initial_condition = initial_condition_advection_sphere

mesh = TrixiAtmo.P4estMeshCubedSphere2D(5, 2.0, polydeg = polydeg,
initial_refinement_level = 0)

# A semidiscretization collects data structures and functions for the spatial discretization
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver,
metric_terms = TrixiAtmo.MetricTermsInvariantCurl(),
source_terms = source_terms_entropy_correction)

###############################################################################
# ODE solvers, callbacks etc.

# Create ODE problem with time span from 0.0 to π
tspan = (0.0, pi)
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_callback = AnalysisCallback(semi, interval = 10,
save_analysis = true,
extra_analysis_errors = (:conservation_error,),
extra_analysis_integrals = (waterheight, energy_total))

# The SaveSolutionCallback allows to save the solution to a file in regular intervals
save_solution = SaveSolutionCallback(interval = 10,
solution_variables = cons2prim)

# The StepsizeCallback handles the re-calculation of the maximum Δt after each time step
stepsize_callback = StepsizeCallback(cfl = 0.7)

# Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver
callbacks = CallbackSet(summary_callback, analysis_callback, save_solution,
stepsize_callback)

###############################################################################
# run the simulation

# OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks
sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false),
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()
120 changes: 120 additions & 0 deletions examples/elixir_shallowwater_cubed_sphere_shell_EC_projection.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@

using OrdinaryDiffEq
using Trixi
using TrixiAtmo

###############################################################################
# Entropy conservation for the spherical shallow water equations in Cartesian
# form obtained through the projection of the momentum onto the divergence-free
# tangential contravariant vectors

equations = ShallowWaterEquations3D(gravity_constant = 9.81)

# Create DG solver with polynomial degree = 3 and Wintemeyer et al.'s flux as surface flux
polydeg = 3
volume_flux = flux_wintermeyer_etal # flux_fjordholm_etal
surface_flux = flux_wintermeyer_etal # flux_fjordholm_etal #flux_lax_friedrichs
solver = DGSEM(polydeg = polydeg,
surface_flux = surface_flux,
volume_integral = VolumeIntegralFluxDifferencing(volume_flux))

# Initial condition for a Gaussian density profile with constant pressure
# and the velocity of a rotating solid body
function initial_condition_advection_sphere(x, t, equations::ShallowWaterEquations3D)
# Gaussian density
rho = 1.0 + exp(-20 * (x[1]^2 + x[3]^2))

# Spherical coordinates for the point x
if sign(x[2]) == 0.0
signy = 1.0
else
signy = sign(x[2])
end
# Co-latitude
colat = acos(x[3] / sqrt(x[1]^2 + x[2]^2 + x[3]^2))
# Latitude (auxiliary variable)
lat = -colat + 0.5 * pi
# Longitude
r_xy = sqrt(x[1]^2 + x[2]^2)
if r_xy == 0.0
phi = pi / 2
else
phi = signy * acos(x[1] / r_xy)
end

# Compute the velocity of a rotating solid body
# (alpha is the angle between the rotation axis and the polar axis of the spherical coordinate system)
v0 = 1.0 # Velocity at the "equator"
alpha = 0.0 #pi / 4
v_long = v0 * (cos(lat) * cos(alpha) + sin(lat) * cos(phi) * sin(alpha))
v_lat = -v0 * sin(phi) * sin(alpha)

# Transform to Cartesian coordinate system
v1 = -cos(colat) * cos(phi) * v_lat - sin(phi) * v_long
v2 = -cos(colat) * sin(phi) * v_lat + cos(phi) * v_long
v3 = sin(colat) * v_lat

return prim2cons(SVector(rho, v1, v2, v3, 0), equations)
end

initial_condition = initial_condition_advection_sphere

mesh = TrixiAtmo.P4estMeshCubedSphere2D(5, 2.0, polydeg = polydeg,
initial_refinement_level = 0)

# A semidiscretization collects data structures and functions for the spatial discretization
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver,
metric_terms = TrixiAtmo.MetricTermsInvariantCurl(),
source_terms = source_terms_lagrange_multiplier)

###############################################################################
# ODE solvers, callbacks etc.

# Create ODE problem with time span from 0.0 to π
tspan = (0.0, pi)
ode = semidiscretize(semi, tspan)

# Clean the initial condition
for element in eachelement(solver, semi.cache)
for j in eachnode(solver), i in eachnode(solver)
u0 = Trixi.wrap_array(ode.u0, semi)

contravariant_normal_vector = Trixi.get_contravariant_vector(3,
semi.cache.elements.contravariant_vectors,
i, j, element)
clean_solution_lagrange_multiplier!(u0[:, i, j, element], equations,
contravariant_normal_vector)
end
end

# 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_callback = AnalysisCallback(semi, interval = 10,
save_analysis = true,
extra_analysis_errors = (:conservation_error,),
extra_analysis_integrals = (waterheight, energy_total))

# The SaveSolutionCallback allows to save the solution to a file in regular intervals
save_solution = SaveSolutionCallback(interval = 10,
solution_variables = cons2prim)

# The StepsizeCallback handles the re-calculation of the maximum Δt after each time step
stepsize_callback = StepsizeCallback(cfl = 0.7)

# Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver
callbacks = CallbackSet(summary_callback, analysis_callback, save_solution,
stepsize_callback)

###############################################################################
# run the simulation

# OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks
sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false),
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()
Loading
Loading