From 96a321c255564fb0dafa3a82846d694c97109cf9 Mon Sep 17 00:00:00 2001 From: Benedict <135045760+benegee@users.noreply.github.com> Date: Thu, 18 Jul 2024 14:39:55 +0200 Subject: [PATCH 001/115] Fix CompatHelper with copy from libtrixi --- .github/workflows/CompatHelper.yml | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml index f80bcb00..22584371 100644 --- a/.github/workflows/CompatHelper.yml +++ b/.github/workflows/CompatHelper.yml @@ -10,12 +10,30 @@ jobs: CompatHelper: runs-on: ubuntu-latest steps: - - name: "Add CompatHelper" + - name: Check if Julia is already available in the PATH + id: julia_in_path + run: which julia + continue-on-error: true + - name: Install Julia, but only if it is not already available in the PATH + uses: julia-actions/setup-julia@v2 + with: + version: '1' + arch: ${{ runner.arch }} + if: steps.julia_in_path.outcome != 'success' + - name: "Add the General registry via Git" run: | import Pkg - Pkg.add("CompatHelper") + ENV["JULIA_PKG_SERVER"] = "" + Pkg.Registry.add("General") + shell: julia --color=yes {0} + - name: "Install CompatHelper" + run: | + import Pkg + name = "CompatHelper" + uuid = "aa819f21-2bde-4658-8897-bab36330d9b7" + version = "3" + Pkg.add(; name, uuid, version) shell: julia --color=yes {0} - - name: "Run CompatHelper" run: | import CompatHelper @@ -24,3 +42,4 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} COMPATHELPER_PRIV: ${{ secrets.DOCUMENTER_KEY }} + # COMPATHELPER_PRIV: ${{ secrets.COMPATHELPER_PRIV }} From 8b4b4e070b117a8308692bcd4f19c0334a0f5f6e Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Thu, 18 Jul 2024 15:18:31 +0200 Subject: [PATCH 002/115] try full write --- .github/workflows/CompatHelper.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml index 22584371..5be66f8f 100644 --- a/.github/workflows/CompatHelper.yml +++ b/.github/workflows/CompatHelper.yml @@ -3,9 +3,7 @@ on: schedule: - cron: 0 0 * * * workflow_dispatch: -permissions: - contents: write - pull-requests: write +permissions: write-all jobs: CompatHelper: runs-on: ubuntu-latest From 6a41dc7b32bb6eb9099db6776ba5de93c07b72a9 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:20:34 +0200 Subject: [PATCH 003/115] structural setup, work in progress --- examples/elixir_rainy_euler_bubble.jl | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/elixir_rainy_euler_bubble.jl diff --git a/examples/elixir_rainy_euler_bubble.jl b/examples/elixir_rainy_euler_bubble.jl new file mode 100644 index 00000000..e69de29b From b3518a0b3134e14b6fd7fbb20eeef1142128ace4 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:23:31 +0200 Subject: [PATCH 004/115] structural setup, work in progress --- examples/elixir_rainy_euler_bubble_no_rain.jl | 81 +++++++++++++ src/equations/compressible_rainy_euler_2d.jl | 109 ++++++++++++++++++ 2 files changed, 190 insertions(+) create mode 100644 examples/elixir_rainy_euler_bubble_no_rain.jl create mode 100644 src/equations/compressible_rainy_euler_2d.jl diff --git a/examples/elixir_rainy_euler_bubble_no_rain.jl b/examples/elixir_rainy_euler_bubble_no_rain.jl new file mode 100644 index 00000000..158eb78f --- /dev/null +++ b/examples/elixir_rainy_euler_bubble_no_rain.jl @@ -0,0 +1,81 @@ +using OrdinaryDiffEq +using Trixi + + + +function initial_condition_bubble_no_rain(x, t, equations::CompressibleRainyEulerEquations2D) + #TODO + return +end + + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleRainyEulerEquations2D() + +#TODO check boundary conditions +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 = 3 +basis = LobattoLegendreBasis(polydeg) + +surface_flux = flux_lax_friedrichs + +solver = DGSEM(basis, surface_flux) + +#TODO adjust values +coordinates_min = (0.0, 0.0) +coordinates_max = (1.0, 1.0) + +cells_per_dimension = (64, 32) +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, + periodicity = (true, false)) + +#TODO import source terms from equations +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_bubble_no_rain, solver, + source_terms = source_terms_no_rain, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +#TODO adjust values +tspan = (0.0, 1000.0) # 1000 seconds final time + +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 + +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:entropy_conservation_error,)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = analysis_interval, + save_initial_solution = true, + save_final_solution = true, + output_directory = "out", + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) + +############################################################################### +# run the simulation +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + maxiters = 1.0e7, + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); + +summary_callback() \ No newline at end of file diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl new file mode 100644 index 00000000..3ba7b8ff --- /dev/null +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -0,0 +1,109 @@ +using Trixi + + + +### equation, parameters and constants ### + +struct CompressibleRainyEulerEquations2D{RealT <: Real} + # Specific heat capacities: + c_liquid_water ::Float64 + c_dry_air_const_pressure ::Float64 + c_dry_air_const_volume ::Float64 + c_vapour_const_pressure ::Float64 + c_vapour_const_volume ::Float64 + + # Gas constants: + R_dry_air ::Float64 + R_vapour ::Float64 + eps ::Float64 + + # Reference values: + ref_saturation_pressure ::Float64 + ref_temperature ::Float64 + ref_latent_heat_vap_temp ::Float64 + ref_pressure ::Float64 + + # Other: + gravity ::Float64 + rain_water_distr ::Float64 + v_mean_rain ::Float64 +end + + +function CompressibleRainyEulerEquations2D() + # Specific heat capacities: + c_liquid_water = 4186.0 + c_dry_air_const_pressure = 1004.0 + c_dry_air_const_volume = 717.0 + c_vapour_const_pressure = 1885.0 + c_vapour_const_volume = 1424.0 + + # Gas constants: + R_dry_air = c_dry_air_const_pressure - c_dry_air_const_volume + R_vapour = c_vapour_const_pressure - c_vapour_const_volume + eps = R_dry_air / R_vapour + + # Reference values: + saturation_vapour_pressure = 610.7 + ref_temperature = 273.15 + latent_heat_vap_ref_temp = 2.5e6 + ref_pressure = 1e5 + + # Other: + gravity = 9.81 + rain_water_distr = 8e6 + v_mean_rain = 130.0 + + return CompressibleRainyEulerEquations2D{RealT}(c_liquid_water, c_dry_air_const_pressure, c_dry_air_const_volume, + c_vapour_const_pressure, c_vapour_const_volume, R_dry_air, + R_vapour, eps, saturation_vapour_pressure, ref_temperature, + latent_heat_vap_ref_temp, ref_pressure, gravity, + rain_water_distr, v_mean_rain) +end + + + +### conversion ### + +@inline function cons2prim(u, equations::CompressibleRainyEulerEquations2D) + #TODO + return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) +end + + + +### physics variables ### + +@inline function speed_of_sound(u, equations::CompressibleRainyEulerEquations2D) + #TODO + return v_sound +end + +@inline function terminal_velocity_rain(u, equations::CompressibleRainyEulerEquations2D) + #TODO + return v_terminal_rain +end + +@inline function saturation_vapour_pressure(u, equations::CompressibleRainyEulerEquations2D) + #TODO + return p_vapour_saturation +end + + + +### pde discretization ### + +@inline function flux(u, orientation::Integer, equations::CompressibleRainyEulerEquations2D) + #TODO + return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) +end + +@inline function source_terms_rainy(u, x, t, equations::CompressibleRainyEulerEquations2D) + #TODO + return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) +end + +@inline function source_terms_no_rain(u, x, t, equations::CompressibleRainyEulerEquations2D) + #TODO + return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) +end \ No newline at end of file From ec087c6068d08c50eb4f54f0c0538caa4366745d Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:24:01 +0200 Subject: [PATCH 005/115] ignore VS Code files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 7e53c4ec..8078b1df 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ **/Manifest.toml run run/* +.vscode \ No newline at end of file From bc9bb5b8eceeb79219b0532a8d4fa0d4599071e8 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:25:25 +0200 Subject: [PATCH 006/115] updating equations --- src/equations/equations.jl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 8b137891..fe23c5f7 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -1 +1,9 @@ +using Trixi: AbstractEquations +abstract type AbstractCompressibleMoistEulerEquations{NDIMS, NVARS} <: + AbstractEquations{NDIMS, NVARS} end + +abstract type AbstractCompressibleRainyEulerEquations{NDIMS, NVARS} <: + AbstractEquations{NDIMS, NVARS} end + +include("compressible_rainy_euler_2d.jl") From dc4b1662bd269b46fa37ef41c0bc1d7331d4a600 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 30 Jul 2024 19:42:42 +0200 Subject: [PATCH 007/115] back to default --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 8078b1df..9e1c0470 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ **/Manifest.toml run -run/* -.vscode \ No newline at end of file +run/* \ No newline at end of file From 661b079e13bcf64c49856f5f787c41a9534ac386 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 30 Jul 2024 19:45:18 +0200 Subject: [PATCH 008/115] export of rainy equations --- src/TrixiAtmo.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/TrixiAtmo.jl b/src/TrixiAtmo.jl index 84eac18d..759e76a4 100644 --- a/src/TrixiAtmo.jl +++ b/src/TrixiAtmo.jl @@ -21,5 +21,6 @@ bar() = false baz() = Trixi.examples_dir() include("equations/equations.jl") +export CompressibleRainyEulerEquations2D end # module TrixiAtmo From c23a160f8134c688aaa736f7346798a265c12d46 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 30 Jul 2024 19:50:52 +0200 Subject: [PATCH 009/115] basic structural equation setup --- src/equations/compressible_rainy_euler_2d.jl | 122 ++++++++++++++++--- 1 file changed, 104 insertions(+), 18 deletions(-) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 3ba7b8ff..ccf17ac1 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -1,36 +1,47 @@ using Trixi +import Trixi: varnames, + cons2prim, cons2entropy, + flux, + max_abs_speeds, max_abs_speed_naive, + boundary_condition_slip_wall +#TODO add description of equations and idea + sources + + + +@muladd begin + ### equation, parameters and constants ### -struct CompressibleRainyEulerEquations2D{RealT <: Real} +struct CompressibleRainyEulerEquations2D{RealT <: Real} <: AbstractCompressibleMoistEulerEquations{2, 15} # Specific heat capacities: - c_liquid_water ::Float64 - c_dry_air_const_pressure ::Float64 - c_dry_air_const_volume ::Float64 - c_vapour_const_pressure ::Float64 - c_vapour_const_volume ::Float64 + c_liquid_water ::RealT + c_dry_air_const_pressure ::RealT + c_dry_air_const_volume ::RealT + c_vapour_const_pressure ::RealT + c_vapour_const_volume ::RealT # Gas constants: - R_dry_air ::Float64 - R_vapour ::Float64 - eps ::Float64 + R_dry_air ::RealT + R_vapour ::RealT + eps ::RealT # Reference values: - ref_saturation_pressure ::Float64 - ref_temperature ::Float64 - ref_latent_heat_vap_temp ::Float64 - ref_pressure ::Float64 + ref_saturation_pressure ::RealT + ref_temperature ::RealT + ref_latent_heat_vap_temp ::RealT + ref_pressure ::RealT # Other: - gravity ::Float64 - rain_water_distr ::Float64 - v_mean_rain ::Float64 + gravity ::RealT + rain_water_distr ::RealT + v_mean_rain ::RealT end -function CompressibleRainyEulerEquations2D() +function CompressibleRainyEulerEquations2D(; RealT = Float64) # Specific heat capacities: c_liquid_water = 4186.0 c_dry_air_const_pressure = 1004.0 @@ -63,6 +74,32 @@ end +### varnames ### + +varnames(::typeof(cons2cons), ::CompressibleRainyEulerEquations2D) = ("_rho_dry", "_rho_moist", "_rho_rain", + "rho_v1", "rho_v2", + "_energy", + "rho_vapour", "rho_cloud", + "temperature", + "rho_dry_hydrostatic", "rho_moist_hydrostatic", "rho_rain_hydrostatic", + "energy_hydrostatic", + "rho_vapour_hydrostatic", + "temperature_hydrostatic") + + +varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_moist", "rho_rain", + "v1", "v2", + "energy", + "rho_vapour", "rho_cloud", + "temperature", + "rho_dry_hydrostatic", "rho_moist_hydrostatic", "rho_rain_hydrostatic", + "energy_hydrostatic", + "rho_vapour_hydrostatic", + "temperature_hydrostatic") + + + + ### conversion ### @inline function cons2prim(u, equations::CompressibleRainyEulerEquations2D) @@ -71,6 +108,12 @@ end end +@inline function cons2entropy(u, equations::CompressibleRainyEulerEquations2D) + #TODO + return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) +end + + ### physics variables ### @@ -79,11 +122,13 @@ end return v_sound end + @inline function terminal_velocity_rain(u, equations::CompressibleRainyEulerEquations2D) #TODO return v_terminal_rain end + @inline function saturation_vapour_pressure(u, equations::CompressibleRainyEulerEquations2D) #TODO return p_vapour_saturation @@ -98,12 +143,53 @@ end return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) end + +@inline function flux(u, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) + #TODO + return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) +end + + @inline function source_terms_rainy(u, x, t, equations::CompressibleRainyEulerEquations2D) #TODO return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) end + @inline function source_terms_no_rain(u, x, t, equations::CompressibleRainyEulerEquations2D) #TODO return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) -end \ No newline at end of file +end + + +@inline function max_abs_speeds(u, equations::CompressibleRainyEulerEquations2D) + #TODO + return 0.0, 0.0 +end + + +@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) + #TODO + return 0.0 +end + + + +### boundary conditions ### + +@inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, x, t, + surface_flux_function, equations::CompressibleRainyEulerEquations2D) + #TODO + return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) +end + + +@inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, direction, x, t, + surface_flux_function, equations::CompressibleRainyEulerEquations2D) + #TODO + return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) +end + + + +end # muladd end \ No newline at end of file From 06a73dd26e107a7fd5b90aae161654bf061826ed Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 30 Jul 2024 19:51:37 +0200 Subject: [PATCH 010/115] basic elixir setup for 2D testcases --- examples/elixir_rainy_euler_bubble.jl | 83 +++++++++++++++++++ examples/elixir_rainy_euler_bubble_no_rain.jl | 14 ++-- 2 files changed, 91 insertions(+), 6 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble.jl b/examples/elixir_rainy_euler_bubble.jl index e69de29b..426f1dc1 100644 --- a/examples/elixir_rainy_euler_bubble.jl +++ b/examples/elixir_rainy_euler_bubble.jl @@ -0,0 +1,83 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: source_terms_rainy + + + +function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerEquations2D) + #TODO + return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) +end + + + +############################################################################### +# semidiscretization of the compressible rainy Euler equations + +equations = CompressibleRainyEulerEquations2D() + +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 = 3 +basis = LobattoLegendreBasis(polydeg) + +surface_flux = flux_lax_friedrichs + +solver = DGSEM(basis, surface_flux) + +#TODO adjust values +coordinates_min = (0.0, 0.0) +coordinates_max = (1.0, 1.0) + +cells_per_dimension = (64, 32) +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, + periodicity = (true, false)) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_bubble_rainy, solver, + source_terms = source_terms_rainy, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +#TODO adjust values +tspan = (0.0, 1000.0) + +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 + +# entropy? +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:entropy_conservation_error,)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = analysis_interval, + save_initial_solution = true, + save_final_solution = true, + output_directory = "out", + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) + +############################################################################### +# run the simulation +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + maxiters = 1.0e7, + dt = 1.0, + save_everystep = false, callback = callbacks); + +summary_callback() \ No newline at end of file diff --git a/examples/elixir_rainy_euler_bubble_no_rain.jl b/examples/elixir_rainy_euler_bubble_no_rain.jl index 158eb78f..60a30844 100644 --- a/examples/elixir_rainy_euler_bubble_no_rain.jl +++ b/examples/elixir_rainy_euler_bubble_no_rain.jl @@ -1,20 +1,22 @@ using OrdinaryDiffEq using Trixi +using TrixiAtmo +using TrixiAtmo: source_terms_no_rain function initial_condition_bubble_no_rain(x, t, equations::CompressibleRainyEulerEquations2D) #TODO - return + return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) end + ############################################################################### -# semidiscretization of the compressible Euler equations +# semidiscretization of the compressible rainy Euler equations equations = CompressibleRainyEulerEquations2D() -#TODO check boundary conditions boundary_conditions = (x_neg = boundary_condition_periodic, x_pos = boundary_condition_periodic, y_neg = boundary_condition_slip_wall, @@ -35,7 +37,6 @@ cells_per_dimension = (64, 32) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = (true, false)) -#TODO import source terms from equations semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_bubble_no_rain, solver, source_terms = source_terms_no_rain, boundary_conditions = boundary_conditions) @@ -44,7 +45,7 @@ semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_bubble_no # ODE solvers, callbacks etc. #TODO adjust values -tspan = (0.0, 1000.0) # 1000 seconds final time +tspan = (0.0, 1000.0) ode = semidiscretize(semi, tspan) @@ -52,6 +53,7 @@ summary_callback = SummaryCallback() analysis_interval = 1000 +# entropy? analysis_callback = AnalysisCallback(semi, interval = analysis_interval, extra_analysis_errors = (:entropy_conservation_error,)) @@ -75,7 +77,7 @@ callbacks = CallbackSet(summary_callback, # run the simulation sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), maxiters = 1.0e7, - dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + dt = 1.0, save_everystep = false, callback = callbacks); summary_callback() \ No newline at end of file From 118b06d3f8078617341c1fcfb23afa8be54eeb03 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Fri, 2 Aug 2024 17:04:15 +0200 Subject: [PATCH 011/115] rename and partial implementation of initial condition --- ...xir_rainy_euler_bubble_no_phase_change.jl} | 39 +++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) rename examples/{elixir_rainy_euler_bubble_no_rain.jl => elixir_rainy_euler_bubble_no_phase_change.jl} (69%) diff --git a/examples/elixir_rainy_euler_bubble_no_rain.jl b/examples/elixir_rainy_euler_bubble_no_phase_change.jl similarity index 69% rename from examples/elixir_rainy_euler_bubble_no_rain.jl rename to examples/elixir_rainy_euler_bubble_no_phase_change.jl index 60a30844..3a87922e 100644 --- a/examples/elixir_rainy_euler_bubble_no_rain.jl +++ b/examples/elixir_rainy_euler_bubble_no_phase_change.jl @@ -1,12 +1,37 @@ using OrdinaryDiffEq using Trixi using TrixiAtmo -using TrixiAtmo: source_terms_no_rain +using TrixiAtmo: source_terms_no_phase_change -function initial_condition_bubble_no_rain(x, t, equations::CompressibleRainyEulerEquations2D) +### Bryan-Fritsch Moist Benchmark similar to Example 4.2 of: +# Sabine Doppler, Philip L. Lederer, Joachim Schöberl, Henry von Wahl, +# A discontinuous Galerkin approach for atmospheric flows with implicit condensation, +# Journal of Computational Physics, +# Volume 499, +# 2024, +# 112713, +# ISSN 0021-9991 + +function initial_condition_bubble_bryan_fritsch(x, t, equations::CompressibleRainyEulerEquations2D) + # Position of the bubble defined by center and radius: + x_center = 10_000.0 + z_center = 2_000.0 + + x_radius = 2_000.0 + z_radius = 2_000.0 + + # Hydrostatic Base State (compare Doppler et al. Appendix B.2) + q_w = 0.02 # total water fraction + theta_e = 320.0 # wet equivalent potential temperature + + p_ref = equations.ref_pressure + + L = min(sqrt(((x[1] - x_center) / x_radius)^2 + ((x[2] - z_center) / z_radius)^2), 1.0) + #TODO + return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) end @@ -29,22 +54,20 @@ surface_flux = flux_lax_friedrichs solver = DGSEM(basis, surface_flux) -#TODO adjust values -coordinates_min = (0.0, 0.0) -coordinates_max = (1.0, 1.0) +coordinates_min = ( 0.0, 0.0) +coordinates_max = (20_000.0, 10_000.0) cells_per_dimension = (64, 32) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = (true, false)) -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_bubble_no_rain, solver, - source_terms = source_terms_no_rain, +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_bubble_bryan_fritsch, solver, + source_terms = source_terms_no_phase_change, boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. -#TODO adjust values tspan = (0.0, 1000.0) ode = semidiscretize(semi, tspan) From 2b3666a5cc5ac812bcfb3ec064f4ce1e4b8547f2 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Fri, 2 Aug 2024 17:05:49 +0200 Subject: [PATCH 012/115] varname changes, cons2prim and physics variables --- src/equations/compressible_rainy_euler_2d.jl | 135 +++++++++++++++---- 1 file changed, 106 insertions(+), 29 deletions(-) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index ccf17ac1..29dec04e 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -7,7 +7,14 @@ import Trixi: varnames, -#TODO add description of equations and idea + sources +### Implementation similar to: +# Sabine Doppler, Philip L. Lederer, Joachim Schöberl, Henry von Wahl, +# A discontinuous Galerkin approach for atmospheric flows with implicit condensation, +# Journal of Computational Physics, +# Volume 499, +# 2024, +# 112713, +# ISSN 0021-9991 @@ -43,11 +50,11 @@ end function CompressibleRainyEulerEquations2D(; RealT = Float64) # Specific heat capacities: - c_liquid_water = 4186.0 + c_liquid_water = 4186.0 c_dry_air_const_pressure = 1004.0 - c_dry_air_const_volume = 717.0 - c_vapour_const_pressure = 1885.0 - c_vapour_const_volume = 1424.0 + c_dry_air_const_volume = 717.0 + c_vapour_const_pressure = 1885.0 + c_vapour_const_volume = 1424.0 # Gas constants: R_dry_air = c_dry_air_const_pressure - c_dry_air_const_volume @@ -56,14 +63,14 @@ function CompressibleRainyEulerEquations2D(; RealT = Float64) # Reference values: saturation_vapour_pressure = 610.7 - ref_temperature = 273.15 - latent_heat_vap_ref_temp = 2.5e6 - ref_pressure = 1e5 + ref_temperature = 273.15 + latent_heat_vap_ref_temp = 2.5e6 + ref_pressure = 1e5 # Other: - gravity = 9.81 + gravity = 9.81 rain_water_distr = 8e6 - v_mean_rain = 130.0 + v_mean_rain = 130.0 return CompressibleRainyEulerEquations2D{RealT}(c_liquid_water, c_dry_air_const_pressure, c_dry_air_const_volume, c_vapour_const_pressure, c_vapour_const_volume, R_dry_air, @@ -76,15 +83,15 @@ end ### varnames ### -varnames(::typeof(cons2cons), ::CompressibleRainyEulerEquations2D) = ("_rho_dry", "_rho_moist", "_rho_rain", +varnames(::typeof(cons2cons), ::CompressibleRainyEulerEquations2D) = ("rho_dry_", "rho_moist_", "rho_rain_", "rho_v1", "rho_v2", - "_energy", - "rho_vapour", "rho_cloud", + "energy_", + "rho_vapour_h", "rho_cloud_h", "temperature", - "rho_dry_hydrostatic", "rho_moist_hydrostatic", "rho_rain_hydrostatic", - "energy_hydrostatic", - "rho_vapour_hydrostatic", - "temperature_hydrostatic") + "rho_dry_h_0", "rho_moist_h_0", "rho_rain_h_0", + "energy_h_0", + "rho_vapour_h_0", + "temperature_0") varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_moist", "rho_rain", @@ -92,10 +99,10 @@ varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "energy", "rho_vapour", "rho_cloud", "temperature", - "rho_dry_hydrostatic", "rho_moist_hydrostatic", "rho_rain_hydrostatic", - "energy_hydrostatic", - "rho_vapour_hydrostatic", - "temperature_hydrostatic") + "rho_dry_h_0", "rho_moist_h_0", "rho_rain_h_0", + "energy_h_0", + "rho_vapour_h_0", + "temperature_0") @@ -103,8 +110,30 @@ varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", ### conversion ### @inline function cons2prim(u, equations::CompressibleRainyEulerEquations2D) - #TODO - return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + # name needed variables + rho_dry_, rho_moist_, rho_rain_, + rho_v1, rho_v2, + energy_, + _, _, _, + rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, + energy_h_0, + _, _ = u + + # densities + rho_dry = rho_dry_ + rho_dry_h_0 + rho_moist = rho_moist_ + rho_moist_h_0 + rho_rain = rho_rain_ + rho_rain_h_0 + rho_inv = 1 / (rho_dry + rho_moist + rho_rain) + + # velocity + v1 = rho_v1 * rho_inv + v2 = rho_v2 * rho_inv + + # energy + energy = energy_ + energy_h_0 + + return SVector(rho_dry, rho_moist, rho_rain, v1, v2, energy, + u[7], u[8], u[9], u[10], u[11], u[12], u[13], u[14], u[15]) end @@ -118,19 +147,67 @@ end ### physics variables ### @inline function speed_of_sound(u, equations::CompressibleRainyEulerEquations2D) - #TODO + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + + # name needed variables + rho_dry_, rho_moist_, rho_rain_, + _, _, + _, + rho_vapour_h, rho_cloud_h, + temperature, + rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, + _, + _, _ = u + + # densities + rho_dry = rho_dry_ + rho_dry_h_0 + rho_moist = rho_moist_ + rho_moist_h_0 + rho_rain = rho_rain_ + rho_rain_h_0 + rho_vapour = rho_vapour_h #TODO double check formula because this seems weird at first + rho_cloud = rho_cloud_h #TODO ^ + rho_inv = 1 / (rho_dry + rho_moist + rho_rain) + + # formula + p = R_d * rho_dry * temperature + R_v * rho_vapour * temperature + q_v = rho_vapour / rho_dry + q_l = (rho_cloud + rho_rain) / rho_dry + gamma_m = 1 + (R_d + R_v * q_v) / (c_vd + c_vv * q_v + c_l * q_l) + v_sound = sqrt(gamma_m * p * rho_inv) + return v_sound end -@inline function terminal_velocity_rain(u, equations::CompressibleRainyEulerEquations2D) - #TODO +@inline function terminal_velocity_rain(rho_moist, rho_rain, equations::CompressibleRainyEulerEquations2D) + # constants + N_0 = equations.rain_water_distr + v_0 = equations.v_mean_rain + + # formula ( gamma(4.5) / 6 ~= 1.9386213994279082 ) + v_terminal_rain = v_0 * 1.9386213994279082 * (rho_rain / (pi * rho_moist * N_0))^(0.125) + return v_terminal_rain end -@inline function saturation_vapour_pressure(u, equations::CompressibleRainyEulerEquations2D) - #TODO +@inline function saturation_vapour_pressure(temperature, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_pv = equations.c_vapour_const_pressure + R_v = equations.R_vapour + ref_s_p = equations.ref_saturation_pressure + ref_temp = equations.ref_temperature + ref_L = equations.ref_latent_heat_vap_temp + + # Clausius Clapeyron formula + p_vapour_saturation = ref_s_p * (temperature / ref_temp)^((c_pv - c_l) / R_v) + p_vapour_saturation *= exp(((ref_L - (c_pv - c_l) * ref_temp) / R_v) * (1 / ref_temp - 1 / temperature)) + return p_vapour_saturation end @@ -156,7 +233,7 @@ end end -@inline function source_terms_no_rain(u, x, t, equations::CompressibleRainyEulerEquations2D) +@inline function source_terms_no_phase_change(u, x, t, equations::CompressibleRainyEulerEquations2D) #TODO return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) end From 1d1f20bf12a9c31f3ca5404601488355d541dcf7 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 6 Aug 2024 20:46:18 +0200 Subject: [PATCH 013/115] added source terms without phase change, added flux, fixed some mistakes and formatting --- src/equations/compressible_rainy_euler_2d.jl | 214 +++++++++++++++++-- 1 file changed, 192 insertions(+), 22 deletions(-) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 29dec04e..3a248bca 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -58,8 +58,8 @@ function CompressibleRainyEulerEquations2D(; RealT = Float64) # Gas constants: R_dry_air = c_dry_air_const_pressure - c_dry_air_const_volume - R_vapour = c_vapour_const_pressure - c_vapour_const_volume - eps = R_dry_air / R_vapour + R_vapour = c_vapour_const_pressure - c_vapour_const_volume + eps = R_dry_air / R_vapour # Reference values: saturation_vapour_pressure = 610.7 @@ -120,17 +120,17 @@ varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", _, _ = u # densities - rho_dry = rho_dry_ + rho_dry_h_0 - rho_moist = rho_moist_ + rho_moist_h_0 - rho_rain = rho_rain_ + rho_rain_h_0 + rho_dry = rho_dry_ + rho_dry_h_0 + rho_moist = rho_moist_ + rho_moist_h_0 + rho_rain = rho_rain_ + rho_rain_h_0 rho_inv = 1 / (rho_dry + rho_moist + rho_rain) # velocity - v1 = rho_v1 * rho_inv - v2 = rho_v2 * rho_inv + v1 = rho_v1 * rho_inv + v2 = rho_v2 * rho_inv # energy - energy = energy_ + energy_h_0 + energy = energy_ + energy_h_0 return SVector(rho_dry, rho_moist, rho_rain, v1, v2, energy, u[7], u[8], u[9], u[10], u[11], u[12], u[13], u[14], u[15]) @@ -162,15 +162,15 @@ end temperature, rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, _, - _, _ = u + _, _ = u # densities - rho_dry = rho_dry_ + rho_dry_h_0 - rho_moist = rho_moist_ + rho_moist_h_0 - rho_rain = rho_rain_ + rho_rain_h_0 + rho_dry = rho_dry_ + rho_dry_h_0 + rho_moist = rho_moist_ + rho_moist_h_0 + rho_rain = rho_rain_ + rho_rain_h_0 rho_vapour = rho_vapour_h #TODO double check formula because this seems weird at first rho_cloud = rho_cloud_h #TODO ^ - rho_inv = 1 / (rho_dry + rho_moist + rho_rain) + rho_inv = 1 / (rho_dry + rho_moist + rho_rain) # formula p = R_d * rho_dry * temperature + R_v * rho_vapour * temperature @@ -189,7 +189,7 @@ end v_0 = equations.v_mean_rain # formula ( gamma(4.5) / 6 ~= 1.9386213994279082 ) - v_terminal_rain = v_0 * 1.9386213994279082 * (rho_rain / (pi * rho_moist * N_0))^(0.125) + v_terminal_rain = v_0 * 1.9386213994279082 * (rho_rain / (pi * (rho_moist + rho_rain) * N_0))^(0.125) return v_terminal_rain end @@ -216,26 +216,196 @@ end ### pde discretization ### @inline function flux(u, orientation::Integer, equations::CompressibleRainyEulerEquations2D) - #TODO - return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + # constants + c_l = equations.c_liquid_water + R_d = equations.R_dry_air + R_v = equations.R_vapour + T_ref = equations.ref_temperature + + # name needed variables + rho_dry_, rho_moist_, rho_rain_, + rho_v1, rho_v2, + energy_, + rho_vapour_h, _, + temperature, + rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, + energy_h_0, + rho_vapour_h_0, + temperature_0 = u + + # densities + rho_dry = rho_dry_ + rho_dry_h_0 + rho_moist = rho_moist_ + rho_moist_h_0 + rho_rain = rho_rain_ + rho_rain_h_0 + rho_vapour = rho_vapour_h #TODO ? + rho = rho_dry + rho_moist + rho_rain + rho_inv = 1 / (rho) + + # velocity + v1 = rho_v1 * rho_inv + v2 = rho_v2 * rho_inv + v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) + + # pressure + p = R_d * rho_dry * temperature + R_v * rho_vapour * temperature + p_0 = R_d * rho_dry_h_0 * temperature_0 + R_v * rho_vapour_h_0 * temperature_0 + p_ = p - p_0 + + # energy + energy = energy_ + energy_h_0 + + # flux for orientation cases + if (orientation == 1) + # "mass" + f1 = rho_dry * v1 + f2 = rho_moist * v1 + f3 = rho_rain * v1 + + # "impulse" + f4 = rho * v1 * v1 + p_ + f5 = rho * v1 * v2 + + # "energy" + f6 = (energy + p) * v1 + + else + # "mass" + f1 = rho_dry * v2 + f2 = rho_moist * v2 + f3 = rho_rain * (v2 - v_r) + + # "impulse" + f4 = rho * v1 * v2 - rho_rain * v_r * v1 + f5 = rho * v2 * v2 - rho_rain * v_r * v2 + p_ + + # "energy" + f6 = ((energy + p) * v2 - (c_l * (temperature - T_ref) + 0.5 * (v1^2 + v2^2))) * rho_rain * v_r + end + + return SVector(f1, f2, f3, f4, f5, f6, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) end @inline function flux(u, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) - #TODO - return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + #TODO Double-check for mistakes in "impulse" and "energy"! + # constants + c_l = equations.c_liquid_water + R_d = equations.R_dry_air + R_v = equations.R_vapour + T_ref = equations.ref_temperature + + # name needed variables + rho_dry_, rho_moist_, rho_rain_, + rho_v1, rho_v2, + energy_, + rho_vapour_h, _, + temperature, + rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, + energy_h_0, + rho_vapour_h_0, + temperature_0 = u + + # densities + rho_dry = rho_dry_ + rho_dry_h_0 + rho_moist = rho_moist_ + rho_moist_h_0 + rho_rain = rho_rain_ + rho_rain_h_0 + rho_vapour = rho_vapour_h #TODO ? + rho = rho_dry + rho_moist + rho_rain + rho_inv = 1 / (rho) + + # velocity + v1 = rho_v1 * rho_inv + v2 = rho_v2 * rho_inv + v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) + + # normal velocities + v_normal = v1 * normal_direction[1] + v2 * normal_direction[2] + v_r_normal = v_r * normal_direction[2] #TODO correct? + + # pressure + p = R_d * rho_dry * temperature + R_v * rho_vapour * temperature + p_0 = R_d * rho_dry_h_0 * temperature_0 + R_v * rho_vapour_h_0 * temperature_0 + p_ = p - p_0 + + # energy + energy = energy_ + energy_h_0 + + # flux + # "mass" + f1 = rho_dry * v_normal + f2 = rho_moist * v_normal + f3 = rho_rain * (v_normal - v_r_normal) + + # "impulse" + f4 = rho * v_normal * v1 - rho_rain * v_r_normal * v1 + p_ * normal_direction[1] + f5 = rho * v_normal * v2 - rho_rain * v_r_normal * v2 + p_ * normal_direction[2] + + # "energy" + f6 = ((energy + p) * v_normal - (c_l * (temperature - T_ref) + 0.5 * (v_normal^2))) * rho_rain * v_r_normal + + return SVector(f1, f2, f3, f4, f5, f6, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) end @inline function source_terms_rainy(u, x, t, equations::CompressibleRainyEulerEquations2D) - #TODO - return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + #TODO implement conversion source terms + # constants + g = equations.gravity + + # name needed variables + rho_dry_, rho_moist_, rho_rain_, + _, rho_v2, + _, + rho_vapour_h, rho_cloud_h, + _, + rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, + _, + _, _ = u + + # densities + rho_dry = rho_dry_ + rho_dry_h_0 + rho_moist = rho_moist_ + rho_moist_h_0 + rho_rain = rho_rain_ + rho_rain_h_0 + + rho = rho_dry + rho_moist + rho_rain + rho_h_0 = rho_dry_h_0 + rho_moist_h_0 + rho_rain_h_0 + rho_ = rho - rho_h_0 + + #TODO non-linear solve for temperature, rho_vapour_h, rho_cloud_h + + return SVector(0.0, 0.0, 0.0, 0.0, + rho_ * g, 0.0, rho_v2 * g, #TODO check signs + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) end +# no phase changes and no Coriolis term + @inline function source_terms_no_phase_change(u, x, t, equations::CompressibleRainyEulerEquations2D) - #TODO - return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + # constants + g = equations.gravity + + # name needed variables + rho_dry_, rho_moist_, rho_rain_, + _, rho_v2, + _, _, _, _, + rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, + _, _, _ = u + + # densities + rho_dry = rho_dry_ + rho_dry_h_0 + rho_moist = rho_moist_ + rho_moist_h_0 + rho_rain = rho_rain_ + rho_rain_h_0 + + rho = rho_dry + rho_moist + rho_rain + rho_h_0 = rho_dry_h_0 + rho_moist_h_0 + rho_rain_h_0 + rho_ = rho - rho_h_0 + + return SVector(0.0, 0.0, 0.0, 0.0, + rho_ * g, 0.0, rho_v2 * g, #TODO check signs + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) end From 7d1e66cd5558a5be80e76efb0b8474fd03a91e5d Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 7 Aug 2024 14:41:24 +0200 Subject: [PATCH 014/115] added max abs speed calculations --- src/equations/compressible_rainy_euler_2d.jl | 51 ++++++++++++++++++-- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 3a248bca..083e8088 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -143,6 +143,35 @@ end end +# for convenience +@inline function cons2speeds(u, equations::CompressibleRainyEulerEquations2D) + # name needed variables + rho_dry_, rho_moist_, rho_rain_, + rho_v1, rho_v2, + _, _, _, _, + rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, + _, _, _ = u + + # densities + rho_dry = rho_dry_ + rho_dry_h_0 + rho_moist = rho_moist_ + rho_moist_h_0 + rho_rain = rho_rain_ + rho_rain_h_0 + rho_inv = 1 / (rho_dry + rho_moist + rho_rain) + + # velocity + v1 = rho_v1 * rho_inv + v2 = rho_v2 * rho_inv + + # get speed of sound + v_sound = speed_of_sound(u, equations) + + # get terminal velocity rain + v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) + + return SVector(v1, v2, v_sound, v_r) +end + + ### physics variables ### @@ -410,14 +439,28 @@ end @inline function max_abs_speeds(u, equations::CompressibleRainyEulerEquations2D) - #TODO - return 0.0, 0.0 + # name needed variables + v1, v2, v_sound, v_r = cons2speeds(u, equations) + + return abs(v1) + v_sound, abs(v2) + v_sound + abs(v_r) end @inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) - #TODO - return 0.0 + # name needed variables + v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) + v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) + + # calculate upper bounds for left and right speed + v_ll_max = abs(v1_ll * normal_direction[1] + v2_ll * normal_direction[2]) + v_ll_max += abs( v_r_ll * normal_direction[2]) + v_ll_max += v_sound_ll + + v_rr_max = abs(v1_rr * normal_direction[1] + v2_rr * normal_direction[2]) + v_rr_max += abs( v_r_rr * normal_direction[2]) + v_rr_max += v_sound_rr + + return max(v_ll_max, v_rr_max) end From 76653b14e7e6a4ddb4e5c824c45c11c9366bb067 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Mon, 12 Aug 2024 16:51:42 +0200 Subject: [PATCH 015/115] most simple test case I could find --- ...xir_rainy_euler_bubble_dry_(basic_test).jl | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 examples/elixir_rainy_euler_bubble_dry_(basic_test).jl diff --git a/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl b/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl new file mode 100644 index 00000000..87d36eb1 --- /dev/null +++ b/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl @@ -0,0 +1,120 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: source_terms_no_phase_change + + + +# copied from elixir_euler_warm_bubble.jl for quick tests +function initial_condition_bubble_dry(x, t, equations::CompressibleRainyEulerEquations2D) + g = equations.gravity + c_v = equations.c_dry_air_const_volume + c_p = equations.c_dry_air_const_pressure + + # center of perturbation + center_x = 10000.0 + center_z = 2000.0 + # radius of perturbation + radius = 2000.0 + # 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 = 273.15 + potential_temperature_perturbation = 0.0 + if r <= radius + potential_temperature_perturbation = 2 * cospi(0.5 * 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.0 # 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 = 0.0 + v2 = 0.0 + E = c_v * T + 0.5 * (v1^2 + v2^2) + + # random experiments + return SVector(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, T, rho, 0.0, 0.0, E, 0.0, potential_temperature) +end + + + +############################################################################### +# semidiscretization of the compressible rainy Euler equations + +equations = CompressibleRainyEulerEquations2D() + +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 = 3 +basis = LobattoLegendreBasis(polydeg) + +surface_flux = flux_lax_friedrichs + +solver = DGSEM(basis, surface_flux) + +coordinates_min = ( 0.0, 0.0) +coordinates_max = (20_000.0, 10_000.0) + +cells_per_dimension = (64, 32) +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, + periodicity = (true, false)) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_bubble_dry, solver, + source_terms = source_terms_no_phase_change, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 1000.0) + +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 + +# entropy? +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:entropy_conservation_error,)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = analysis_interval, + save_initial_solution = true, + save_final_solution = true, + output_directory = "out", + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) + +############################################################################### +# run the simulation +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + maxiters = 1.0e7, + dt = 1.0, + save_everystep = false, callback = callbacks); + +summary_callback() \ No newline at end of file From 03e0f12bc24b58f048f50c30ac87e056ab08bb1e Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Mon, 12 Aug 2024 16:51:59 +0200 Subject: [PATCH 016/115] added NLsolve --- Project.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Project.toml b/Project.toml index d468d756..7e5479f7 100644 --- a/Project.toml +++ b/Project.toml @@ -6,6 +6,7 @@ version = "0.1.0-DEV" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" +NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Trixi = "a7f1ee26-1774-49b1-8366-f1abc58fbfcb" From e3a9288e06b3aa43816d9a63a2dda8e464cb53c4 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Mon, 12 Aug 2024 16:53:11 +0200 Subject: [PATCH 017/115] renamed initial condition function --- examples/elixir_rainy_euler_bubble_no_phase_change.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_no_phase_change.jl b/examples/elixir_rainy_euler_bubble_no_phase_change.jl index 3a87922e..08c451cc 100644 --- a/examples/elixir_rainy_euler_bubble_no_phase_change.jl +++ b/examples/elixir_rainy_euler_bubble_no_phase_change.jl @@ -14,7 +14,7 @@ using TrixiAtmo: source_terms_no_phase_change # 112713, # ISSN 0021-9991 -function initial_condition_bubble_bryan_fritsch(x, t, equations::CompressibleRainyEulerEquations2D) +function initial_condition_moist_bubble_bryan_fritsch(x, t, equations::CompressibleRainyEulerEquations2D) # Position of the bubble defined by center and radius: x_center = 10_000.0 z_center = 2_000.0 @@ -32,7 +32,7 @@ function initial_condition_bubble_bryan_fritsch(x, t, equations::CompressibleRai #TODO - return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + return SVector(0, 0, 0.0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0, 0, 0, 0) end @@ -61,7 +61,7 @@ cells_per_dimension = (64, 32) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = (true, false)) -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_bubble_bryan_fritsch, solver, +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_moist_bubble_bryan_fritsch, solver, source_terms = source_terms_no_phase_change, boundary_conditions = boundary_conditions) From 5d45cad06ec1d5f8d42e40158bd94a6b11050b76 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Mon, 12 Aug 2024 16:54:48 +0200 Subject: [PATCH 018/115] fixed and updated some source terms, boundary experiment --- src/equations/compressible_rainy_euler_2d.jl | 104 ++++++++++++++++--- 1 file changed, 89 insertions(+), 15 deletions(-) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 083e8088..7f6539a0 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -1,4 +1,5 @@ using Trixi +using NLsolve import Trixi: varnames, cons2prim, cons2entropy, flux, @@ -123,7 +124,7 @@ varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", rho_dry = rho_dry_ + rho_dry_h_0 rho_moist = rho_moist_ + rho_moist_h_0 rho_rain = rho_rain_ + rho_rain_h_0 - rho_inv = 1 / (rho_dry + rho_moist + rho_rain) + rho_inv = inv(rho_dry + rho_moist + rho_rain) # velocity v1 = rho_v1 * rho_inv @@ -156,7 +157,7 @@ end rho_dry = rho_dry_ + rho_dry_h_0 rho_moist = rho_moist_ + rho_moist_h_0 rho_rain = rho_rain_ + rho_rain_h_0 - rho_inv = 1 / (rho_dry + rho_moist + rho_rain) + rho_inv = inv(rho_dry + rho_moist + rho_rain) # velocity v1 = rho_v1 * rho_inv @@ -199,13 +200,14 @@ end rho_rain = rho_rain_ + rho_rain_h_0 rho_vapour = rho_vapour_h #TODO double check formula because this seems weird at first rho_cloud = rho_cloud_h #TODO ^ - rho_inv = 1 / (rho_dry + rho_moist + rho_rain) + rho_inv = inv(rho_dry + rho_moist + rho_rain) # formula p = R_d * rho_dry * temperature + R_v * rho_vapour * temperature q_v = rho_vapour / rho_dry q_l = (rho_cloud + rho_rain) / rho_dry gamma_m = 1 + (R_d + R_v * q_v) / (c_vd + c_vv * q_v + c_l * q_l) + v_sound = sqrt(gamma_m * p * rho_inv) return v_sound @@ -218,7 +220,11 @@ end v_0 = equations.v_mean_rain # formula ( gamma(4.5) / 6 ~= 1.9386213994279082 ) - v_terminal_rain = v_0 * 1.9386213994279082 * (rho_rain / (pi * (rho_moist + rho_rain) * N_0))^(0.125) + if ( rho_rain > 0.0) + v_terminal_rain = v_0 * 1.9386213994279082 * (rho_rain / (pi * (rho_moist + rho_rain) * N_0))^(0.125) + else + v_terminal_rain = 0.0 + end return v_terminal_rain end @@ -268,7 +274,7 @@ end rho_rain = rho_rain_ + rho_rain_h_0 rho_vapour = rho_vapour_h #TODO ? rho = rho_dry + rho_moist + rho_rain - rho_inv = 1 / (rho) + rho_inv = inv(rho) # velocity v1 = rho_v1 * rho_inv @@ -341,7 +347,7 @@ end rho_rain = rho_rain_ + rho_rain_h_0 rho_vapour = rho_vapour_h #TODO ? rho = rho_dry + rho_moist + rho_rain - rho_inv = 1 / (rho) + rho_inv = inv(rho) # velocity v1 = rho_v1 * rho_inv @@ -378,21 +384,24 @@ end end +# no Coriolis term @inline function source_terms_rainy(u, x, t, equations::CompressibleRainyEulerEquations2D) - #TODO implement conversion source terms # constants - g = equations.gravity + R_v = equations.R_vapour + T_ref = equations.ref_temperature + g = equations.gravity # name needed variables rho_dry_, rho_moist_, rho_rain_, _, rho_v2, _, rho_vapour_h, rho_cloud_h, - _, + temperature, rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, _, _, _ = u + # densities rho_dry = rho_dry_ + rho_dry_h_0 rho_moist = rho_moist_ + rho_moist_h_0 @@ -402,10 +411,21 @@ end rho_h_0 = rho_dry_h_0 + rho_moist_h_0 + rho_rain_h_0 rho_ = rho - rho_h_0 + rho_v = rho_vapour_h + rho_cloud = rho_cloud_h + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + + # source terms phase change + S_evaporation = (3.86e-3 - 9.41e-5 * (temperature - T_ref)) * (1 + 9.1 * rho_rain^(0.1875)) + S_evaporation *= (rho_vs - rho_v) * rho_r^(0.5) + S_auto_conversion = 0.001 * rho_cloud + S_accretion = 1.72 * rho_cloud * rho_rain^(0.875) + S_rain = S_auto_conversion + S_accretion - S_evaporation + #TODO non-linear solve for temperature, rho_vapour_h, rho_cloud_h - return SVector(0.0, 0.0, 0.0, 0.0, - rho_ * g, 0.0, rho_v2 * g, #TODO check signs + return SVector(0.0, S_rain, -S_rain, 0.0, + -rho_ * g, -rho_v2 * g, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) end @@ -432,8 +452,49 @@ end rho_h_0 = rho_dry_h_0 + rho_moist_h_0 + rho_rain_h_0 rho_ = rho - rho_h_0 + #TODO non-linear solve for temperature, rho_vapour_h, rho_cloud_h + return SVector(0.0, 0.0, 0.0, 0.0, - rho_ * g, 0.0, rho_v2 * g, #TODO check signs + -rho_ * g, -rho_v2 * g, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) +end + + +@inline function source_terms_dry(u, x, t, equations::CompressibleRainyEulerEquations2D) + # constants + c_vd = equations.c_dry_air_const_volume + T_ref = equations.ref_temperature + g = equations.gravity + + # name needed variables + rho_dry_, rho_moist_, rho_rain_, + rho_v1, rho_v2, + _, _, energy_, _, + rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, + energy_h_0, _, _ = u + + # densities + rho_dry = rho_dry_ + rho_dry_h_0 + rho_moist = rho_moist_ + rho_moist_h_0 + rho_rain = rho_rain_ + rho_rain_h_0 + + rho = rho_dry + rho_moist + rho_rain + rho_inv = inv(rho) + rho_h_0 = rho_dry_h_0 + rho_moist_h_0 + rho_rain_h_0 + rho_ = rho - rho_h_0 + + # velocities + v1 = rho_v1 * rho_inv + v2 = rho_v2 * rho_inv + + # energy + energy = energy_ + energy_h_0 + + # update temperature + u[9] = (energy - 0.5 * (v1^2 + v2^2) * rho) / (c_vd * rho) + T_ref + + return SVector(0.0, 0.0, 0.0, 0.0, + -rho_ * g, -rho_v2 * g, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) end @@ -465,8 +526,9 @@ end -### boundary conditions ### +### boundary conditions ### TODO: double check the idea of this boundary condition +# should probably be similar to the approach in compressible_euler_2d.jl @inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, x, t, surface_flux_function, equations::CompressibleRainyEulerEquations2D) #TODO @@ -474,10 +536,22 @@ end end +# same as in compressible_euler_2d.jl @inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, direction, x, t, surface_flux_function, equations::CompressibleRainyEulerEquations2D) - #TODO - return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + # flip sign of normal to make it outward pointing, then flip the sign of the normal flux back + # to be inward pointing on the -x and -y sides due to the orientation convention used by StructuredMesh + if isodd(direction) + boundary_flux = -boundary_condition_slip_wall(u_inner, -normal_direction, + x, t, surface_flux_function, + equations) + else + boundary_flux = boundary_condition_slip_wall(u_inner, normal_direction, + x, t, surface_flux_function, + equations) + end + + return boundary_flux end From 16532c70b5942234612a10f5a9fffdf8fd4e5176 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 14 Aug 2024 15:40:18 +0200 Subject: [PATCH 019/115] updated source terms and initial condition energy --- examples/elixir_rainy_euler_bubble_dry_(basic_test).jl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl b/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl index 87d36eb1..68654151 100644 --- a/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl +++ b/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl @@ -1,7 +1,7 @@ using OrdinaryDiffEq using Trixi using TrixiAtmo -using TrixiAtmo: source_terms_no_phase_change +using TrixiAtmo: source_terms_dry @@ -43,10 +43,11 @@ function initial_condition_bubble_dry(x, t, equations::CompressibleRainyEulerEqu v1 = 0.0 v2 = 0.0 - E = c_v * T + 0.5 * (v1^2 + v2^2) + E_0 = c_v * T + E_ = 0.5 * (v1^2 + v2^2) # random experiments - return SVector(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, T, rho, 0.0, 0.0, E, 0.0, potential_temperature) + return SVector(0.0, 0.0, 0.0, 0.0, 0.0, E_, 0.0, 0.0, T, rho, 0.0, 0.0, E_0, 0.0, potential_temperature) end @@ -76,7 +77,7 @@ mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = (true, false)) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_bubble_dry, solver, - source_terms = source_terms_no_phase_change, + source_terms = source_terms_dry, boundary_conditions = boundary_conditions) ############################################################################### From 6f6d4486c80c6934f259fd9a2e8663f25fc6f2e0 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 14 Aug 2024 15:41:34 +0200 Subject: [PATCH 020/115] fixes, source term updates --- src/equations/compressible_rainy_euler_2d.jl | 66 ++++++++++++++------ 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 7f6539a0..64501ac0 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -1,10 +1,10 @@ using Trixi -using NLsolve -import Trixi: varnames, - cons2prim, cons2entropy, - flux, - max_abs_speeds, max_abs_speed_naive, - boundary_condition_slip_wall +using NLsolve: nlsolve +import Trixi: varnames, + cons2prim, cons2entropy, + flux, + max_abs_speeds, max_abs_speed_naive, + boundary_condition_slip_wall @@ -401,7 +401,6 @@ end _, _, _ = u - # densities rho_dry = rho_dry_ + rho_dry_h_0 rho_moist = rho_moist_ + rho_moist_h_0 @@ -411,13 +410,13 @@ end rho_h_0 = rho_dry_h_0 + rho_moist_h_0 + rho_rain_h_0 rho_ = rho - rho_h_0 - rho_v = rho_vapour_h - rho_cloud = rho_cloud_h - rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + rho_vapour = rho_vapour_h + rho_cloud = rho_cloud_h + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) # source terms phase change S_evaporation = (3.86e-3 - 9.41e-5 * (temperature - T_ref)) * (1 + 9.1 * rho_rain^(0.1875)) - S_evaporation *= (rho_vs - rho_v) * rho_r^(0.5) + S_evaporation *= (rho_vs - rho_vapour) * rho_rain^(0.5) S_auto_conversion = 0.001 * rho_cloud S_accretion = 1.72 * rho_cloud * rho_rain^(0.875) S_rain = S_auto_conversion + S_accretion - S_evaporation @@ -434,25 +433,52 @@ end @inline function source_terms_no_phase_change(u, x, t, equations::CompressibleRainyEulerEquations2D) # constants - g = equations.gravity + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp + T_ref = equations.ref_temperature + g = equations.gravity # name needed variables rho_dry_, rho_moist_, rho_rain_, _, rho_v2, - _, _, _, _, + _, + rho_vapour_h, rho_cloud_h, + temperature, rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, _, _, _ = u # densities - rho_dry = rho_dry_ + rho_dry_h_0 - rho_moist = rho_moist_ + rho_moist_h_0 - rho_rain = rho_rain_ + rho_rain_h_0 + rho_dry = rho_dry_ + rho_dry_h_0 + rho_moist = rho_moist_ + rho_moist_h_0 + rho_rain = rho_rain_ + rho_rain_h_0 + + rho_vapour = rho_vapour_h #TODO ?? + rho_cloud = rho_cloud_h rho = rho_dry + rho_moist + rho_rain rho_h_0 = rho_dry_h_0 + rho_moist_h_0 + rho_rain_h_0 rho_ = rho - rho_h_0 - #TODO non-linear solve for temperature, rho_vapour_h, rho_cloud_h + #TODO test type stability + # non-linear solve for rho_vapour, rho_cloud, temperature + # guess = [rho_vapour; rho_cloud; temperature] + + function f!(residual, guess) + residual[1] = (c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain))*(guess[3] - T_ref) + residual[1] += guess[1] * (L_ref - R_v * T_ref) + residual[2] = min(saturation_vapour_pressure(guess[3], equations) / (R_v * guess[3]), rho_moist) + residual[3] = rho_moist - guess[1] - guess[2] + end + + nl_sol = nlsolve(f!, [rho_vapour, rho_cloud, temperature], ftol = 1e-14, iterations = 20) + + # update entries of u + u = SVector(u[1], u[2], u[3], u[4], u[5], u[6], + nl_sol.zero[1], nl_sol.zero[2], nl_sol.zero[3], + u[10], u[11], u[12], u[13], u[14], u[15]) return SVector(0.0, 0.0, 0.0, 0.0, -rho_ * g, -rho_v2 * g, 0.0, @@ -491,7 +517,9 @@ end energy = energy_ + energy_h_0 # update temperature - u[9] = (energy - 0.5 * (v1^2 + v2^2) * rho) / (c_vd * rho) + T_ref + u = SVector(u[1], u[2], u[3], u[4], u[5], u[6], u[7], u[8], + (energy - 0.5 * (v1^2 + v2^2) * rho) / (c_vd * rho) + T_ref, + u[10], u[11], u[12], u[13], u[14], u[15]) return SVector(0.0, 0.0, 0.0, 0.0, -rho_ * g, -rho_v2 * g, 0.0, @@ -532,7 +560,7 @@ end @inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, x, t, surface_flux_function, equations::CompressibleRainyEulerEquations2D) #TODO - return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + return SVector(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) end From 3afb265d9813c9ec6cf26d694378fc21ab0fd49c Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 21 Aug 2024 14:24:08 +0200 Subject: [PATCH 021/115] fixed energy density and adjusted source terms --- examples/elixir_rainy_euler_bubble_dry_(basic_test).jl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl b/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl index 68654151..1af16006 100644 --- a/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl +++ b/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl @@ -1,7 +1,7 @@ using OrdinaryDiffEq using Trixi using TrixiAtmo -using TrixiAtmo: source_terms_dry +using TrixiAtmo: source_terms_no_phase_change @@ -43,11 +43,10 @@ function initial_condition_bubble_dry(x, t, equations::CompressibleRainyEulerEqu v1 = 0.0 v2 = 0.0 - E_0 = c_v * T - E_ = 0.5 * (v1^2 + v2^2) + E = (c_v * T + 0.5 * (v1^2 + v2^2)) # random experiments - return SVector(0.0, 0.0, 0.0, 0.0, 0.0, E_, 0.0, 0.0, T, rho, 0.0, 0.0, E_0, 0.0, potential_temperature) + return SVector(0.0, 0.0, 0.0, 0.0, 0.0, E * rho, 0.0, 0.0, T, rho, 0.0, 0.0, 0.0, 0.0, T) end @@ -77,7 +76,7 @@ mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = (true, false)) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_bubble_dry, solver, - source_terms = source_terms_dry, + source_terms = source_terms_no_phase_change, boundary_conditions = boundary_conditions) ############################################################################### From ae7391b87178daa5045387cf9183c71193a67256 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 21 Aug 2024 14:28:20 +0200 Subject: [PATCH 022/115] moved nonlinear system, removed source_terms_dry, fixed energy flux, fixed rainy source signs, added boundary flux calculations, added temporary debugging code --- src/equations/compressible_rainy_euler_2d.jl | 339 ++++++++++++------- 1 file changed, 208 insertions(+), 131 deletions(-) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 64501ac0..61784a14 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -23,7 +23,7 @@ import Trixi: varnames, ### equation, parameters and constants ### -struct CompressibleRainyEulerEquations2D{RealT <: Real} <: AbstractCompressibleMoistEulerEquations{2, 15} +struct CompressibleRainyEulerEquations2D{RealT <: Real} <: AbstractCompressibleRainyEulerEquations{2, 15} # Specific heat capacities: c_liquid_water ::RealT c_dry_air_const_pressure ::RealT @@ -86,7 +86,7 @@ end varnames(::typeof(cons2cons), ::CompressibleRainyEulerEquations2D) = ("rho_dry_", "rho_moist_", "rho_rain_", "rho_v1", "rho_v2", - "energy_", + "energy", "rho_vapour_h", "rho_cloud_h", "temperature", "rho_dry_h_0", "rho_moist_h_0", "rho_rain_h_0", @@ -144,6 +144,65 @@ end end +@inline function cons2nonlinearsystemsol(u, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp + ref_temp = equations.ref_temperature + + # name needed variables + rho_dry_, rho_moist_, rho_rain_, + rho_v1, rho_v2, + energy_, + rho_vapour_h, rho_cloud_h, + temperature, + rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, + energy_h, _, _ = u + + # densities + rho_dry = rho_dry_ + rho_dry_h_0 + rho_moist = rho_moist_ + rho_moist_h_0 + rho_rain = rho_rain_ + rho_rain_h_0 + + rho = rho_dry + rho_moist + rho_rain + rho_inv = inv(rho) + + # for initial guess + rho_vapour = rho_vapour_h + rho_cloud = rho_cloud_h + + # velocity + v1 = rho_v1 * rho_inv + v2 = rho_v2 * rho_inv + + # energy + energy = energy_ + energy_h + + #TODO test type stability + # non-linear solve for rho_vapour, rho_cloud, temperature + # guess = [rho_vapour; rho_cloud; temperature] + + if (rho_moist == 0.0 && rho_rain == 0.0) + return SVector(0.0, 0.0, (energy - 0.5 * (v1^2 + v2^2) * rho) / (c_vd * rho) + ref_temp) + else + error("wrong system") + function f!(residual, guess) + residual[1] = (c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain))*(guess[3] - ref_temp) + residual[1] += guess[1] * (L_ref - R_v * ref_temp) - (energy - rho * 0.5 * (v1^2 + v2^2)) + residual[2] = min(saturation_vapour_pressure(guess[3], equations) / (R_v * guess[3]), rho_moist) - guess[1] + residual[3] = rho_moist - guess[1] - guess[2] + end + + nl_sol = nlsolve(f!, [rho_vapour; rho_cloud; temperature], ftol = 1e-14, iterations = 20) + + return SVector(nl_sol.zero[1], nl_sol.zero[2], nl_sol.zero[3]) + end +end + + # for convenience @inline function cons2speeds(u, equations::CompressibleRainyEulerEquations2D) # name needed variables @@ -164,7 +223,7 @@ end v2 = rho_v2 * rho_inv # get speed of sound - v_sound = speed_of_sound(u, equations) + v_sound = speed_of_sound(u, equations)[1] # get terminal velocity rain v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) @@ -186,31 +245,51 @@ end # name needed variables rho_dry_, rho_moist_, rho_rain_, - _, _, - _, - rho_vapour_h, rho_cloud_h, - temperature, + _, _, _, _, _, _, rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, - _, - _, _ = u + _, _, _ = u # densities rho_dry = rho_dry_ + rho_dry_h_0 rho_moist = rho_moist_ + rho_moist_h_0 rho_rain = rho_rain_ + rho_rain_h_0 - rho_vapour = rho_vapour_h #TODO double check formula because this seems weird at first - rho_cloud = rho_cloud_h #TODO ^ rho_inv = inv(rho_dry + rho_moist + rho_rain) + # recover rho_vapour, rho_cloud, temperature from nonlinear system + rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) + # formula - p = R_d * rho_dry * temperature + R_v * rho_vapour * temperature - q_v = rho_vapour / rho_dry - q_l = (rho_cloud + rho_rain) / rho_dry + p = R_d * rho_dry * temperature + R_v * rho_vapour * temperature + q_v = rho_vapour / rho_dry + q_l = (rho_cloud + rho_rain) / rho_dry gamma_m = 1 + (R_d + R_v * q_v) / (c_vd + c_vv * q_v + c_l * q_l) + # debugging + if (gamma_m < 0.0) + error("gamma_m kleiner Null") + elseif (p < 0.0) + println("p kleiner Null") + if (rho_dry < 0.0) + error("rho_dry kleiner Null") + elseif (temperature < 0.0) + # velocity + v1 = u[4] * rho_inv + v2 = u[5] * rho_inv + + display(u[6]) + display(u[13]) + display(0.5 * (v1^2 + v2^2) * inv(rho_inv)) + error("temperature kleiner Null") + end + elseif (rho_inv < 0.0) + display(rho_dry_) + display(rho_dry_h_0) + error("rho kleiner Null") + end + v_sound = sqrt(gamma_m * p * rho_inv) - return v_sound + return SVector(v_sound, gamma_m) end @@ -219,7 +298,7 @@ end N_0 = equations.rain_water_distr v_0 = equations.v_mean_rain - # formula ( gamma(4.5) / 6 ~= 1.9386213994279082 ) + # formula ( \Gamma(4.5) / 6 ~= 1.9386213994279082 ) if ( rho_rain > 0.0) v_terminal_rain = v_0 * 1.9386213994279082 * (rho_rain / (pi * (rho_moist + rho_rain) * N_0))^(0.125) else @@ -230,6 +309,7 @@ end end +#TODO name change @inline function saturation_vapour_pressure(temperature, equations::CompressibleRainyEulerEquations2D) # constants c_l = equations.c_liquid_water @@ -252,17 +332,16 @@ end @inline function flux(u, orientation::Integer, equations::CompressibleRainyEulerEquations2D) # constants - c_l = equations.c_liquid_water - R_d = equations.R_dry_air - R_v = equations.R_vapour - T_ref = equations.ref_temperature + c_l = equations.c_liquid_water + R_d = equations.R_dry_air + R_v = equations.R_vapour + ref_temp = equations.ref_temperature # name needed variables rho_dry_, rho_moist_, rho_rain_, rho_v1, rho_v2, energy_, - rho_vapour_h, _, - temperature, + _, _, _, rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, energy_h_0, rho_vapour_h_0, @@ -272,10 +351,12 @@ end rho_dry = rho_dry_ + rho_dry_h_0 rho_moist = rho_moist_ + rho_moist_h_0 rho_rain = rho_rain_ + rho_rain_h_0 - rho_vapour = rho_vapour_h #TODO ? rho = rho_dry + rho_moist + rho_rain rho_inv = inv(rho) + # recover rho_vapour, rho_cloud, temperature from nonlinear system + rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) + # velocity v1 = rho_v1 * rho_inv v2 = rho_v2 * rho_inv @@ -314,7 +395,7 @@ end f5 = rho * v2 * v2 - rho_rain * v_r * v2 + p_ # "energy" - f6 = ((energy + p) * v2 - (c_l * (temperature - T_ref) + 0.5 * (v1^2 + v2^2))) * rho_rain * v_r + f6 = (energy + p) * v2 - (c_l * (temperature - ref_temp) + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r end return SVector(f1, f2, f3, f4, f5, f6, @@ -325,17 +406,16 @@ end @inline function flux(u, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) #TODO Double-check for mistakes in "impulse" and "energy"! # constants - c_l = equations.c_liquid_water - R_d = equations.R_dry_air - R_v = equations.R_vapour - T_ref = equations.ref_temperature + c_l = equations.c_liquid_water + R_d = equations.R_dry_air + R_v = equations.R_vapour + ref_temp = equations.ref_temperature # name needed variables rho_dry_, rho_moist_, rho_rain_, rho_v1, rho_v2, energy_, - rho_vapour_h, _, - temperature, + _, _, _, rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, energy_h_0, rho_vapour_h_0, @@ -345,10 +425,12 @@ end rho_dry = rho_dry_ + rho_dry_h_0 rho_moist = rho_moist_ + rho_moist_h_0 rho_rain = rho_rain_ + rho_rain_h_0 - rho_vapour = rho_vapour_h #TODO ? rho = rho_dry + rho_moist + rho_rain rho_inv = inv(rho) + # recover rho_vapour, rho_cloud, temperature from nonlinear system + rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) + # velocity v1 = rho_v1 * rho_inv v2 = rho_v2 * rho_inv @@ -357,6 +439,7 @@ end # normal velocities v_normal = v1 * normal_direction[1] + v2 * normal_direction[2] v_r_normal = v_r * normal_direction[2] #TODO correct? + #norm_vn = norm(normal_direction) # pressure p = R_d * rho_dry * temperature + R_v * rho_vapour * temperature @@ -377,7 +460,7 @@ end f5 = rho * v_normal * v2 - rho_rain * v_r_normal * v2 + p_ * normal_direction[2] # "energy" - f6 = ((energy + p) * v_normal - (c_l * (temperature - T_ref) + 0.5 * (v_normal^2))) * rho_rain * v_r_normal + f6 = (energy + p) * v_normal - (c_l * (temperature - ref_temp) + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r_normal return SVector(f1, f2, f3, f4, f5, f6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) @@ -387,43 +470,39 @@ end # no Coriolis term @inline function source_terms_rainy(u, x, t, equations::CompressibleRainyEulerEquations2D) # constants - R_v = equations.R_vapour - T_ref = equations.ref_temperature - g = equations.gravity + R_v = equations.R_vapour + ref_temp = equations.ref_temperature + g = equations.gravity # name needed variables rho_dry_, rho_moist_, rho_rain_, _, rho_v2, - _, - rho_vapour_h, rho_cloud_h, - temperature, + _, _, _, _, rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, - _, - _, _ = u + _, _, _ = u # densities - rho_dry = rho_dry_ + rho_dry_h_0 - rho_moist = rho_moist_ + rho_moist_h_0 - rho_rain = rho_rain_ + rho_rain_h_0 + rho_dry = rho_dry_ + rho_dry_h_0 + rho_moist = rho_moist_ + rho_moist_h_0 + rho_rain = rho_rain_ + rho_rain_h_0 - rho = rho_dry + rho_moist + rho_rain - rho_h_0 = rho_dry_h_0 + rho_moist_h_0 + rho_rain_h_0 - rho_ = rho - rho_h_0 + rho = rho_dry + rho_moist + rho_rain + rho_h_0 = rho_dry_h_0 + rho_moist_h_0 + rho_rain_h_0 + rho_ = rho - rho_h_0 + + # recover rho_vapour, rho_cloud, temperature from nonlinear system + rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) - rho_vapour = rho_vapour_h - rho_cloud = rho_cloud_h rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) # source terms phase change - S_evaporation = (3.86e-3 - 9.41e-5 * (temperature - T_ref)) * (1 + 9.1 * rho_rain^(0.1875)) + S_evaporation = (3.86e-3 - 9.41e-5 * (temperature - ref_temp)) * (1 + 9.1 * rho_rain^(0.1875)) S_evaporation *= (rho_vs - rho_vapour) * rho_rain^(0.5) S_auto_conversion = 0.001 * rho_cloud S_accretion = 1.72 * rho_cloud * rho_rain^(0.875) S_rain = S_auto_conversion + S_accretion - S_evaporation - #TODO non-linear solve for temperature, rho_vapour_h, rho_cloud_h - - return SVector(0.0, S_rain, -S_rain, 0.0, + return SVector(0.0, -S_rain, S_rain, 0.0, -rho_ * g, -rho_v2 * g, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) end @@ -433,93 +512,23 @@ end @inline function source_terms_no_phase_change(u, x, t, equations::CompressibleRainyEulerEquations2D) # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_v = equations.R_vapour - L_ref = equations.ref_latent_heat_vap_temp - T_ref = equations.ref_temperature - g = equations.gravity + g = equations.gravity # name needed variables rho_dry_, rho_moist_, rho_rain_, _, rho_v2, - _, - rho_vapour_h, rho_cloud_h, - temperature, + _, _, _, _, rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, - _, _, _ = u + _, _, _ = u # densities rho_dry = rho_dry_ + rho_dry_h_0 rho_moist = rho_moist_ + rho_moist_h_0 rho_rain = rho_rain_ + rho_rain_h_0 - - rho_vapour = rho_vapour_h #TODO ?? - rho_cloud = rho_cloud_h - rho = rho_dry + rho_moist + rho_rain - rho_h_0 = rho_dry_h_0 + rho_moist_h_0 + rho_rain_h_0 - rho_ = rho - rho_h_0 - - #TODO test type stability - # non-linear solve for rho_vapour, rho_cloud, temperature - # guess = [rho_vapour; rho_cloud; temperature] - - function f!(residual, guess) - residual[1] = (c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain))*(guess[3] - T_ref) - residual[1] += guess[1] * (L_ref - R_v * T_ref) - residual[2] = min(saturation_vapour_pressure(guess[3], equations) / (R_v * guess[3]), rho_moist) - residual[3] = rho_moist - guess[1] - guess[2] - end - - nl_sol = nlsolve(f!, [rho_vapour, rho_cloud, temperature], ftol = 1e-14, iterations = 20) - - # update entries of u - u = SVector(u[1], u[2], u[3], u[4], u[5], u[6], - nl_sol.zero[1], nl_sol.zero[2], nl_sol.zero[3], - u[10], u[11], u[12], u[13], u[14], u[15]) - - return SVector(0.0, 0.0, 0.0, 0.0, - -rho_ * g, -rho_v2 * g, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) -end - - -@inline function source_terms_dry(u, x, t, equations::CompressibleRainyEulerEquations2D) - # constants - c_vd = equations.c_dry_air_const_volume - T_ref = equations.ref_temperature - g = equations.gravity - - # name needed variables - rho_dry_, rho_moist_, rho_rain_, - rho_v1, rho_v2, - _, _, energy_, _, - rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, - energy_h_0, _, _ = u - - # densities - rho_dry = rho_dry_ + rho_dry_h_0 - rho_moist = rho_moist_ + rho_moist_h_0 - rho_rain = rho_rain_ + rho_rain_h_0 - - rho = rho_dry + rho_moist + rho_rain - rho_inv = inv(rho) - rho_h_0 = rho_dry_h_0 + rho_moist_h_0 + rho_rain_h_0 - rho_ = rho - rho_h_0 - - # velocities - v1 = rho_v1 * rho_inv - v2 = rho_v2 * rho_inv - - # energy - energy = energy_ + energy_h_0 - - # update temperature - u = SVector(u[1], u[2], u[3], u[4], u[5], u[6], u[7], u[8], - (energy - 0.5 * (v1^2 + v2^2) * rho) / (c_vd * rho) + T_ref, - u[10], u[11], u[12], u[13], u[14], u[15]) + rho = rho_dry + rho_moist + rho_rain + rho_h_0 = rho_dry_h_0 + rho_moist_h_0 + rho_rain_h_0 + rho_ = rho - rho_h_0 return SVector(0.0, 0.0, 0.0, 0.0, -rho_ * g, -rho_v2 * g, 0.0, @@ -556,11 +565,79 @@ end ### boundary conditions ### TODO: double check the idea of this boundary condition -# should probably be similar to the approach in compressible_euler_2d.jl +# adapted from compressible_moist_euler_2d.jl which was probably adapted from compressible_euler_2d.jl @inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, x, t, surface_flux_function, equations::CompressibleRainyEulerEquations2D) - #TODO - return SVector(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + + norm_ = norm(normal_direction) + # Normalize the vector without using `normalize` since we need to multiply by the `norm_` later + normal = normal_direction / norm_ + + # rotate the internal solution state + @inline function rotate_to_x(u, normal_vector, equations::CompressibleRainyEulerEquations2D) + # cos and sin of the angle between the x-axis and the normalized normal_vector are + # the normalized vector's x and y coordinates respectively (see unit circle). + c = normal_vector[1] + s = normal_vector[2] + + return SVector(u[1], u[2], u[3], + c * u[4] + s * u[5], + -s * u[4] + c * u[5], + u[6], u[7], u[8], u[9], u[10], u[11], u[12], u[13], u[14], u[15]) + end + + u_local = rotate_to_x(u_inner, normal, equations) + + # name needed variables + rho_dry_, rho_moist_, rho_rain_, + rho_v1, _, + _, _, _, _, + rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, + _, _, _ = u_local + + # densities + rho_dry = rho_dry_ + rho_dry_h_0 + rho_moist = rho_moist_ + rho_moist_h_0 + rho_rain = rho_rain_ + rho_rain_h_0 + + rho_local = rho_dry + rho_moist + rho_rain + + # velocities + v_normal = rho_v1 * inv(rho_local) + v_sound, gamma = speed_of_sound(u_local, equations) + + # pressure + _, rho_vapour, temperature = cons2nonlinearsystemsol(u_local, equations) + p_local = (rho_dry * equations.R_dry_air + rho_vapour * equations.R_vapour) * temperature + + #=qd_local = 1 - qv_local - ql_local + gamma = (qd_local * c_pd + qv_local * c_pv + ql_local * c_l) * + inv(qd_local * c_vd + qv_local * c_vv + ql_local * c_l)=# + # Get the solution of the pressure Riemann problem + # See Section 6.3.3 of + # Eleuterio F. Toro (2009) + # Riemann Solvers and Numerical Methods for Fluid Dynamics: A Practical Introduction + # [DOI: 10.1007/b79761](https://doi.org/10.1007/b79761) + if v_normal <= 0.0 + p_star = p_local * + (1.0 + 0.5 * (gamma - 1) * v_normal / v_sound)^(2.0 * gamma * + inv(gamma - 1)) + else # v_normal > 0.0 + A = 2.0 / ((gamma + 1) * rho_local) + B = p_local * (gamma - 1) / (gamma + 1) + p_star = p_local + + 0.5 * v_normal / A * + (v_normal + sqrt(v_normal^2 + 4.0 * A * (p_local + B))) + end + + # For the slip wall we directly set the flux as the normal velocity is zero + return SVector(zero(eltype(u_inner)), 0.0, 0.0, + p_star * normal[1] * norm_, + p_star * normal[2] * norm_, + zero(eltype(u_inner)), + zero(eltype(u_inner)), + zero(eltype(u_inner)), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + end From 050250db71c42346ed75690e46af6feee24cffb6 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Thu, 22 Aug 2024 17:38:48 +0200 Subject: [PATCH 023/115] experiments and small fixes --- ...xir_rainy_euler_bubble_dry_(basic_test).jl | 4 +-- src/equations/compressible_rainy_euler_2d.jl | 28 +++++++++---------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl b/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl index 1af16006..c98e412b 100644 --- a/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl +++ b/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl @@ -20,7 +20,7 @@ function initial_condition_bubble_dry(x, t, equations::CompressibleRainyEulerEqu r = sqrt((x[1] - center_x)^2 + (x[2] - center_z)^2) # perturbation in potential temperature - potential_temperature_ref = 273.15 + potential_temperature_ref = 300.0 potential_temperature_perturbation = 0.0 if r <= radius potential_temperature_perturbation = 2 * cospi(0.5 * r / radius)^2 @@ -102,7 +102,7 @@ save_solution = SaveSolutionCallback(interval = analysis_interval, output_directory = "out", solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl = 1.0) +stepsize_callback = StepsizeCallback(cfl = 0.1) callbacks = CallbackSet(summary_callback, analysis_callback, diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 61784a14..f420f93c 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -146,11 +146,11 @@ end @inline function cons2nonlinearsystemsol(u, equations::CompressibleRainyEulerEquations2D) # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_v = equations.R_vapour - L_ref = equations.ref_latent_heat_vap_temp + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp ref_temp = equations.ref_temperature # name needed variables @@ -266,11 +266,11 @@ end # debugging if (gamma_m < 0.0) - error("gamma_m kleiner Null") + error("gamma_m less than zero") elseif (p < 0.0) - println("p kleiner Null") + println("p less than zero") if (rho_dry < 0.0) - error("rho_dry kleiner Null") + error("rho_dry less than zero") elseif (temperature < 0.0) # velocity v1 = u[4] * rho_inv @@ -279,12 +279,11 @@ end display(u[6]) display(u[13]) display(0.5 * (v1^2 + v2^2) * inv(rho_inv)) - error("temperature kleiner Null") + error("temperature less than zero") end elseif (rho_inv < 0.0) - display(rho_dry_) - display(rho_dry_h_0) - error("rho kleiner Null") + println(u) + error("rho less than zero") end v_sound = sqrt(gamma_m * p * rho_inv) @@ -607,7 +606,7 @@ end v_sound, gamma = speed_of_sound(u_local, equations) # pressure - _, rho_vapour, temperature = cons2nonlinearsystemsol(u_local, equations) + rho_vapour, _, temperature = cons2nonlinearsystemsol(u_local, equations) p_local = (rho_dry * equations.R_dry_air + rho_vapour * equations.R_vapour) * temperature #=qd_local = 1 - qv_local - ql_local @@ -636,8 +635,7 @@ end p_star * normal[2] * norm_, zero(eltype(u_inner)), zero(eltype(u_inner)), - zero(eltype(u_inner)), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) - + zero(eltype(u_inner)), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) end From 53ea8e723595f610b213bc8a52fe2b37baea67cb Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Fri, 23 Aug 2024 14:43:11 +0200 Subject: [PATCH 024/115] testing --- .../elixir_rainy_euler_bubble_dry_(basic_test).jl | 10 +++++----- src/equations/compressible_rainy_euler_2d.jl | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl b/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl index c98e412b..dc8b1bd8 100644 --- a/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl +++ b/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl @@ -20,7 +20,7 @@ function initial_condition_bubble_dry(x, t, equations::CompressibleRainyEulerEqu r = sqrt((x[1] - center_x)^2 + (x[2] - center_z)^2) # perturbation in potential temperature - potential_temperature_ref = 300.0 + potential_temperature_ref = 273.15 potential_temperature_perturbation = 0.0 if r <= radius potential_temperature_perturbation = 2 * cospi(0.5 * r / radius)^2 @@ -41,12 +41,12 @@ function initial_condition_bubble_dry(x, t, equations::CompressibleRainyEulerEqu # density rho = p / (R * T) - v1 = 0.0 + v1 = 20.0 v2 = 0.0 E = (c_v * T + 0.5 * (v1^2 + v2^2)) # random experiments - return SVector(0.0, 0.0, 0.0, 0.0, 0.0, E * rho, 0.0, 0.0, T, rho, 0.0, 0.0, 0.0, 0.0, T) + return SVector(0.0, 0.0, 0.0, rho * v1, rho * v2, E * rho, 0.0, 0.0, T, rho, 0.0, 0.0, 0.0, 0.0, potential_temperature) end @@ -61,7 +61,7 @@ boundary_conditions = (x_neg = boundary_condition_periodic, y_neg = boundary_condition_slip_wall, y_pos = boundary_condition_slip_wall) -polydeg = 3 +polydeg = 1 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_lax_friedrichs @@ -102,7 +102,7 @@ save_solution = SaveSolutionCallback(interval = analysis_interval, output_directory = "out", solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl = 0.1) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index f420f93c..d82b496b 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -265,8 +265,8 @@ end gamma_m = 1 + (R_d + R_v * q_v) / (c_vd + c_vv * q_v + c_l * q_l) # debugging - if (gamma_m < 0.0) - error("gamma_m less than zero") + if (gamma_m != 1 + R_d / c_vd) + error("gamma_m wrong") elseif (p < 0.0) println("p less than zero") if (rho_dry < 0.0) @@ -377,7 +377,7 @@ end f3 = rho_rain * v1 # "impulse" - f4 = rho * v1 * v1 + p_ + f4 = rho * v1 * v1 + p f5 = rho * v1 * v2 # "energy" @@ -391,7 +391,7 @@ end # "impulse" f4 = rho * v1 * v2 - rho_rain * v_r * v1 - f5 = rho * v2 * v2 - rho_rain * v_r * v2 + p_ + f5 = rho * v2 * v2 - rho_rain * v_r * v2 + p # "energy" f6 = (energy + p) * v2 - (c_l * (temperature - ref_temp) + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r @@ -455,8 +455,8 @@ end f3 = rho_rain * (v_normal - v_r_normal) # "impulse" - f4 = rho * v_normal * v1 - rho_rain * v_r_normal * v1 + p_ * normal_direction[1] - f5 = rho * v_normal * v2 - rho_rain * v_r_normal * v2 + p_ * normal_direction[2] + f4 = rho * v_normal * v1 - rho_rain * v_r_normal * v1 + p * normal_direction[1] + f5 = rho * v_normal * v2 - rho_rain * v_r_normal * v2 + p * normal_direction[2] # "energy" f6 = (energy + p) * v_normal - (c_l * (temperature - ref_temp) + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r_normal @@ -530,7 +530,7 @@ end rho_ = rho - rho_h_0 return SVector(0.0, 0.0, 0.0, 0.0, - -rho_ * g, -rho_v2 * g, 0.0, + -rho * g, -rho_v2 * g, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) end From a5fd8c376cc7f240b25f6fe0c916b3705e473891 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Fri, 23 Aug 2024 23:59:52 +0200 Subject: [PATCH 025/115] testing --- examples/elixir_rainy_euler_bubble_dry_(basic_test).jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl b/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl index dc8b1bd8..6ee0a88c 100644 --- a/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl +++ b/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl @@ -8,8 +8,8 @@ using TrixiAtmo: source_terms_no_phase_change # copied from elixir_euler_warm_bubble.jl for quick tests function initial_condition_bubble_dry(x, t, equations::CompressibleRainyEulerEquations2D) g = equations.gravity - c_v = equations.c_dry_air_const_volume c_p = equations.c_dry_air_const_pressure + c_v = equations.c_dry_air_const_volume # center of perturbation center_x = 10000.0 @@ -20,7 +20,7 @@ function initial_condition_bubble_dry(x, t, equations::CompressibleRainyEulerEqu r = sqrt((x[1] - center_x)^2 + (x[2] - center_z)^2) # perturbation in potential temperature - potential_temperature_ref = 273.15 + potential_temperature_ref = 300.0 potential_temperature_perturbation = 0.0 if r <= radius potential_temperature_perturbation = 2 * cospi(0.5 * r / radius)^2 @@ -43,10 +43,10 @@ function initial_condition_bubble_dry(x, t, equations::CompressibleRainyEulerEqu v1 = 20.0 v2 = 0.0 - E = (c_v * T + 0.5 * (v1^2 + v2^2)) + E = c_v * T + 0.5 * (v1^2 + v2^2) # random experiments - return SVector(0.0, 0.0, 0.0, rho * v1, rho * v2, E * rho, 0.0, 0.0, T, rho, 0.0, 0.0, 0.0, 0.0, potential_temperature) + return SVector(rho, 0.0, 0.0, rho * v1, rho * v2, rho * E, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) end From 00a13f601c6e1be6b7d67019b3c04b2c82936ff9 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Sat, 24 Aug 2024 00:00:41 +0200 Subject: [PATCH 026/115] code cleanup --- src/equations/compressible_rainy_euler_2d.jl | 251 +++++++------------ 1 file changed, 86 insertions(+), 165 deletions(-) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index d82b496b..f4c4b3f2 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -111,27 +111,14 @@ varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", ### conversion ### @inline function cons2prim(u, equations::CompressibleRainyEulerEquations2D) - # name needed variables - rho_dry_, rho_moist_, rho_rain_, - rho_v1, rho_v2, - energy_, - _, _, _, - rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, - energy_h_0, - _, _ = u - # densities - rho_dry = rho_dry_ + rho_dry_h_0 - rho_moist = rho_moist_ + rho_moist_h_0 - rho_rain = rho_rain_ + rho_rain_h_0 - rho_inv = inv(rho_dry + rho_moist + rho_rain) + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) # velocity - v1 = rho_v1 * rho_inv - v2 = rho_v2 * rho_inv + v1, v2 = velocities(u, rho_inv, equations) - # energy - energy = energy_ + energy_h_0 + # energy density + energy = energy_densitiy(u, equations) return SVector(rho_dry, rho_moist, rho_rain, v1, v2, energy, u[7], u[8], u[9], u[10], u[11], u[12], u[13], u[14], u[15]) @@ -152,39 +139,22 @@ end R_v = equations.R_vapour L_ref = equations.ref_latent_heat_vap_temp ref_temp = equations.ref_temperature - - # name needed variables - rho_dry_, rho_moist_, rho_rain_, - rho_v1, rho_v2, - energy_, - rho_vapour_h, rho_cloud_h, - temperature, - rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, - energy_h, _, _ = u # densities - rho_dry = rho_dry_ + rho_dry_h_0 - rho_moist = rho_moist_ + rho_moist_h_0 - rho_rain = rho_rain_ + rho_rain_h_0 - - rho = rho_dry + rho_moist + rho_rain - rho_inv = inv(rho) + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) # for initial guess - rho_vapour = rho_vapour_h - rho_cloud = rho_cloud_h + rho_vapour_h = u[7] + rho_cloud_h = u[8] + temperature_0 = u[9] # velocity - v1 = rho_v1 * rho_inv - v2 = rho_v2 * rho_inv - - # energy - energy = energy_ + energy_h + v1, v2 = velocities(u, rho_inv, equations) - #TODO test type stability - # non-linear solve for rho_vapour, rho_cloud, temperature - # guess = [rho_vapour; rho_cloud; temperature] + # energy density + energy = energy_densitiy(u, equations) + # recover temperature explicitly from inner energy when other variables are zero if (rho_moist == 0.0 && rho_rain == 0.0) return SVector(0.0, 0.0, (energy - 0.5 * (v1^2 + v2^2) * rho) / (c_vd * rho) + ref_temp) else @@ -196,7 +166,7 @@ end residual[3] = rho_moist - guess[1] - guess[2] end - nl_sol = nlsolve(f!, [rho_vapour; rho_cloud; temperature], ftol = 1e-14, iterations = 20) + nl_sol = nlsolve(f!, [rho_vapour_h; rho_cloud_h; temperature_0], ftol = 1e-14, iterations = 20) return SVector(nl_sol.zero[1], nl_sol.zero[2], nl_sol.zero[3]) end @@ -205,22 +175,11 @@ end # for convenience @inline function cons2speeds(u, equations::CompressibleRainyEulerEquations2D) - # name needed variables - rho_dry_, rho_moist_, rho_rain_, - rho_v1, rho_v2, - _, _, _, _, - rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, - _, _, _ = u - # densities - rho_dry = rho_dry_ + rho_dry_h_0 - rho_moist = rho_moist_ + rho_moist_h_0 - rho_rain = rho_rain_ + rho_rain_h_0 - rho_inv = inv(rho_dry + rho_moist + rho_rain) + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) # velocity - v1 = rho_v1 * rho_inv - v2 = rho_v2 * rho_inv + v1, v2 = velocities(u, rho_inv, equations) # get speed of sound v_sound = speed_of_sound(u, equations)[1] @@ -235,14 +194,7 @@ end ### physics variables ### -@inline function speed_of_sound(u, equations::CompressibleRainyEulerEquations2D) - # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_d = equations.R_dry_air - R_v = equations.R_vapour - +@inline function densities(u, equations::CompressibleRainyEulerEquations2D) # name needed variables rho_dry_, rho_moist_, rho_rain_, _, _, _, _, _, _, @@ -253,7 +205,33 @@ end rho_dry = rho_dry_ + rho_dry_h_0 rho_moist = rho_moist_ + rho_moist_h_0 rho_rain = rho_rain_ + rho_rain_h_0 - rho_inv = inv(rho_dry + rho_moist + rho_rain) + rho = rho_dry + rho_moist + rho_rain + rho_inv = inv(rho) + + return SVector(rho_dry, rho_moist, rho_rain, rho, rho_inv) +end + + +@inline function velocities(u, rho_inv, equations::CompressibleRainyEulerEquations2D) + return SVector(u[4] * rho_inv, u[5] * rho_inv) +end + + +@inline function energy_densitiy(u, equations::CompressibleRainyEulerEquations2D) + return u[6] +end + + +@inline function speed_of_sound(u, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + + # densities + rho_dry, _, rho_rain, _, rho_inv = densities(u, equations) # recover rho_vapour, rho_cloud, temperature from nonlinear system rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) @@ -273,8 +251,7 @@ end error("rho_dry less than zero") elseif (temperature < 0.0) # velocity - v1 = u[4] * rho_inv - v2 = u[5] * rho_inv + v1, v2 = velocities(u, rho_inv, equations) display(u[6]) display(u[13]) @@ -336,38 +313,23 @@ end R_v = equations.R_vapour ref_temp = equations.ref_temperature - # name needed variables - rho_dry_, rho_moist_, rho_rain_, - rho_v1, rho_v2, - energy_, - _, _, _, - rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, - energy_h_0, - rho_vapour_h_0, - temperature_0 = u - - # densities - rho_dry = rho_dry_ + rho_dry_h_0 - rho_moist = rho_moist_ + rho_moist_h_0 - rho_rain = rho_rain_ + rho_rain_h_0 - rho = rho_dry + rho_moist + rho_rain - rho_inv = inv(rho) + #densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) # recover rho_vapour, rho_cloud, temperature from nonlinear system rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) # velocity - v1 = rho_v1 * rho_inv - v2 = rho_v2 * rho_inv - v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) + v1, v2 = velocities(u, rho_inv, equations) + v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) # pressure - p = R_d * rho_dry * temperature + R_v * rho_vapour * temperature - p_0 = R_d * rho_dry_h_0 * temperature_0 + R_v * rho_vapour_h_0 * temperature_0 - p_ = p - p_0 + p = R_d * rho_dry * temperature + R_v * rho_vapour * temperature + #p_0 = R_d * rho_dry_h_0 * temperature_0 + R_v * rho_vapour_h_0 * temperature_0 + #p_ = p - p_0 - # energy - energy = energy_ + energy_h_0 + # energy density + energy = energy_densitiy(u, equations) # flux for orientation cases if (orientation == 1) @@ -410,30 +372,15 @@ end R_v = equations.R_vapour ref_temp = equations.ref_temperature - # name needed variables - rho_dry_, rho_moist_, rho_rain_, - rho_v1, rho_v2, - energy_, - _, _, _, - rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, - energy_h_0, - rho_vapour_h_0, - temperature_0 = u - # densities - rho_dry = rho_dry_ + rho_dry_h_0 - rho_moist = rho_moist_ + rho_moist_h_0 - rho_rain = rho_rain_ + rho_rain_h_0 - rho = rho_dry + rho_moist + rho_rain - rho_inv = inv(rho) + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) # recover rho_vapour, rho_cloud, temperature from nonlinear system rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) # velocity - v1 = rho_v1 * rho_inv - v2 = rho_v2 * rho_inv - v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) + v1, v2 = velocities(u, rho_inv, equations) + v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) # normal velocities v_normal = v1 * normal_direction[1] + v2 * normal_direction[2] @@ -441,12 +388,12 @@ end #norm_vn = norm(normal_direction) # pressure - p = R_d * rho_dry * temperature + R_v * rho_vapour * temperature - p_0 = R_d * rho_dry_h_0 * temperature_0 + R_v * rho_vapour_h_0 * temperature_0 - p_ = p - p_0 + p = R_d * rho_dry * temperature + R_v * rho_vapour * temperature + #p_0 = R_d * rho_dry_h_0 * temperature_0 + R_v * rho_vapour_h_0 * temperature_0 + #p_ = p - p_0 - # energy - energy = energy_ + energy_h_0 + # energy density + energy = energy_densitiy(u, equations) # flux # "mass" @@ -474,20 +421,10 @@ end g = equations.gravity # name needed variables - rho_dry_, rho_moist_, rho_rain_, - _, rho_v2, - _, _, _, _, - rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, - _, _, _ = u + rho_v2 = u[5] # densities - rho_dry = rho_dry_ + rho_dry_h_0 - rho_moist = rho_moist_ + rho_moist_h_0 - rho_rain = rho_rain_ + rho_rain_h_0 - - rho = rho_dry + rho_moist + rho_rain - rho_h_0 = rho_dry_h_0 + rho_moist_h_0 + rho_rain_h_0 - rho_ = rho - rho_h_0 + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) # recover rho_vapour, rho_cloud, temperature from nonlinear system rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) @@ -502,35 +439,26 @@ end S_rain = S_auto_conversion + S_accretion - S_evaporation return SVector(0.0, -S_rain, S_rain, 0.0, - -rho_ * g, -rho_v2 * g, 0.0, + -rho * g, -rho_v2 * g, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) end # no phase changes and no Coriolis term - @inline function source_terms_no_phase_change(u, x, t, equations::CompressibleRainyEulerEquations2D) # constants g = equations.gravity # name needed variables - rho_dry_, rho_moist_, rho_rain_, - _, rho_v2, - _, _, _, _, - rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, - _, _, _ = u + rho_v2 = u[5] # densities - rho_dry = rho_dry_ + rho_dry_h_0 - rho_moist = rho_moist_ + rho_moist_h_0 - rho_rain = rho_rain_ + rho_rain_h_0 - - rho = rho_dry + rho_moist + rho_rain - rho_h_0 = rho_dry_h_0 + rho_moist_h_0 + rho_rain_h_0 - rho_ = rho - rho_h_0 + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + #rho_h_0 = rho_dry_h_0 + rho_moist_h_0 + rho_rain_h_0 + #rho_ = rho - rho_h_0 return SVector(0.0, 0.0, 0.0, 0.0, - -rho * g, -rho_v2 * g, 0.0, + -g * rho, -g * rho_v2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) end @@ -573,41 +501,21 @@ end normal = normal_direction / norm_ # rotate the internal solution state - @inline function rotate_to_x(u, normal_vector, equations::CompressibleRainyEulerEquations2D) - # cos and sin of the angle between the x-axis and the normalized normal_vector are - # the normalized vector's x and y coordinates respectively (see unit circle). - c = normal_vector[1] - s = normal_vector[2] - - return SVector(u[1], u[2], u[3], - c * u[4] + s * u[5], - -s * u[4] + c * u[5], - u[6], u[7], u[8], u[9], u[10], u[11], u[12], u[13], u[14], u[15]) - end - u_local = rotate_to_x(u_inner, normal, equations) # name needed variables - rho_dry_, rho_moist_, rho_rain_, - rho_v1, _, - _, _, _, _, - rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, - _, _, _ = u_local + rho_v1 = u_local[4] # densities - rho_dry = rho_dry_ + rho_dry_h_0 - rho_moist = rho_moist_ + rho_moist_h_0 - rho_rain = rho_rain_ + rho_rain_h_0 - - rho_local = rho_dry + rho_moist + rho_rain + rho_dry_local, rho_moist_local, rho_rain_local, rho_local, rho_inv_local = densities(u_local, equations) # velocities - v_normal = rho_v1 * inv(rho_local) + v_normal = rho_v1 * rho_inv_local v_sound, gamma = speed_of_sound(u_local, equations) # pressure rho_vapour, _, temperature = cons2nonlinearsystemsol(u_local, equations) - p_local = (rho_dry * equations.R_dry_air + rho_vapour * equations.R_vapour) * temperature + p_local = (rho_dry_local * equations.R_dry_air + rho_vapour * equations.R_vapour) * temperature #=qd_local = 1 - qv_local - ql_local gamma = (qd_local * c_pd + qv_local * c_pv + ql_local * c_l) * @@ -658,5 +566,18 @@ end end +@inline function rotate_to_x(u, normal_vector, equations::CompressibleRainyEulerEquations2D) + # cos and sin of the angle between the x-axis and the normalized normal_vector are + # the normalized vector's x and y coordinates respectively (see unit circle). + c = normal_vector[1] + s = normal_vector[2] + + return SVector(u[1], u[2], u[3], + c * u[4] + s * u[5], + -s * u[4] + c * u[5], + u[6], u[7], u[8], u[9], u[10], u[11], u[12], u[13], u[14], u[15]) +end + + end # muladd end \ No newline at end of file From 8aae0322941ff53b44f93d732220151406030c9c Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Sun, 25 Aug 2024 17:27:15 +0200 Subject: [PATCH 027/115] rename, testing and dimension reduction of u --- ...e_dry_(basic_test).jl => elixir_rainy_euler_bubble_dry.jl} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename examples/{elixir_rainy_euler_bubble_dry_(basic_test).jl => elixir_rainy_euler_bubble_dry.jl} (98%) diff --git a/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl b/examples/elixir_rainy_euler_bubble_dry.jl similarity index 98% rename from examples/elixir_rainy_euler_bubble_dry_(basic_test).jl rename to examples/elixir_rainy_euler_bubble_dry.jl index 6ee0a88c..c9c201dd 100644 --- a/examples/elixir_rainy_euler_bubble_dry_(basic_test).jl +++ b/examples/elixir_rainy_euler_bubble_dry.jl @@ -46,7 +46,7 @@ function initial_condition_bubble_dry(x, t, equations::CompressibleRainyEulerEqu E = c_v * T + 0.5 * (v1^2 + v2^2) # random experiments - return SVector(rho, 0.0, 0.0, rho * v1, rho * v2, rho * E, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + return SVector(rho, 0.0, 0.0, rho * v1, rho * v2, rho * E, 0.0, 0.0, 0.0) end @@ -61,7 +61,7 @@ boundary_conditions = (x_neg = boundary_condition_periodic, y_neg = boundary_condition_slip_wall, y_pos = boundary_condition_slip_wall) -polydeg = 1 +polydeg = 3 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_lax_friedrichs From 6e55868793e3629c3a9ca061f2945cd4eca2d0aa Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Sun, 25 Aug 2024 17:28:55 +0200 Subject: [PATCH 028/115] fixed temperature for dry testcase, cleanup, got rid of unused 'variables' --- src/equations/compressible_rainy_euler_2d.jl | 158 +++++++------------ 1 file changed, 61 insertions(+), 97 deletions(-) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index f4c4b3f2..44cd1fe9 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -23,7 +23,7 @@ import Trixi: varnames, ### equation, parameters and constants ### -struct CompressibleRainyEulerEquations2D{RealT <: Real} <: AbstractCompressibleRainyEulerEquations{2, 15} +struct CompressibleRainyEulerEquations2D{RealT <: Real} <: AbstractCompressibleRainyEulerEquations{2, 9} # Specific heat capacities: c_liquid_water ::RealT c_dry_air_const_pressure ::RealT @@ -63,10 +63,10 @@ function CompressibleRainyEulerEquations2D(; RealT = Float64) eps = R_dry_air / R_vapour # Reference values: - saturation_vapour_pressure = 610.7 - ref_temperature = 273.15 - latent_heat_vap_ref_temp = 2.5e6 - ref_pressure = 1e5 + ref_saturation_pressure = 610.7 + ref_temperature = 273.15 + ref_latent_heat_vap_temp = 2.5e6 + ref_pressure = 1e5 # Other: gravity = 9.81 @@ -75,8 +75,8 @@ function CompressibleRainyEulerEquations2D(; RealT = Float64) return CompressibleRainyEulerEquations2D{RealT}(c_liquid_water, c_dry_air_const_pressure, c_dry_air_const_volume, c_vapour_const_pressure, c_vapour_const_volume, R_dry_air, - R_vapour, eps, saturation_vapour_pressure, ref_temperature, - latent_heat_vap_ref_temp, ref_pressure, gravity, + R_vapour, eps, ref_saturation_pressure, ref_temperature, + ref_latent_heat_vap_temp, ref_pressure, gravity, rain_water_distr, v_mean_rain) end @@ -84,26 +84,18 @@ end ### varnames ### -varnames(::typeof(cons2cons), ::CompressibleRainyEulerEquations2D) = ("rho_dry_", "rho_moist_", "rho_rain_", +varnames(::typeof(cons2cons), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_moist", "rho_rain", "rho_v1", "rho_v2", - "energy", + "energy_density", "rho_vapour_h", "rho_cloud_h", - "temperature", - "rho_dry_h_0", "rho_moist_h_0", "rho_rain_h_0", - "energy_h_0", - "rho_vapour_h_0", - "temperature_0") + "temperature_h") varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_moist", "rho_rain", "v1", "v2", - "energy", - "rho_vapour", "rho_cloud", - "temperature", - "rho_dry_h_0", "rho_moist_h_0", "rho_rain_h_0", - "energy_h_0", - "rho_vapour_h_0", - "temperature_0") + "energy_density", + "rho_vapour_h", "rho_cloud_h", + "temperature_h") @@ -118,16 +110,16 @@ varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", v1, v2 = velocities(u, rho_inv, equations) # energy density - energy = energy_densitiy(u, equations) + energy = energy_density(u, equations) return SVector(rho_dry, rho_moist, rho_rain, v1, v2, energy, - u[7], u[8], u[9], u[10], u[11], u[12], u[13], u[14], u[15]) + u[7], u[8], u[9]) end @inline function cons2entropy(u, equations::CompressibleRainyEulerEquations2D) #TODO - return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0) end @@ -144,19 +136,19 @@ end rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) # for initial guess - rho_vapour_h = u[7] - rho_cloud_h = u[8] - temperature_0 = u[9] + rho_vapour_h = u[7] + rho_cloud_h = u[8] + temperature_h = u[9] # velocity v1, v2 = velocities(u, rho_inv, equations) # energy density - energy = energy_densitiy(u, equations) + energy = energy_density(u, equations) # recover temperature explicitly from inner energy when other variables are zero if (rho_moist == 0.0 && rho_rain == 0.0) - return SVector(0.0, 0.0, (energy - 0.5 * (v1^2 + v2^2) * rho) / (c_vd * rho) + ref_temp) + return SVector(0.0, 0.0, (energy - 0.5 * (v1^2 + v2^2) * rho) / (c_vd * rho)) else error("wrong system") function f!(residual, guess) @@ -166,7 +158,7 @@ end residual[3] = rho_moist - guess[1] - guess[2] end - nl_sol = nlsolve(f!, [rho_vapour_h; rho_cloud_h; temperature_0], ftol = 1e-14, iterations = 20) + nl_sol = nlsolve(f!, [rho_vapour_h; rho_cloud_h; temperature_h], ftol = 1e-14, iterations = 20) return SVector(nl_sol.zero[1], nl_sol.zero[2], nl_sol.zero[3]) end @@ -195,16 +187,10 @@ end ### physics variables ### @inline function densities(u, equations::CompressibleRainyEulerEquations2D) - # name needed variables - rho_dry_, rho_moist_, rho_rain_, - _, _, _, _, _, _, - rho_dry_h_0, rho_moist_h_0, rho_rain_h_0, - _, _, _ = u - # densities - rho_dry = rho_dry_ + rho_dry_h_0 - rho_moist = rho_moist_ + rho_moist_h_0 - rho_rain = rho_rain_ + rho_rain_h_0 + rho_dry = u[1] + rho_moist = u[2] + rho_rain = u[3] rho = rho_dry + rho_moist + rho_rain rho_inv = inv(rho) @@ -217,11 +203,27 @@ end end -@inline function energy_densitiy(u, equations::CompressibleRainyEulerEquations2D) +@inline function energy_density(u, equations::CompressibleRainyEulerEquations2D) return u[6] end +@inline function pressure(u, equations::CompressibleRainyEulerEquations2D) + # constants + R_d = equations.R_dry_air + R_v = equations.R_vapour + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) + + p = (R_d * rho_dry + R_v * rho_vapour) * temperature + + return p +end + + @inline function speed_of_sound(u, equations::CompressibleRainyEulerEquations2D) # constants c_l = equations.c_liquid_water @@ -237,32 +239,12 @@ end rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) # formula - p = R_d * rho_dry * temperature + R_v * rho_vapour * temperature + #p = R_d * rho_dry * temperature + R_v * rho_vapour * temperature + p = pressure(u, equations) q_v = rho_vapour / rho_dry q_l = (rho_cloud + rho_rain) / rho_dry gamma_m = 1 + (R_d + R_v * q_v) / (c_vd + c_vv * q_v + c_l * q_l) - # debugging - if (gamma_m != 1 + R_d / c_vd) - error("gamma_m wrong") - elseif (p < 0.0) - println("p less than zero") - if (rho_dry < 0.0) - error("rho_dry less than zero") - elseif (temperature < 0.0) - # velocity - v1, v2 = velocities(u, rho_inv, equations) - - display(u[6]) - display(u[13]) - display(0.5 * (v1^2 + v2^2) * inv(rho_inv)) - error("temperature less than zero") - end - elseif (rho_inv < 0.0) - println(u) - error("rho less than zero") - end - v_sound = sqrt(gamma_m * p * rho_inv) return SVector(v_sound, gamma_m) @@ -309,8 +291,6 @@ end @inline function flux(u, orientation::Integer, equations::CompressibleRainyEulerEquations2D) # constants c_l = equations.c_liquid_water - R_d = equations.R_dry_air - R_v = equations.R_vapour ref_temp = equations.ref_temperature #densities @@ -324,12 +304,10 @@ end v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) # pressure - p = R_d * rho_dry * temperature + R_v * rho_vapour * temperature - #p_0 = R_d * rho_dry_h_0 * temperature_0 + R_v * rho_vapour_h_0 * temperature_0 - #p_ = p - p_0 + p = pressure(u, equations) # energy density - energy = energy_densitiy(u, equations) + energy = energy_density(u, equations) # flux for orientation cases if (orientation == 1) @@ -360,7 +338,7 @@ end end return SVector(f1, f2, f3, f4, f5, f6, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + 0.0, 0.0, 0.0) end @@ -368,8 +346,6 @@ end #TODO Double-check for mistakes in "impulse" and "energy"! # constants c_l = equations.c_liquid_water - R_d = equations.R_dry_air - R_v = equations.R_vapour ref_temp = equations.ref_temperature # densities @@ -385,15 +361,12 @@ end # normal velocities v_normal = v1 * normal_direction[1] + v2 * normal_direction[2] v_r_normal = v_r * normal_direction[2] #TODO correct? - #norm_vn = norm(normal_direction) # pressure - p = R_d * rho_dry * temperature + R_v * rho_vapour * temperature - #p_0 = R_d * rho_dry_h_0 * temperature_0 + R_v * rho_vapour_h_0 * temperature_0 - #p_ = p - p_0 + p = pressure(u, equations) # energy density - energy = energy_densitiy(u, equations) + energy = energy_density(u, equations) # flux # "mass" @@ -409,7 +382,7 @@ end f6 = (energy + p) * v_normal - (c_l * (temperature - ref_temp) + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r_normal return SVector(f1, f2, f3, f4, f5, f6, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + 0.0, 0.0, 0.0) end @@ -429,7 +402,7 @@ end # recover rho_vapour, rho_cloud, temperature from nonlinear system rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) - rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) # source terms phase change S_evaporation = (3.86e-3 - 9.41e-5 * (temperature - ref_temp)) * (1 + 9.1 * rho_rain^(0.1875)) @@ -439,8 +412,7 @@ end S_rain = S_auto_conversion + S_accretion - S_evaporation return SVector(0.0, -S_rain, S_rain, 0.0, - -rho * g, -rho_v2 * g, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + -rho * g, -rho_v2 * g, 0.0, 0.0, 0.0) end @@ -454,12 +426,9 @@ end # densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - #rho_h_0 = rho_dry_h_0 + rho_moist_h_0 + rho_rain_h_0 - #rho_ = rho - rho_h_0 return SVector(0.0, 0.0, 0.0, 0.0, - -g * rho, -g * rho_v2, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + -g * rho, -g * rho_v2, 0.0, 0.0, 0.0) end @@ -490,7 +459,7 @@ end -### boundary conditions ### TODO: double check the idea of this boundary condition +### boundary conditions ### # adapted from compressible_moist_euler_2d.jl which was probably adapted from compressible_euler_2d.jl @inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, x, t, @@ -512,14 +481,10 @@ end # velocities v_normal = rho_v1 * rho_inv_local v_sound, gamma = speed_of_sound(u_local, equations) - - # pressure - rho_vapour, _, temperature = cons2nonlinearsystemsol(u_local, equations) - p_local = (rho_dry_local * equations.R_dry_air + rho_vapour * equations.R_vapour) * temperature - #=qd_local = 1 - qv_local - ql_local - gamma = (qd_local * c_pd + qv_local * c_pv + ql_local * c_l) * - inv(qd_local * c_vd + qv_local * c_vv + ql_local * c_l)=# + # pressure + p_local = pressure(u_local, equations) + # Get the solution of the pressure Riemann problem # See Section 6.3.3 of # Eleuterio F. Toro (2009) @@ -538,12 +503,10 @@ end end # For the slip wall we directly set the flux as the normal velocity is zero - return SVector(zero(eltype(u_inner)), 0.0, 0.0, + return SVector(0.0, 0.0, 0.0, p_star * normal[1] * norm_, p_star * normal[2] * norm_, - zero(eltype(u_inner)), - zero(eltype(u_inner)), - zero(eltype(u_inner)), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + 0.0, 0.0, 0.0, 0.0) end @@ -566,6 +529,7 @@ end end +# same as in compressible_euler_2d.jl @inline function rotate_to_x(u, normal_vector, equations::CompressibleRainyEulerEquations2D) # cos and sin of the angle between the x-axis and the normalized normal_vector are # the normalized vector's x and y coordinates respectively (see unit circle). @@ -575,7 +539,7 @@ end return SVector(u[1], u[2], u[3], c * u[4] + s * u[5], -s * u[4] + c * u[5], - u[6], u[7], u[8], u[9], u[10], u[11], u[12], u[13], u[14], u[15]) + u[6], u[7], u[8], u[9]) end From 8d6b7ae95e5d52efc04922c18d02082f5140c4b7 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Thu, 29 Aug 2024 18:42:09 +0200 Subject: [PATCH 029/115] added elixir for dry convergence test --- examples/test_elixirs/convergence_test_dry.jl | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 examples/test_elixirs/convergence_test_dry.jl diff --git a/examples/test_elixirs/convergence_test_dry.jl b/examples/test_elixirs/convergence_test_dry.jl new file mode 100644 index 00000000..d564df42 --- /dev/null +++ b/examples/test_elixirs/convergence_test_dry.jl @@ -0,0 +1,108 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo + + + +# from compressible_euler_2d.jl +function initial_condition_convergence_test(x, t, equations::CompressibleRainyEulerEquations2D) + RealT = eltype(x) + c = 2 + A = convert(RealT, 0.1) + L = 2 + f = 1.0f0 / L + ω = 2 * convert(RealT, pi) * f + ini = c + A * sin(ω * (x[1] + x[2] - t)) + + rho = ini + rho_v1 = ini + rho_v2 = ini + rho_e = ini^2 + + return SVector(rho, 0.0, 0.0, rho_v1, rho_v2, rho_e, 0.0, 0.0, 0.0) +end + + +# from compressible_euler_2d.jl +function source_terms_convergence_test(u, x, t, equations::CompressibleRainyEulerEquations2D) + # Same settings as in `initial_condition` + RealT = eltype(u) + c = 2 + A = convert(RealT, 0.1) + L = 2 + f = 1.0f0 / L + ω = 2 * convert(RealT, pi) * f + γ = equations.c_dry_air_const_pressure / equations.c_dry_air_const_volume + + x1, x2 = x + si, co = sincos(ω * (x1 + x2 - t)) + rho = c + A * si + rho_x = ω * A * co + # Note that d/dt rho = -d/dx rho = -d/dy rho. + + tmp = (2 * rho - 1) * (γ - 1) + + du1 = rho_x + du2 = rho_x * (1 + tmp) + du3 = du2 + du4 = 2 * rho_x * (rho + tmp) + + return SVector(du1, 0.0, 0.0, du2, du3, du4, 0.0, 0.0, 0.0) +end + + +# from elixir_euler_source_terms.jl +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleRainyEulerEquations2D() + +initial_condition = initial_condition_convergence_test + +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) + +coordinates_min = (0.0, 0.0) +coordinates_max = (2.0, 2.0) + +cells_per_dimension = (16, 16) + +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_convergence_test) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 2.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) + +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback) + +############################################################################### +# run the simulation + +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); +summary_callback() # print the timer summary + +# For copy-paste convenience: +#convergence_test("TrixiAtmo.jl/examples/test_elixirs/convergence_test_dry.jl", 4) \ No newline at end of file From 568079381a872398b2e093b783676d76be1bcb12 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Thu, 29 Aug 2024 18:42:26 +0200 Subject: [PATCH 030/115] formatting changes --- examples/elixir_rainy_euler_bubble_dry.jl | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_dry.jl b/examples/elixir_rainy_euler_bubble_dry.jl index c9c201dd..9af5c3b6 100644 --- a/examples/elixir_rainy_euler_bubble_dry.jl +++ b/examples/elixir_rainy_euler_bubble_dry.jl @@ -72,11 +72,17 @@ coordinates_min = ( 0.0, 0.0) coordinates_max = (20_000.0, 10_000.0) cells_per_dimension = (64, 32) + +periodicity = (true, false) + mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, - periodicity = (true, false)) + periodicity = periodicity) + +initial_condition = initial_condition_bubble_dry +source_terms = source_terms_no_phase_change -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_bubble_dry, solver, - source_terms = source_terms_no_phase_change, +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms, boundary_conditions = boundary_conditions) ############################################################################### From 7b9ba25808affbe616e24392b22ef4ce14c66498 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Thu, 29 Aug 2024 18:43:32 +0200 Subject: [PATCH 031/115] fixed max_abs_speed_naive, formatting changes and temporary tests --- src/equations/compressible_rainy_euler_2d.jl | 40 +++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 44cd1fe9..61a28354 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -148,7 +148,15 @@ end # recover temperature explicitly from inner energy when other variables are zero if (rho_moist == 0.0 && rho_rain == 0.0) - return SVector(0.0, 0.0, (energy - 0.5 * (v1^2 + v2^2) * rho) / (c_vd * rho)) + energy_kinetic = 0.5 * (v1^2 + v2^2) * rho + temperature = (energy - energy_kinetic) / (c_vd * rho) + + if (temperature < 0.0) + display(energy-energy_kinetic) + error("temp negative") + end + + return SVector(0.0, 0.0, temperature) else error("wrong system") function f!(residual, guess) @@ -174,10 +182,10 @@ end v1, v2 = velocities(u, rho_inv, equations) # get speed of sound - v_sound = speed_of_sound(u, equations)[1] + v_sound = speed_of_sound(u, equations)[1] # get terminal velocity rain - v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) + v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) return SVector(v1, v2, v_sound, v_r) end @@ -219,6 +227,8 @@ end rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) p = (R_d * rho_dry + R_v * rho_vapour) * temperature + #v1, v2 = velocities(u, rho_inv, equations) + #p = (equations.c_dry_air_const_pressure / equations.c_dry_air_const_volume - 1) * (energy_density(u, equations) - 0.5f0 * (u[4] * v1 + u[5] * v2)) return p end @@ -239,12 +249,17 @@ end rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) # formula - #p = R_d * rho_dry * temperature + R_v * rho_vapour * temperature p = pressure(u, equations) q_v = rho_vapour / rho_dry q_l = (rho_cloud + rho_rain) / rho_dry gamma_m = 1 + (R_d + R_v * q_v) / (c_vd + c_vv * q_v + c_l * q_l) + if (rho_inv < 0.0) + error("rho less than zero") + elseif (p < 0.0) + error("pressure less than zero") + end + v_sound = sqrt(gamma_m * p * rho_inv) return SVector(v_sound, gamma_m) @@ -267,7 +282,6 @@ end end -#TODO name change @inline function saturation_vapour_pressure(temperature, equations::CompressibleRainyEulerEquations2D) # constants c_l = equations.c_liquid_water @@ -330,8 +344,8 @@ end f3 = rho_rain * (v2 - v_r) # "impulse" - f4 = rho * v1 * v2 - rho_rain * v_r * v1 - f5 = rho * v2 * v2 - rho_rain * v_r * v2 + p + f4 = rho * v1 * v2 - rho_rain * v_r * v1 + f5 = rho * v2 * v2 + p - rho_rain * v_r * v2 # "energy" f6 = (energy + p) * v2 - (c_l * (temperature - ref_temp) + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r @@ -343,7 +357,7 @@ end @inline function flux(u, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) - #TODO Double-check for mistakes in "impulse" and "energy"! + #TODO Double-check for mistakes in "impulse" and "energy" # constants c_l = equations.c_liquid_water ref_temp = equations.ref_temperature @@ -375,8 +389,8 @@ end f3 = rho_rain * (v_normal - v_r_normal) # "impulse" - f4 = rho * v_normal * v1 - rho_rain * v_r_normal * v1 + p * normal_direction[1] - f5 = rho * v_normal * v2 - rho_rain * v_r_normal * v2 + p * normal_direction[2] + f4 = rho * v_normal * v1 + p * normal_direction[1] - rho_rain * v_r_normal * v1 + f5 = rho * v_normal * v2 + p * normal_direction[2] - rho_rain * v_r_normal * v2 # "energy" f6 = (energy + p) * v_normal - (c_l * (temperature - ref_temp) + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r_normal @@ -448,13 +462,11 @@ end # calculate upper bounds for left and right speed v_ll_max = abs(v1_ll * normal_direction[1] + v2_ll * normal_direction[2]) v_ll_max += abs( v_r_ll * normal_direction[2]) - v_ll_max += v_sound_ll v_rr_max = abs(v1_rr * normal_direction[1] + v2_rr * normal_direction[2]) v_rr_max += abs( v_r_rr * normal_direction[2]) - v_rr_max += v_sound_rr - return max(v_ll_max, v_rr_max) + return max(v_ll_max, v_rr_max) + max(v_sound_ll, v_sound_rr) * norm(normal_direction) end @@ -538,7 +550,7 @@ end return SVector(u[1], u[2], u[3], c * u[4] + s * u[5], - -s * u[4] + c * u[5], + -s * u[4] + c * u[5], u[6], u[7], u[8], u[9]) end From 7c100bf01aa5290f87bfc4d3fc8c7e31853b70d0 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Mon, 2 Sep 2024 16:34:30 +0200 Subject: [PATCH 032/115] added Lucas' compressible moist Euler equations --- src/TrixiAtmo.jl | 2 +- .../compressible_moist_euler_2d_lucas.jl | 1029 +++++++++++++++++ src/equations/equations.jl | 1 + 3 files changed, 1031 insertions(+), 1 deletion(-) create mode 100644 src/equations/compressible_moist_euler_2d_lucas.jl diff --git a/src/TrixiAtmo.jl b/src/TrixiAtmo.jl index 759e76a4..04cfd8df 100644 --- a/src/TrixiAtmo.jl +++ b/src/TrixiAtmo.jl @@ -21,6 +21,6 @@ bar() = false baz() = Trixi.examples_dir() include("equations/equations.jl") -export CompressibleRainyEulerEquations2D +export CompressibleMoistEulerEquations2D, CompressibleRainyEulerEquations2D end # module TrixiAtmo diff --git a/src/equations/compressible_moist_euler_2d_lucas.jl b/src/equations/compressible_moist_euler_2d_lucas.jl new file mode 100644 index 00000000..638cc398 --- /dev/null +++ b/src/equations/compressible_moist_euler_2d_lucas.jl @@ -0,0 +1,1029 @@ +# Implemented by Lucas Gemein +# https://github.com/NichtLucas/Trixi.jl/tree/thesis_gemein_2022 + +using Trixi +using Trixi: ln_mean, inv_ln_mean +import Trixi: varnames, flux_chandrashekar, boundary_condition_slip_wall, + cons2prim, cons2entropy, max_abs_speed_naive, max_abs_speeds, + entropy, energy_total, flux + +@muladd begin +#! format: noindent +struct CompressibleMoistEulerEquations2D{RealT <: Real} <: + AbstractCompressibleMoistEulerEquations{2, 6} + p_0::RealT # constant reference pressure 1000 hPa(100000 Pa) + c_pd::RealT # dry air constant + c_vd::RealT # dry air constant + R_d::RealT # dry air gas constant + c_pv::RealT # moist air constant + c_vv::RealT # moist air constant + R_v::RealT # moist air gas constant + c_pl::RealT # liqid water constant + g::RealT # gravitation constant + kappa::RealT # ratio of the gas constant R_d + gamma::RealT # = inv(kappa- 1); can be used to write slow divisions as fast multiplications + L_00::RealT # latent heat of evaporation at 0 K + a::RealT +end + +function CompressibleMoistEulerEquations2D(; g = 9.81, RealT = Float64) + p_0 = 100000.0 + c_pd = 1004.0 + c_vd = 717.0 + R_d = c_pd - c_vd + c_pv = 1885.0 + c_vv = 1424.0 + R_v = c_pv - c_vv + c_pl = 4186.0 + gamma = c_pd / c_vd # = 1/(1 - kappa) + kappa = 1 - inv(gamma) + L_00 = 3147620.0 + a = 360.0 + return CompressibleMoistEulerEquations2D{RealT}(p_0, c_pd, c_vd, R_d, c_pv, c_vv, + R_v, c_pl, g, kappa, gamma, L_00, a) +end + +# Calculate 1D flux for a single point. +@inline function flux(u, orientation::Integer, + equations::CompressibleMoistEulerEquations2D) + rho, rho_v1, rho_v2, rho_E, rho_qv, rho_ql = u + v1 = rho_v1 / rho + v2 = rho_v2 / rho + qv = rho_qv / rho + ql = rho_ql / rho + p, T = get_current_condition(u, equations) + if orientation == 1 + f1 = rho_v1 + f2 = rho_v1 * v1 + p + f3 = rho_v1 * v2 + f4 = (rho_E + p) * v1 + f5 = rho_v1 * qv + f6 = rho_v1 * ql + else + f1 = rho_v2 + f2 = rho_v2 * v1 + f3 = rho_v2 * v2 + p + f4 = (rho_E + p) * v2 + f5 = rho_v2 * qv + f6 = rho_v2 * ql + end + return SVector(f1, f2, f3, f4, f5, f6) +end + +# Calculate 1D flux for a single point in the normal direction. +# Note, this directional vector is not normalized. +@inline function flux(u, normal_direction::AbstractVector, + equations::CompressibleMoistEulerEquations2D) + rho, rho_v1, rho_v2, rho_e, rho_qv, rho_ql = u + v1 = rho_v1 / rho + v2 = rho_v2 / rho + qv = rho_qv / rho + ql = rho_ql / rho + p, T = get_current_condition(u, equations) + v_normal = v1 * normal_direction[1] + v2 * normal_direction[2] + rho_v_normal = rho * v_normal + f1 = rho_v_normal + f2 = (rho_v_normal) * v1 + p * normal_direction[1] + f3 = (rho_v_normal) * v2 + p * normal_direction[2] + f4 = (rho_e + p) * v_normal + f5 = rho_v_normal * qv + f6 = (rho_v_normal) * ql + return SVector(f1, f2, f3, f4, f5, f6) +end + +# Slip-wall boundary condition +# Determine the boundary numerical surface flux for a slip wall condition. +# Imposes a zero normal velocity at the wall. +@inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, + x, t, + surface_flux_function, + equations::CompressibleMoistEulerEquations2D) + @unpack c_pd, c_pv, c_pl, c_vd, c_vv = equations + norm_ = norm(normal_direction) + # Normalize the vector without using `normalize` since we need to multiply by the `norm_` later + normal = normal_direction / norm_ + + # rotate the internal solution state + u_local = rotate_to_x(u_inner, normal, equations) + + # compute the primitive variables + rho_local, v_normal, v_tangent, p_local, qv_local, ql_local = cons2prim(u_local, + equations) + qd_local = 1 - qv_local - ql_local + gamma = (qd_local * c_pd + qv_local * c_pv + ql_local * c_pl) * + inv(qd_local * c_vd + qv_local * c_vv + ql_local * c_pl) + # Get the solution of the pressure Riemann problem + # See Section 6.3.3 of + # Eleuterio F. Toro (2009) + # Riemann Solvers and Numerical Methods for Fluid Dynamics: A Practical Introduction + # [DOI: 10.1007/b79761](https://doi.org/10.1007/b79761) + if v_normal <= 0.0 + sound_speed = sqrt(gamma * p_local / rho_local) # local sound speed + p_star = p_local * + (1.0 + 0.5 * (gamma - 1) * v_normal / sound_speed)^(2.0 * gamma * + inv(gamma - 1)) + else # v_normal > 0.0 + A = 2.0 / ((gamma + 1) * rho_local) + B = p_local * (gamma - 1) / (gamma + 1) + p_star = p_local + + 0.5 * v_normal / A * + (v_normal + sqrt(v_normal^2 + 4.0 * A * (p_local + B))) + end + + # For the slip wall we directly set the flux as the normal velocity is zero + return SVector(zero(eltype(u_inner)), + p_star * normal[1], + p_star * normal[2], + zero(eltype(u_inner)), + zero(eltype(u_inner)), + zero(eltype(u_inner))) * norm_ +end + +# Fix sign for structured mesh. +@inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, + direction, x, t, + surface_flux_function, + equations::CompressibleMoistEulerEquations2D) + # flip sign of normal to make it outward pointing, then flip the sign of the normal flux back + # to be inward pointing on the -x and -y sides due to the orientation convention used by StructuredMesh + if isodd(direction) + boundary_flux = -boundary_condition_slip_wall(u_inner, -normal_direction, + x, t, surface_flux_function, + equations) + else + boundary_flux = boundary_condition_slip_wall(u_inner, normal_direction, + x, t, surface_flux_function, + equations) + end + + return boundary_flux +end + +# Rotate momentum flux. The same as in compressible Euler. +@inline function rotate_to_x(u, normal_vector::AbstractVector, + equations::CompressibleMoistEulerEquations2D) + # cos and sin of the angle between the x-axis and the normalized normal_vector are + # the normalized vector's x and y coordinates respectively (see unit circle). + c = normal_vector[1] + s = normal_vector[2] + + # Apply the 2D rotation matrix with normal and tangent directions of the form + # [ 1 0 0 0; + # 0 n_1 n_2 0; + # 0 t_1 t_2 0; + # 0 0 0 1 ] + # where t_1 = -n_2 and t_2 = n_1 + + return SVector(u[1], + c * u[2] + s * u[3], + -s * u[2] + c * u[3], + u[4], u[5], u[6]) +end + +# Recreates the convergence test initial condition from compressible euler 2D. +function initial_condition_convergence_test_dry(x, t, + equations::CompressibleMoistEulerEquations2D) + @unpack R_d, R_v, c_vd, c_vv, c_pl, L_00 = equations + + c = 2 + A = 0.1 + L = 2 + f = 1 / L + ω = 2 * pi * f + ini = c + A * sin(ω * (x[1] + x[2] - t)) + + qv = 0 + ql = 0 + + mu = ((1 - qv - ql) * c_vd + qv * c_vv + ql * c_pl) + + T = (ini - 1) / c_vd + E = (mu * T + qv * L_00 + 1) + + rho = ini + rho_v1 = ini + rho_v2 = ini + rho_e = E * ini + rho_qv = qv * ini + rho_ql = ql * ini + + return SVector(rho, rho_v1, rho_v2, rho_e, rho_qv, rho_ql) +end + +# Recreates the convergence test source term from compressible euler 2D. +@inline function source_terms_convergence_test_dry(u, x, t, + equations::CompressibleMoistEulerEquations2D) + # Same settings as in `initial_condition` + @unpack R_d, R_v, c_vd, c_vv, c_pl, L_00 = equations + c = 2 + A = 0.1 + L = 2 + f = 1 / L + ω = 2 * pi * f + + x1, x2 = x + si, co = sincos(ω * (x1 + x2 - t)) + rho = c + A * si + rho_x = ω * A * co + + qv = 0 + ql = 0 + mu = ((1 - qv - ql) * c_vd + qv * c_vv + ql * c_pl) + xi = ((1 - qv - ql) * R_d + qv * R_v) + + T = (rho - 1) / c_vd + dT = rho_x / c_vd + E = (mu * T + qv * L_00 + 1) + dE = E * rho_x + rho * mu * dT + dp = xi * (T * rho_x + rho * dT) + # Note that d/dt rho = -d/dx rho = -d/dy rho. + + du1, du2, du3, du4, du5, du6 = source_terms_moist_bubble(u, x, t, equations) + + du1 += rho_x + du2 += rho_x + dp + du3 += du2 + du4 += dE + 2 * dp + du5 += qv * du1 + du6 += ql * du1 + + return SVector(du1, du2, du3, du4, du5, du6) +end + +# Initial condition for the convergence analysis. +# Extends the convergence test to the system with gravity and phase change. +function initial_condition_convergence_test_moist(x, t, + equations::CompressibleMoistEulerEquations2D) + @unpack R_d, R_v, c_vd, c_vv, c_pl, L_00 = equations + + c = 2 + A = 0.1 + L = 2 + f = 1 / L + ω = 2 * pi * f + ini = c + A * sin(ω * (x[1] + x[2] - t)) + + qv = 100 / L_00 + ql = qv / 10 + + mu = ((1 - qv - ql) * c_vd + qv * c_vv + ql * c_pl) + + T = (ini - 1) / mu + 10 / c_vd + 40 + E = (mu * T + qv * L_00 + 1) + + rho = ini + rho_v1 = ini + rho_v2 = ini + rho_e = E * ini + rho_qv = qv * ini + rho_ql = ql * ini + + return SVector(rho, rho_v1, rho_v2, rho_e, rho_qv, rho_ql) +end + +# Source term for the convergence analysis. +# Extends the convergence test to the system with gravity and phase change. +@inline function source_terms_convergence_test_moist(u, x, t, + equations::CompressibleMoistEulerEquations2D) + # Same settings as in `initial_condition` + @unpack R_d, R_v, c_vd, c_vv, c_pl, L_00 = equations + c = 2 + A = 0.1 + L = 2 + f = 1 / L + ω = 2 * pi * f + + x1, x2 = x + si, co = sincos(ω * (x1 + x2 - t)) + rho = c + A * si + rho_x = ω * A * co + + qv = 100 / L_00 + ql = qv / 10 + mu = ((1 - qv - ql) * c_vd + qv * c_vv + ql * c_pl) + xi = ((1 - qv - ql) * R_d + qv * R_v) + + T = (rho - 1) / mu + 10 / c_vd + 40 + dT = rho_x / c_vd + E = (mu * T + qv * L_00 + 1) + dE = E * rho_x + rho * mu * dT + dp = xi * (T * rho_x + rho * dT) + + # Calculate Error in Sources with exact solution and u + u_exact = SVector(rho, rho, rho, rho * E, rho * qv, rho * ql) + + du1, du2, du3, du4, du5, du6 = (source_terms_moist_bubble(u, x, t, equations) - + source_terms_moist_bubble(u_exact, x, t, equations)) + + # Note that d/dt rho = -d/dx rho = -d/dy rho. + + du1 += rho_x + du2 += rho_x + dp + du3 += rho_x + dp + du4 += dE + 2 * dp + du5 += qv * rho_x + du6 += ql * rho_x + + return SVector(du1, du2, du3, du4, du5, du6) +end + +# Gravity source term +@inline function source_terms_geopotential(u, x, t, + equations::CompressibleMoistEulerEquations2D) + @unpack g = equations + rho, rho_v1, rho_v2, rho_e, rho_qv, rho_ql = u + tmp = rho_v2 + + return SVector(zero(eltype(u)), zero(eltype(u)), + -g * rho, -g * tmp, + zero(eltype(u)), zero(eltype(u))) +end + +@inline function source_terms_geopotential(u, + equations::CompressibleMoistEulerEquations2D) + @unpack g = equations + rho, rho_v1, rho_v2, rho_e, rho_qv, rho_ql = u + tmp = rho_v2 + + return SVector(zero(eltype(u)), zero(eltype(u)), + -g * rho, -g * tmp, + zero(eltype(u)), zero(eltype(u))) +end + +# Rayleigh damping sponge source term form A. Sridhar et al., +# Large-eddy simulations with ClimateMachine: a new open-sourcecode for +# atmospheric simulations on GPUs and CPUs, 2 Oct 2021, doi: 10.5194/gmd-15-6259-2022, +# https://arxiv.org/abs/2110.00853 [physics.ao-ph] . +@inline function source_terms_nonhydrostatic_rayleigh_sponge(u, x, t, + equations::CompressibleMoistEulerEquations2D) + rho, rho_v1, rho_v2, rho_e, rho_qv, rho_ql = u + v1 = rho_v1 / rho + v2 = rho_v2 / rho + z = x[2] + + # relaxed background velocity + vr1, vr2 = (10.0, 0.0) + # damping threshold + z_s = 9000.0 + # boundary top + z_top = 16000.0 + # positive even power with default value 2 + gamma = 2.0 + # relaxation coefficient > 0 + alpha = 0.5 + + tau_s = zero(eltype(u)) + if z > z_s + tau_s = alpha * sin(0.5 * (z - z_s) * inv(z_top - z_s))^(gamma) + end + + return SVector(zero(eltype(u)), + -tau_s * rho * (v1 - vr1), + -tau_s * rho * (v2 - vr2), + zero(eltype(u)), zero(eltype(u)), zero(eltype(u))) +end + +# Source term with gravity and phase change +@inline function source_terms_moist_bubble(u, x, t, + equations::CompressibleMoistEulerEquations2D) + return source_terms_geopotential(u, equations) + + source_terms_phase_change(u, equations) +end + +# Calculate pressure and temperature from a state u. +@inline function get_current_condition(u, equations::CompressibleMoistEulerEquations2D) + @unpack c_vd, R_d, c_vv, c_pv, R_v, c_pl, L_00 = equations + rho, rho_v1, rho_v2, rho_E, rho_qv, rho_ql = u + rho_qd = rho - rho_qv - rho_ql + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + + # Inner energy + rho_e = (rho_E - 0.5 * (rho_v1 * v1 + rho_v2 * v2)) + + # Absolute temperature + T = (rho_e - L_00 * rho_qv) / (rho_qd * c_vd + rho_qv * c_vv + rho_ql * c_pl) + + # Pressure + p = (rho_qd * R_d + rho_qv * R_v) * T + + return SVector(p, T) +end + +# Calculate Q_ph for a state u. +# This source term models the phase chance between could water and vapor. +@inline function phase_change_term(u, equations::CompressibleMoistEulerEquations2D) + @unpack R_v = equations + rho, _, _, _, rho_qv, rho_ql = u + _, T = get_current_condition(u, equations) + rho_qd = rho - rho_qv - rho_ql + + T_C = T - 273.15 + # saturation vapor pressure + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + + # saturation density of vapor + rho_star_qv = p_vs / (R_v * T) + + # Fisher-Burgmeister-Function + a = rho_star_qv - rho_qv + b = rho - rho_qv - rho_qd + + # saturation control factor + # < 1: stronger saturation effect + # > 1: weaker saturation effect + C = 1 + + return (a + b - sqrt(a^2 + b^2)) * C +end + +# Add the source containing Q_ph +@inline function source_terms_phase_change(u, + equations::CompressibleMoistEulerEquations2D) + Q_ph = phase_change_term(u, equations) + + return SVector(zero(eltype(u)), zero(eltype(u)), zero(eltype(u)), + zero(eltype(u)), Q_ph, -Q_ph) +end + +# Low Mach number approximate Riemann solver (LMARS) from +# X. Chen, N. Andronova, B. Van Leer, J. E. Penner, J. P. Boyd, C. Jablonowski, S. +# Lin, A Control-Volume Model of the Compressible Euler Equations with a Vertical Lagrangian +# Coordinate Monthly Weather Review Vol. 141.7, pages 2526–2544, 2013, +# https://journals.ametsoc.org/view/journals/mwre/141/7/mwr-d-12-00129.1.xml. +@inline function flux_LMARS(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleMoistEulerEquations2D) + @unpack a = equations + # Unpack left and right state + rho_ll, rho_v1_ll, rho_v2_ll, rho_e_ll, rho_qv_ll, rho_ql_ll = u_ll + rho_rr, rho_v1_rr, rho_v2_rr, rho_e_rr, rho_qv_rr, rho_ql_rr = u_rr + p_ll, T_ll = get_current_condition(u_ll, equations) + p_rr, T_rr = get_current_condition(u_rr, equations) + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + + v_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] + v_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] + + # diffusion parameter <= 1 + beta = 1 + + # Compute the necessary interface flux components + norm_ = norm(normal_direction) + + rho = 0.5 * (rho_ll + rho_rr) + p_interface = 0.5 * (p_ll + p_rr) - beta * 0.5 * a * rho * (v_rr - v_ll) / norm_ + v_interface = 0.5 * (v_ll + v_rr) - beta * 1 / (2 * a * rho) * (p_rr - p_ll) * norm_ + + if (v_interface > 0) + f1, f2, f3, f4, f5, f6 = u_ll * v_interface + f4 += p_ll * v_interface + else + f1, f2, f3, f4, f5, f6 = u_rr * v_interface + f4 += p_rr * v_interface + end + + return SVector(f1, + f2 + p_interface * normal_direction[1], + f3 + p_interface * normal_direction[2], + f4, f5, f6) +end + +# Convert conservative variables to primitive. +@inline function cons2prim(u, equations::CompressibleMoistEulerEquations2D) + rho, rho_v1, rho_v2, rho_E, rho_qv, rho_ql = u + v1 = rho_v1 / rho + v2 = rho_v2 / rho + p = get_current_condition(u, equations)[1] + qv = rho_qv / rho + ql = rho_ql / rho + + return SVector(rho, v1, v2, p, qv, ql) +end + +# Convert conservative variables to primitive with +# temperature instead of pressure. +@inline function cons2temp(u, equations::CompressibleMoistEulerEquations2D) + rho, rho_v1, rho_v2, rho_E, rho_qv, rho_ql = u + v1 = rho_v1 / rho + v2 = rho_v2 / rho + T = get_current_condition(u, equations)[2] + qv = rho_qv / rho + ql = rho_ql / rho + + return SVector(rho, v1, v2, T, qv, ql) +end + +# Convert conservative variables to entropy +@inline function cons2entropy(u, equations::CompressibleMoistEulerEquations2D) + @unpack R_d, R_v, c_pd, c_pv, c_pl, L_00 = equations + rho, rho_v1, rho_v2, rho_E, rho_qv, rho_ql = u + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + p, T = get_current_condition(u, equations) + v_square = v1^2 + v2^2 + rho_qd = rho - rho_qv - rho_ql + + # Workaround if an individual density is zero + # Thermodynamic entropy + s_d = 0 + s_v = 0 + s_l = 0 + + # Thermodynamic entropy + if (rho_qd > 0.0) + s_d = c_pd * log(T) - R_d * log(rho_qd * R_d * T) + end + if (rho_qv > 0.0) + s_v = c_pv * log(T) - R_v * log(rho_qv * R_v * T) + end + if (rho_ql > 0.0) + s_l = c_pl * log(T) + end + + g_d = (c_pd - s_d) * T + g_v = L_00 + (c_pv - s_v) * T + g_l = (c_pl - s_l) * T + + w1 = g_d - 0.5 * v_square + w2 = v1 + w3 = v2 + w4 = -1 + w5 = g_v - g_d + w6 = g_l - g_d + + return inv(T) * SVector(w1, w2, w3, w4, w5, w6) +end + +# Convert primitive to conservative variables. +@inline function prim2cons(prim, equations::CompressibleMoistEulerEquations2D) + rho, v1, v2, p, qv, ql = prim + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_qv = rho * qv + rho_ql = rho * ql + rho_E = p * equations.inv_gamma_minus_one + 0.5 * (rho_v1 * v1 + rho_v2 * v2) + return SVector(rho, rho_v1, rho_v2, rho_E, rho_qv, rho_ql) +end + +# Convert conservative variables to primitive with +# potential temperature instead of pressure. +@inline function cons2drypot(u, equations::CompressibleMoistEulerEquations2D) + rho, rho_v1, rho_v2, rho_E, rho_qv, rho_ql = u + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + qv = rho_qv / rho + ql = rho_ql / rho + + pot1 = rho + pot2 = v1 + pot3 = v2 + pot4 = dry_pottemp_thermodynamic(u, equations) + pot5 = qv + pot6 = ql + + return SVector(pot1, pot2, pot3, pot4, pot5, pot6) +end + +# Convert conservative variables to primitive with +# moist potential temperature instead of pressure. +@inline function cons2moistpot(u, equations::CompressibleMoistEulerEquations2D) + rho, rho_v1, rho_v2, rho_E, rho_qv, rho_ql = u + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + qv = rho_qv / rho + ql = rho_ql / rho + + pot1 = rho + pot2 = v1 + pot3 = v2 + pot4 = moist_pottemp_thermodynamic(u, equations) + pot5 = qv + pot6 = ql + + return SVector(pot1, pot2, pot3, pot4, pot5, pot6) +end + +# Convert conservative variables to moisture related variables. +@inline function cons2moist(u, equations::CompressibleMoistEulerEquations2D) + @unpack R_d, R_v, c_pd, c_pv, c_pl, p_0 = equations + rho, rho_v1, rho_v2, rho_E, rho_qv, rho_ql = u + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + qv = rho_qv / rho + ql = rho_ql / rho + p, T = get_current_condition(u, equations) + + p_v = rho_qv * R_v * T + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + H = p_v * inv(p_vs) + + rho_d = rho - (rho_qv + rho_ql) + r_v = inv(rho_d) * rho_qv + r_l = inv(rho_d) * rho_ql + + # Potential temperature + R_m = R_d + r_v * R_v + c_pml = c_pd + r_v * c_pv + r_l * c_pl + kappa_m = R_m * inv(c_pml) + pot = T * (p_0 / p)^(kappa_m) + + pot1 = qv + pot2 = ql + pot3 = r_v + r_l + pot4 = T + pot5 = H + pot6 = equivalent_pottemp_thermodynamic(u, equations) + + return SVector(pot1, pot2, pot3, pot4, pot5, pot6) +end + +@inline function density(u, equations::CompressibleMoistEulerEquations2D) + rho = u[1] + return rho +end + +@inline function density_dry(u, equations::CompressibleMoistEulerEquations2D) + rho_qd = u[1] - (u[5] + u[6]) + return rho_qd +end + +@inline function density_vapor(u, equations::CompressibleMoistEulerEquations2D) + rho_qv = u[5] + return rho_qv +end + +@inline function temperature(u, equations::CompressibleMoistEulerEquations2D) + @unpack c_vd, R_d, c_vv, c_pv, R_v, c_pl, L_00 = equations + rho, rho_v1, rho_v2, rho_E, rho_qv, rho_ql = u + rho_qd = rho - rho_qv - rho_ql + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + + # inner energy + rho_e = (rho_E - 0.5 * (rho_v1 * v1 + rho_v2 * v2)) + + # Absolute Temperature + T = (rho_e - L_00 * rho_qv) / (rho_qd * c_vd + rho_qv * c_vv + rho_ql * c_pl) + return T +end + +@inline function saturation_pressure(u, equations::CompressibleMoistEulerEquations2D) + @unpack R_v = equations + rho, rho_v1, rho_v2, rho_E, rho_qv, rho_ql = u + T = get_current_condition(u, equations)[2] + p_v = rho_qv * R_v * T + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + H = p_v / p_vs + return H +end + +@inline function density_liquid(u, equations::CompressibleMoistEulerEquations2D) + rho_ql = u[6] + return rho_ql +end + +@inline function ratio_liquid(u, equations::CompressibleMoistEulerEquations2D) + rho = u[1] + rho_ql = u[6] + ql = rho_ql / rho + return ql +end + +@inline function ratio_vapor(u, equations::CompressibleMoistEulerEquations2D) + rho = u[1] + rho_qv = u[5] + qv = rho_qv / rho + return qv +end + +@inline function pressure(u, equations::CompressibleMoistEulerEquations2D) + @unpack c_vd, R_d, c_vv, c_pv, R_v, c_pl, L_00 = equations + rho, rho_v1, rho_v2, rho_E, rho_qv, rho_ql = u + rho_qd = rho - rho_qv - rho_ql + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + + # inner energy + rho_e = (rho_E - 0.5 * (rho_v1 * v1 + rho_v2 * v2)) + + # Absolute Temperature + T = (rho_e - L_00 * rho_qv) / (rho_qd * c_vd + rho_qv * c_vv + rho_ql * c_pl) + + # Pressure + p = (rho_qd * R_d + rho_qv * R_v) * T + return p +end + +@inline function density_pressure(u, equations::CompressibleMoistEulerEquations2D) + rho = u[1] + rho_times_p = rho * get_current_condition(u, equations)[1] + return rho_times_p +end + +# Calculate thermodynamic entropy for a conservative state `cons`. +# This is the dryspecific entropy multiplied by the dry air density. +@inline function entropy_thermodynamic(cons, + equations::CompressibleMoistEulerEquations2D) + @unpack c_vd, c_vv, c_pl, R_d, R_v = equations + # Pressure + p, T = get_current_condition(cons, equations) + rho_qd = cons[1] - cons[5] - cons[6] + rho_qv = cons[5] + rho_ql = cons[6] + # Thermodynamic entropy + s_d = c_vd * log(T) - R_d * log(rho_qd * R_d) + + s_v = c_vv * log(T) - R_v * log(rho_qv * R_v) + + s_l = c_pl * log(T) + + return rho_qd * s_d + rho_qv * s_v + rho_ql * s_l +end + +# Calculate mathematical entropy for a conservative state `cons`. +@inline function entropy_math(cons, equations::CompressibleMoistEulerEquations2D) + # Mathematical entropy + S = -entropy_thermodynamic(cons, equations) + + return S +end + +# Default entropy is the mathematical entropy. +@inline entropy(cons, equations::CompressibleMoistEulerEquations2D) = entropy_math(cons, + equations) + +# Calculate total energy for a conservative state `cons`. +@inline energy_total(cons, ::CompressibleMoistEulerEquations2D) = cons[4] + +# Calculate kinetic energy for a conservative state `cons`. +@inline function energy_kinetic(u, equations::CompressibleMoistEulerEquations2D) + rho, rho_v1, rho_v2, rho_E, rho_qv, rho_ql = u + return (rho_v1^2 + rho_v2^2) / (2 * rho) +end + +# Calculate internal energy for a conservative state `cons`. +@inline function energy_internal(cons, equations::CompressibleMoistEulerEquations2D) + return energy_total(cons, equations) - energy_kinetic(cons, equations) +end + +# Calculate the dry potential temperature for a conservative state `cons`. +@inline function dry_pottemp_thermodynamic(cons, + equations::CompressibleMoistEulerEquations2D) + @unpack R_d, p_0, kappa = equations + # Pressure + p = get_current_condition(cons, equations)[1] + # Potential temperature + pot = p_0 * (p / p_0)^(1 - kappa) / (R_d * cons[1]) + + return pot +end + +# Calculate the moist potential temperature for a conservative state `cons`. +@inline function moist_pottemp_thermodynamic(cons, + equations::CompressibleMoistEulerEquations2D) + @unpack R_d, R_v, c_pd, c_pv, c_pl, p_0 = equations + # Pressure + p, T = get_current_condition(cons, equations) + rho_d = cons[1] - (cons[5] + cons[6]) + r_v = inv(rho_d) * cons[5] + r_l = inv(rho_d) * cons[6] + + # Potential temperature + R_m = R_d + r_v * R_v + c_pml = c_pd + r_v * c_pv + r_l * c_pl + kappa_m = R_m * inv(c_pml) + pot = T * (p_0 / p)^(kappa_m) + return pot +end + +# Calculate the equivalent potential temperature for a conservative state `cons`. +@inline function equivalent_pottemp_thermodynamic(cons, + equations::CompressibleMoistEulerEquations2D) + @unpack c_pd, c_pv, c_pl, R_d, R_v, p_0, kappa, L_00 = equations + rho, rho_v1, rho_v2, rho_E, rho_qv, rho_ql = cons + rho_d = rho - rho_qv - rho_ql + p, T = get_current_condition(cons, equations) + p_v = rho_qv * R_v * T + p_d = p - p_v + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + H = p_v / p_vs + r_v = rho_qv / rho_d + r_l = rho_ql / rho_d + r_t = r_v + r_l + L_v = L_00 + (c_pv - c_pl) * T + c_p = c_pd + r_t * c_pl + + # equivalent potential temperature + aeq_pot = (T * (p_0 / p_d)^(R_d / c_p) * H^(-r_v * R_v / c_p) * + exp(L_v * r_v * inv(c_p * T))) + + return aeq_pot +end + +# Convert conservative variables to primitive varuables with +# equivalent potential temperature instead of pressure +# and mixing ratios innstead of specific contend. +@inline function cons2aeqpot(cons, equations::CompressibleMoistEulerEquations2D) + @unpack c_pd, c_pv, c_pl, R_d, R_v, p_0, L_00 = equations + rho, rho_v1, rho_v2, rho_E, rho_qv, rho_ql = cons + rho_d = rho - rho_qv - rho_ql + p, T = get_current_condition(cons, equations) + p_v = rho_qv * R_v * T + p_d = p - p_v + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + H = p_v / p_vs + r_v = rho_qv / rho_d + r_l = rho_ql / rho_d + r_t = r_v + r_l + L_v = L_00 + (c_pv - c_pl) * T + c_p = c_pd + r_t * c_pl + + # equivalent potential temperature + aeq_pot = (T * (p_0 / p_d)^(R_d / c_p) * H^(-r_v * R_v / c_p) * + exp(L_v * r_v * inv(c_p * T))) + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + + pot1 = rho + pot2 = v1 + pot3 = v2 + pot4 = aeq_pot + pot5 = r_v + pot6 = r_t + return SVector(pot1, pot2, pot3, pot4, pot5, pot6) +end + +@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, + equations::CompressibleMoistEulerEquations2D) + @unpack c_pd, c_pv, c_pl, c_vd, c_vv = equations + rho_ll, v1_ll, v2_ll, p_ll, qv_ll, ql_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr, p_rr, qv_rr, ql_rr = cons2prim(u_rr, equations) + qd_ll = 1 - qv_ll - ql_ll + qd_rr = 1 - qv_rr - ql_rr + # Get the density and gas gamma + gamma_ll = (qd_ll * c_pd + qv_ll * c_pv + ql_ll * c_pl) * + inv(qd_ll * c_vd + qv_ll * c_vv + ql_ll * c_pl) + gamma_rr = (qd_rr * c_pd + qv_rr * c_pv + ql_rr * c_pl) * + inv(qd_rr * c_vd + qv_rr * c_vv + ql_rr * c_pl) + + # Compute the sound speeds on the left and right + v_mag_ll = sqrt(v1_ll^2 + v2_ll^2) + c_ll = sqrt(gamma_ll * p_ll / rho_ll) + v_mag_rr = sqrt(v1_rr^2 + v2_rr^2) + c_rr = sqrt(gamma_rr * p_rr / rho_rr) + + return max(v_mag_ll, v_mag_rr) + max(c_ll, c_rr) +end + +# Adjusted version of LLF dissipation from compressible euler. +@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleMoistEulerEquations2D) + @unpack c_pd, c_pv, c_pl, c_vd, c_vv = equations + rho_ll, v1_ll, v2_ll, p_ll, qv_ll, ql_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr, p_rr, qv_rr, ql_rr = cons2prim(u_rr, equations) + qd_ll = 1 - qv_ll - ql_ll + qd_rr = 1 - qv_rr - ql_rr + # Get the density and gas gamma + gamma_ll = (qd_ll * c_pd + qv_ll * c_pv + ql_ll * c_pl) * + inv(qd_ll * c_vd + qv_ll * c_vv + ql_ll * c_pl) + gamma_rr = (qd_rr * c_pd + qv_rr * c_pv + ql_rr * c_pl) * + inv(qd_rr * c_vd + qv_rr * c_vv + ql_rr * c_pl) + # Calculate normal velocities and sound speed + # left + v_ll = (v1_ll * normal_direction[1] + + + v2_ll * normal_direction[2]) + c_ll = sqrt(gamma_ll * p_ll / rho_ll) + # right + v_rr = (v1_rr * normal_direction[1] + + + v2_rr * normal_direction[2]) + c_rr = sqrt(gamma_rr * p_rr / rho_rr) + + return max(abs(v_ll), abs(v_rr)) + max(c_ll, c_rr) * norm(normal_direction) +end + +# Adjusted version of lambda_max from compressible euler. +@inline function max_abs_speeds(u, equations::CompressibleMoistEulerEquations2D) + @unpack c_pd, c_pv, c_pl, c_vd, c_vv = equations + rho, v1, v2, p, qv, ql = cons2prim(u, equations) + qd = 1 - qv - ql + + gamma = (qd * c_pd + qv * c_pv + ql * c_pl) * inv(qd * c_vd + qv * c_vv + ql * c_pl) + c = sqrt(gamma * p / rho) + + return (abs(v1) + c, abs(v2) + c) +end + +# Adjusted EC flux in a normal direction with R_q=0. This is based on +# A. Gouasmi, K. Duraisamy, S. M. Murman, Formulation of Entropy-Stable schemes for the +# multicomponent compressible Euler equations, 4 Feb 2020, doi:10.1016/j.cma.2020.112912, +# https://arxiv.org/abs/1904.00972 [math.NA]. +@inline function flux_chandrashekar(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleMoistEulerEquations2D) + @unpack R_d, R_v, c_vd, c_vv, c_pl, L_00 = equations + R_q = 0 + # Unpack left and right state + rho_ll, rho_v1_ll, rho_v2_ll, rho_E_ll, rho_qv_ll, rho_ql_ll = u_ll + rho_rr, rho_v1_rr, rho_v2_rr, rho_E_rr, rho_qv_rr, rho_ql_rr = u_rr + + rho_qd_ll = rho_ll - rho_qv_ll - rho_ql_ll + rho_qd_rr = rho_rr - rho_qv_rr - rho_ql_rr + v1_ll = rho_v1_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v2_ll = rho_v2_ll / rho_ll + v2_rr = rho_v2_rr / rho_rr + + # inner energy + rho_e_ll = (rho_E_ll - 0.5 * (rho_v1_ll * v1_ll + rho_v2_ll * v2_ll)) + rho_e_rr = (rho_E_rr - 0.5 * (rho_v1_rr * v1_rr + rho_v2_rr * v2_rr)) + + # Absolute Temperature + T_ll = (rho_e_ll - L_00 * rho_qv_ll) / + (rho_qd_ll * c_vd + rho_qv_ll * c_vv + rho_ql_ll * c_pl) + T_rr = (rho_e_rr - L_00 * rho_qv_rr) / + (rho_qd_rr * c_vd + rho_qv_rr * c_vv + rho_ql_rr * c_pl) + + # Compute the necessary mean values + rho_qd_mean = 0 + rho_qv_mean = 0 + rho_ql_mean = 0 + inv_T_mean = 0 + if (!(rho_qd_ll == 0.0) && !(rho_qd_rr == 0.0)) + rho_qd_mean = ln_mean(rho_qd_ll, rho_qd_rr) + end + if (!(rho_qv_ll == 0.0) && !(rho_qv_rr == 0.0)) + rho_qv_mean = ln_mean(rho_qv_ll, rho_qv_rr) + end + if (!(rho_ql_ll == 0.0) && !(rho_ql_rr == 0.0)) + rho_ql_mean = ln_mean(rho_ql_ll, rho_ql_rr) + end + if (!(inv(T_ll) == 0.0) && !(inv(T_rr) == 0.0)) + inv_T_mean = inv_ln_mean(inv(T_ll), inv(T_rr)) + end + + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) + v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) + rho_qd_avg = 0.5 * (rho_qd_ll + rho_qd_rr) + rho_qv_avg = 0.5 * (rho_qv_ll + rho_qv_rr) + rho_ql_avg = 0.5 * (rho_ql_ll + rho_ql_rr) + inv_T_avg = 0.5 * (inv(T_ll) + inv(T_rr)) + v_dot_n_avg = normal_direction[1] * v1_avg + normal_direction[2] * v2_avg + + p_int = inv(inv_T_avg) * (R_d * rho_qd_avg + R_v * rho_qv_avg + R_q * rho_ql_avg) + K_avg = 0.5 * (v1_square_avg + v2_square_avg) + + f_1d = rho_qd_mean * v_dot_n_avg + f_1v = rho_qv_mean * v_dot_n_avg + f_1l = rho_ql_mean * v_dot_n_avg + f1 = f_1d + f_1v + f_1l + f2 = f1 * v1_avg + normal_direction[1] * p_int + f3 = f1 * v2_avg + normal_direction[2] * p_int + f4 = ((c_vd * inv_T_mean - K_avg) * f_1d + + (L_00 + c_vv * inv_T_mean - K_avg) * f_1v + + (c_pl * inv_T_mean - K_avg) * f_1l + v1_avg * f2 + v2_avg * f3) + + return SVector(f1, f2, f3, f4, f_1v, f_1l) +end + +varnames(::typeof(cons2cons), ::CompressibleMoistEulerEquations2D) = ("rho", "rho_v1", + "rho_v2", "rho_E", + "rho_qv", + "rho_ql") +varnames(::typeof(cons2prim), ::CompressibleMoistEulerEquations2D) = ("rho", "v1", "v2", + "p", "qv", "ql") +varnames(::typeof(cons2temp), ::CompressibleMoistEulerEquations2D) = ("rho", "v1", "v2", + "T", "qv", "ql") +varnames(::typeof(cons2drypot), ::CompressibleMoistEulerEquations2D) = ("rho", "v1", + "v2", + "drypottemp", + "qv", "ql") +varnames(::typeof(cons2moistpot), ::CompressibleMoistEulerEquations2D) = ("rho", "v1", + "v2", + "moistpottemp", + "qv", "ql") +varnames(::typeof(cons2moist), ::CompressibleMoistEulerEquations2D) = ("qv", "ql", "rt", + "T", "H", + "aeqpottemp") +varnames(::typeof(cons2aeqpot), ::CompressibleMoistEulerEquations2D) = ("rho", "v1", + "v2", + "aeqpottemp", + "rv", "rt") +end # @muladd diff --git a/src/equations/equations.jl b/src/equations/equations.jl index fe23c5f7..ea2f5c7a 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -7,3 +7,4 @@ abstract type AbstractCompressibleRainyEulerEquations{NDIMS, NVARS} <: AbstractEquations{NDIMS, NVARS} end include("compressible_rainy_euler_2d.jl") +include("compressible_moist_euler_2d_lucas.jl") \ No newline at end of file From 98025e1141d73fe56291bcbe88b1e40955146041 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Mon, 2 Sep 2024 16:34:46 +0200 Subject: [PATCH 033/115] moist bubble testing --- ...ixir_rainy_euler_bubble_no_phase_change.jl | 254 +++++++++++++++--- src/equations/compressible_rainy_euler_2d.jl | 23 +- 2 files changed, 239 insertions(+), 38 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_no_phase_change.jl b/examples/elixir_rainy_euler_bubble_no_phase_change.jl index 08c451cc..a6c68808 100644 --- a/examples/elixir_rainy_euler_bubble_no_phase_change.jl +++ b/examples/elixir_rainy_euler_bubble_no_phase_change.jl @@ -2,37 +2,228 @@ using OrdinaryDiffEq using Trixi using TrixiAtmo using TrixiAtmo: source_terms_no_phase_change +using NLsolve: nlsolve -### Bryan-Fritsch Moist Benchmark similar to Example 4.2 of: -# Sabine Doppler, Philip L. Lederer, Joachim Schöberl, Henry von Wahl, -# A discontinuous Galerkin approach for atmospheric flows with implicit condensation, -# Journal of Computational Physics, -# Volume 499, -# 2024, -# 112713, -# ISSN 0021-9991 +# Initial condition from -function initial_condition_moist_bubble_bryan_fritsch(x, t, equations::CompressibleRainyEulerEquations2D) - # Position of the bubble defined by center and radius: - x_center = 10_000.0 - z_center = 2_000.0 - - x_radius = 2_000.0 - z_radius = 2_000.0 +function moist_state(y, dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) - # Hydrostatic Base State (compare Doppler et al. Appendix B.2) - q_w = 0.02 # total water fraction - theta_e = 320.0 # wet equivalent potential temperature - - p_ref = equations.ref_pressure + @unpack p_0, g, c_pd, c_pv, c_vd, c_vv, R_d, R_v, c_pl, L_00 = equations - L = min(sqrt(((x[1] - x_center) / x_radius)^2 + ((x[2] - z_center) / z_radius)^2), 1.0) + (p, rho, T, r_t, r_v, rho_qv, theta_e) = y + p0 = y0[1] - #TODO + F = zeros(7, 1) + rho_d = rho / (1 + r_t) + p_d = R_d * rho_d * T + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + L = L_00 - (c_pl - c_pv) * T - return SVector(0, 0, 0.0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0, 0, 0, 0) + F[1] = (p - p0) / dz + g * rho + F[2] = p - (R_d * rho_d + R_v * rho_qv) * T + # H = 1 is assumed + F[3] = (theta_e - + T * (p_d / p_0)^(-R_d / (c_pd + c_pl * r_t)) * + exp(L * r_v / ((c_pd + c_pl * r_t) * T))) + F[4] = r_t - r_t0 + F[5] = rho_qv - rho_d * r_v + F[6] = theta_e - theta_e0 + a = p_vs / (R_v * T) - rho_qv + b = rho - rho_qv - rho_d + # H=1 => phi=0 + F[7] = a + b - sqrt(a * a + b * b) + + return F +end + +function generate_function_of_y(dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) + function function_of_y(y) + return moist_state(y, dz, y0, r_t0, theta_e0, equations) + end +end + +struct AtmosphereLayers{RealT <: Real} + equations::CompressibleMoistEulerEquations2D + # structure: 1--> i-layer (z = total_height/precision *(i-1)), 2--> rho, rho_theta, rho_qv, rho_ql + layer_data::Matrix{RealT} + total_height::RealT + preciseness::Int + layers::Int + ground_state::NTuple{2, RealT} + equivalent_potential_temperature::RealT + mixing_ratios::NTuple{2, RealT} +end + +function AtmosphereLayers(equations; total_height = 10010.0, preciseness = 10, + ground_state = (1.4, 100000.0), + equivalent_potential_temperature = 320, + mixing_ratios = (0.02, 0.02), RealT = Float64) + + @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl = equations + rho0, p0 = ground_state + r_t0, r_v0 = mixing_ratios + theta_e0 = equivalent_potential_temperature + + rho_qv0 = rho0 * r_v0 + T0 = theta_e0 + y0 = [p0, rho0, T0, r_t0, r_v0, rho_qv0, theta_e0] + + n = convert(Int, total_height / preciseness) + dz = 0.01 + layer_data = zeros(RealT, n + 1, 4) + + F = generate_function_of_y(dz, y0, r_t0, theta_e0, equations) + sol = nlsolve(F, y0) + p, rho, T, r_t, r_v, rho_qv, theta_e = sol.zero + + rho_d = rho / (1 + r_t) + rho_ql = rho - rho_d - rho_qv + kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * (p0 / p)^kappa_M * T * (1 + (R_v / R_d) * r_v) / (1 + r_t) + + layer_data[1, :] = [rho, rho_theta, rho_qv, rho_ql] + for i in (1:n) + y0 = deepcopy(sol.zero) + dz = preciseness + F = generate_function_of_y(dz, y0, r_t0, theta_e0, equations) + sol = nlsolve(F, y0) + p, rho, T, r_t, r_v, rho_qv, theta_e = sol.zero + + rho_d = rho / (1 + r_t) + rho_ql = rho - rho_d - rho_qv + kappa_M = (R_d * rho_d + R_v * rho_qv) / + (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * (p0 / p)^kappa_M * T * (1 + (R_v / R_d) * r_v) / (1 + r_t) + + layer_data[i + 1, :] = [rho, rho_theta, rho_qv, rho_ql] + end + + return AtmosphereLayers{RealT}(equations, layer_data, total_height, dz, n, ground_state, + theta_e0, mixing_ratios) +end + +# Moist bubble test case from paper: +# G.H. Bryan, J.M. Fritsch, A Benchmark Simulation for Moist Nonhydrostatic Numerical +# Models, MonthlyWeather Review Vol.130, 2917–2928, 2002, +# https://journals.ametsoc.org/view/journals/mwre/130/12/1520-0493_2002_130_2917_absfmn_2.0.co_2.xml. +function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, atmosphere_layers::AtmosphereLayers) + @unpack layer_data, preciseness, total_height = atmosphere_layers + dz = preciseness + z = x[2] + if (z > total_height && !(isapprox(z, total_height))) + error("The atmosphere does not match the simulation domain") + end + n = convert(Int, floor((z + eps()) / dz)) + 1 + z_l = (n - 1) * dz + (rho_l, rho_theta_l, rho_qv_l, rho_ql_l) = layer_data[n, :] + z_r = n * dz + if (z_l == total_height) + z_r = z_l + dz + n = n - 1 + end + (rho_r, rho_theta_r, rho_qv_r, rho_ql_r) = layer_data[n + 1, :] + rho = (rho_r * (z - z_l) + rho_l * (z_r - z)) / dz + rho_theta = rho * (rho_theta_r / rho_r * (z - z_l) + rho_theta_l / rho_l * (z_r - z)) / + dz + rho_qv = rho * (rho_qv_r / rho_r * (z - z_l) + rho_qv_l / rho_l * (z_r - z)) / dz + rho_ql = rho * (rho_ql_r / rho_r * (z - z_l) + rho_ql_l / rho_l * (z_r - z)) / dz + + rho, rho_e, rho_qv, rho_ql = perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, + equations::CompressibleMoistEulerEquations2D) + + v1 = 0.0 + v2 = 0.0 + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_E = rho_e + 1 / 2 * rho * (v1^2 + v2^2) + + return SVector(rho, rho_qv + rho_ql, 0.0, rho_v1, rho_v2, rho_E, rho_qv, rho_ql, 300.0) +end + +function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, + equations::CompressibleMoistEulerEquations2D) + @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl, L_00 = equations + xc = 10000.0 + zc = 2000.0 + rc = 2000.0 + Δθ = 2.0 + + r = sqrt((x[1] - xc)^2 + (x[2] - zc)^2) + rho_d = rho - rho_qv - rho_ql + kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + p_loc = p_0 * (R_d * rho_theta / p_0)^(1 / (1 - kappa_M)) + T_loc = p_loc / (R_d * rho_d + R_v * rho_qv) + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv + + p_v = rho_qv * R_v * T_loc + p_d = p_loc - p_v + T_C = T_loc - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + H = p_v / p_vs + r_v = rho_qv / rho_d + r_l = rho_ql / rho_d + r_t = r_v + r_l + + # equivalent potential temperature + a = T_loc * (p_0 / p_d)^(R_d / (c_pd + r_t * c_pl)) + b = H^(-r_v * R_v / c_pd) + L_v = L_00 + (c_pv - c_pl) * T_loc + c = exp(L_v * r_v / ((c_pd + r_t * c_pl) * T_loc)) + aeq_pot = (a * b * c) # TODO: this is not used. remove? + + # Assume pressure stays constant + if (r < rc && Δθ > 0) + # Calculate background density potential temperature + θ_dens = rho_theta / rho * (p_loc / p_0)^(kappa_M - kappa) + # Calculate perturbed density potential temperature + θ_dens_new = θ_dens * (1 + Δθ * cospi(0.5 * r / rc)^2 / 300) + rt = (rho_qv + rho_ql) / rho_d + rv = rho_qv / rho_d + # Calculate moist potential temperature + θ_loc = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rv) + # Adjust varuables until the temperature is met + if rt > 0 + while true + T_loc = θ_loc * (p_loc / p_0)^kappa + T_C = T_loc - 273.15 + # SaturVapor + pvs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + rho_d_new = (p_loc - pvs) / (R_d * T_loc) + rvs = pvs / (R_v * rho_d_new * T_loc) + θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) + if abs(θ_new - θ_loc) <= θ_loc * 1.0e-12 + break + else + θ_loc = θ_new + end + end + else + rvs = 0 + T_loc = θ_loc * (p_loc / p_0)^kappa + rho_d_new = p_loc / (R_d * T_loc) + θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) + end + rho_qv = rvs * rho_d_new + rho_ql = (rt - rvs) * rho_d_new + rho = rho_d_new * (1 + rt) + rho_d = rho - rho_qv - rho_ql + kappa_M = (R_d * rho_d + R_v * rho_qv) / + (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * θ_dens_new * (p_loc / p_0)^(kappa - kappa_M) + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv + end + return SVector(rho, rho_e, rho_qv, rho_ql) +end + +# Create background atmosphere data set +atmosphere_data = AtmosphereLayers(CompressibleMoistEulerEquations2D()) + +# Create the initial condition with the initial data set +function initial_condition_moist(x, t, equations::CompressibleRainyEulerEquations2D) + return initial_condition_moist_bubble(x, t, CompressibleMoistEulerEquations2D(), atmosphere_data) end @@ -42,12 +233,12 @@ end equations = CompressibleRainyEulerEquations2D() -boundary_conditions = (x_neg = boundary_condition_periodic, - x_pos = boundary_condition_periodic, +boundary_conditions = (x_neg = boundary_condition_slip_wall, + x_pos = boundary_condition_slip_wall, y_neg = boundary_condition_slip_wall, y_pos = boundary_condition_slip_wall) -polydeg = 3 +polydeg = 1 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_lax_friedrichs @@ -57,11 +248,12 @@ solver = DGSEM(basis, surface_flux) coordinates_min = ( 0.0, 0.0) coordinates_max = (20_000.0, 10_000.0) -cells_per_dimension = (64, 32) +cells_per_dimension = (32, 16) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, - periodicity = (true, false)) + periodicity = (false, false)) -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_moist_bubble_bryan_fritsch, solver, +semi = SemidiscretizationHyperbolic(mesh, equations, + initial_condition_moist, solver, source_terms = source_terms_no_phase_change, boundary_conditions = boundary_conditions) @@ -74,7 +266,7 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -analysis_interval = 1000 +analysis_interval = 10 # entropy? analysis_callback = AnalysisCallback(semi, interval = analysis_interval, @@ -100,7 +292,7 @@ callbacks = CallbackSet(summary_callback, # run the simulation sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), maxiters = 1.0e7, - dt = 1.0, + dt = 1.0, save_everystep = false, callback = callbacks); summary_callback() \ No newline at end of file diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 61a28354..2c6745d8 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -158,15 +158,19 @@ end return SVector(0.0, 0.0, temperature) else - error("wrong system") + # experiment with ref_temp = 0 function f!(residual, guess) - residual[1] = (c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain))*(guess[3] - ref_temp) - residual[1] += guess[1] * (L_ref - R_v * ref_temp) - (energy - rho * 0.5 * (v1^2 + v2^2)) + residual[1] = (c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain)) * guess[3] + residual[1] += guess[1] * L_ref - (energy - rho * 0.5 * (v1^2 + v2^2)) + residual[2] = min(saturation_vapour_pressure(guess[3], equations) / (R_v * guess[3]), rho_moist) - guess[1] + residual[3] = rho_moist - guess[1] - guess[2] end - nl_sol = nlsolve(f!, [rho_vapour_h; rho_cloud_h; temperature_h], ftol = 1e-14, iterations = 20) + nl_sol = nlsolve(f!, [rho_vapour_h; rho_cloud_h; temperature_h], ftol = 1e-9)#, iterations = 10) + + #display([nl_sol.zero[1] - u[7], nl_sol.zero[2] - u[8], nl_sol.zero[3] - u[9]]) return SVector(nl_sol.zero[1], nl_sol.zero[2], nl_sol.zero[3]) end @@ -291,6 +295,11 @@ end ref_temp = equations.ref_temperature ref_L = equations.ref_latent_heat_vap_temp + # testing + if (temperature < 0.0) + error("temp less than zero") + end + # Clausius Clapeyron formula p_vapour_saturation = ref_s_p * (temperature / ref_temp)^((c_pv - c_l) / R_v) p_vapour_saturation *= exp(((ref_L - (c_pv - c_l) * ref_temp) / R_v) * (1 / ref_temp - 1 / temperature)) @@ -347,7 +356,7 @@ end f4 = rho * v1 * v2 - rho_rain * v_r * v1 f5 = rho * v2 * v2 + p - rho_rain * v_r * v2 - # "energy" + # "energy" TODO correct the ref_temp term if it proves to be wrong here!!! f6 = (energy + p) * v2 - (c_l * (temperature - ref_temp) + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r end @@ -392,7 +401,7 @@ end f4 = rho * v_normal * v1 + p * normal_direction[1] - rho_rain * v_r_normal * v1 f5 = rho * v_normal * v2 + p * normal_direction[2] - rho_rain * v_r_normal * v2 - # "energy" + # "energy" TODO correct the ref_temp term if it proves to be wrong here!!! f6 = (energy + p) * v_normal - (c_l * (temperature - ref_temp) + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r_normal return SVector(f1, f2, f3, f4, f5, f6, @@ -418,7 +427,7 @@ end rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) - # source terms phase change + # source terms phase change TODO correct the ref_temp term if it proves to be wrong here!!! S_evaporation = (3.86e-3 - 9.41e-5 * (temperature - ref_temp)) * (1 + 9.1 * rho_rain^(0.1875)) S_evaporation *= (rho_vs - rho_vapour) * rho_rain^(0.5) S_auto_conversion = 0.001 * rho_cloud From 474bfefbfdffa8dad979fe407787f911f1e6d993 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 4 Sep 2024 22:15:29 +0200 Subject: [PATCH 034/115] added for future implementation --- examples/test_elixirs/convergence_test_moist.jl | 1 + 1 file changed, 1 insertion(+) create mode 100644 examples/test_elixirs/convergence_test_moist.jl diff --git a/examples/test_elixirs/convergence_test_moist.jl b/examples/test_elixirs/convergence_test_moist.jl new file mode 100644 index 00000000..503fa1da --- /dev/null +++ b/examples/test_elixirs/convergence_test_moist.jl @@ -0,0 +1 @@ +#TODO \ No newline at end of file From 15dbccd19c97f5292607e775ee4d5f1295cf95d6 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 4 Sep 2024 22:15:42 +0200 Subject: [PATCH 035/115] moist bubble testing --- ...ixir_rainy_euler_bubble_no_phase_change.jl | 8 +++---- src/equations/compressible_rainy_euler_2d.jl | 23 +++++++++++-------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_no_phase_change.jl b/examples/elixir_rainy_euler_bubble_no_phase_change.jl index a6c68808..af9c9960 100644 --- a/examples/elixir_rainy_euler_bubble_no_phase_change.jl +++ b/examples/elixir_rainy_euler_bubble_no_phase_change.jl @@ -156,7 +156,7 @@ function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) p_loc = p_0 * (R_d * rho_theta / p_0)^(1 / (1 - kappa_M)) T_loc = p_loc / (R_d * rho_d + R_v * rho_qv) - rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * (T_loc - 273.15) + (L_00 - R_v * 273.15) * rho_qv p_v = rho_qv * R_v * T_loc p_d = p_loc - p_v @@ -213,7 +213,7 @@ function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) rho_theta = rho * θ_dens_new * (p_loc / p_0)^(kappa - kappa_M) - rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * (T_loc - 273.15) + (L_00 - R_v * 273.15) * rho_qv end return SVector(rho, rho_e, rho_qv, rho_ql) end @@ -248,7 +248,7 @@ solver = DGSEM(basis, surface_flux) coordinates_min = ( 0.0, 0.0) coordinates_max = (20_000.0, 10_000.0) -cells_per_dimension = (32, 16) +cells_per_dimension = (64, 32) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = (false, false)) @@ -260,7 +260,7 @@ semi = SemidiscretizationHyperbolic(mesh, equations, ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 1000.0) +tspan = (0.0, 100.0) ode = semidiscretize(semi, tspan) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 2c6745d8..56851889 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -65,7 +65,7 @@ function CompressibleRainyEulerEquations2D(; RealT = Float64) # Reference values: ref_saturation_pressure = 610.7 ref_temperature = 273.15 - ref_latent_heat_vap_temp = 2.5e6 + ref_latent_heat_vap_temp = 3147620.0#2.5e6 ref_pressure = 1e5 # Other: @@ -147,7 +147,9 @@ end energy = energy_density(u, equations) # recover temperature explicitly from inner energy when other variables are zero + # energy density definition without ref_temp for dry case if (rho_moist == 0.0 && rho_rain == 0.0) + error("wrong system") energy_kinetic = 0.5 * (v1^2 + v2^2) * rho temperature = (energy - energy_kinetic) / (c_vd * rho) @@ -160,12 +162,15 @@ end else # experiment with ref_temp = 0 function f!(residual, guess) - residual[1] = (c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain)) * guess[3] - residual[1] += guess[1] * L_ref - (energy - rho * 0.5 * (v1^2 + v2^2)) + residual[1] = (c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain)) * (guess[3] - ref_temp) + residual[1] += guess[1] * (L_ref - R_v * ref_temp) + residual[1] -= (energy - rho * 0.5 * (v1^2 + v2^2)) - residual[2] = min(saturation_vapour_pressure(guess[3], equations) / (R_v * guess[3]), rho_moist) - guess[1] + residual[2] = min(saturation_vapour_pressure(guess[3], equations) / (R_v * guess[3]), rho_moist) + residual[2] -= guess[1] - residual[3] = rho_moist - guess[1] - guess[2] + residual[3] = rho_moist + residual[3] -= guess[1] + guess[2] end nl_sol = nlsolve(f!, [rho_vapour_h; rho_cloud_h; temperature_h], ftol = 1e-9)#, iterations = 10) @@ -203,7 +208,7 @@ end rho_dry = u[1] rho_moist = u[2] rho_rain = u[3] - rho = rho_dry + rho_moist + rho_rain + rho = rho_dry + rho_moist + rho_rain rho_inv = inv(rho) return SVector(rho_dry, rho_moist, rho_rain, rho, rho_inv) @@ -356,7 +361,7 @@ end f4 = rho * v1 * v2 - rho_rain * v_r * v1 f5 = rho * v2 * v2 + p - rho_rain * v_r * v2 - # "energy" TODO correct the ref_temp term if it proves to be wrong here!!! + # "energy" f6 = (energy + p) * v2 - (c_l * (temperature - ref_temp) + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r end @@ -401,7 +406,7 @@ end f4 = rho * v_normal * v1 + p * normal_direction[1] - rho_rain * v_r_normal * v1 f5 = rho * v_normal * v2 + p * normal_direction[2] - rho_rain * v_r_normal * v2 - # "energy" TODO correct the ref_temp term if it proves to be wrong here!!! + # "energy" f6 = (energy + p) * v_normal - (c_l * (temperature - ref_temp) + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r_normal return SVector(f1, f2, f3, f4, f5, f6, @@ -427,7 +432,7 @@ end rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) - # source terms phase change TODO correct the ref_temp term if it proves to be wrong here!!! + # source terms phase change S_evaporation = (3.86e-3 - 9.41e-5 * (temperature - ref_temp)) * (1 + 9.1 * rho_rain^(0.1875)) S_evaporation *= (rho_vs - rho_vapour) * rho_rain^(0.5) S_auto_conversion = 0.001 * rho_cloud From b016330b05535132cd3bbd65fe2cf9ac492de02f Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Thu, 5 Sep 2024 16:28:01 +0200 Subject: [PATCH 036/115] moist bubble testing --- examples/elixir_rainy_euler_bubble_no_phase_change.jl | 6 +++--- src/equations/compressible_rainy_euler_2d.jl | 8 +++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_no_phase_change.jl b/examples/elixir_rainy_euler_bubble_no_phase_change.jl index af9c9960..c793710a 100644 --- a/examples/elixir_rainy_euler_bubble_no_phase_change.jl +++ b/examples/elixir_rainy_euler_bubble_no_phase_change.jl @@ -158,7 +158,7 @@ function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, T_loc = p_loc / (R_d * rho_d + R_v * rho_qv) rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * (T_loc - 273.15) + (L_00 - R_v * 273.15) * rho_qv - p_v = rho_qv * R_v * T_loc + #=p_v = rho_qv * R_v * T_loc p_d = p_loc - p_v T_C = T_loc - 273.15 p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) @@ -170,9 +170,9 @@ function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, # equivalent potential temperature a = T_loc * (p_0 / p_d)^(R_d / (c_pd + r_t * c_pl)) b = H^(-r_v * R_v / c_pd) - L_v = L_00 + (c_pv - c_pl) * T_loc + L_v = L_00 + (c_pv - c_pl) * (T_loc - 273.15) c = exp(L_v * r_v / ((c_pd + r_t * c_pl) * T_loc)) - aeq_pot = (a * b * c) # TODO: this is not used. remove? + aeq_pot = (a * b * c) # TODO: this is not used. remove? =# # Assume pressure stays constant if (r < rc && Δθ > 0) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 56851889..cba06cf1 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -34,7 +34,7 @@ struct CompressibleRainyEulerEquations2D{RealT <: Real} <: AbstractCompressibleR # Gas constants: R_dry_air ::RealT R_vapour ::RealT - eps ::RealT + eps ::RealT #TODO not used? # Reference values: ref_saturation_pressure ::RealT @@ -256,6 +256,12 @@ end # recover rho_vapour, rho_cloud, temperature from nonlinear system rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) + if ( rho_vapour < 0.0 ) + error("rho vapour less than zero") + end + if ( rho_cloud < 0.0 ) + error("rho cloud less than zero") + end # formula p = pressure(u, equations) From 056d66dba4124b8332a88902113ce96429e4da55 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Fri, 13 Sep 2024 20:57:56 +0200 Subject: [PATCH 037/115] formatting and parameter adjustments/tests --- examples/elixir_rainy_euler_bubble_dry.jl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_dry.jl b/examples/elixir_rainy_euler_bubble_dry.jl index 9af5c3b6..bf44faeb 100644 --- a/examples/elixir_rainy_euler_bubble_dry.jl +++ b/examples/elixir_rainy_euler_bubble_dry.jl @@ -41,11 +41,10 @@ function initial_condition_bubble_dry(x, t, equations::CompressibleRainyEulerEqu # density rho = p / (R * T) - v1 = 20.0 + v1 = 0.0 v2 = 0.0 E = c_v * T + 0.5 * (v1^2 + v2^2) - # random experiments return SVector(rho, 0.0, 0.0, rho * v1, rho * v2, rho * E, 0.0, 0.0, 0.0) end @@ -61,7 +60,7 @@ boundary_conditions = (x_neg = boundary_condition_periodic, y_neg = boundary_condition_slip_wall, y_pos = boundary_condition_slip_wall) -polydeg = 3 +polydeg = 1 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_lax_friedrichs @@ -88,7 +87,7 @@ semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 1000.0) +tspan = (0.0, 1100.0) ode = semidiscretize(semi, tspan) @@ -102,7 +101,7 @@ analysis_callback = AnalysisCallback(semi, interval = analysis_interval, alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval = analysis_interval, +save_solution = SaveSolutionCallback(interval = 100, save_initial_solution = true, save_final_solution = true, output_directory = "out", From a6299ab4c6a13207070b93b090afd19394564ac1 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Fri, 13 Sep 2024 20:59:06 +0200 Subject: [PATCH 038/115] moved the nonlinear system to callback_stage for performance --- ...ixir_rainy_euler_bubble_no_phase_change.jl | 18 ++-- src/TrixiAtmo.jl | 3 + src/callbacks_stage/callbacks_stage.jl | 7 ++ src/callbacks_stage/nonlinear_solve_dg.jl | 33 +++++++ src/callbacks_stage/nonlinear_solve_dg2d.jl | 32 +++++++ src/equations/compressible_rainy_euler_2d.jl | 92 +++++++++++-------- 6 files changed, 139 insertions(+), 46 deletions(-) create mode 100644 src/callbacks_stage/callbacks_stage.jl create mode 100644 src/callbacks_stage/nonlinear_solve_dg.jl create mode 100644 src/callbacks_stage/nonlinear_solve_dg2d.jl diff --git a/examples/elixir_rainy_euler_bubble_no_phase_change.jl b/examples/elixir_rainy_euler_bubble_no_phase_change.jl index c793710a..a42b0d60 100644 --- a/examples/elixir_rainy_euler_bubble_no_phase_change.jl +++ b/examples/elixir_rainy_euler_bubble_no_phase_change.jl @@ -1,7 +1,7 @@ using OrdinaryDiffEq using Trixi using TrixiAtmo -using TrixiAtmo: source_terms_no_phase_change +using TrixiAtmo: source_terms_no_phase_change, saturation_residual, NonlinearSolver using NLsolve: nlsolve @@ -131,7 +131,7 @@ function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerE rho_qv = rho * (rho_qv_r / rho_r * (z - z_l) + rho_qv_l / rho_l * (z_r - z)) / dz rho_ql = rho * (rho_ql_r / rho_r * (z - z_l) + rho_ql_l / rho_l * (z_r - z)) / dz - rho, rho_e, rho_qv, rho_ql = perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, + rho, rho_e, rho_qv, rho_ql, T_loc = perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, equations::CompressibleMoistEulerEquations2D) v1 = 0.0 @@ -140,7 +140,7 @@ function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerE rho_v2 = rho * v2 rho_E = rho_e + 1 / 2 * rho * (v1^2 + v2^2) - return SVector(rho, rho_qv + rho_ql, 0.0, rho_v1, rho_v2, rho_E, rho_qv, rho_ql, 300.0) + return SVector(rho, rho_qv + rho_ql, 0.0, rho_v1, rho_v2, rho_E, rho_qv, rho_ql, T_loc) end function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, @@ -215,7 +215,7 @@ function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, rho_theta = rho * θ_dens_new * (p_loc / p_0)^(kappa - kappa_M) rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * (T_loc - 273.15) + (L_00 - R_v * 273.15) * rho_qv end - return SVector(rho, rho_e, rho_qv, rho_ql) + return SVector(rho, rho_e, rho_qv, rho_ql, T_loc) end # Create background atmosphere data set @@ -238,7 +238,7 @@ boundary_conditions = (x_neg = boundary_condition_slip_wall, y_neg = boundary_condition_slip_wall, y_pos = boundary_condition_slip_wall) -polydeg = 1 +polydeg = 3 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_lax_friedrichs @@ -260,13 +260,13 @@ semi = SemidiscretizationHyperbolic(mesh, equations, ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 100.0) +tspan = (0.0, 10.0) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -analysis_interval = 10 +analysis_interval = 1000 # entropy? analysis_callback = AnalysisCallback(semi, interval = analysis_interval, @@ -288,9 +288,11 @@ callbacks = CallbackSet(summary_callback, save_solution, stepsize_callback) +stage_limiter! = NonlinearSolver(saturation_residual, 1e-9, SVector(7, 8, 9)) + ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limiter!), maxiters = 1.0e7, dt = 1.0, save_everystep = false, callback = callbacks); diff --git a/src/TrixiAtmo.jl b/src/TrixiAtmo.jl index 04cfd8df..96290b3f 100644 --- a/src/TrixiAtmo.jl +++ b/src/TrixiAtmo.jl @@ -23,4 +23,7 @@ baz() = Trixi.examples_dir() include("equations/equations.jl") export CompressibleMoistEulerEquations2D, CompressibleRainyEulerEquations2D +include("callbacks_stage/callbacks_stage.jl") +export NonlinearSolver + end # module TrixiAtmo diff --git a/src/callbacks_stage/callbacks_stage.jl b/src/callbacks_stage/callbacks_stage.jl new file mode 100644 index 00000000..5fb63654 --- /dev/null +++ b/src/callbacks_stage/callbacks_stage.jl @@ -0,0 +1,7 @@ +# 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 + include("nonlinear_solve_dg.jl") +end \ No newline at end of file diff --git a/src/callbacks_stage/nonlinear_solve_dg.jl b/src/callbacks_stage/nonlinear_solve_dg.jl new file mode 100644 index 00000000..b9ec638e --- /dev/null +++ b/src/callbacks_stage/nonlinear_solve_dg.jl @@ -0,0 +1,33 @@ +using Trixi: wrap_array, AbstractSemidiscretization#, TimerOutputs +#using TimerOutputs + + +@muladd begin + + +struct NonlinearSolver + residual + tolerance ::Real + variables_index_vector::Vector{Int} +end + +#= +function NonlinearSolver(residual!, variables_index_vector; tolerance) + NonlinearSolver(residual!, tolerance, variables_index_vector) +end +=# + +function (limiter!::NonlinearSolver)(u_ode, integrator, semi::AbstractSemidiscretization, t) + u = wrap_array(u_ode, semi) + + #@trixi_timeit timer() "nonlinear system solver" begin + nonlinear_solve_dg_2d!(u, limiter!.residual, limiter!.tolerance, limiter!.variables_index_vector, + semi.equations, semi.solver, semi.cache) + #end +end + + +include("nonlinear_solve_dg2d.jl") + + +end \ No newline at end of file diff --git a/src/callbacks_stage/nonlinear_solve_dg2d.jl b/src/callbacks_stage/nonlinear_solve_dg2d.jl new file mode 100644 index 00000000..7d144cd9 --- /dev/null +++ b/src/callbacks_stage/nonlinear_solve_dg2d.jl @@ -0,0 +1,32 @@ +using NLsolve +using Trixi: get_node_vars + + +# 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 + +function nonlinear_solve_dg_2d!(u, residual, tolerance, variables_index_vector, equations, dg::DGSEM, cache) + + #TODO @threaded not defined + for element in eachelement(dg, cache) + + initial_guess = similar(variables_index_vector) + + for j in eachnode(dg), i in eachnode(dg) + + u_node = get_node_vars(u, equations, dg, i, j, element) + initial_guess = u_node[variables_index_vector] + nl_sol = nlsolve(residual(u_node, equations), initial_guess, ftol = tolerance) + + # similar to set_node_vars! + for index in eachindex(variables_index_vector) + u[variables_index_vector[index], i, j, element] = nl_sol.zero[index] + end + end + end +end + +end # muladd end \ No newline at end of file diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index cba06cf1..b99021bf 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -94,8 +94,8 @@ varnames(::typeof(cons2cons), ::CompressibleRainyEulerEquations2D) = ("rho_dry", varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_moist", "rho_rain", "v1", "v2", "energy_density", - "rho_vapour_h", "rho_cloud_h", - "temperature_h") + "rho_vapour", "rho_cloud", + "temperature") @@ -112,72 +112,47 @@ varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", # energy density energy = energy_density(u, equations) - return SVector(rho_dry, rho_moist, rho_rain, v1, v2, energy, - u[7], u[8], u[9]) + # nonlinear system + rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) + + return SVector(rho_dry, rho_moist, rho_rain, v1, v2, energy, rho_vapour, rho_cloud, temperature) end @inline function cons2entropy(u, equations::CompressibleRainyEulerEquations2D) #TODO - return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0) + return SVector(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) end @inline function cons2nonlinearsystemsol(u, equations::CompressibleRainyEulerEquations2D) # constants - c_l = equations.c_liquid_water c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_v = equations.R_vapour - L_ref = equations.ref_latent_heat_vap_temp - ref_temp = equations.ref_temperature # densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - # for initial guess - rho_vapour_h = u[7] - rho_cloud_h = u[8] - temperature_h = u[9] - # velocity v1, v2 = velocities(u, rho_inv, equations) # energy density energy = energy_density(u, equations) - # recover temperature explicitly from inner energy when other variables are zero + # recover temperature explicitly from energy when other variables are zero # energy density definition without ref_temp for dry case if (rho_moist == 0.0 && rho_rain == 0.0) - error("wrong system") + #error("wrong system") energy_kinetic = 0.5 * (v1^2 + v2^2) * rho temperature = (energy - energy_kinetic) / (c_vd * rho) if (temperature < 0.0) - display(energy-energy_kinetic) + #display(energy - energy_kinetic) error("temp negative") end return SVector(0.0, 0.0, temperature) - else - # experiment with ref_temp = 0 - function f!(residual, guess) - residual[1] = (c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain)) * (guess[3] - ref_temp) - residual[1] += guess[1] * (L_ref - R_v * ref_temp) - residual[1] -= (energy - rho * 0.5 * (v1^2 + v2^2)) - - residual[2] = min(saturation_vapour_pressure(guess[3], equations) / (R_v * guess[3]), rho_moist) - residual[2] -= guess[1] - - residual[3] = rho_moist - residual[3] -= guess[1] + guess[2] - end - - nl_sol = nlsolve(f!, [rho_vapour_h; rho_cloud_h; temperature_h], ftol = 1e-9)#, iterations = 10) - - #display([nl_sol.zero[1] - u[7], nl_sol.zero[2] - u[8], nl_sol.zero[3] - u[9]]) - - return SVector(nl_sol.zero[1], nl_sol.zero[2], nl_sol.zero[3]) + else + return SVector(u[7], u[8], u[9]) end end @@ -234,7 +209,12 @@ end rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) - + #= + if (temperature > 333.15) + display(temperature - 273.15) + error("temp high") + end + =# p = (R_d * rho_dry + R_v * rho_vapour) * temperature #v1, v2 = velocities(u, rho_inv, equations) #p = (equations.c_dry_air_const_pressure / equations.c_dry_air_const_volume - 1) * (energy_density(u, equations) - 0.5f0 * (u[4] * v1 + u[5] * v2)) @@ -576,4 +556,40 @@ end +### Nonlinear System Residual ### + +# in preparation for a callback to solve the nonlinear system +@inline function saturation_residual(u, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp + ref_temp = equations.ref_temperature + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + + # energy density + energy = energy_density(u, equations) + + function saturation_residual!(residual, guess) + residual[1] = (c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain)) * (guess[3] - ref_temp) + residual[1] += guess[1] * (L_ref - R_v * ref_temp) + residual[1] -= (energy - rho * 0.5 * (v1^2 + v2^2)) + + residual[2] = min(saturation_vapour_pressure(guess[3], equations) / (R_v * guess[3]), rho_moist) + residual[2] -= guess[1] + + residual[3] = rho_moist + residual[3] -= guess[1] + guess[2] + end + + return saturation_residual! +end + end # muladd end \ No newline at end of file From 39b84506cc260cea5f5a0c2487bf023b4d8cc1a1 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Sun, 15 Sep 2024 22:18:13 +0200 Subject: [PATCH 039/115] name change of callback to NonlineaarSolveDG --- examples/elixir_rainy_euler_bubble_no_phase_change.jl | 10 +++++----- src/TrixiAtmo.jl | 2 +- src/callbacks_stage/nonlinear_solve_dg.jl | 4 ++-- src/callbacks_stage/nonlinear_solve_dg2d.jl | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_no_phase_change.jl b/examples/elixir_rainy_euler_bubble_no_phase_change.jl index a42b0d60..3314282b 100644 --- a/examples/elixir_rainy_euler_bubble_no_phase_change.jl +++ b/examples/elixir_rainy_euler_bubble_no_phase_change.jl @@ -1,7 +1,7 @@ using OrdinaryDiffEq using Trixi using TrixiAtmo -using TrixiAtmo: source_terms_no_phase_change, saturation_residual, NonlinearSolver +using TrixiAtmo: source_terms_no_phase_change, saturation_residual, NonlinearSolveDG using NLsolve: nlsolve @@ -260,7 +260,7 @@ semi = SemidiscretizationHyperbolic(mesh, equations, ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 10.0) +tspan = (0.0, 1000.0) ode = semidiscretize(semi, tspan) @@ -272,9 +272,9 @@ analysis_interval = 1000 analysis_callback = AnalysisCallback(semi, interval = analysis_interval, extra_analysis_errors = (:entropy_conservation_error,)) -alive_callback = AliveCallback(analysis_interval = analysis_interval) +alive_callback = AliveCallback(analysis_interval = 100) -save_solution = SaveSolutionCallback(interval = analysis_interval, +save_solution = SaveSolutionCallback(interval = 100, save_initial_solution = true, save_final_solution = true, output_directory = "out", @@ -288,7 +288,7 @@ callbacks = CallbackSet(summary_callback, save_solution, stepsize_callback) -stage_limiter! = NonlinearSolver(saturation_residual, 1e-9, SVector(7, 8, 9)) +stage_limiter! = NonlinearSolveDG(saturation_residual, 1e-9, SVector(7, 8, 9)) ############################################################################### # run the simulation diff --git a/src/TrixiAtmo.jl b/src/TrixiAtmo.jl index 96290b3f..4974fa4d 100644 --- a/src/TrixiAtmo.jl +++ b/src/TrixiAtmo.jl @@ -24,6 +24,6 @@ include("equations/equations.jl") export CompressibleMoistEulerEquations2D, CompressibleRainyEulerEquations2D include("callbacks_stage/callbacks_stage.jl") -export NonlinearSolver +export NonlinearSolveDG end # module TrixiAtmo diff --git a/src/callbacks_stage/nonlinear_solve_dg.jl b/src/callbacks_stage/nonlinear_solve_dg.jl index b9ec638e..6a6193ac 100644 --- a/src/callbacks_stage/nonlinear_solve_dg.jl +++ b/src/callbacks_stage/nonlinear_solve_dg.jl @@ -5,7 +5,7 @@ using Trixi: wrap_array, AbstractSemidiscretization#, TimerOutputs @muladd begin -struct NonlinearSolver +struct NonlinearSolveDG residual tolerance ::Real variables_index_vector::Vector{Int} @@ -17,7 +17,7 @@ function NonlinearSolver(residual!, variables_index_vector; tolerance) end =# -function (limiter!::NonlinearSolver)(u_ode, integrator, semi::AbstractSemidiscretization, t) +function (limiter!::NonlinearSolveDG)(u_ode, integrator, semi::AbstractSemidiscretization, t) u = wrap_array(u_ode, semi) #@trixi_timeit timer() "nonlinear system solver" begin diff --git a/src/callbacks_stage/nonlinear_solve_dg2d.jl b/src/callbacks_stage/nonlinear_solve_dg2d.jl index 7d144cd9..c5f74612 100644 --- a/src/callbacks_stage/nonlinear_solve_dg2d.jl +++ b/src/callbacks_stage/nonlinear_solve_dg2d.jl @@ -13,7 +13,7 @@ function nonlinear_solve_dg_2d!(u, residual, tolerance, variables_index_vector, #TODO @threaded not defined for element in eachelement(dg, cache) - initial_guess = similar(variables_index_vector) + initial_guess = Vector{eltype(u)}(undef, length(variables_index_vector)) for j in eachnode(dg), i in eachnode(dg) From 21c52a0cd511d8e8cc901fce483eb1154fba31d9 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Sun, 15 Sep 2024 22:18:32 +0200 Subject: [PATCH 040/115] moist bubble experiments --- .../compressible_moist_euler_2d_lucas.jl | 2 +- src/equations/compressible_rainy_euler_2d.jl | 25 +++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/equations/compressible_moist_euler_2d_lucas.jl b/src/equations/compressible_moist_euler_2d_lucas.jl index 638cc398..aae3eaf1 100644 --- a/src/equations/compressible_moist_euler_2d_lucas.jl +++ b/src/equations/compressible_moist_euler_2d_lucas.jl @@ -37,7 +37,7 @@ function CompressibleMoistEulerEquations2D(; g = 9.81, RealT = Float64) c_pl = 4186.0 gamma = c_pd / c_vd # = 1/(1 - kappa) kappa = 1 - inv(gamma) - L_00 = 3147620.0 + L_00 = 2.5e6#3147620.0 a = 360.0 return CompressibleMoistEulerEquations2D{RealT}(p_0, c_pd, c_vd, R_d, c_pv, c_vv, R_v, c_pl, g, kappa, gamma, L_00, a) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index b99021bf..614942f4 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -65,7 +65,7 @@ function CompressibleRainyEulerEquations2D(; RealT = Float64) # Reference values: ref_saturation_pressure = 610.7 ref_temperature = 273.15 - ref_latent_heat_vap_temp = 3147620.0#2.5e6 + ref_latent_heat_vap_temp = 2.5e6#3147620.0 ref_pressure = 1e5 # Other: @@ -152,7 +152,24 @@ end return SVector(0.0, 0.0, temperature) else - return SVector(u[7], u[8], u[9]) + # experimental and overly simple positivity check + rho_vapour = u[7] + rho_cloud = u[8] + temperature = u[9] + #= + if (rho_vapour < 0.0 && isapprox(rho_vapour, 0.0, atol = 1e-15)) + rho_vapour = 0.0 + end + + if (rho_cloud < 0.0 && isapprox(rho_cloud, 0.0, atol = 1e-15)) + rho_cloud = 0.0 + end + + if (temperature < 0.0 && isapprox(temperature, 0.0, atol = 1e-15)) + temperature = 0.0 + end + =# + return SVector(rho_vapour, rho_cloud, temperature) end end @@ -240,6 +257,7 @@ end error("rho vapour less than zero") end if ( rho_cloud < 0.0 ) + display(rho_cloud) error("rho cloud less than zero") end @@ -288,6 +306,7 @@ end # testing if (temperature < 0.0) + display(temp) error("temp less than zero") end @@ -584,9 +603,11 @@ end residual[2] = min(saturation_vapour_pressure(guess[3], equations) / (R_v * guess[3]), rho_moist) residual[2] -= guess[1] + residual[2] *= 1e7 residual[3] = rho_moist residual[3] -= guess[1] + guess[2] + residual[3] *= 1e7 end return saturation_residual! From e1befab41428e51a4320ace235cfdd0d5ec2bf40 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 18 Sep 2024 18:11:37 +0200 Subject: [PATCH 041/115] testing --- src/equations/compressible_rainy_euler_2d.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 614942f4..c6f67c82 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -156,7 +156,7 @@ end rho_vapour = u[7] rho_cloud = u[8] temperature = u[9] - #= + if (rho_vapour < 0.0 && isapprox(rho_vapour, 0.0, atol = 1e-15)) rho_vapour = 0.0 end @@ -164,7 +164,7 @@ end if (rho_cloud < 0.0 && isapprox(rho_cloud, 0.0, atol = 1e-15)) rho_cloud = 0.0 end - + #= if (temperature < 0.0 && isapprox(temperature, 0.0, atol = 1e-15)) temperature = 0.0 end @@ -306,7 +306,7 @@ end # testing if (temperature < 0.0) - display(temp) + display(temperature) error("temp less than zero") end From d1ca8d7c932a1801650e570fa893723eb5cc06a3 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 18 Sep 2024 18:12:29 +0200 Subject: [PATCH 042/115] added Trixi timer, added threading, formatting changes --- src/callbacks_stage/callbacks_stage.jl | 4 ---- src/callbacks_stage/nonlinear_solve_dg.jl | 17 +++++------------ src/callbacks_stage/nonlinear_solve_dg2d.jl | 16 +++++----------- 3 files changed, 10 insertions(+), 27 deletions(-) diff --git a/src/callbacks_stage/callbacks_stage.jl b/src/callbacks_stage/callbacks_stage.jl index 5fb63654..4be1d434 100644 --- a/src/callbacks_stage/callbacks_stage.jl +++ b/src/callbacks_stage/callbacks_stage.jl @@ -1,7 +1,3 @@ -# 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 include("nonlinear_solve_dg.jl") end \ No newline at end of file diff --git a/src/callbacks_stage/nonlinear_solve_dg.jl b/src/callbacks_stage/nonlinear_solve_dg.jl index 6a6193ac..8c7485cb 100644 --- a/src/callbacks_stage/nonlinear_solve_dg.jl +++ b/src/callbacks_stage/nonlinear_solve_dg.jl @@ -1,33 +1,26 @@ -using Trixi: wrap_array, AbstractSemidiscretization#, TimerOutputs -#using TimerOutputs +using Trixi: wrap_array, AbstractSemidiscretization, TimerOutputs, @trixi_timeit, timer -@muladd begin - +@muladd begin + struct NonlinearSolveDG residual tolerance ::Real variables_index_vector::Vector{Int} end -#= -function NonlinearSolver(residual!, variables_index_vector; tolerance) - NonlinearSolver(residual!, tolerance, variables_index_vector) -end -=# function (limiter!::NonlinearSolveDG)(u_ode, integrator, semi::AbstractSemidiscretization, t) u = wrap_array(u_ode, semi) - #@trixi_timeit timer() "nonlinear system solver" begin + @trixi_timeit timer() "nonlinear system solver" begin nonlinear_solve_dg_2d!(u, limiter!.residual, limiter!.tolerance, limiter!.variables_index_vector, semi.equations, semi.solver, semi.cache) - #end + end end include("nonlinear_solve_dg2d.jl") - end \ No newline at end of file diff --git a/src/callbacks_stage/nonlinear_solve_dg2d.jl b/src/callbacks_stage/nonlinear_solve_dg2d.jl index c5f74612..a0a84250 100644 --- a/src/callbacks_stage/nonlinear_solve_dg2d.jl +++ b/src/callbacks_stage/nonlinear_solve_dg2d.jl @@ -1,29 +1,23 @@ using NLsolve -using Trixi: get_node_vars +using Trixi: get_node_vars, @batch + -# 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 function nonlinear_solve_dg_2d!(u, residual, tolerance, variables_index_vector, equations, dg::DGSEM, cache) - #TODO @threaded not defined - for element in eachelement(dg, cache) - - initial_guess = Vector{eltype(u)}(undef, length(variables_index_vector)) + @batch for element in eachelement(dg, cache) for j in eachnode(dg), i in eachnode(dg) u_node = get_node_vars(u, equations, dg, i, j, element) initial_guess = u_node[variables_index_vector] - nl_sol = nlsolve(residual(u_node, equations), initial_guess, ftol = tolerance) + nl_sol = nlsolve(residual(u_node, equations), initial_guess, ftol = tolerance, method=:newton).zero # similar to set_node_vars! for index in eachindex(variables_index_vector) - u[variables_index_vector[index], i, j, element] = nl_sol.zero[index] + u[variables_index_vector[index], i, j, element] = nl_sol[index] end end end From d230a90d34ca1fb4e1418031f0e7954c48dd37ff Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Mon, 23 Sep 2024 15:26:06 +0200 Subject: [PATCH 043/115] added Lucas' equations to directly compare --- .../elixir_moist_euler_moist_bubble_lucas.jl | 305 ++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 examples/elixir_moist_euler_moist_bubble_lucas.jl diff --git a/examples/elixir_moist_euler_moist_bubble_lucas.jl b/examples/elixir_moist_euler_moist_bubble_lucas.jl new file mode 100644 index 00000000..2caddac5 --- /dev/null +++ b/examples/elixir_moist_euler_moist_bubble_lucas.jl @@ -0,0 +1,305 @@ +using OrdinaryDiffEq +using Trixi, TrixiAtmo +using TrixiAtmo: cons2aeqpot, saturation_pressure, source_terms_moist_bubble, + flux_LMARS +using NLsolve: nlsolve + +############################################################################### +# semidiscretization of the compressible moist Euler equations + +equations = CompressibleMoistEulerEquations2D() + +function moist_state(y, dz, y0, r_t0, theta_e0, + equations::CompressibleMoistEulerEquations2D) + @unpack p_0, g, c_pd, c_pv, c_vd, c_vv, R_d, R_v, c_pl, L_00 = equations + (p, rho, T, r_t, r_v, rho_qv, theta_e) = y + p0 = y0[1] + + F = zeros(7, 1) + rho_d = rho / (1 + r_t) + p_d = R_d * rho_d * T + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + L = L_00 - (c_pl - c_pv) * T + + F[1] = (p - p0) / dz + g * rho + F[2] = p - (R_d * rho_d + R_v * rho_qv) * T + # H = 1 is assumed + F[3] = (theta_e - + T * (p_d / p_0)^(-R_d / (c_pd + c_pl * r_t)) * + exp(L * r_v / ((c_pd + c_pl * r_t) * T))) + F[4] = r_t - r_t0 + F[5] = rho_qv - rho_d * r_v + F[6] = theta_e - theta_e0 + a = p_vs / (R_v * T) - rho_qv + b = rho - rho_qv - rho_d + # H=1 => phi=0 + F[7] = a + b - sqrt(a * a + b * b) + + return F +end + +function generate_function_of_y(dz, y0, r_t0, theta_e0, + equations::CompressibleMoistEulerEquations2D) + function function_of_y(y) + return moist_state(y, dz, y0, r_t0, theta_e0, equations) + end +end + +struct AtmosphereLayers{RealT <: Real} + equations::CompressibleMoistEulerEquations2D + # structure: 1--> i-layer (z = total_height/precision *(i-1)), 2--> rho, rho_theta, rho_qv, rho_ql + layer_data::Matrix{RealT} + total_height::RealT + preciseness::Int + layers::Int + ground_state::NTuple{2, RealT} + equivalent_potential_temperature::RealT + mixing_ratios::NTuple{2, RealT} +end + +function AtmosphereLayers(equations; total_height = 10010.0, preciseness = 10, + ground_state = (1.4, 100000.0), + equivalent_potential_temperature = 320, + mixing_ratios = (0.02, 0.02), RealT = Float64) + @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl = equations + rho0, p0 = ground_state + r_t0, r_v0 = mixing_ratios + theta_e0 = equivalent_potential_temperature + + rho_qv0 = rho0 * r_v0 + T0 = theta_e0 + y0 = [p0, rho0, T0, r_t0, r_v0, rho_qv0, theta_e0] + + n = convert(Int, total_height / preciseness) + dz = 0.01 + layer_data = zeros(RealT, n + 1, 4) + + F = generate_function_of_y(dz, y0, r_t0, theta_e0, equations) + sol = nlsolve(F, y0) + p, rho, T, r_t, r_v, rho_qv, theta_e = sol.zero + + rho_d = rho / (1 + r_t) + rho_ql = rho - rho_d - rho_qv + kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * (p0 / p)^kappa_M * T * (1 + (R_v / R_d) * r_v) / (1 + r_t) + + layer_data[1, :] = [rho, rho_theta, rho_qv, rho_ql] + for i in (1:n) + y0 = deepcopy(sol.zero) + dz = preciseness + F = generate_function_of_y(dz, y0, r_t0, theta_e0, equations) + sol = nlsolve(F, y0) + p, rho, T, r_t, r_v, rho_qv, theta_e = sol.zero + + rho_d = rho / (1 + r_t) + rho_ql = rho - rho_d - rho_qv + kappa_M = (R_d * rho_d + R_v * rho_qv) / + (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * (p0 / p)^kappa_M * T * (1 + (R_v / R_d) * r_v) / (1 + r_t) + + layer_data[i + 1, :] = [rho, rho_theta, rho_qv, rho_ql] + end + + return AtmosphereLayers{RealT}(equations, layer_data, total_height, dz, n, ground_state, + theta_e0, mixing_ratios) +end + +# Moist bubble test case from paper: +# G.H. Bryan, J.M. Fritsch, A Benchmark Simulation for Moist Nonhydrostatic Numerical +# Models, MonthlyWeather Review Vol.130, 2917–2928, 2002, +# https://journals.ametsoc.org/view/journals/mwre/130/12/1520-0493_2002_130_2917_absfmn_2.0.co_2.xml. +function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, + atmosphere_layers::AtmosphereLayers) + @unpack layer_data, preciseness, total_height = atmosphere_layers + dz = preciseness + z = x[2] + if (z > total_height && !(isapprox(z, total_height))) + error("The atmosphere does not match the simulation domain") + end + n = convert(Int, floor((z + eps()) / dz)) + 1 + z_l = (n - 1) * dz + (rho_l, rho_theta_l, rho_qv_l, rho_ql_l) = layer_data[n, :] + z_r = n * dz + if (z_l == total_height) + z_r = z_l + dz + n = n - 1 + end + (rho_r, rho_theta_r, rho_qv_r, rho_ql_r) = layer_data[n + 1, :] + rho = (rho_r * (z - z_l) + rho_l * (z_r - z)) / dz + rho_theta = rho * (rho_theta_r / rho_r * (z - z_l) + rho_theta_l / rho_l * (z_r - z)) / + dz + rho_qv = rho * (rho_qv_r / rho_r * (z - z_l) + rho_qv_l / rho_l * (z_r - z)) / dz + rho_ql = rho * (rho_ql_r / rho_r * (z - z_l) + rho_ql_l / rho_l * (z_r - z)) / dz + + rho, rho_e, rho_qv, rho_ql = perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, + equations::CompressibleMoistEulerEquations2D) + + v1 = 0.0 + v2 = 0.0 + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_E = rho_e + 1 / 2 * rho * (v1^2 + v2^2) + + return SVector(rho, rho_v1, rho_v2, rho_E, rho_qv, rho_ql) +end + +function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, + equations::CompressibleMoistEulerEquations2D) + @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl, L_00 = equations + xc = 10000.0 + zc = 2000.0 + rc = 2000.0 + Δθ = 2.0 + + r = sqrt((x[1] - xc)^2 + (x[2] - zc)^2) + rho_d = rho - rho_qv - rho_ql + kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + p_loc = p_0 * (R_d * rho_theta / p_0)^(1 / (1 - kappa_M)) + T_loc = p_loc / (R_d * rho_d + R_v * rho_qv) + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv + + p_v = rho_qv * R_v * T_loc + p_d = p_loc - p_v + T_C = T_loc - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + H = p_v / p_vs + r_v = rho_qv / rho_d + r_l = rho_ql / rho_d + r_t = r_v + r_l + + # equivalent potential temperature + a = T_loc * (p_0 / p_d)^(R_d / (c_pd + r_t * c_pl)) + b = H^(-r_v * R_v / c_pd) + L_v = L_00 + (c_pv - c_pl) * T_loc + c = exp(L_v * r_v / ((c_pd + r_t * c_pl) * T_loc)) + aeq_pot = (a * b * c) # TODO: this is not used. remove? + + # Assume pressure stays constant + if (r < rc && Δθ > 0) + # Calculate background density potential temperature + θ_dens = rho_theta / rho * (p_loc / p_0)^(kappa_M - kappa) + # Calculate perturbed density potential temperature + θ_dens_new = θ_dens * (1 + Δθ * cospi(0.5 * r / rc)^2 / 300) + rt = (rho_qv + rho_ql) / rho_d + rv = rho_qv / rho_d + # Calculate moist potential temperature + θ_loc = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rv) + # Adjust varuables until the temperature is met + if rt > 0 + while true + T_loc = θ_loc * (p_loc / p_0)^kappa + T_C = T_loc - 273.15 + # SaturVapor + pvs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + rho_d_new = (p_loc - pvs) / (R_d * T_loc) + rvs = pvs / (R_v * rho_d_new * T_loc) + θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) + if abs(θ_new - θ_loc) <= θ_loc * 1.0e-12 + break + else + θ_loc = θ_new + end + end + else + rvs = 0 + T_loc = θ_loc * (p_loc / p_0)^kappa + rho_d_new = p_loc / (R_d * T_loc) + θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) + end + rho_qv = rvs * rho_d_new + rho_ql = (rt - rvs) * rho_d_new + rho = rho_d_new * (1 + rt) + rho_d = rho - rho_qv - rho_ql + kappa_M = (R_d * rho_d + R_v * rho_qv) / + (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * θ_dens_new * (p_loc / p_0)^(kappa - kappa_M) + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv + end + return SVector(rho, rho_e, rho_qv, rho_ql) +end + +# Create background atmosphere data set +atmosphere_data = AtmosphereLayers(equations) + +# Create the initial condition with the initial data set +function initial_condition_moist(x, t, equations) + return initial_condition_moist_bubble(x, t, equations, atmosphere_data) +end + +initial_condition = initial_condition_moist + +boundary_condition = (x_neg = boundary_condition_slip_wall, + x_pos = boundary_condition_slip_wall, + y_neg = boundary_condition_slip_wall, + y_pos = boundary_condition_slip_wall) + +source_term = source_terms_moist_bubble + +############################################################################### +# Get the DG approximation space + +polydeg = 3 +basis = LobattoLegendreBasis(polydeg) + +surface_flux = flux_LMARS +volume_flux = flux_chandrashekar + +volume_integral = VolumeIntegralFluxDifferencing(volume_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + +coordinates_min = (0.0, 0.0) +coordinates_max = (20000.0, 10000.0) + +cells_per_dimension = (64, 32) + +# Create curved mesh with 64 x 32 elements +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, + periodicity = (false, false)) + +############################################################################### +# create the semi discretization object + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_condition, + source_terms = source_term) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 10.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 +solution_variables = cons2aeqpot + +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:entropy_conservation_error,), + extra_analysis_integrals = (entropy, energy_total, + saturation_pressure)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + solution_variables = solution_variables) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) + +############################################################################### +# run the simulation + +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); +summary_callback() # print the timer summary From 5895f74391a7e3c05035ff032e8093d254137a62 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Mon, 23 Sep 2024 15:27:05 +0200 Subject: [PATCH 044/115] added Jacobian of the nonlinear system to increase performance --- ...ixir_rainy_euler_bubble_no_phase_change.jl | 11 +-- src/callbacks_stage/nonlinear_solve_dg.jl | 7 +- src/callbacks_stage/nonlinear_solve_dg2d.jl | 6 +- src/equations/compressible_rainy_euler_2d.jl | 84 +++++++++++++++---- 4 files changed, 82 insertions(+), 26 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_no_phase_change.jl b/examples/elixir_rainy_euler_bubble_no_phase_change.jl index 3314282b..82634352 100644 --- a/examples/elixir_rainy_euler_bubble_no_phase_change.jl +++ b/examples/elixir_rainy_euler_bubble_no_phase_change.jl @@ -1,7 +1,8 @@ using OrdinaryDiffEq using Trixi using TrixiAtmo -using TrixiAtmo: source_terms_no_phase_change, saturation_residual, NonlinearSolveDG +using TrixiAtmo: source_terms_no_phase_change, saturation_residual, + saturation_residual_jacobian, NonlinearSolveDG using NLsolve: nlsolve @@ -260,7 +261,7 @@ semi = SemidiscretizationHyperbolic(mesh, equations, ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 1000.0) +tspan = (0.0, 10.0) ode = semidiscretize(semi, tspan) @@ -272,9 +273,9 @@ analysis_interval = 1000 analysis_callback = AnalysisCallback(semi, interval = analysis_interval, extra_analysis_errors = (:entropy_conservation_error,)) -alive_callback = AliveCallback(analysis_interval = 100) +alive_callback = AliveCallback(analysis_interval = 1000) -save_solution = SaveSolutionCallback(interval = 100, +save_solution = SaveSolutionCallback(interval = 1000, save_initial_solution = true, save_final_solution = true, output_directory = "out", @@ -288,7 +289,7 @@ callbacks = CallbackSet(summary_callback, save_solution, stepsize_callback) -stage_limiter! = NonlinearSolveDG(saturation_residual, 1e-9, SVector(7, 8, 9)) +stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) ############################################################################### # run the simulation diff --git a/src/callbacks_stage/nonlinear_solve_dg.jl b/src/callbacks_stage/nonlinear_solve_dg.jl index 8c7485cb..87155ecd 100644 --- a/src/callbacks_stage/nonlinear_solve_dg.jl +++ b/src/callbacks_stage/nonlinear_solve_dg.jl @@ -6,8 +6,9 @@ using Trixi: wrap_array, AbstractSemidiscretization, TimerOutputs, @trixi_timeit struct NonlinearSolveDG residual - tolerance ::Real + jacobian variables_index_vector::Vector{Int} + tolerance ::Real end @@ -15,8 +16,8 @@ function (limiter!::NonlinearSolveDG)(u_ode, integrator, semi::AbstractSemidiscr u = wrap_array(u_ode, semi) @trixi_timeit timer() "nonlinear system solver" begin - nonlinear_solve_dg_2d!(u, limiter!.residual, limiter!.tolerance, limiter!.variables_index_vector, - semi.equations, semi.solver, semi.cache) + nonlinear_solve_dg_2d!(u, limiter!.residual, limiter!.jacobian, limiter!.variables_index_vector, + limiter!.tolerance, semi.equations, semi.solver, semi.cache) end end diff --git a/src/callbacks_stage/nonlinear_solve_dg2d.jl b/src/callbacks_stage/nonlinear_solve_dg2d.jl index a0a84250..f421829d 100644 --- a/src/callbacks_stage/nonlinear_solve_dg2d.jl +++ b/src/callbacks_stage/nonlinear_solve_dg2d.jl @@ -5,7 +5,7 @@ using Trixi: get_node_vars, @batch @muladd begin -function nonlinear_solve_dg_2d!(u, residual, tolerance, variables_index_vector, equations, dg::DGSEM, cache) +function nonlinear_solve_dg_2d!(u, residual, jacobian, variables_index_vector, tolerance, equations, dg::DGSEM, cache) @batch for element in eachelement(dg, cache) @@ -13,7 +13,9 @@ function nonlinear_solve_dg_2d!(u, residual, tolerance, variables_index_vector, u_node = get_node_vars(u, equations, dg, i, j, element) initial_guess = u_node[variables_index_vector] - nl_sol = nlsolve(residual(u_node, equations), initial_guess, ftol = tolerance, method=:newton).zero + nl_sol = nlsolve(residual(u_node, equations), + jacobian(u_node, equations), + initial_guess, ftol = tolerance, method = :newton).zero # similar to set_node_vars! for index in eachindex(variables_index_vector) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index c6f67c82..a412033c 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -139,14 +139,12 @@ end energy = energy_density(u, equations) # recover temperature explicitly from energy when other variables are zero - # energy density definition without ref_temp for dry case if (rho_moist == 0.0 && rho_rain == 0.0) - #error("wrong system") + # energy density definition without ref_temp for dry case energy_kinetic = 0.5 * (v1^2 + v2^2) * rho temperature = (energy - energy_kinetic) / (c_vd * rho) if (temperature < 0.0) - #display(energy - energy_kinetic) error("temp negative") end @@ -164,11 +162,7 @@ end if (rho_cloud < 0.0 && isapprox(rho_cloud, 0.0, atol = 1e-15)) rho_cloud = 0.0 end - #= - if (temperature < 0.0 && isapprox(temperature, 0.0, atol = 1e-15)) - temperature = 0.0 - end - =# + return SVector(rho_vapour, rho_cloud, temperature) end end @@ -226,15 +220,8 @@ end rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) - #= - if (temperature > 333.15) - display(temperature - 273.15) - error("temp high") - end - =# + p = (R_d * rho_dry + R_v * rho_vapour) * temperature - #v1, v2 = velocities(u, rho_inv, equations) - #p = (equations.c_dry_air_const_pressure / equations.c_dry_air_const_volume - 1) * (energy_density(u, equations) - 0.5f0 * (u[4] * v1 + u[5] * v2)) return p end @@ -318,6 +305,32 @@ end end +@inline function saturation_vapour_pressure_derivative(temperature, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_pv = equations.c_vapour_const_pressure + R_v = equations.R_vapour + ref_s_p = equations.ref_saturation_pressure + ref_temp = equations.ref_temperature + ref_L = equations.ref_latent_heat_vap_temp + + # testing + if (temperature < 0.0) + display(temperature) + error("temp less than zero") + end + + const_1 = (c_pv - c_l) / R_v + const_2 = (ref_L - (c_pv - c_l) * ref_temp) / R_v + + p_vapour_saturation_derivative = ref_s_p / (ref_temp^const_1) + p_vapour_saturation_derivative *= (const_1 * temperature^(const_1 - 1) + const_2 * temperature^(const_1 - 2)) + p_vapour_saturation_derivative *= exp(const_2 * (1 / ref_temp - 1 / temperature)) + + return p_vapour_saturation_derivative +end + + ### pde discretization ### @@ -613,4 +626,43 @@ end return saturation_residual! end + +@inline function saturation_residual_jacobian(u, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp + ref_temp = equations.ref_temperature + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + function jacobian!(J, guess) + svp = saturation_vapour_pressure(guess[3], equations) + d_dtemp_svp = saturation_vapour_pressure_derivative(guess[3], equations) + + J[1, 1] = c_vv * (guess[3] - ref_temp) + L_ref - R_v * ref_temp + J[1, 2] = c_l * (guess[3] - ref_temp) + J[1, 3] = c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain) + + J[2, 1] = -1e7 + J[2, 2] = 0.0 + + if (svp / (R_v * guess[3]) < rho_moist) + J[2, 3] = (d_dtemp_svp * guess[3] - svp) / (R_v * guess[3]^2) * 1e7 + else + J[2, 3] = 0.0 + end + + J[3, 1] = -1e7 + J[3, 2] = -1e7 + J[3, 3] = 0.0 + end + + return jacobian! +end + + end # muladd end \ No newline at end of file From 1238175a36ce9f11e5c18f360356d6cddb25ef1a Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:10:53 +0200 Subject: [PATCH 045/115] moved comparison elixirs to a separate folder --- .../elixir_moist_euler_moist_bubble_lucas.jl | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{ => comparison_elixirs}/elixir_moist_euler_moist_bubble_lucas.jl (100%) diff --git a/examples/elixir_moist_euler_moist_bubble_lucas.jl b/examples/comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl similarity index 100% rename from examples/elixir_moist_euler_moist_bubble_lucas.jl rename to examples/comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl From cbf60c6295dafd24f7d96c4786a7ffca831f81d1 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:12:40 +0200 Subject: [PATCH 046/115] tested a different energy definition, commented / reverted changes --- examples/elixir_rainy_euler_bubble_dry.jl | 2 +- examples/test_elixirs/convergence_test_dry.jl | 15 ++++++++++----- src/equations/compressible_rainy_euler_2d.jl | 3 ++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_dry.jl b/examples/elixir_rainy_euler_bubble_dry.jl index bf44faeb..4b2166a2 100644 --- a/examples/elixir_rainy_euler_bubble_dry.jl +++ b/examples/elixir_rainy_euler_bubble_dry.jl @@ -60,7 +60,7 @@ boundary_conditions = (x_neg = boundary_condition_periodic, y_neg = boundary_condition_slip_wall, y_pos = boundary_condition_slip_wall) -polydeg = 1 +polydeg = 3 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_lax_friedrichs diff --git a/examples/test_elixirs/convergence_test_dry.jl b/examples/test_elixirs/convergence_test_dry.jl index d564df42..b0ffd201 100644 --- a/examples/test_elixirs/convergence_test_dry.jl +++ b/examples/test_elixirs/convergence_test_dry.jl @@ -4,7 +4,7 @@ using TrixiAtmo -# from compressible_euler_2d.jl +# adapted from compressible_euler_2d.jl function initial_condition_convergence_test(x, t, equations::CompressibleRainyEulerEquations2D) RealT = eltype(x) c = 2 @@ -23,8 +23,13 @@ function initial_condition_convergence_test(x, t, equations::CompressibleRainyEu end -# from compressible_euler_2d.jl +# adapted from compressible_euler_2d.jl function source_terms_convergence_test(u, x, t, equations::CompressibleRainyEulerEquations2D) + c_pd = equations.c_dry_air_const_pressure + c_vd = equations.c_dry_air_const_volume + #R_d = equations.R_dry_air + #ref_temp = equations.ref_temperature + # Same settings as in `initial_condition` RealT = eltype(u) c = 2 @@ -32,7 +37,7 @@ function source_terms_convergence_test(u, x, t, equations::CompressibleRainyEule L = 2 f = 1.0f0 / L ω = 2 * convert(RealT, pi) * f - γ = equations.c_dry_air_const_pressure / equations.c_dry_air_const_volume + γ = c_pd / c_vd x1, x2 = x si, co = sincos(ω * (x1 + x2 - t)) @@ -40,7 +45,7 @@ function source_terms_convergence_test(u, x, t, equations::CompressibleRainyEule rho_x = ω * A * co # Note that d/dt rho = -d/dx rho = -d/dy rho. - tmp = (2 * rho - 1) * (γ - 1) + tmp = (2 * rho - 1) * (γ - 1) #+ R_d * ref_temp du1 = rho_x du2 = rho_x * (1 + tmp) @@ -84,7 +89,7 @@ analysis_callback = AnalysisCallback(semi, interval = analysis_interval) alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval = 100, +save_solution = SaveSolutionCallback(interval = analysis_interval, save_initial_solution = true, save_final_solution = true, solution_variables = cons2prim) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index a412033c..713611d0 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -128,6 +128,7 @@ end @inline function cons2nonlinearsystemsol(u, equations::CompressibleRainyEulerEquations2D) # constants c_vd = equations.c_dry_air_const_volume + #ref_temp = equations.ref_temperature # densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) @@ -142,7 +143,7 @@ end if (rho_moist == 0.0 && rho_rain == 0.0) # energy density definition without ref_temp for dry case energy_kinetic = 0.5 * (v1^2 + v2^2) * rho - temperature = (energy - energy_kinetic) / (c_vd * rho) + temperature = (energy - energy_kinetic) / (c_vd * rho) #+ ref_temp if (temperature < 0.0) error("temp negative") From 2a0db9e4eb127115280ff455026dfd9e2c116e25 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:14:07 +0200 Subject: [PATCH 047/115] testing performance and accuracy --- examples/elixir_rainy_euler_bubble_no_phase_change.jl | 11 +++++------ src/callbacks_stage/nonlinear_solve_dg.jl | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_no_phase_change.jl b/examples/elixir_rainy_euler_bubble_no_phase_change.jl index 82634352..535f4f58 100644 --- a/examples/elixir_rainy_euler_bubble_no_phase_change.jl +++ b/examples/elixir_rainy_euler_bubble_no_phase_change.jl @@ -7,8 +7,7 @@ using NLsolve: nlsolve -# Initial condition from - +# Initial condition from elixir_moist_euler_bubble.jl function moist_state(y, dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) @unpack p_0, g, c_pd, c_pv, c_vd, c_vv, R_d, R_v, c_pl, L_00 = equations @@ -261,7 +260,7 @@ semi = SemidiscretizationHyperbolic(mesh, equations, ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 10.0) +tspan = (0.0, 1020.0) ode = semidiscretize(semi, tspan) @@ -273,15 +272,15 @@ analysis_interval = 1000 analysis_callback = AnalysisCallback(semi, interval = analysis_interval, extra_analysis_errors = (:entropy_conservation_error,)) -alive_callback = AliveCallback(analysis_interval = 1000) +alive_callback = AliveCallback(analysis_interval = 100) -save_solution = SaveSolutionCallback(interval = 1000, +save_solution = SaveSolutionCallback(interval = 100, save_initial_solution = true, save_final_solution = true, output_directory = "out", solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl = 1.0) +stepsize_callback = StepsizeCallback(cfl = 0.2) callbacks = CallbackSet(summary_callback, analysis_callback, diff --git a/src/callbacks_stage/nonlinear_solve_dg.jl b/src/callbacks_stage/nonlinear_solve_dg.jl index 87155ecd..8398edd8 100644 --- a/src/callbacks_stage/nonlinear_solve_dg.jl +++ b/src/callbacks_stage/nonlinear_solve_dg.jl @@ -5,8 +5,8 @@ using Trixi: wrap_array, AbstractSemidiscretization, TimerOutputs, @trixi_timeit @muladd begin struct NonlinearSolveDG - residual - jacobian + residual ::Function + jacobian ::Function variables_index_vector::Vector{Int} tolerance ::Real end From 5aa7c61ae124d0a64c0733ee2fe6279087edcfe3 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Sat, 28 Sep 2024 20:53:23 +0200 Subject: [PATCH 048/115] rename, relocating of convergence tests and implementation of moist convergence test --- .../test_elixirs/convergence_test_moist.jl | 1 - ...t_dry.jl => convergence_test_rainy_dry.jl} | 2 +- .../convergence_test_rainy_no_rain.jl | 168 ++++++++++++++++++ 3 files changed, 169 insertions(+), 2 deletions(-) delete mode 100644 examples/test_elixirs/convergence_test_moist.jl rename examples/test_elixirs/{convergence_test_dry.jl => convergence_test_rainy_dry.jl} (99%) create mode 100644 examples/test_elixirs/convergence_test_rainy_no_rain.jl diff --git a/examples/test_elixirs/convergence_test_moist.jl b/examples/test_elixirs/convergence_test_moist.jl deleted file mode 100644 index 503fa1da..00000000 --- a/examples/test_elixirs/convergence_test_moist.jl +++ /dev/null @@ -1 +0,0 @@ -#TODO \ No newline at end of file diff --git a/examples/test_elixirs/convergence_test_dry.jl b/examples/test_elixirs/convergence_test_rainy_dry.jl similarity index 99% rename from examples/test_elixirs/convergence_test_dry.jl rename to examples/test_elixirs/convergence_test_rainy_dry.jl index b0ffd201..09d234d0 100644 --- a/examples/test_elixirs/convergence_test_dry.jl +++ b/examples/test_elixirs/convergence_test_rainy_dry.jl @@ -110,4 +110,4 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), summary_callback() # print the timer summary # For copy-paste convenience: -#convergence_test("TrixiAtmo.jl/examples/test_elixirs/convergence_test_dry.jl", 4) \ No newline at end of file +#convergence_test("TrixiAtmo.jl/examples/test_elixirs/convergence_test_rainy_dry.jl", 4) \ No newline at end of file diff --git a/examples/test_elixirs/convergence_test_rainy_no_rain.jl b/examples/test_elixirs/convergence_test_rainy_no_rain.jl new file mode 100644 index 00000000..22649638 --- /dev/null +++ b/examples/test_elixirs/convergence_test_rainy_no_rain.jl @@ -0,0 +1,168 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: saturation_vapour_pressure, saturation_vapour_pressure_derivative, + saturation_residual, saturation_residual_jacobian + + + +function initial_condition_convergence_test_rainy_no_rain(x, t, equations::CompressibleRainyEulerEquations2D) + # needed constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour + ref_temp = equations.ref_temperature + ref_L = equations.ref_latent_heat_vap_temp + + # define rho like in dry convergence test + c = 2.0 + A = 0.1 + L = 2.0 + f = 1.0 / L + ω = 2 * pi * f + rho = c + A * sin(ω * (x[1] + x[2] - t)) + + # define variables of rho + temperature = rho + ref_temp + rho_vapour = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + rho_cloud = rho / c_l + rho_moist = rho_vapour + rho_cloud + rho_dry = rho - rho_moist + + # define matching energydensity with v1 := 1 and v2 := 1 , initially + energy = (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud) * (temperature - ref_temp) + energy += rho_vapour * (ref_L - R_v * ref_temp) + rho + + return SVector(rho_dry, rho_moist, 0.0, rho, rho, energy, rho_vapour, rho_cloud, temperature) +end + + +function source_terms_convergence_test_rainy_no_rain(u, x, t, equations::CompressibleRainyEulerEquations2D) + # needed constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + ref_temp = equations.ref_temperature + ref_L = equations.ref_latent_heat_vap_temp + + # define rho like initial condition + c = 2.0 + A = 0.1 + L = 2.0 + f = 1.0 / L + ω = 2 * pi * f + si, co = sincos(ω * (x[1] + x[2] - t)) + rho = c + A * si + rho_x = ω * A * co + rho_t = -rho_x + + # define variables of rho + temperature = rho + ref_temp + sat_vap_p = saturation_vapour_pressure(temperature, equations) + rho_vapour = sat_vap_p / (R_v * temperature) + rho_cloud = rho / c_l + rho_moist = rho_vapour + rho_cloud + rho_dry = rho - rho_moist + + # define needed derivatives + sat_vap_p_t = rho_t * saturation_vapour_pressure_derivative(temperature, equations) + sat_vap_p_x = rho_x * saturation_vapour_pressure_derivative(temperature, equations) + + rho_vapour_t = (sat_vap_p_t * temperature - rho_t * sat_vap_p) / (R_v * temperature^2) + rho_vapour_x = (sat_vap_p_x * temperature - rho_x * sat_vap_p) / (R_v * temperature^2) + + rho_cloud_t = rho_t / c_l + rho_cloud_x = rho_x / c_l + + rho_moist_t = rho_vapour_t + rho_cloud_t + rho_moist_x = rho_vapour_x + rho_cloud_x + + rho_dry_t = rho_t - rho_moist_t + rho_dry_x = rho_x - rho_moist_x + + energy_t = (c_vd * rho_dry_t + c_vv * rho_vapour_t + rho_t) * rho + energy_t += (c_vd * rho_dry + c_vv * rho_vapour + rho ) * rho_t + energy_t += rho_vapour_t * (ref_L - R_v * ref_temp) + rho_t + + energy_x = (c_vd * rho_dry_x + c_vv * rho_vapour_x + rho_x) * rho + energy_x += (c_vd * rho_dry + c_vv * rho_vapour + rho ) * rho_x + energy_x += rho_vapour_x * (ref_L - R_v * ref_temp) + rho_x + + pressure_x = (rho_dry_x * R_d + rho_vapour_x * R_v) * temperature + pressure_x += (rho_dry * R_d + rho_vapour * R_v) * rho_x # temperature_x = rho_x + + # calculate source terms for manufactured solution + # density + S_rho_dry = rho_dry_t + 2.0 * rho_dry_x + S_rho_moist = rho_moist_t + 2.0 * rho_moist_x + + # "momentum" + S_rho_v1 = rho_x + pressure_x + S_rho_v2 = rho_x + pressure_x + + # "energy" + S_energy = energy_t + 2.0 * (energy_x + pressure_x) + + return SVector(S_rho_dry, S_rho_moist, 0.0, S_rho_v1, S_rho_v2, S_energy, 0.0, 0.0, 0.0) +end + + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleRainyEulerEquations2D() + +initial_condition = initial_condition_convergence_test_rainy_no_rain + +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) + +coordinates_min = (0.0, 0.0) +coordinates_max = (2.0, 2.0) + +cells_per_dimension = (8, 8) + +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_convergence_test_rainy_no_rain) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 2.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = analysis_interval, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback) + +stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limiter!), + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); +summary_callback() # print the timer summary + +# For copy-paste convenience: +#convergence_test("TrixiAtmo.jl/examples/test_elixirs/convergence_test_rainy_no_rain.jl", 3) \ No newline at end of file From 738d5c4cb080168d0104b86bd109cf375958a408 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Sat, 28 Sep 2024 20:54:10 +0200 Subject: [PATCH 049/115] testing of initial condition and parameters --- examples/elixir_rainy_euler_bubble_no_phase_change.jl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_no_phase_change.jl b/examples/elixir_rainy_euler_bubble_no_phase_change.jl index 535f4f58..dc544249 100644 --- a/examples/elixir_rainy_euler_bubble_no_phase_change.jl +++ b/examples/elixir_rainy_euler_bubble_no_phase_change.jl @@ -140,7 +140,7 @@ function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerE rho_v2 = rho * v2 rho_E = rho_e + 1 / 2 * rho * (v1^2 + v2^2) - return SVector(rho, rho_qv + rho_ql, 0.0, rho_v1, rho_v2, rho_E, rho_qv, rho_ql, T_loc) + return SVector(rho - rho_qv - rho_ql, rho_qv + rho_ql, 0.0, rho_v1, rho_v2, rho_E, rho_qv, rho_ql, T_loc) end function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, @@ -206,6 +206,9 @@ function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, rho_d_new = p_loc / (R_d * T_loc) θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) end + # test + #T_loc = θ_new * (p_loc / p_0)^kappa + # rho_qv = rvs * rho_d_new rho_ql = (rt - rvs) * rho_d_new rho = rho_d_new * (1 + rt) @@ -238,7 +241,7 @@ boundary_conditions = (x_neg = boundary_condition_slip_wall, y_neg = boundary_condition_slip_wall, y_pos = boundary_condition_slip_wall) -polydeg = 3 +polydeg = 4 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_lax_friedrichs @@ -280,7 +283,7 @@ save_solution = SaveSolutionCallback(interval = 100, output_directory = "out", solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl = 0.2) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, From 28e9e7deab24df311d2e03eaefdc70b8c1f6b2e6 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Sat, 28 Sep 2024 20:55:24 +0200 Subject: [PATCH 050/115] comment changes --- src/equations/compressible_rainy_euler_2d.jl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 713611d0..0a69e649 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -63,7 +63,7 @@ function CompressibleRainyEulerEquations2D(; RealT = Float64) eps = R_dry_air / R_vapour # Reference values: - ref_saturation_pressure = 610.7 + ref_saturation_pressure = 610.7 # This needs to be adjusted if ref_temperature is changed! ref_temperature = 273.15 ref_latent_heat_vap_temp = 2.5e6#3147620.0 ref_pressure = 1e5 @@ -363,7 +363,7 @@ end f2 = rho_moist * v1 f3 = rho_rain * v1 - # "impulse" + # "momentum" f4 = rho * v1 * v1 + p f5 = rho * v1 * v2 @@ -376,7 +376,7 @@ end f2 = rho_moist * v2 f3 = rho_rain * (v2 - v_r) - # "impulse" + # "momentum" f4 = rho * v1 * v2 - rho_rain * v_r * v1 f5 = rho * v2 * v2 + p - rho_rain * v_r * v2 @@ -390,7 +390,6 @@ end @inline function flux(u, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) - #TODO Double-check for mistakes in "impulse" and "energy" # constants c_l = equations.c_liquid_water ref_temp = equations.ref_temperature @@ -421,7 +420,7 @@ end f2 = rho_moist * v_normal f3 = rho_rain * (v_normal - v_r_normal) - # "impulse" + # "momentum" f4 = rho * v_normal * v1 + p * normal_direction[1] - rho_rain * v_r_normal * v1 f5 = rho * v_normal * v2 + p * normal_direction[2] - rho_rain * v_r_normal * v2 From 4340e9a58ed17f77e66a65df0841f3d83e98c897 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:45:10 +0200 Subject: [PATCH 051/115] rename --- .../convergence_test_rainy_dry.jl | 0 .../convergence_test_rainy_no_rain.jl | 8 ++++---- ...nge.jl => elixir_rainy_euler_bubble_no_rain.jl} | 14 +++++++------- 3 files changed, 11 insertions(+), 11 deletions(-) rename examples/{test_elixirs => convergence_test_elixirs}/convergence_test_rainy_dry.jl (100%) rename examples/{test_elixirs => convergence_test_elixirs}/convergence_test_rainy_no_rain.jl (95%) rename examples/{elixir_rainy_euler_bubble_no_phase_change.jl => elixir_rainy_euler_bubble_no_rain.jl} (96%) diff --git a/examples/test_elixirs/convergence_test_rainy_dry.jl b/examples/convergence_test_elixirs/convergence_test_rainy_dry.jl similarity index 100% rename from examples/test_elixirs/convergence_test_rainy_dry.jl rename to examples/convergence_test_elixirs/convergence_test_rainy_dry.jl diff --git a/examples/test_elixirs/convergence_test_rainy_no_rain.jl b/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl similarity index 95% rename from examples/test_elixirs/convergence_test_rainy_no_rain.jl rename to examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl index 22649638..f1c14313 100644 --- a/examples/test_elixirs/convergence_test_rainy_no_rain.jl +++ b/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl @@ -2,7 +2,7 @@ using OrdinaryDiffEq using Trixi using TrixiAtmo using TrixiAtmo: saturation_vapour_pressure, saturation_vapour_pressure_derivative, - saturation_residual, saturation_residual_jacobian + saturation_residual_custom, saturation_residual_jacobian_custom @@ -122,7 +122,7 @@ solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0, 0.0) coordinates_max = (2.0, 2.0) -cells_per_dimension = (8, 8) +cells_per_dimension = (12, 12) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) @@ -137,7 +137,7 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -analysis_interval = 1000 +analysis_interval = 10000 analysis_callback = AnalysisCallback(semi, interval = analysis_interval) alive_callback = AliveCallback(analysis_interval = analysis_interval) @@ -154,7 +154,7 @@ callbacks = CallbackSet(summary_callback, save_solution, stepsize_callback) -stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) +stage_limiter! = NonlinearSolveDG(saturation_residual_custom, saturation_residual_jacobian_custom, SVector(7, 8, 9), 1e-9) ############################################################################### # run the simulation diff --git a/examples/elixir_rainy_euler_bubble_no_phase_change.jl b/examples/elixir_rainy_euler_bubble_no_rain.jl similarity index 96% rename from examples/elixir_rainy_euler_bubble_no_phase_change.jl rename to examples/elixir_rainy_euler_bubble_no_rain.jl index dc544249..a23e6eb1 100644 --- a/examples/elixir_rainy_euler_bubble_no_phase_change.jl +++ b/examples/elixir_rainy_euler_bubble_no_rain.jl @@ -1,8 +1,8 @@ using OrdinaryDiffEq using Trixi using TrixiAtmo -using TrixiAtmo: source_terms_no_phase_change, saturation_residual, - saturation_residual_jacobian, NonlinearSolveDG +using TrixiAtmo: source_terms_no_phase_change, saturation_residual_custom, + saturation_residual_jacobian_custom, NonlinearSolveDG using NLsolve: nlsolve @@ -241,7 +241,7 @@ boundary_conditions = (x_neg = boundary_condition_slip_wall, y_neg = boundary_condition_slip_wall, y_pos = boundary_condition_slip_wall) -polydeg = 4 +polydeg = 3 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_lax_friedrichs @@ -263,7 +263,7 @@ semi = SemidiscretizationHyperbolic(mesh, equations, ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 1020.0) +tspan = (0.0, 10.0) ode = semidiscretize(semi, tspan) @@ -275,9 +275,9 @@ analysis_interval = 1000 analysis_callback = AnalysisCallback(semi, interval = analysis_interval, extra_analysis_errors = (:entropy_conservation_error,)) -alive_callback = AliveCallback(analysis_interval = 100) +alive_callback = AliveCallback(analysis_interval = 1000) -save_solution = SaveSolutionCallback(interval = 100, +save_solution = SaveSolutionCallback(interval = 1000, save_initial_solution = true, save_final_solution = true, output_directory = "out", @@ -291,7 +291,7 @@ callbacks = CallbackSet(summary_callback, save_solution, stepsize_callback) -stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) +stage_limiter! = NonlinearSolveDG(saturation_residual_custom, saturation_residual_jacobian_custom, SVector(7, 8, 9), 1e-9) ############################################################################### # run the simulation From 671f4886c7c52b757691a86723a7767d11a2e5d2 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:45:51 +0200 Subject: [PATCH 052/115] custom newton method for much better performance --- src/callbacks_stage/nonlinear_solve_dg2d.jl | 43 ++++++++++- src/equations/compressible_rainy_euler_2d.jl | 78 ++++++++++++++++++++ 2 files changed, 118 insertions(+), 3 deletions(-) diff --git a/src/callbacks_stage/nonlinear_solve_dg2d.jl b/src/callbacks_stage/nonlinear_solve_dg2d.jl index f421829d..f4014074 100644 --- a/src/callbacks_stage/nonlinear_solve_dg2d.jl +++ b/src/callbacks_stage/nonlinear_solve_dg2d.jl @@ -1,25 +1,62 @@ -using NLsolve +#using NLsolve using Trixi: get_node_vars, @batch +using LinearAlgebra +using StaticArrays +### Warning: Hardcoded for performance reasons. +### will not work with differently structured problems + @muladd begin function nonlinear_solve_dg_2d!(u, residual, jacobian, variables_index_vector, tolerance, equations, dg::DGSEM, cache) + max_iterations = 50 + + # iterate over every DGSEM element @batch for element in eachelement(dg, cache) + # allocate static arrays for every thread + res_vector = SVector{3, Real} + jac_matrix = SMatrix{3, 3, Real} + # iterate over every node for j in eachnode(dg), i in eachnode(dg) u_node = get_node_vars(u, equations, dg, i, j, element) - initial_guess = u_node[variables_index_vector] + initial_guess = SVector(u_node[7], u_node[8], u_node[9]) + + # define residual function and jacobian function at the given node + res = residual(u_node, equations) + jac = jacobian(u_node, equations) + + # newton method + for iteration in range(1, max_iterations) + res_vector = res(res_vector, initial_guess) + + if (maximum(abs.(res_vector)) < tolerance) + break + end + + jac_matrix = jac(jac_matrix, initial_guess) + initial_guess += - jac_matrix \ res_vector + + #= warnings seem to have allocations... + if iteration == max_iterations + @warn "newton method: tolerance not met" + end + =# + end + + #= Old slow solver nl_sol = nlsolve(residual(u_node, equations), jacobian(u_node, equations), initial_guess, ftol = tolerance, method = :newton).zero + =# # similar to set_node_vars! for index in eachindex(variables_index_vector) - u[variables_index_vector[index], i, j, element] = nl_sol[index] + u[variables_index_vector[index], i, j, element] = initial_guess[index] end end end diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 0a69e649..4afac700 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -627,6 +627,44 @@ end end +@inline function saturation_residual_custom(u, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp + ref_temp = equations.ref_temperature + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + + # energy density + energy = energy_density(u, equations) + + function saturation_residual!(residual, guess) + residual1 = (c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain)) * (guess[3] - ref_temp) + residual1 += guess[1] * (L_ref - R_v * ref_temp) + residual1 -= (energy - rho * 0.5 * (v1^2 + v2^2)) + + residual2 = min(saturation_vapour_pressure(guess[3], equations) / (R_v * guess[3]), rho_moist) + residual2 -= guess[1] + residual2 *= 1e7 + + residual3 = rho_moist + residual3 -= guess[1] + guess[2] + residual3 *= 1e7 + + residual = SVector(residual1, residual2, residual3) + end + + return saturation_residual! +end + + @inline function saturation_residual_jacobian(u, equations::CompressibleRainyEulerEquations2D) # constants c_l = equations.c_liquid_water @@ -665,4 +703,44 @@ end end +@inline function saturation_residual_jacobian_custom(u, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp + ref_temp = equations.ref_temperature + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + function jacobian!(J, guess) + svp = saturation_vapour_pressure(guess[3], equations) + d_dtemp_svp = saturation_vapour_pressure_derivative(guess[3], equations) + + J_11 = c_vv * (guess[3] - ref_temp) + L_ref - R_v * ref_temp + J_12 = c_l * (guess[3] - ref_temp) + J_13 = c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain) + + J_21 = -1e7 + J_22 = 0.0 + + if (svp / (R_v * guess[3]) < rho_moist) + J_23 = (d_dtemp_svp * guess[3] - svp) / (R_v * guess[3]^2) * 1e7 + else + J_23 = 0.0 + end + + J_31 = -1e7 + J_32 = -1e7 + J_33 = 0.0 + + J = SMatrix{3, 3}(J_11, J_21, J_31, J_12, J_22, J_32, J_13, J_23, J_33) + end + + return jacobian! +end + + end # muladd end \ No newline at end of file From 92f3e49eb8c26db5e0d5d7cc62c91c47957bd94a Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 8 Oct 2024 02:17:09 +0200 Subject: [PATCH 053/115] testing --- .../elixir_moist_euler_moist_bubble_lucas.jl | 12 +++++----- .../convergence_test_rainy_dry.jl | 2 +- .../convergence_test_rainy_no_rain.jl | 18 +++++++-------- examples/elixir_rainy_euler_bubble_no_rain.jl | 23 ++++++++++--------- 4 files changed, 27 insertions(+), 28 deletions(-) diff --git a/examples/comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl b/examples/comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl index 2caddac5..70c7f021 100644 --- a/examples/comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl +++ b/examples/comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl @@ -242,12 +242,12 @@ source_term = source_terms_moist_bubble polydeg = 3 basis = LobattoLegendreBasis(polydeg) -surface_flux = flux_LMARS -volume_flux = flux_chandrashekar +#surface_flux = flux_LMARS +#volume_flux = flux_chandrashekar -volume_integral = VolumeIntegralFluxDifferencing(volume_flux) - -solver = DGSEM(basis, surface_flux, volume_integral) +#volume_integral = VolumeIntegralFluxDifferencing(volume_flux) +surface_flux = flux_lax_friedrichs +solver = DGSEM(basis, surface_flux)#, volume_integral) coordinates_min = (0.0, 0.0) coordinates_max = (20000.0, 10000.0) @@ -268,7 +268,7 @@ semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 10.0) +tspan = (0.0, 1000.0) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() diff --git a/examples/convergence_test_elixirs/convergence_test_rainy_dry.jl b/examples/convergence_test_elixirs/convergence_test_rainy_dry.jl index 09d234d0..40ca7f83 100644 --- a/examples/convergence_test_elixirs/convergence_test_rainy_dry.jl +++ b/examples/convergence_test_elixirs/convergence_test_rainy_dry.jl @@ -110,4 +110,4 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), summary_callback() # print the timer summary # For copy-paste convenience: -#convergence_test("TrixiAtmo.jl/examples/test_elixirs/convergence_test_rainy_dry.jl", 4) \ No newline at end of file +#convergence_test("TrixiAtmo.jl/examples/convergence_test_elixirs/convergence_test_rainy_dry.jl", 4) \ No newline at end of file diff --git a/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl b/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl index f1c14313..6703e4da 100644 --- a/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl +++ b/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl @@ -12,7 +12,6 @@ function initial_condition_convergence_test_rainy_no_rain(x, t, equations::Compr c_vd = equations.c_dry_air_const_volume c_vv = equations.c_vapour_const_volume R_v = equations.R_vapour - ref_temp = equations.ref_temperature ref_L = equations.ref_latent_heat_vap_temp # define rho like in dry convergence test @@ -24,15 +23,15 @@ function initial_condition_convergence_test_rainy_no_rain(x, t, equations::Compr rho = c + A * sin(ω * (x[1] + x[2] - t)) # define variables of rho - temperature = rho + ref_temp + temperature = rho rho_vapour = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) rho_cloud = rho / c_l rho_moist = rho_vapour + rho_cloud rho_dry = rho - rho_moist # define matching energydensity with v1 := 1 and v2 := 1 , initially - energy = (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud) * (temperature - ref_temp) - energy += rho_vapour * (ref_L - R_v * ref_temp) + rho + energy = (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud) * temperature + energy += rho_vapour * ref_L + rho return SVector(rho_dry, rho_moist, 0.0, rho, rho, energy, rho_vapour, rho_cloud, temperature) end @@ -45,7 +44,6 @@ function source_terms_convergence_test_rainy_no_rain(u, x, t, equations::Compres c_vv = equations.c_vapour_const_volume R_d = equations.R_dry_air R_v = equations.R_vapour - ref_temp = equations.ref_temperature ref_L = equations.ref_latent_heat_vap_temp # define rho like initial condition @@ -60,7 +58,7 @@ function source_terms_convergence_test_rainy_no_rain(u, x, t, equations::Compres rho_t = -rho_x # define variables of rho - temperature = rho + ref_temp + temperature = rho sat_vap_p = saturation_vapour_pressure(temperature, equations) rho_vapour = sat_vap_p / (R_v * temperature) rho_cloud = rho / c_l @@ -85,11 +83,11 @@ function source_terms_convergence_test_rainy_no_rain(u, x, t, equations::Compres energy_t = (c_vd * rho_dry_t + c_vv * rho_vapour_t + rho_t) * rho energy_t += (c_vd * rho_dry + c_vv * rho_vapour + rho ) * rho_t - energy_t += rho_vapour_t * (ref_L - R_v * ref_temp) + rho_t + energy_t += rho_vapour_t * ref_L + rho_t energy_x = (c_vd * rho_dry_x + c_vv * rho_vapour_x + rho_x) * rho energy_x += (c_vd * rho_dry + c_vv * rho_vapour + rho ) * rho_x - energy_x += rho_vapour_x * (ref_L - R_v * ref_temp) + rho_x + energy_x += rho_vapour_x * ref_L + rho_x pressure_x = (rho_dry_x * R_d + rho_vapour_x * R_v) * temperature pressure_x += (rho_dry * R_d + rho_vapour * R_v) * rho_x # temperature_x = rho_x @@ -122,7 +120,7 @@ solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0, 0.0) coordinates_max = (2.0, 2.0) -cells_per_dimension = (12, 12) +cells_per_dimension = (16, 16) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) @@ -165,4 +163,4 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limite summary_callback() # print the timer summary # For copy-paste convenience: -#convergence_test("TrixiAtmo.jl/examples/test_elixirs/convergence_test_rainy_no_rain.jl", 3) \ No newline at end of file +#convergence_test("TrixiAtmo.jl/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl", 3) \ No newline at end of file diff --git a/examples/elixir_rainy_euler_bubble_no_rain.jl b/examples/elixir_rainy_euler_bubble_no_rain.jl index a23e6eb1..25674e7b 100644 --- a/examples/elixir_rainy_euler_bubble_no_rain.jl +++ b/examples/elixir_rainy_euler_bubble_no_rain.jl @@ -1,8 +1,9 @@ using OrdinaryDiffEq using Trixi using TrixiAtmo -using TrixiAtmo: source_terms_no_phase_change, saturation_residual_custom, - saturation_residual_jacobian_custom, NonlinearSolveDG +using TrixiAtmo: source_terms_no_phase_change, saturation_residual, + saturation_residual_jacobian, NonlinearSolveDG, + cons2eq_pot_temp using NLsolve: nlsolve @@ -156,7 +157,7 @@ function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) p_loc = p_0 * (R_d * rho_theta / p_0)^(1 / (1 - kappa_M)) T_loc = p_loc / (R_d * rho_d + R_v * rho_qv) - rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * (T_loc - 273.15) + (L_00 - R_v * 273.15) * rho_qv + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv #=p_v = rho_qv * R_v * T_loc p_d = p_loc - p_v @@ -216,7 +217,7 @@ function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) rho_theta = rho * θ_dens_new * (p_loc / p_0)^(kappa - kappa_M) - rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * (T_loc - 273.15) + (L_00 - R_v * 273.15) * rho_qv + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv end return SVector(rho, rho_e, rho_qv, rho_ql, T_loc) end @@ -236,8 +237,8 @@ end equations = CompressibleRainyEulerEquations2D() -boundary_conditions = (x_neg = boundary_condition_slip_wall, - x_pos = boundary_condition_slip_wall, +boundary_conditions = (x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, y_neg = boundary_condition_slip_wall, y_pos = boundary_condition_slip_wall) @@ -251,9 +252,9 @@ solver = DGSEM(basis, surface_flux) coordinates_min = ( 0.0, 0.0) coordinates_max = (20_000.0, 10_000.0) -cells_per_dimension = (64, 32) +cells_per_dimension = (200, 100) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, - periodicity = (false, false)) + periodicity = (true, false)) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_moist, solver, @@ -263,7 +264,7 @@ semi = SemidiscretizationHyperbolic(mesh, equations, ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 10.0) +tspan = (0.0, 1000.0) ode = semidiscretize(semi, tspan) @@ -281,7 +282,7 @@ save_solution = SaveSolutionCallback(interval = 1000, save_initial_solution = true, save_final_solution = true, output_directory = "out", - solution_variables = cons2prim) + solution_variables = cons2eq_pot_temp) stepsize_callback = StepsizeCallback(cfl = 1.0) @@ -291,7 +292,7 @@ callbacks = CallbackSet(summary_callback, save_solution, stepsize_callback) -stage_limiter! = NonlinearSolveDG(saturation_residual_custom, saturation_residual_jacobian_custom, SVector(7, 8, 9), 1e-9) +stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) ############################################################################### # run the simulation From 2bc47100ff5f4b1b36b9f6d4a4b5db5016055fc3 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 8 Oct 2024 02:18:03 +0200 Subject: [PATCH 054/115] added visualization function and modified nonlinear system setup structure --- src/callbacks_stage/nonlinear_solve_dg2d.jl | 35 +-- src/equations/compressible_rainy_euler_2d.jl | 227 ++++++++----------- 2 files changed, 107 insertions(+), 155 deletions(-) diff --git a/src/callbacks_stage/nonlinear_solve_dg2d.jl b/src/callbacks_stage/nonlinear_solve_dg2d.jl index f4014074..94f6b14d 100644 --- a/src/callbacks_stage/nonlinear_solve_dg2d.jl +++ b/src/callbacks_stage/nonlinear_solve_dg2d.jl @@ -1,45 +1,34 @@ -#using NLsolve using Trixi: get_node_vars, @batch using LinearAlgebra using StaticArrays -### Warning: Hardcoded for performance reasons. -### will not work with differently structured problems - @muladd begin -function nonlinear_solve_dg_2d!(u, residual, jacobian, variables_index_vector, tolerance, equations, dg::DGSEM, cache) - - max_iterations = 50 +function nonlinear_solve_dg_2d!(u, residual, jacobian, variables_index_vector, tolerance, + equations::CompressibleRainyEulerEquations2D, dg::DGSEM, cache) + max_iterations = 20 # iterate over every DGSEM element @batch for element in eachelement(dg, cache) - # allocate static arrays for every thread - res_vector = SVector{3, Real} - jac_matrix = SMatrix{3, 3, Real} # iterate over every node for j in eachnode(dg), i in eachnode(dg) - u_node = get_node_vars(u, equations, dg, i, j, element) - initial_guess = SVector(u_node[7], u_node[8], u_node[9]) - - # define residual function and jacobian function at the given node - res = residual(u_node, equations) - jac = jacobian(u_node, equations) + u_node = get_node_vars(u, equations, dg, i, j, element) + guess = SVector(u_node[7], u_node[8], u_node[9]) # newton method for iteration in range(1, max_iterations) - res_vector = res(res_vector, initial_guess) + res_vector = residual(u_node, guess, equations) if (maximum(abs.(res_vector)) < tolerance) break end - jac_matrix = jac(jac_matrix, initial_guess) - initial_guess += - jac_matrix \ res_vector + jac_matrix = jacobian(u_node, guess, equations) + guess += - jac_matrix \ res_vector #= warnings seem to have allocations... if iteration == max_iterations @@ -47,16 +36,10 @@ function nonlinear_solve_dg_2d!(u, residual, jacobian, variables_index_vector, t end =# end - - #= Old slow solver - nl_sol = nlsolve(residual(u_node, equations), - jacobian(u_node, equations), - initial_guess, ftol = tolerance, method = :newton).zero - =# # similar to set_node_vars! for index in eachindex(variables_index_vector) - u[variables_index_vector[index], i, j, element] = initial_guess[index] + u[variables_index_vector[index], i, j, element] = guess[index] end end end diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 4afac700..84e06dd3 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -82,24 +82,6 @@ end -### varnames ### - -varnames(::typeof(cons2cons), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_moist", "rho_rain", - "rho_v1", "rho_v2", - "energy_density", - "rho_vapour_h", "rho_cloud_h", - "temperature_h") - - -varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_moist", "rho_rain", - "v1", "v2", - "energy_density", - "rho_vapour", "rho_cloud", - "temperature") - - - - ### conversion ### @inline function cons2prim(u, equations::CompressibleRainyEulerEquations2D) @@ -125,6 +107,52 @@ end end +# adapted from compressible_moist_euler_2d.jl +@inline function cons2eq_pot_temp(u, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_pd = equations.c_dry_air_const_pressure + c_pv = equations.c_vapour_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + ref_p = equations.ref_pressure + ref_temp = equations.ref_temperature + ref_L = equations.ref_latent_heat_vap_temp + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + + # energy density + energy = energy_density(u, equations) + + # nonlinear system + rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) + + # pressure + p = pressure(u, equations) + + p_v = rho_vapour * R_v * temperature + p_d = p - p_v + T_C = temperature - ref_temp + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + H = p_v / p_vs + r_v = rho_vapour / rho_dry + r_c = rho_cloud / rho_dry + r_r = rho_rain / rho_dry + L_v = ref_L + (c_pv - c_l) * temperature + c_p = c_pd + r_v * c_pv + (r_c + r_r) * c_l + + # equivalent potential temperature + eq_pot = (temperature * (ref_p / p_d)^(R_d / c_p) * H^(-r_v * R_v / c_p) * + exp(L_v * r_v * inv(c_p * temperature))) + + return SVector(rho, r_v, r_c, r_r, v1, v2, eq_pot) +end + + @inline function cons2nonlinearsystemsol(u, equations::CompressibleRainyEulerEquations2D) # constants c_vd = equations.c_dry_air_const_volume @@ -188,6 +216,27 @@ end +### varnames ### + +varnames(::typeof(cons2cons), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_moist", "rho_rain", + "rho_v1", "rho_v2", + "energy_density", + "rho_vapour_h", "rho_cloud_h", + "temperature_h") + + +varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_moist", "rho_rain", + "v1", "v2", + "energy_density", + "rho_vapour", "rho_cloud", + "temperature") + +varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquations2D) = ("rho", "r_vapour", + "r_cloud", "r_rain", + "v1", "v2", "eq_pot_temp") + + + ### physics variables ### @inline function densities(u, equations::CompressibleRainyEulerEquations2D) @@ -482,7 +531,7 @@ end # name needed variables v1, v2, v_sound, v_r = cons2speeds(u, equations) - return abs(v1) + v_sound, abs(v2) + v_sound + abs(v_r) + return SVector((abs(v1) + v_sound), (abs(v2) + v_sound + abs(v_r))) end @@ -591,14 +640,13 @@ end ### Nonlinear System Residual ### # in preparation for a callback to solve the nonlinear system -@inline function saturation_residual(u, equations::CompressibleRainyEulerEquations2D) +@inline function saturation_residual(u, guess, equations::CompressibleRainyEulerEquations2D) # constants c_l = equations.c_liquid_water c_vd = equations.c_dry_air_const_volume c_vv = equations.c_vapour_const_volume R_v = equations.R_vapour L_ref = equations.ref_latent_heat_vap_temp - ref_temp = equations.ref_temperature # densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) @@ -609,137 +657,58 @@ end # energy density energy = energy_density(u, equations) - function saturation_residual!(residual, guess) - residual[1] = (c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain)) * (guess[3] - ref_temp) - residual[1] += guess[1] * (L_ref - R_v * ref_temp) - residual[1] -= (energy - rho * 0.5 * (v1^2 + v2^2)) + # define residual + residual1 = (c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain)) * guess[3] + residual1 += guess[1] * L_ref + residual1 -= (energy - rho * 0.5 * (v1^2 + v2^2)) - residual[2] = min(saturation_vapour_pressure(guess[3], equations) / (R_v * guess[3]), rho_moist) - residual[2] -= guess[1] - residual[2] *= 1e7 + residual2 = min(saturation_vapour_pressure(guess[3], equations) / (R_v * guess[3]), rho_moist) + residual2 -= guess[1] + residual2 *= 1e7 - residual[3] = rho_moist - residual[3] -= guess[1] + guess[2] - residual[3] *= 1e7 - end + residual3 = rho_moist + residual3 -= guess[1] + guess[2] + residual3 *= 1e7 - return saturation_residual! + return SVector(residual1, residual2, residual3) end -@inline function saturation_residual_custom(u, equations::CompressibleRainyEulerEquations2D) - # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_v = equations.R_vapour - L_ref = equations.ref_latent_heat_vap_temp - ref_temp = equations.ref_temperature - - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - - # velocity - v1, v2 = velocities(u, rho_inv, equations) - # energy density - energy = energy_density(u, equations) - - function saturation_residual!(residual, guess) - residual1 = (c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain)) * (guess[3] - ref_temp) - residual1 += guess[1] * (L_ref - R_v * ref_temp) - residual1 -= (energy - rho * 0.5 * (v1^2 + v2^2)) - - residual2 = min(saturation_vapour_pressure(guess[3], equations) / (R_v * guess[3]), rho_moist) - residual2 -= guess[1] - residual2 *= 1e7 - - residual3 = rho_moist - residual3 -= guess[1] + guess[2] - residual3 *= 1e7 - - residual = SVector(residual1, residual2, residual3) - end - - return saturation_residual! -end - - -@inline function saturation_residual_jacobian(u, equations::CompressibleRainyEulerEquations2D) +@inline function saturation_residual_jacobian(u, guess, equations::CompressibleRainyEulerEquations2D) # constants c_l = equations.c_liquid_water c_vd = equations.c_dry_air_const_volume c_vv = equations.c_vapour_const_volume R_v = equations.R_vapour L_ref = equations.ref_latent_heat_vap_temp - ref_temp = equations.ref_temperature # densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - function jacobian!(J, guess) - svp = saturation_vapour_pressure(guess[3], equations) - d_dtemp_svp = saturation_vapour_pressure_derivative(guess[3], equations) + # saturation + svp = saturation_vapour_pressure(guess[3], equations) + svp_t = saturation_vapour_pressure_derivative(guess[3], equations) - J[1, 1] = c_vv * (guess[3] - ref_temp) + L_ref - R_v * ref_temp - J[1, 2] = c_l * (guess[3] - ref_temp) - J[1, 3] = c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain) + # define jacobian + J_11 = c_vv * guess[3] + L_ref + J_12 = c_l * guess[3] + J_13 = c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain) - J[2, 1] = -1e7 - J[2, 2] = 0.0 + J_21 = -1e7 + J_22 = 0.0 - if (svp / (R_v * guess[3]) < rho_moist) - J[2, 3] = (d_dtemp_svp * guess[3] - svp) / (R_v * guess[3]^2) * 1e7 - else - J[2, 3] = 0.0 - end - - J[3, 1] = -1e7 - J[3, 2] = -1e7 - J[3, 3] = 0.0 + if (svp / (R_v * guess[3]) < rho_moist) + J_23 = (svp_t * guess[3] - svp) / (R_v * guess[3]^2) * 1e7 + else + J_23 = 0.0 end - return jacobian! -end - - -@inline function saturation_residual_jacobian_custom(u, equations::CompressibleRainyEulerEquations2D) - # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_v = equations.R_vapour - L_ref = equations.ref_latent_heat_vap_temp - ref_temp = equations.ref_temperature - - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - - function jacobian!(J, guess) - svp = saturation_vapour_pressure(guess[3], equations) - d_dtemp_svp = saturation_vapour_pressure_derivative(guess[3], equations) - - J_11 = c_vv * (guess[3] - ref_temp) + L_ref - R_v * ref_temp - J_12 = c_l * (guess[3] - ref_temp) - J_13 = c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain) - - J_21 = -1e7 - J_22 = 0.0 - - if (svp / (R_v * guess[3]) < rho_moist) - J_23 = (d_dtemp_svp * guess[3] - svp) / (R_v * guess[3]^2) * 1e7 - else - J_23 = 0.0 - end - - J_31 = -1e7 - J_32 = -1e7 - J_33 = 0.0 - - J = SMatrix{3, 3}(J_11, J_21, J_31, J_12, J_22, J_32, J_13, J_23, J_33) - end + J_31 = -1e7 + J_32 = -1e7 + J_33 = 0.0 - return jacobian! + return SMatrix{3, 3}(J_11, J_21, J_31, J_12, J_22, J_32, J_13, J_23, J_33) end From e3a7c610e4d31a00fe81027f67757bdb299788c5 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 15 Oct 2024 17:18:15 +0200 Subject: [PATCH 055/115] fixes and updates --- .../convergence_test_rainy_no_rain.jl | 26 ++++++++--------- examples/elixir_rainy_euler_bubble.jl | 29 ++++++++++++++++++- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl b/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl index 6703e4da..3c24df0f 100644 --- a/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl +++ b/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl @@ -2,7 +2,7 @@ using OrdinaryDiffEq using Trixi using TrixiAtmo using TrixiAtmo: saturation_vapour_pressure, saturation_vapour_pressure_derivative, - saturation_residual_custom, saturation_residual_jacobian_custom + saturation_residual, saturation_residual_jacobian @@ -23,9 +23,9 @@ function initial_condition_convergence_test_rainy_no_rain(x, t, equations::Compr rho = c + A * sin(ω * (x[1] + x[2] - t)) # define variables of rho - temperature = rho + temperature = rho + 250.0 rho_vapour = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) - rho_cloud = rho / c_l + rho_cloud = rho / c_l * 4000 rho_moist = rho_vapour + rho_cloud rho_dry = rho - rho_moist @@ -58,10 +58,10 @@ function source_terms_convergence_test_rainy_no_rain(u, x, t, equations::Compres rho_t = -rho_x # define variables of rho - temperature = rho + temperature = rho + 250.0 sat_vap_p = saturation_vapour_pressure(temperature, equations) rho_vapour = sat_vap_p / (R_v * temperature) - rho_cloud = rho / c_l + rho_cloud = rho / c_l * 4000 rho_moist = rho_vapour + rho_cloud rho_dry = rho - rho_moist @@ -72,8 +72,8 @@ function source_terms_convergence_test_rainy_no_rain(u, x, t, equations::Compres rho_vapour_t = (sat_vap_p_t * temperature - rho_t * sat_vap_p) / (R_v * temperature^2) rho_vapour_x = (sat_vap_p_x * temperature - rho_x * sat_vap_p) / (R_v * temperature^2) - rho_cloud_t = rho_t / c_l - rho_cloud_x = rho_x / c_l + rho_cloud_t = rho_t / c_l * 4000 + rho_cloud_x = rho_x / c_l * 4000 rho_moist_t = rho_vapour_t + rho_cloud_t rho_moist_x = rho_vapour_x + rho_cloud_x @@ -81,12 +81,12 @@ function source_terms_convergence_test_rainy_no_rain(u, x, t, equations::Compres rho_dry_t = rho_t - rho_moist_t rho_dry_x = rho_x - rho_moist_x - energy_t = (c_vd * rho_dry_t + c_vv * rho_vapour_t + rho_t) * rho - energy_t += (c_vd * rho_dry + c_vv * rho_vapour + rho ) * rho_t + energy_t = (c_vd * rho_dry_t + c_vv * rho_vapour_t + c_l * rho_cloud_t) * temperature + energy_t += (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud ) * rho_t energy_t += rho_vapour_t * ref_L + rho_t - energy_x = (c_vd * rho_dry_x + c_vv * rho_vapour_x + rho_x) * rho - energy_x += (c_vd * rho_dry + c_vv * rho_vapour + rho ) * rho_x + energy_x = (c_vd * rho_dry_x + c_vv * rho_vapour_x + c_l * rho_cloud_x) * temperature + energy_x += (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud ) * rho_x energy_x += rho_vapour_x * ref_L + rho_x pressure_x = (rho_dry_x * R_d + rho_vapour_x * R_v) * temperature @@ -140,7 +140,7 @@ analysis_callback = AnalysisCallback(semi, interval = analysis_interval) alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval = analysis_interval, +save_solution = SaveSolutionCallback(interval = 1000, save_initial_solution = true, save_final_solution = true, solution_variables = cons2prim) @@ -152,7 +152,7 @@ callbacks = CallbackSet(summary_callback, save_solution, stepsize_callback) -stage_limiter! = NonlinearSolveDG(saturation_residual_custom, saturation_residual_jacobian_custom, SVector(7, 8, 9), 1e-9) +stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) ############################################################################### # run the simulation diff --git a/examples/elixir_rainy_euler_bubble.jl b/examples/elixir_rainy_euler_bubble.jl index 426f1dc1..482ddc85 100644 --- a/examples/elixir_rainy_euler_bubble.jl +++ b/examples/elixir_rainy_euler_bubble.jl @@ -1,9 +1,36 @@ using OrdinaryDiffEq using Trixi using TrixiAtmo -using TrixiAtmo: source_terms_rainy +using TrixiAtmo: source_terms_rainy, saturation_residual, + saturation_residual_jacobian, NonlinearSolveDG, + cons2eq_pot_temp, saturation_vapour_pressure +using NLsolve: nlsolve +## Hydrostatic base state + +function initial_constraint_residual(guess, equations::CompressibleRainyEulerEquations2D) + # rho_dry, rho_vapour, temperature = guess + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_p = equations.ref_pressure + surf_p = 8.5e4 # surface pressure + humidity_rel0 = 0.2 # hydrostatic relative humidity + + rho_vs = saturation_vapour_pressure(guess[3]) / (R_v * guess[3]) + + res1 = surf_p - guess[3] * (guess[1] * R_d + guess[2] * R_v) + res2 = theta_d0 - guess[3] * (ref_p / surf_p)^(R_d / c_pd) + res3 = rho_vs * (guess[1] + guess[2] / eps) * humidity_rel0 + res3 -= guess[2] * (guess[1] + rho_vs / eps) + + return SVector(res1, res2, 1000 * res3) +end + + +## Initial condition function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerEquations2D) #TODO From 098f868ab312c493a8ceab7a293ddc2d6d11b140 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 15 Oct 2024 17:19:13 +0200 Subject: [PATCH 056/115] fixes and updates --- src/equations/compressible_rainy_euler_2d.jl | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 84e06dd3..915b9687 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -143,13 +143,13 @@ end r_c = rho_cloud / rho_dry r_r = rho_rain / rho_dry L_v = ref_L + (c_pv - c_l) * temperature - c_p = c_pd + r_v * c_pv + (r_c + r_r) * c_l + c_p = c_pd + (r_v + r_c + r_r) * c_l # equivalent potential temperature eq_pot = (temperature * (ref_p / p_d)^(R_d / c_p) * H^(-r_v * R_v / c_p) * exp(L_v * r_v * inv(c_p * temperature))) - return SVector(rho, r_v, r_c, r_r, v1, v2, eq_pot) + return SVector(rho, r_v, r_c, r_r, v1, v2, eq_pot, p) end @@ -233,7 +233,8 @@ varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquations2D) = ("rho", "r_vapour", "r_cloud", "r_rain", - "v1", "v2", "eq_pot_temp") + "v1", "v2", "eq_pot_temp", + "pressure") @@ -430,7 +431,7 @@ end f5 = rho * v2 * v2 + p - rho_rain * v_r * v2 # "energy" - f6 = (energy + p) * v2 - (c_l * (temperature - ref_temp) + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r + f6 = (energy + p) * v2 - (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r end return SVector(f1, f2, f3, f4, f5, f6, @@ -474,7 +475,7 @@ end f5 = rho * v_normal * v2 + p * normal_direction[2] - rho_rain * v_r_normal * v2 # "energy" - f6 = (energy + p) * v_normal - (c_l * (temperature - ref_temp) + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r_normal + f6 = (energy + p) * v_normal - (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r_normal return SVector(f1, f2, f3, f4, f5, f6, 0.0, 0.0, 0.0) @@ -499,7 +500,7 @@ end rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) - # source terms phase change + # source terms phase change #TODO no ref_temp? S_evaporation = (3.86e-3 - 9.41e-5 * (temperature - ref_temp)) * (1 + 9.1 * rho_rain^(0.1875)) S_evaporation *= (rho_vs - rho_vapour) * rho_rain^(0.5) S_auto_conversion = 0.001 * rho_cloud From c7897c7e0f5e5cc877a2376ad1423bbfac65297e Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Sat, 19 Oct 2024 22:26:28 +0200 Subject: [PATCH 057/115] added flux LMARS and volume flux chandrashekar --- examples/elixir_rainy_euler_bubble_no_rain.jl | 14 +- src/equations/compressible_rainy_euler_2d.jl | 138 ++++++++++++++++++ 2 files changed, 147 insertions(+), 5 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_no_rain.jl b/examples/elixir_rainy_euler_bubble_no_rain.jl index 25674e7b..ec5b8711 100644 --- a/examples/elixir_rainy_euler_bubble_no_rain.jl +++ b/examples/elixir_rainy_euler_bubble_no_rain.jl @@ -3,7 +3,7 @@ using Trixi using TrixiAtmo using TrixiAtmo: source_terms_no_phase_change, saturation_residual, saturation_residual_jacobian, NonlinearSolveDG, - cons2eq_pot_temp + cons2eq_pot_temp, flux_LMARS, flux_chandrashekar using NLsolve: nlsolve @@ -242,17 +242,21 @@ boundary_conditions = (x_neg = boundary_condition_periodic, y_neg = boundary_condition_slip_wall, y_pos = boundary_condition_slip_wall) -polydeg = 3 +polydeg = 4 basis = LobattoLegendreBasis(polydeg) -surface_flux = flux_lax_friedrichs +#surface_flux = flux_lax_friedrichs +surface_flux = flux_LMARS +volume_flux = flux_chandrashekar -solver = DGSEM(basis, surface_flux) +volume_integral = VolumeIntegralFluxDifferencing(volume_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = ( 0.0, 0.0) coordinates_max = (20_000.0, 10_000.0) -cells_per_dimension = (200, 100) +cells_per_dimension = (64, 32) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = (true, false)) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 915b9687..d89835f2 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -713,4 +713,142 @@ end end + +# fluxes adapted from compressible_moist_euler_2d.jl + +# Low Mach number approximate Riemann solver (LMARS) from +# X. Chen, N. Andronova, B. Van Leer, J. E. Penner, J. P. Boyd, C. Jablonowski, S. +# Lin, A Control-Volume Model of the Compressible Euler Equations with a Vertical Lagrangian +# Coordinate Monthly Weather Review Vol. 141.7, pages 2526–2544, 2013, +# https://journals.ametsoc.org/view/journals/mwre/141/7/mwr-d-12-00129.1.xml. +@inline function flux_LMARS(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) + # constants + a = 360.0 # TODO try with different speeds of sound + #a = max(speed_of_sound(u_ll, equations)[1], speed_of_sound(u_rr, equations)[1]) + + # densities + rho_dry_ll, rho_moist_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) + rho_dry_rr, rho_moist_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) + + # pressure + p_ll = pressure(u_ll, equations) + p_rr = pressure(u_rr, equations) + + # velocities + v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) + v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) + + v_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] + v_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] + norm_ = norm(normal_direction) + + # diffusion parameter 0.0 < beta <= 1.0 + beta = 1.0 + + # interface flux components + rho = 0.5 * (rho_ll + rho_rr) + p_interface = 0.5 * (p_ll + p_rr) - beta * 0.5 * a * rho * (v_rr - v_ll) / norm_ + v_interface = 0.5 * (v_ll + v_rr) - beta * 1 / (2 * a * rho) * (p_rr - p_ll) * norm_ + + if (v_interface > 0) + f1, f2, f3, f4, f5, f6, _, _, _ = u_ll * v_interface + f6 += p_ll * v_interface + f7 = u_ll[7] + f8 = u_ll[8] + f9 = u_ll[9] + else + f1, f2, f3, f4, f5, f6, _, _, _ = u_rr * v_interface + f6 += p_rr * v_interface + f7 = u_rr[7] + f8 = u_rr[8] + f9 = u_rr[9] + end + + return SVector(f1, f2, f3, + f4 + p_interface * normal_direction[1], + f5 + p_interface * normal_direction[2], + f6, f7, f8, f9) +end + + +# Adjusted EC flux in a normal direction with R_q=0. This is based on +# A. Gouasmi, K. Duraisamy, S. M. Murman, Formulation of Entropy-Stable schemes for the +# multicomponent compressible Euler equations, 4 Feb 2020, doi:10.1016/j.cma.2020.112912, +# https://arxiv.org/abs/1904.00972 [math.NA]. +@inline function flux_chandrashekar(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + ref_L = equations.ref_latent_heat_vap_temp + R_q = 0.0 + + # densities and temperatures + rho_dry_ll, rho_moist_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) + rho_dry_rr, rho_moist_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) + rho_vapour_ll, rho_cloud_ll, temperature_ll = cons2nonlinearsystemsol(u_ll, equations) + rho_vapour_rr, rho_cloud_rr, temperature_rr = cons2nonlinearsystemsol(u_rr, equations) + + # velocities + v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) + v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) + + # mean values + rho_dry_mean = 0.0 + rho_vapour_mean = 0.0 + rho_cloud_mean = 0.0 + rho_rain_mean = 0.0 + inv_temperature_mean = 0.0 + + if (!(rho_dry_ll == 0.0) && !(rho_dry_rr == 0.0)) + rho_dry_mean = ln_mean(rho_dry_ll, rho_dry_rr) + end + + if (!(rho_vapour_ll == 0.0) && !(rho_vapour_rr == 0.0)) + rho_vapour_mean = ln_mean(rho_vapour_ll, rho_vapour_rr) + end + + if (!(rho_cloud_ll == 0.0) && !(rho_cloud_rr == 0.0)) + rho_cloud_mean = ln_mean(rho_cloud_ll, rho_cloud_rr) + end + + if (!(rho_rain_ll == 0.0) && !(rho_rain_rr == 0.0)) + rho_rain_mean = ln_mean(rho_rain_ll, rho_rain_rr) + end + + if (!(inv(temperature_ll) == 0.0) && !(inv(temperature_rr) == 0.0)) + inv_temperature_mean = inv_ln_mean(inv(temperature_ll), inv(temperature_rr)) + end + + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) + v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) + rho_dry_avg = 0.5 * (rho_dry_ll + rho_dry_rr) + rho_vapour_avg = 0.5 * (rho_vapour_ll + rho_vapour_rr) + rho_cloud_avg = 0.5 * (rho_cloud_ll + rho_cloud_rr) + rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) + inv_temperature_avg = 0.5 * (inv(temperature_ll) + inv(temperature_rr)) + v_dot_n_avg = normal_direction[1]*v1_avg + normal_direction[2]*v2_avg + + p_int = inv(inv_temperature_avg) * (R_d * rho_dry_avg + R_v * rho_vapour_avg + R_q * (rho_cloud_avg + rho_rain_avg)) + K_avg = 0.5 * (v1_square_avg + v2_square_avg) + + # assemble the flux + f_dry = rho_dry_mean * v_dot_n_avg + f_rain = rho_rain_mean * v_dot_n_avg + f_vapour = rho_vapour_mean * v_dot_n_avg + f_cloud = rho_cloud_mean * v_dot_n_avg + f_moist = (rho_vapour_mean + rho_cloud_mean) * v_dot_n_avg + f_rhov1 = (f_dry + f_moist + f_rain) * v1_avg + normal_direction[1] * p_int + f_rhov2 = (f_dry + f_moist + f_rain) * v2_avg + normal_direction[2] * p_int + f_energy = ((c_vd * inv_temperature_mean - K_avg) * f_dry + + (ref_L + c_vv * inv_temperature_mean - K_avg) * f_vapour + + (c_l * inv_temperature_mean - K_avg) * (f_cloud + f_rain) + v1_avg * f_rhov1 + v2_avg * f_rhov2) + + return SVector(f_dry, f_moist, f_rain, f_rhov1, f_rhov2, f_energy, 0.0, 0.0, 0.0) +end + end # muladd end \ No newline at end of file From e59eabe2054a0913ab89b71eed89d49aa1b0dc9c Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Sat, 19 Oct 2024 22:27:28 +0200 Subject: [PATCH 058/115] work in progress convergence test rain --- .../convergence_test_rainy.jl | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 examples/convergence_test_elixirs/convergence_test_rainy.jl diff --git a/examples/convergence_test_elixirs/convergence_test_rainy.jl b/examples/convergence_test_elixirs/convergence_test_rainy.jl new file mode 100644 index 00000000..508b9184 --- /dev/null +++ b/examples/convergence_test_elixirs/convergence_test_rainy.jl @@ -0,0 +1,185 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: saturation_vapour_pressure, saturation_vapour_pressure_derivative, + saturation_residual, saturation_residual_jacobian, + terminal_velocity_rain + + + +function initial_condition_convergence_test_rainy(x, t, equations::CompressibleRainyEulerEquations2D) + # needed constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour + ref_L = equations.ref_latent_heat_vap_temp + + # define rho like in dry convergence test + c = 2.0 + A = 0.1 + L = 2.0 + f = 1.0 / L + ω = 2 * pi * f + rho = c + A * sin(ω * (x[1] + x[2] - t)) + + # define variables of rho + temperature = rho + 250.0 + rho_vapour = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + rho_cloud = rho / c_l * 3000 + rho_rain = rho / c_l * 1000 + rho_moist = rho_vapour + rho_cloud + rho_dry = rho - rho_moist - rho_rain + + # define matching energydensity with v1 := 1 and v2 := 1 , initially + energy = (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * temperature + energy += rho_vapour * ref_L + rho + + return SVector(rho_dry, rho_moist, rho_rain, rho, rho, energy, rho_vapour, rho_cloud, temperature) +end + + +function source_terms_convergence_test_rainy(u, x, t, equations::CompressibleRainyEulerEquations2D) + # needed constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + ref_L = equations.ref_latent_heat_vap_temp + N_0 = equations.rain_water_distr + v_0 = equations.v_mean_rain + + # help constant for terminal rain velocity derivative ( \Gamma(4.5) / 6 ~= 1.9386213994279082 ) + c_help = v_0 * 1.9386213994279082 * (pi * N_0)^(-0.125) + + # define rho like initial condition + c = 2.0 + A = 0.1 + L = 2.0 + f = 1.0 / L + ω = 2 * pi * f + si, co = sincos(ω * (x[1] + x[2] - t)) + rho = c + A * si + rho_x = ω * A * co + rho_t = -rho_x + + # define variables of rho + temperature = rho + 250.0 + sat_vap_p = saturation_vapour_pressure(temperature, equations) + rho_vapour = sat_vap_p / (R_v * temperature) + rho_cloud = rho / c_l * 3000 + rho_rain = rho / c_l * 1000 + rho_moist = rho_vapour + rho_cloud + rho_dry = rho - rho_moist - rho_rain + vr = terminal_velocity_rain(rho_moist, rho_rain, equations) + + # define needed derivatives + sat_vap_p_t = rho_t * saturation_vapour_pressure_derivative(temperature, equations) + sat_vap_p_x = rho_x * saturation_vapour_pressure_derivative(temperature, equations) + + rho_vapour_t = (sat_vap_p_t * temperature - rho_t * sat_vap_p) / (R_v * temperature^2) + rho_vapour_x = (sat_vap_p_x * temperature - rho_x * sat_vap_p) / (R_v * temperature^2) + + rho_cloud_t = rho_t / c_l * 3000 + rho_cloud_x = rho_x / c_l * 3000 + + rho_rain_t = rho_t / c_l * 1000 + rho_rain_x = rho_x / c_l * 1000 + + rho_moist_t = rho_vapour_t + rho_cloud_t + rho_moist_x = rho_vapour_x + rho_cloud_x + + rho_dry_t = rho_t - rho_moist_t - rho_rain_t + rho_dry_x = rho_x - rho_moist_x - rho_rain_x + + energy_t = (c_vd * rho_dry_t + c_vv * rho_vapour_t + c_l * (rho_cloud_t + rho_rain_t)) * temperature + energy_t += (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * rho_t + energy_t += rho_vapour_t * ref_L + rho_t + + energy_x = (c_vd * rho_dry_x + c_vv * rho_vapour_x + c_l * (rho_cloud_x + rho_rain_x)) * temperature + energy_x += (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * rho_x + energy_x += rho_vapour_x * ref_L + rho_x + + pressure_x = (rho_dry_x * R_d + rho_vapour_x * R_v) * temperature + pressure_x += (rho_dry * R_d + rho_vapour * R_v) * rho_x # temperature_x = rho_x + + vr_x = c_help * 0.125 * ((rho_rain_x * rho_moist - rho_rain * rho_moist_x) / (rho_moist + rho_rain)^2) + vr_x *= (rho_rain / (rho_moist + rho_rain))^(-0.875) + + rhor_vr__x = rho_rain_x * vr + rho_rain * vr_x + + # calculate source terms for manufactured solution + # density + S_rho_dry = rho_dry_t + 2.0 * rho_dry_x + S_rho_moist = rho_moist_t + 2.0 * rho_moist_x + S_rho_rain = rho_rain_t + 2.0 * rho_rain_x - rhor_vr__x + + # "momentum" + S_rho_v1 = rho_x + pressure_x - rhor_vr__x + S_rho_v2 = rho_x + pressure_x - rhor_vr__x + + # "energy" + S_energy = energy_t + 2.0 * (energy_x + pressure_x) - (c_l * rho_x * rho_rain * vr) + S_energy -= (c_l * temperature + 1) * rhor_vr__x + + return SVector(S_rho_dry, S_rho_moist, S_rho_rain, S_rho_v1, S_rho_v2, S_energy, 0.0, 0.0, 0.0) +end + + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleRainyEulerEquations2D() + +initial_condition = initial_condition_convergence_test_rainy + +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) + +coordinates_min = (0.0, 0.0) +coordinates_max = (2.0, 2.0) + +cells_per_dimension = (16, 16) + +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_convergence_test_rainy) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 2.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 10000 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback) + +stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limiter!), + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); +summary_callback() # print the timer summary + +# For copy-paste convenience: +#convergence_test("TrixiAtmo.jl/examples/convergence_test_elixirs/convergence_test_rainy.jl", 3) \ No newline at end of file From 85ad006b96a75c5415e5c2a52f0fbcc0b2107c8e Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Sat, 26 Oct 2024 22:35:58 +0200 Subject: [PATCH 059/115] formatting, fixes and testing --- src/equations/compressible_rainy_euler_2d.jl | 29 ++++++++------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index d89835f2..f7fdb6c1 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -2,7 +2,7 @@ using Trixi using NLsolve: nlsolve import Trixi: varnames, cons2prim, cons2entropy, - flux, + flux, flux_chandrashekar, max_abs_speeds, max_abs_speed_naive, boundary_condition_slip_wall @@ -34,7 +34,7 @@ struct CompressibleRainyEulerEquations2D{RealT <: Real} <: AbstractCompressibleR # Gas constants: R_dry_air ::RealT R_vapour ::RealT - eps ::RealT #TODO not used? + eps ::RealT # Reference values: ref_saturation_pressure ::RealT @@ -221,15 +221,13 @@ end varnames(::typeof(cons2cons), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_moist", "rho_rain", "rho_v1", "rho_v2", "energy_density", - "rho_vapour_h", "rho_cloud_h", - "temperature_h") + "rho_vapour", "rho_cloud", "temperature") varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_moist", "rho_rain", "v1", "v2", "energy_density", - "rho_vapour", "rho_cloud", - "temperature") + "rho_vapour", "rho_cloud", "temperature") varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquations2D) = ("rho", "r_vapour", "r_cloud", "r_rain", @@ -456,7 +454,7 @@ end # normal velocities v_normal = v1 * normal_direction[1] + v2 * normal_direction[2] - v_r_normal = v_r * normal_direction[2] #TODO correct? + v_r_normal = v_r * normal_direction[2] # pressure p = pressure(u, equations) @@ -495,12 +493,14 @@ end # densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + rho_rain = max(rho_rain, 0.0) # test + # recover rho_vapour, rho_cloud, temperature from nonlinear system rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) - # source terms phase change #TODO no ref_temp? + # source terms phase change S_evaporation = (3.86e-3 - 9.41e-5 * (temperature - ref_temp)) * (1 + 9.1 * rho_rain^(0.1875)) S_evaporation *= (rho_vs - rho_vapour) * rho_rain^(0.5) S_auto_conversion = 0.001 * rho_cloud @@ -713,7 +713,7 @@ end end - +# TODO Careful with rain != 0.0, double check the fluxes! # fluxes adapted from compressible_moist_euler_2d.jl # Low Mach number approximate Riemann solver (LMARS) from @@ -723,8 +723,7 @@ end # https://journals.ametsoc.org/view/journals/mwre/141/7/mwr-d-12-00129.1.xml. @inline function flux_LMARS(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) # constants - a = 360.0 # TODO try with different speeds of sound - #a = max(speed_of_sound(u_ll, equations)[1], speed_of_sound(u_rr, equations)[1]) + a = 360.0 # densities rho_dry_ll, rho_moist_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) @@ -753,21 +752,15 @@ end if (v_interface > 0) f1, f2, f3, f4, f5, f6, _, _, _ = u_ll * v_interface f6 += p_ll * v_interface - f7 = u_ll[7] - f8 = u_ll[8] - f9 = u_ll[9] else f1, f2, f3, f4, f5, f6, _, _, _ = u_rr * v_interface f6 += p_rr * v_interface - f7 = u_rr[7] - f8 = u_rr[8] - f9 = u_rr[9] end return SVector(f1, f2, f3, f4 + p_interface * normal_direction[1], f5 + p_interface * normal_direction[2], - f6, f7, f8, f9) + f6, 0.0, 0.0, 0.0) end From 4478fd816f0e5493feffe6aceb0538c49aec2e70 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Sat, 26 Oct 2024 22:36:18 +0200 Subject: [PATCH 060/115] adjusted parameters for good results --- examples/elixir_rainy_euler_bubble_no_rain.jl | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_no_rain.jl b/examples/elixir_rainy_euler_bubble_no_rain.jl index ec5b8711..25d3574e 100644 --- a/examples/elixir_rainy_euler_bubble_no_rain.jl +++ b/examples/elixir_rainy_euler_bubble_no_rain.jl @@ -159,22 +159,6 @@ function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, T_loc = p_loc / (R_d * rho_d + R_v * rho_qv) rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv - #=p_v = rho_qv * R_v * T_loc - p_d = p_loc - p_v - T_C = T_loc - 273.15 - p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) - H = p_v / p_vs - r_v = rho_qv / rho_d - r_l = rho_ql / rho_d - r_t = r_v + r_l - - # equivalent potential temperature - a = T_loc * (p_0 / p_d)^(R_d / (c_pd + r_t * c_pl)) - b = H^(-r_v * R_v / c_pd) - L_v = L_00 + (c_pv - c_pl) * (T_loc - 273.15) - c = exp(L_v * r_v / ((c_pd + r_t * c_pl) * T_loc)) - aeq_pot = (a * b * c) # TODO: this is not used. remove? =# - # Assume pressure stays constant if (r < rc && Δθ > 0) # Calculate background density potential temperature @@ -242,7 +226,7 @@ boundary_conditions = (x_neg = boundary_condition_periodic, y_neg = boundary_condition_slip_wall, y_pos = boundary_condition_slip_wall) -polydeg = 4 +polydeg = 3 basis = LobattoLegendreBasis(polydeg) #surface_flux = flux_lax_friedrichs @@ -256,7 +240,7 @@ solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = ( 0.0, 0.0) coordinates_max = (20_000.0, 10_000.0) -cells_per_dimension = (64, 32) +cells_per_dimension = (65, 32) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = (true, false)) From 1cc155e0909a90aa83d4334b9a5d63fab85247f0 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Sat, 26 Oct 2024 22:36:54 +0200 Subject: [PATCH 061/115] testing and results --- .../convergence_test_rainy.jl | 46 ++++++++++++++++--- .../convergence_test_rainy_no_rain.jl | 4 +- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/examples/convergence_test_elixirs/convergence_test_rainy.jl b/examples/convergence_test_elixirs/convergence_test_rainy.jl index 508b9184..451cef05 100644 --- a/examples/convergence_test_elixirs/convergence_test_rainy.jl +++ b/examples/convergence_test_elixirs/convergence_test_rainy.jl @@ -8,7 +8,7 @@ using TrixiAtmo: saturation_vapour_pressure, saturation_vapour_pressure_derivati function initial_condition_convergence_test_rainy(x, t, equations::CompressibleRainyEulerEquations2D) - # needed constants + # constants c_l = equations.c_liquid_water c_vd = equations.c_dry_air_const_volume c_vv = equations.c_vapour_const_volume @@ -40,7 +40,7 @@ end function source_terms_convergence_test_rainy(u, x, t, equations::CompressibleRainyEulerEquations2D) - # needed constants + # constants c_l = equations.c_liquid_water c_vd = equations.c_dry_air_const_volume c_vv = equations.c_vapour_const_volume @@ -94,11 +94,11 @@ function source_terms_convergence_test_rainy(u, x, t, equations::CompressibleRai rho_dry_x = rho_x - rho_moist_x - rho_rain_x energy_t = (c_vd * rho_dry_t + c_vv * rho_vapour_t + c_l * (rho_cloud_t + rho_rain_t)) * temperature - energy_t += (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * rho_t + energy_t += (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * rho_t energy_t += rho_vapour_t * ref_L + rho_t energy_x = (c_vd * rho_dry_x + c_vv * rho_vapour_x + c_l * (rho_cloud_x + rho_rain_x)) * temperature - energy_x += (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * rho_x + energy_x += (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * rho_x energy_x += rho_vapour_x * ref_L + rho_x pressure_x = (rho_dry_x * R_d + rho_vapour_x * R_v) * temperature @@ -139,7 +139,7 @@ solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0, 0.0) coordinates_max = (2.0, 2.0) -cells_per_dimension = (16, 16) +cells_per_dimension = (6, 6) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) @@ -182,4 +182,38 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limite summary_callback() # print the timer summary # For copy-paste convenience: -#convergence_test("TrixiAtmo.jl/examples/convergence_test_elixirs/convergence_test_rainy.jl", 3) \ No newline at end of file +#convergence_test("TrixiAtmo.jl/examples/convergence_test_elixirs/convergence_test_rainy.jl", 5) + +#= +#################################################################################################### +l2 +rho_dry rho_moist rho_rain rho_v1 rho_v2 energy_density rho_vapour rho_cloud temperature + +error EOC error EOC error EOC error EOC error EOC error EOC error EOC error EOC error EOC +2.40e-06 - 3.89e-05 - 1.52e-05 - 7.53e-03 - 2.09e-02 - 5.20e+01 - 1.75e-08 - 3.89e-05 - 2.16e-04 - + +1.43e-07 4.07 2.32e-06 4.07 9.72e-07 3.97 2.90e-04 4.70 1.39e-03 3.91 3.14e+00 4.05 1.15e-09 3.93 2.32e-06 4.07 1.42e-05 3.93 +8.48e-09 4.08 1.37e-07 4.08 1.20e-07 3.02 1.13e-05 4.68 3.10e-05 5.49 1.78e-01 4.14 2.69e-11 5.42 1.37e-07 4.08 3.32e-07 5.41 +5.29e-10 4.00 8.57e-09 4.00 5.27e-09 4.51 6.34e-07 4.16 9.54e-07 5.02 1.39e-02 3.68 1.24e-12 4.43 8.57e-09 4.00 1.54e-08 4.43 +3.31e-11 4.00 5.34e-10 4.00 2.02e-10 4.70 3.85e-08 4.04 3.80e-08 4.65 7.79e-04 4.16 7.09e-14 4.13 5.34e-10 4.00 8.78e-10 4.13 + +mean 4.04 mean 4.04 mean 4.05 mean 4.39 mean 4.77 mean 4.01 mean 4.48 mean 4.04 mean 4.48 +---------------------------------------------------------------------------------------------------- +linf +rho_dry rho_moist rho_rain rho_v1 rho_v2 energy_density rho_vapour rho_cloud temperature + +error EOC error EOC error EOC error EOC error EOC error EOC error EOC error EOC error EOC +1.68e-05 - 2.74e-04 - 8.69e-05 - 2.34e-02 - 6.25e-02 - 3.85e+02 - 6.00e-08 - 2.74e-04 - 7.43e-04 - + +1.07e-06 3.97 1.73e-05 3.98 4.36e-06 4.32 1.13e-03 4.38 3.11e-03 4.33 2.29e+01 4.07 5.72e-09 3.39 1.73e-05 3.98 7.09e-05 3.39 +6.01e-08 4.15 9.73e-07 4.16 3.46e-07 3.66 4.43e-05 4.67 6.53e-05 5.57 1.08e+00 4.40 1.63e-10 5.13 9.73e-07 4.16 2.00e-06 5.15 +3.69e-09 4.02 5.98e-08 4.03 2.91e-08 3.57 2.47e-06 4.16 2.37e-06 4.79 9.44e-02 3.52 9.40e-12 4.12 5.97e-08 4.03 1.15e-07 4.12 +2.30e-10 4.01 3.71e-09 4.01 1.47e-09 4.31 1.50e-07 4.04 1.16e-07 4.35 5.51e-03 4.10 5.70e-13 4.04 3.71e-09 4.01 6.97e-09 4.04 + +mean 4.04 mean 4.04 mean 3.96 mean 4.31 mean 4.76 mean 4.02 mean 4.17 mean 4.04 mean 4.18 +---------------------------------------------------------------------------------------------------- +Dict{Symbol, Any} with 3 entries: + :variables => ("rho_dry", "rho_moist", "rho_rain", "rho_v1", "rho_v2", "energy_density", "rho_vapour", "rho_cloud", "temperature") + :l2 => [4.03641, 4.03834, 4.04901, 4.39454, 4.7665, 4.00677, 4.47752, 4.03837, 4.47639] + :linf => [4.03824, 4.04306, 3.96283, 4.31327, 4.76078, 4.023, 4.17127, 4.04306, 4.17577] +=# \ No newline at end of file diff --git a/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl b/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl index 3c24df0f..b704e2a9 100644 --- a/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl +++ b/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl @@ -120,7 +120,7 @@ solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0, 0.0) coordinates_max = (2.0, 2.0) -cells_per_dimension = (16, 16) +cells_per_dimension = (8, 8) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) @@ -163,4 +163,4 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limite summary_callback() # print the timer summary # For copy-paste convenience: -#convergence_test("TrixiAtmo.jl/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl", 3) \ No newline at end of file +#convergence_test("TrixiAtmo.jl/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl", 4) \ No newline at end of file From 3f648ed58d9fc443f3a8c74a44be1f6b57dd960d Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Sat, 26 Oct 2024 22:37:15 +0200 Subject: [PATCH 062/115] added rainy bubble initial condition --- examples/elixir_rainy_euler_bubble.jl | 227 ++++++++++++++++++++++---- 1 file changed, 197 insertions(+), 30 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble.jl b/examples/elixir_rainy_euler_bubble.jl index 482ddc85..19ddb889 100644 --- a/examples/elixir_rainy_euler_bubble.jl +++ b/examples/elixir_rainy_euler_bubble.jl @@ -3,38 +3,208 @@ using Trixi using TrixiAtmo using TrixiAtmo: source_terms_rainy, saturation_residual, saturation_residual_jacobian, NonlinearSolveDG, - cons2eq_pot_temp, saturation_vapour_pressure + cons2eq_pot_temp, saturation_vapour_pressure, + flux_chandrashekar using NLsolve: nlsolve -## Hydrostatic base state -function initial_constraint_residual(guess, equations::CompressibleRainyEulerEquations2D) - # rho_dry, rho_vapour, temperature = guess +# domain +coordinates_min = ( 0.0, 0.0) +coordinates_max = (3600.0, 2400.0) + + +# hydrostatic dry potential temperature +function theta_d(z, equations::CompressibleRainyEulerEquations2D) + # constants + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + ref_pressure = equations.ref_pressure + + # problem specific constants + surface_temperature = 283.0 + surface_pressure = 8.5e4 + stratification = 1.3e-5 + + # dry potential temperature at surface + Theta0 = surface_temperature * (ref_pressure / surface_pressure)^(R_d / c_pd) + # at height z + theta_d = Theta0 * exp(stratification * z) + + return theta_d +end + + +# hydrostatic base state residual +function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equations::CompressibleRainyEulerEquations2D) + # equations constants c_pd = equations.c_dry_air_const_pressure R_d = equations.R_dry_air R_v = equations.R_vapour eps = equations.eps - ref_p = equations.ref_pressure - surf_p = 8.5e4 # surface pressure - humidity_rel0 = 0.2 # hydrostatic relative humidity + ref_pressure = equations.ref_pressure + g = equations.gravity + + function hydrostatic_residual!(residual, guess) + # variables + pressure, rho_dry, rho_vapour, temperature = guess + + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + + # pressure derivative residual + residual[1] = (pressure - pressure_lower) / dz + (rho_dry + rho_vapour) * g + + # pressure residual + residual[2] = pressure - temperature * (rho_dry * R_d + rho_vapour * R_v) + + # hydrostatic dry potential temperature residual + residual[3] = theta_d(z, equations) - temperature * (ref_pressure / pressure)^(R_d / c_pd) - rho_vs = saturation_vapour_pressure(guess[3]) / (R_v * guess[3]) + # humidity residual + residual[4] = rho_vs * (rho_dry + rho_vapour / eps) * humidity_rel0 + residual[4] -= rho_vapour * (rho_dry + rho_vs / eps) + residual[4] *= 1000.0 + end + + return hydrostatic_residual! +end - res1 = surf_p - guess[3] * (guess[1] * R_d + guess[2] * R_v) - res2 = theta_d0 - guess[3] * (ref_p / surf_p)^(R_d / c_pd) - res3 = rho_vs * (guess[1] + guess[2] / eps) * humidity_rel0 - res3 -= guess[2] * (guess[1] + rho_vs / eps) - return SVector(res1, res2, 1000 * res3) +function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equations::CompressibleRainyEulerEquations2D) + # equations constants + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure + + function perturbation_residual!(residual, guess) + # variables + rho_dry, rho_vapour, temperature = guess + + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + pressure = (rho_dry * R_d + rho_vapour * R_v) * temperature + + # humidity residual + residual[1] = rho_vs * (rho_dry + rho_vapour / eps) * H_init + residual[1] -= rho_vapour * (rho_dry + rho_vs / eps) + residual[1] *= 30.0 + + # hydrostatic dry potential temperature residual + residual[2] = theta_d(z, equations) - temperature * (ref_pressure / pressure_hydrostatic)^(R_d / c_pd) + + # pressure residual + residual[3] = pressure_hydrostatic - pressure + end + + return perturbation_residual! end -## Initial condition +# for approximating the dz pressure gradient +struct AtmosphereLayers{RealT <: Real} + layer_data ::Matrix{RealT} + total_height ::RealT + precision ::RealT +end + -function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerEquations2D) - #TODO - return SVector(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) +function AtmosphereLayers(equations::CompressibleRainyEulerEquations2D; total_height = coordinates_max[2] + 2.0, precision = 2.0, RealT = Float64) + # constants + humidity_rel0 = 0.2 # hydrostatic relative humidity + surface_pressure = 8.5e4 + + # surface layer with initial guesses for rho_dry, rho_vapour and temperature + surface_layer = [surface_pressure, 1.4, 0.04, 300.0] + + # allocate layer_data + n = convert(Int, total_height / precision) + layer_data = zeros(RealT, n + 1, 4) + + # solve (slightly above) surface layer + dz = 0.01 + z = 0.01 + residual_function! = generate_hydrostatic_residual(surface_pressure, humidity_rel0, z, dz, equations) + layer_data[1, :] .= nlsolve(residual_function!, surface_layer).zero + + # adjust to chosen precision + dz = precision + + # iterate up the atmosphere + for i in (1:n) + z += dz + residual_function! = generate_hydrostatic_residual(layer_data[i, 1], humidity_rel0, z, dz, equations) + guess = deepcopy(layer_data[i, :]) + layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, iterations = 10).zero + end + + return AtmosphereLayers{RealT}(layer_data, total_height, precision) +end + + +# create layers for initial condition +equations = CompressibleRainyEulerEquations2D() +layers = AtmosphereLayers(equations) + + +function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerEquations2D; atmosphere_layers = layers) + # equations constants + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + ref_L = equations.ref_latent_heat_vap_temp + + # problem specific constants + humidity_rel_bar = 0.2 # background relative humidity field + + # bubble parameters + radius_outer, radius_inner = 300.0, 200.0 # radii of humidity bubble + x_center, z_center = 1800.0, 800.0 # center of humidity bubble + + # radius relative to bubble center + r = sqrt((x[1] - x_center)^2 + (x[2] - z_center)^2) + + # humidity definition + if (r > radius_outer) + # outside the bubble + humidity = humidity_rel_bar + elseif (r > radius_inner) + # outer layers of the bubble + humidity = humidity_rel_bar + (1.0 - humidity_rel_bar) * cos(pi * (r - radius_inner) / (2.0 * (radius_outer - radius_inner)))^2 + else + # inner layer + humidity = 1.0 + end + + # get atmosphere layer and height information + @unpack layer_data, total_height, precision = atmosphere_layers + dz = precision + z = x[2] + n = convert(Int, floor((z + eps()) / dz)) + 1 + z_lower = (n - 1) * dz + z_upper = n * dz + + if (z_lower == total_height) + z_upper = z_lower + dz + n = n - 1 + end + + # check height consistency + if (z > total_height && !(isapprox(z, total_height))) + error("The atmosphere does not match the simulation domain") + end + + # get hydrostatic pressures and approximate between lower and upper data point + pressure_hydrostatic_lower = layer_data[n, 1] + pressure_hydrostatic_upper = layer_data[n + 1, 1] + pressure_hydrostatic = (pressure_hydrostatic_upper * (z - z_lower) + pressure_hydrostatic_lower * (z_upper - z)) / dz + + # solve perturbation + residual_function! = generate_perturbation_residual(pressure_hydrostatic, humidity, z, equations) + rho_dry, rho_vapour, temperature = nlsolve(residual_function!, layer_data[n, 2:4], ftol = 1e-9, iterations = 10).zero + + energy_density = (c_vd * rho_dry + c_vv * rho_vapour) * temperature + rho_vapour * ref_L + + return SVector(rho_dry, rho_vapour, 0.0, 0.0, 0.0, energy_density, rho_vapour, 0.0, temperature) end @@ -42,25 +212,21 @@ end ############################################################################### # semidiscretization of the compressible rainy Euler equations -equations = CompressibleRainyEulerEquations2D() 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 = 3 +polydeg = 1 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_lax_friedrichs +#volume_integral = VolumeIntegralFluxDifferencing(flux_chandrashekar) -solver = DGSEM(basis, surface_flux) - -#TODO adjust values -coordinates_min = (0.0, 0.0) -coordinates_max = (1.0, 1.0) +solver = DGSEM(basis, surface_flux)#, volume_integral) -cells_per_dimension = (64, 32) +cells_per_dimension = (201, 100) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = (true, false)) @@ -71,8 +237,7 @@ semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_bubble_ra ############################################################################### # ODE solvers, callbacks etc. -#TODO adjust values -tspan = (0.0, 1000.0) +tspan = (0.0, 600.0) ode = semidiscretize(semi, tspan) @@ -86,11 +251,11 @@ analysis_callback = AnalysisCallback(semi, interval = analysis_interval, alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval = analysis_interval, +save_solution = SaveSolutionCallback(interval = 100, save_initial_solution = true, save_final_solution = true, output_directory = "out", - solution_variables = cons2prim) + solution_variables = cons2eq_pot_temp) stepsize_callback = StepsizeCallback(cfl = 1.0) @@ -100,9 +265,11 @@ callbacks = CallbackSet(summary_callback, save_solution, stepsize_callback) +stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) + ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limiter!), maxiters = 1.0e7, dt = 1.0, save_everystep = false, callback = callbacks); From 1855c1840c4644f663a11ddf4b32e4ac5d419bac Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Sun, 27 Oct 2024 17:09:32 +0100 Subject: [PATCH 063/115] comments and testing --- examples/elixir_rainy_euler_bubble.jl | 9 +++-- src/equations/compressible_rainy_euler_2d.jl | 40 +++++++++++--------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble.jl b/examples/elixir_rainy_euler_bubble.jl index 19ddb889..a95cc9b4 100644 --- a/examples/elixir_rainy_euler_bubble.jl +++ b/examples/elixir_rainy_euler_bubble.jl @@ -4,7 +4,8 @@ using TrixiAtmo using TrixiAtmo: source_terms_rainy, saturation_residual, saturation_residual_jacobian, NonlinearSolveDG, cons2eq_pot_temp, saturation_vapour_pressure, - flux_chandrashekar + flux_chandrashekar, flux_LMARS, + source_terms_no_phase_change using NLsolve: nlsolve @@ -51,7 +52,7 @@ function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equ rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) - # pressure derivative residual + # pressure derivative residual approximation residual[1] = (pressure - pressure_lower) / dz + (rho_dry + rho_vapour) * g # pressure residual @@ -144,7 +145,7 @@ end # create layers for initial condition equations = CompressibleRainyEulerEquations2D() -layers = AtmosphereLayers(equations) +layers = AtmosphereLayers(equations) function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerEquations2D; atmosphere_layers = layers) @@ -226,7 +227,7 @@ surface_flux = flux_lax_friedrichs solver = DGSEM(basis, surface_flux)#, volume_integral) -cells_per_dimension = (201, 100) +cells_per_dimension = (193, 96) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = (true, false)) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index f7fdb6c1..7f4115a7 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -787,6 +787,8 @@ end # velocities v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) + #vr_ll = terminal_velocity_rain(rho_moist_ll, rho_rain_ll, equations) + #vr_rr = terminal_velocity_rain(rho_moist_rr, rho_rain_rr, equations) # mean values rho_dry_mean = 0.0 @@ -815,31 +817,33 @@ end inv_temperature_mean = inv_ln_mean(inv(temperature_ll), inv(temperature_rr)) end - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) - v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) - rho_dry_avg = 0.5 * (rho_dry_ll + rho_dry_rr) - rho_vapour_avg = 0.5 * (rho_vapour_ll + rho_vapour_rr) - rho_cloud_avg = 0.5 * (rho_cloud_ll + rho_cloud_rr) - rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) - inv_temperature_avg = 0.5 * (inv(temperature_ll) + inv(temperature_rr)) - v_dot_n_avg = normal_direction[1]*v1_avg + normal_direction[2]*v2_avg + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) + v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) + rho_dry_avg = 0.5 * (rho_dry_ll + rho_dry_rr) + rho_vapour_avg = 0.5 * (rho_vapour_ll + rho_vapour_rr) + rho_cloud_avg = 0.5 * (rho_cloud_ll + rho_cloud_rr) + rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) + inv_temperature_avg = 0.5 * (inv(temperature_ll) + inv(temperature_rr)) + v_dot_n_avg = normal_direction[1] * v1_avg + normal_direction[2] * v2_avg + #vr_avg = 0.5 * (vr_ll + vr_rr) + #vr_dot_n_avg = normal_direction[2] * vr_avg p_int = inv(inv_temperature_avg) * (R_d * rho_dry_avg + R_v * rho_vapour_avg + R_q * (rho_cloud_avg + rho_rain_avg)) K_avg = 0.5 * (v1_square_avg + v2_square_avg) # assemble the flux - f_dry = rho_dry_mean * v_dot_n_avg - f_rain = rho_rain_mean * v_dot_n_avg - f_vapour = rho_vapour_mean * v_dot_n_avg - f_cloud = rho_cloud_mean * v_dot_n_avg + f_dry = rho_dry_mean * v_dot_n_avg + f_rain = rho_rain_mean * (v_dot_n_avg) #- vr_dot_n_avg) + f_vapour = rho_vapour_mean * v_dot_n_avg + f_cloud = rho_cloud_mean * v_dot_n_avg f_moist = (rho_vapour_mean + rho_cloud_mean) * v_dot_n_avg - f_rhov1 = (f_dry + f_moist + f_rain) * v1_avg + normal_direction[1] * p_int - f_rhov2 = (f_dry + f_moist + f_rain) * v2_avg + normal_direction[2] * p_int - f_energy = ((c_vd * inv_temperature_mean - K_avg) * f_dry + + f_rhov1 = (f_dry + f_moist + f_rain) * v1_avg + normal_direction[1] * p_int #- rho_rain_mean * vr_dot_n_avg * v1_avg + f_rhov2 = (f_dry + f_moist + f_rain) * v2_avg + normal_direction[2] * p_int #- rho_rain_mean * vr_dot_n_avg * v2_avg + f_energy = (( c_vd * inv_temperature_mean - K_avg) * f_dry + (ref_L + c_vv * inv_temperature_mean - K_avg) * f_vapour + - (c_l * inv_temperature_mean - K_avg) * (f_cloud + f_rain) + v1_avg * f_rhov1 + v2_avg * f_rhov2) + ( c_l * inv_temperature_mean - K_avg) * (f_cloud + f_rain) + v1_avg * f_rhov1 + v2_avg * f_rhov2) return SVector(f_dry, f_moist, f_rain, f_rhov1, f_rhov2, f_energy, 0.0, 0.0, 0.0) end From 6c946fbb4fcb4c551606d0862c173886547c8d56 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 5 Nov 2024 17:51:27 +0100 Subject: [PATCH 064/115] rain testing --- examples/elixir_rainy_euler_bubble.jl | 12 +- src/callbacks_stage/nonlinear_solve_dg.jl | 2 +- src/callbacks_stage/nonlinear_solve_dg2d.jl | 122 ++++++++++++++++++- src/equations/compressible_rainy_euler_2d.jl | 54 ++++++-- 4 files changed, 169 insertions(+), 21 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble.jl b/examples/elixir_rainy_euler_bubble.jl index a95cc9b4..ca2d08e3 100644 --- a/examples/elixir_rainy_euler_bubble.jl +++ b/examples/elixir_rainy_euler_bubble.jl @@ -110,7 +110,7 @@ struct AtmosphereLayers{RealT <: Real} end -function AtmosphereLayers(equations::CompressibleRainyEulerEquations2D; total_height = coordinates_max[2] + 2.0, precision = 2.0, RealT = Float64) +function AtmosphereLayers(equations::CompressibleRainyEulerEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) # constants humidity_rel0 = 0.2 # hydrostatic relative humidity surface_pressure = 8.5e4 @@ -136,7 +136,7 @@ function AtmosphereLayers(equations::CompressibleRainyEulerEquations2D; total_he z += dz residual_function! = generate_hydrostatic_residual(layer_data[i, 1], humidity_rel0, z, dz, equations) guess = deepcopy(layer_data[i, :]) - layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, iterations = 10).zero + layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, iterations = 20).zero end return AtmosphereLayers{RealT}(layer_data, total_height, precision) @@ -201,7 +201,7 @@ function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerE # solve perturbation residual_function! = generate_perturbation_residual(pressure_hydrostatic, humidity, z, equations) - rho_dry, rho_vapour, temperature = nlsolve(residual_function!, layer_data[n, 2:4], ftol = 1e-9, iterations = 10).zero + rho_dry, rho_vapour, temperature = nlsolve(residual_function!, layer_data[n, 2:4], ftol = 1e-9, iterations = 20).zero energy_density = (c_vd * rho_dry + c_vv * rho_vapour) * temperature + rho_vapour * ref_L @@ -219,7 +219,7 @@ boundary_conditions = (x_neg = boundary_condition_periodic, y_neg = boundary_condition_slip_wall, y_pos = boundary_condition_slip_wall) -polydeg = 1 +polydeg = 2 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_lax_friedrichs @@ -227,7 +227,7 @@ surface_flux = flux_lax_friedrichs solver = DGSEM(basis, surface_flux)#, volume_integral) -cells_per_dimension = (193, 96) +cells_per_dimension = (400, 200) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = (true, false)) @@ -252,7 +252,7 @@ analysis_callback = AnalysisCallback(semi, interval = analysis_interval, alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval = 100, +save_solution = SaveSolutionCallback(interval = 1000, save_initial_solution = true, save_final_solution = true, output_directory = "out", diff --git a/src/callbacks_stage/nonlinear_solve_dg.jl b/src/callbacks_stage/nonlinear_solve_dg.jl index 8398edd8..264b720e 100644 --- a/src/callbacks_stage/nonlinear_solve_dg.jl +++ b/src/callbacks_stage/nonlinear_solve_dg.jl @@ -17,7 +17,7 @@ function (limiter!::NonlinearSolveDG)(u_ode, integrator, semi::AbstractSemidiscr @trixi_timeit timer() "nonlinear system solver" begin nonlinear_solve_dg_2d!(u, limiter!.residual, limiter!.jacobian, limiter!.variables_index_vector, - limiter!.tolerance, semi.equations, semi.solver, semi.cache) + limiter!.tolerance, semi.equations, semi.solver, semi.cache, semi.mesh) end end diff --git a/src/callbacks_stage/nonlinear_solve_dg2d.jl b/src/callbacks_stage/nonlinear_solve_dg2d.jl index 94f6b14d..544a0234 100644 --- a/src/callbacks_stage/nonlinear_solve_dg2d.jl +++ b/src/callbacks_stage/nonlinear_solve_dg2d.jl @@ -1,4 +1,4 @@ -using Trixi: get_node_vars, @batch +using Trixi: get_node_vars, @batch, get_inverse_jacobian, set_node_vars! using LinearAlgebra using StaticArrays @@ -7,18 +7,132 @@ using StaticArrays @muladd begin function nonlinear_solve_dg_2d!(u, residual, jacobian, variables_index_vector, tolerance, - equations::CompressibleRainyEulerEquations2D, dg::DGSEM, cache) + equations::CompressibleRainyEulerEquations2D, dg::DGSEM, cache, mesh) max_iterations = 20 - + rain_threshold = 1e-4 + #=threshold = 0.0 + @unpack weights = dg.basis + @unpack inverse_jacobian = cache.elements=# + # iterate over every DGSEM element @batch for element in eachelement(dg, cache) + #= positivity preserving limiter zhang shu test determine minimum value + value_min = typemax(eltype(u)) + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, j, element) + value_min = min(value_min, u_node[3]) + end + + # detect if limiting is necessary + if (value_min < threshold) + # compute mean value + u_mean = zero(get_node_vars(u, equations, dg, 1, 1, element)) + total_volume = zero(eltype(u)) + for j in eachnode(dg), i in eachnode(dg) + volume_jacobian = abs(inv(get_inverse_jacobian(inverse_jacobian, mesh, + i, j, element))) + u_node = get_node_vars(u, equations, dg, i, j, element) + u_mean += u_node * weights[i] * weights[j] * volume_jacobian + total_volume += weights[i] * weights[j] * volume_jacobian + end + + # normalize with the total volume + u_mean = u_mean / total_volume + + # We compute the value directly with the mean values, as we assume that + # Jensen's inequality holds (e.g. pressure for compressible Euler equations). + value_mean = u_mean[3] + theta = (value_mean - threshold) / (value_mean - value_min) + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, j, element) + set_node_vars!(u, theta * u_node + (1 - theta) * u_mean, + equations, dg, i, j, element) + end + end + + # positivity preserving limiter zhang shu test determine minimum value + value_min = typemax(eltype(u)) + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, j, element) + value_min = min(value_min, u_node[2]) + end + + # detect if limiting is necessary + if (value_min < 1e-5) + # compute mean value + u_mean = zero(get_node_vars(u, equations, dg, 1, 1, element)) + total_volume = zero(eltype(u)) + for j in eachnode(dg), i in eachnode(dg) + volume_jacobian = abs(inv(get_inverse_jacobian(inverse_jacobian, mesh, + i, j, element))) + u_node = get_node_vars(u, equations, dg, i, j, element) + u_mean += u_node * weights[i] * weights[j] * volume_jacobian + total_volume += weights[i] * weights[j] * volume_jacobian + end + + # normalize with the total volume + u_mean = u_mean / total_volume + + # We compute the value directly with the mean values, as we assume that + # Jensen's inequality holds (e.g. pressure for compressible Euler equations). + value_mean = u_mean[2] + theta = (value_mean - 1e-5) / (value_mean - value_min) + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, j, element) + set_node_vars!(u, theta * u_node + (1 - theta) * u_mean, + equations, dg, i, j, element) + end + end + + # positivity preserving limiter zhang shu test determine minimum value + value_min = typemax(eltype(u)) + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, j, element) + value_min = min(value_min, u_node[1]) + end + + # detect if limiting is necessary + if (value_min < 1e-5) + # compute mean value + u_mean = zero(get_node_vars(u, equations, dg, 1, 1, element)) + total_volume = zero(eltype(u)) + for j in eachnode(dg), i in eachnode(dg) + volume_jacobian = abs(inv(get_inverse_jacobian(inverse_jacobian, mesh, + i, j, element))) + u_node = get_node_vars(u, equations, dg, i, j, element) + u_mean += u_node * weights[i] * weights[j] * volume_jacobian + total_volume += weights[i] * weights[j] * volume_jacobian + end + + # normalize with the total volume + u_mean = u_mean / total_volume + + # We compute the value directly with the mean values, as we assume that + # Jensen's inequality holds (e.g. pressure for compressible Euler equations). + value_mean = u_mean[1] + theta = (value_mean - 1e-5) / (value_mean - value_min) + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, j, element) + set_node_vars!(u, theta * u_node + (1 - theta) * u_mean, + equations, dg, i, j, element) + end + end =# # iterate over every node for j in eachnode(dg), i in eachnode(dg) - u_node = get_node_vars(u, equations, dg, i, j, element) + u_node = get_node_vars(u, equations, dg, i, j, element) guess = SVector(u_node[7], u_node[8], u_node[9]) + # keep rain positive + if (u_node[3] < 0.0) + u[3, i, j, element] = 0.0 + end + + if (u_node[3] > rain_threshold) + u[3, i, j, element] = rain_threshold * 0.1 + end + # newton method for iteration in range(1, max_iterations) res_vector = residual(u_node, guess, equations) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 7f4115a7..0383e461 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -249,6 +249,9 @@ varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquations2D) = ("rh return SVector(rho_dry, rho_moist, rho_rain, rho, rho_inv) end +@inline function rain_density(u, equations::CompressibleRainyEulerEquations2D) + return u[3] +end @inline function velocities(u, rho_inv, equations::CompressibleRainyEulerEquations2D) return SVector(u[4] * rho_inv, u[5] * rho_inv) @@ -386,7 +389,6 @@ end @inline function flux(u, orientation::Integer, equations::CompressibleRainyEulerEquations2D) # constants c_l = equations.c_liquid_water - ref_temp = equations.ref_temperature #densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) @@ -440,7 +442,6 @@ end @inline function flux(u, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) # constants c_l = equations.c_liquid_water - ref_temp = equations.ref_temperature # densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) @@ -493,8 +494,6 @@ end # densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - rho_rain = max(rho_rain, 0.0) # test - # recover rho_vapour, rho_cloud, temperature from nonlinear system rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) @@ -552,6 +551,23 @@ end end +@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::CompressibleRainyEulerEquations2D) + # name needed variables + v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) + v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) + + if (orientation == 1) + v_ll = abs(v1_ll) + v_rr = abs(v1_rr) + else + v_ll = abs(v2_ll) + v_rr = abs(v2_rr) + v_rr += abs(v_r_rr) + end + + return max(v_ll, v_rr) + max(v_sound_ll, v_sound_rr) +end + ### boundary conditions ### @@ -637,6 +653,22 @@ end end +# should be used together with TreeMesh (adapted from compressible_euler_2d.jl) +@inline function boundary_condition_slip_wall(u_inner, orientation, direction, x, t, surface_flux_function, + equations::CompressibleRainyEulerEquations2D) + # get the appropriate normal vector from the orientation + RealT = eltype(u_inner) + if orientation == 1 + normal_direction = SVector(one(RealT), zero(RealT)) + else # orientation == 2 + normal_direction = SVector(zero(RealT), one(RealT)) + end + + # compute and return the flux using `boundary_condition_slip_wall` routine above + return boundary_condition_slip_wall(u_inner, normal_direction, direction, + x, t, surface_flux_function, equations) +end + ### Nonlinear System Residual ### @@ -713,7 +745,7 @@ end end -# TODO Careful with rain != 0.0, double check the fluxes! +# TODO Careful with rain != 0.0 does not really work (bad physics) # fluxes adapted from compressible_moist_euler_2d.jl # Low Mach number approximate Riemann solver (LMARS) from @@ -828,10 +860,12 @@ end inv_temperature_avg = 0.5 * (inv(temperature_ll) + inv(temperature_rr)) v_dot_n_avg = normal_direction[1] * v1_avg + normal_direction[2] * v2_avg #vr_avg = 0.5 * (vr_ll + vr_rr) + #vr_square_avg = 0.5 * ((v2_ll - vr_ll)^2 + (v2_rr - vr_rr)^2) #vr_dot_n_avg = normal_direction[2] * vr_avg - p_int = inv(inv_temperature_avg) * (R_d * rho_dry_avg + R_v * rho_vapour_avg + R_q * (rho_cloud_avg + rho_rain_avg)) - K_avg = 0.5 * (v1_square_avg + v2_square_avg) + p_int = inv(inv_temperature_avg) * (R_d * rho_dry_avg + R_v * rho_vapour_avg + R_q * (rho_cloud_avg + rho_rain_avg)) + K_avg = 0.5 * (v1_square_avg + v2_square_avg) + #K2_avg = 0.5 * (v1_square_avg + (vr_square_avg)) # assemble the flux f_dry = rho_dry_mean * v_dot_n_avg @@ -841,9 +875,9 @@ end f_moist = (rho_vapour_mean + rho_cloud_mean) * v_dot_n_avg f_rhov1 = (f_dry + f_moist + f_rain) * v1_avg + normal_direction[1] * p_int #- rho_rain_mean * vr_dot_n_avg * v1_avg f_rhov2 = (f_dry + f_moist + f_rain) * v2_avg + normal_direction[2] * p_int #- rho_rain_mean * vr_dot_n_avg * v2_avg - f_energy = (( c_vd * inv_temperature_mean - K_avg) * f_dry + - (ref_L + c_vv * inv_temperature_mean - K_avg) * f_vapour + - ( c_l * inv_temperature_mean - K_avg) * (f_cloud + f_rain) + v1_avg * f_rhov1 + v2_avg * f_rhov2) + f_energy = (( c_vd * inv_temperature_mean - K_avg) * f_dry + + (ref_L + c_vv * inv_temperature_mean - K_avg) * f_vapour + + ( c_l * inv_temperature_mean - K_avg) * (f_cloud + f_rain) + v1_avg * f_rhov1 + v2_avg * f_rhov2) return SVector(f_dry, f_moist, f_rain, f_rhov1, f_rhov2, f_energy, 0.0, 0.0, 0.0) end From b12b377d97168f5d963115c4aaf2ec805d3be2ef Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 5 Nov 2024 17:53:17 +0100 Subject: [PATCH 065/115] added rain bubble adaptive mesh refinement (does not work yet) --- examples/elixir_rainy_euler_bubble_amr.jl | 288 ++++++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 examples/elixir_rainy_euler_bubble_amr.jl diff --git a/examples/elixir_rainy_euler_bubble_amr.jl b/examples/elixir_rainy_euler_bubble_amr.jl new file mode 100644 index 00000000..45624771 --- /dev/null +++ b/examples/elixir_rainy_euler_bubble_amr.jl @@ -0,0 +1,288 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: source_terms_rainy, saturation_residual, + saturation_residual_jacobian, NonlinearSolveDG, + cons2eq_pot_temp, saturation_vapour_pressure, + flux_chandrashekar, flux_LMARS, + source_terms_no_phase_change, rain_density +using NLsolve: nlsolve + + + +# domain +coordinates_min = ( 0.0, 0.0) +coordinates_max = (3600.0, 3600.0) + + +# hydrostatic dry potential temperature +function theta_d(z, equations::CompressibleRainyEulerEquations2D) + # constants + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + ref_pressure = equations.ref_pressure + + # problem specific constants + surface_temperature = 283.0 + surface_pressure = 8.5e4 + stratification = 1.3e-5 + + # dry potential temperature at surface + Theta0 = surface_temperature * (ref_pressure / surface_pressure)^(R_d / c_pd) + # at height z + theta_d = Theta0 * exp(stratification * z) + + return theta_d +end + + +# hydrostatic base state residual +function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equations::CompressibleRainyEulerEquations2D) + # equations constants + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure + g = equations.gravity + + function hydrostatic_residual!(residual, guess) + # variables + pressure, rho_dry, rho_vapour, temperature = guess + + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + + # pressure derivative residual approximation + residual[1] = (pressure - pressure_lower) / dz + (rho_dry + rho_vapour) * g + + # pressure residual + residual[2] = pressure - temperature * (rho_dry * R_d + rho_vapour * R_v) + + # hydrostatic dry potential temperature residual + residual[3] = theta_d(z, equations) - temperature * (ref_pressure / pressure)^(R_d / c_pd) + + # humidity residual + residual[4] = rho_vs * (rho_dry + rho_vapour / eps) * humidity_rel0 + residual[4] -= rho_vapour * (rho_dry + rho_vs / eps) + residual[4] *= 1000.0 + end + + return hydrostatic_residual! +end + + +function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equations::CompressibleRainyEulerEquations2D) + # equations constants + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure + + function perturbation_residual!(residual, guess) + # variables + rho_dry, rho_vapour, temperature = guess + + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + pressure = (rho_dry * R_d + rho_vapour * R_v) * temperature + + # humidity residual + residual[1] = rho_vs * (rho_dry + rho_vapour / eps) * H_init + residual[1] -= rho_vapour * (rho_dry + rho_vs / eps) + residual[1] *= 30.0 + + # hydrostatic dry potential temperature residual + residual[2] = theta_d(z, equations) - temperature * (ref_pressure / pressure_hydrostatic)^(R_d / c_pd) + + # pressure residual + residual[3] = pressure_hydrostatic - pressure + end + + return perturbation_residual! +end + + +# for approximating the dz pressure gradient +struct AtmosphereLayers{RealT <: Real} + layer_data ::Matrix{RealT} + total_height ::RealT + precision ::RealT +end + + +function AtmosphereLayers(equations::CompressibleRainyEulerEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) + # constants + humidity_rel0 = 0.2 # hydrostatic relative humidity + surface_pressure = 8.5e4 + + # surface layer with initial guesses for rho_dry, rho_vapour and temperature + surface_layer = [surface_pressure, 1.4, 0.04, 300.0] + + # allocate layer_data + n = convert(Int, total_height / precision) + layer_data = zeros(RealT, n + 1, 4) + + # solve (slightly above) surface layer + dz = 0.01 + z = 0.01 + residual_function! = generate_hydrostatic_residual(surface_pressure, humidity_rel0, z, dz, equations) + layer_data[1, :] .= nlsolve(residual_function!, surface_layer).zero + + # adjust to chosen precision + dz = precision + + # iterate up the atmosphere + for i in (1:n) + z += dz + residual_function! = generate_hydrostatic_residual(layer_data[i, 1], humidity_rel0, z, dz, equations) + guess = deepcopy(layer_data[i, :]) + layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, iterations = 20).zero + end + + return AtmosphereLayers{RealT}(layer_data, total_height, precision) +end + + +# create layers for initial condition +equations = CompressibleRainyEulerEquations2D() +layers = AtmosphereLayers(equations) + + +function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerEquations2D; atmosphere_layers = layers) + # equations constants + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + ref_L = equations.ref_latent_heat_vap_temp + + # problem specific constants + humidity_rel_bar = 0.2 # background relative humidity field + + # bubble parameters + radius_outer, radius_inner = 300.0, 200.0 # radii of humidity bubble + x_center, z_center = 1800.0, 800.0 # center of humidity bubble + + # radius relative to bubble center + r = sqrt((x[1] - x_center)^2 + (x[2] - z_center)^2) + + # humidity definition + if (r > radius_outer) + # outside the bubble + humidity = humidity_rel_bar + elseif (r > radius_inner) + # outer layers of the bubble + humidity = humidity_rel_bar + (1.0 - humidity_rel_bar) * cos(pi * (r - radius_inner) / (2.0 * (radius_outer - radius_inner)))^2 + else + # inner layer + humidity = 1.0 + end + + # get atmosphere layer and height information + @unpack layer_data, total_height, precision = atmosphere_layers + dz = precision + z = x[2] + n = convert(Int, floor((z + eps()) / dz)) + 1 + z_lower = (n - 1) * dz + z_upper = n * dz + + if (z_lower == total_height) + z_upper = z_lower + dz + n = n - 1 + end + + # check height consistency + if (z > total_height && !(isapprox(z, total_height))) + error("The atmosphere does not match the simulation domain") + end + + # (for IndicatorLöhner) + if (n == 0) + n = 1 + end + + # get hydrostatic pressures and approximate between lower and upper data point + pressure_hydrostatic_lower = layer_data[n, 1] + pressure_hydrostatic_upper = layer_data[n + 1, 1] + pressure_hydrostatic = (pressure_hydrostatic_upper * (z - z_lower) + pressure_hydrostatic_lower * (z_upper - z)) / dz + + # solve perturbation + residual_function! = generate_perturbation_residual(pressure_hydrostatic, humidity, z, equations) + rho_dry, rho_vapour, temperature = nlsolve(residual_function!, layer_data[n, 2:4], ftol = 1e-9, iterations = 20).zero + + energy_density = (c_vd * rho_dry + c_vv * rho_vapour) * temperature + rho_vapour * ref_L + + return SVector(rho_dry, rho_vapour, 0.0, 0.0, 0.0, energy_density, rho_vapour, 0.0, temperature) +end + + +initial_condition = initial_condition_bubble_rainy + +boundary_conditions = (x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_slip_wall, + y_pos = boundary_condition_slip_wall) + +surface_flux = flux_lax_friedrichs +#volume_integral = VolumeIntegralFluxDifferencing(flux_chandrashekar) +polydeg = 2 +basis = LobattoLegendreBasis(polydeg) + +solver = DGSEM(basis, surface_flux)#, volume_integral) + +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 8, + periodicity = (true, false), + n_cells_max = 10_000_000) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, + source_terms = source_terms_rainy, solver, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 600.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + output_directory = "out", + solution_variables = cons2eq_pot_temp) + +amr_indicator = IndicatorMax(semi, variable=rain_density) + +amr_controller = ControllerThreeLevel(semi, amr_indicator, + base_level = 8, + med_level = 10, med_threshold = 1e-6, + max_level = 12, max_threshold = 5e-5) + +amr_callback = AMRCallback(semi, amr_controller, + interval = 1, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + amr_callback, save_solution, stepsize_callback) + +# positivity limiter necessary for this tough example +stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) + +############################################################################### +# run the simulation +# use adaptive time stepping based on error estimates +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limiter!), + maxiters = 1.0e7, + dt = 1.0, + save_everystep = false, callback = callbacks); + +summary_callback() # print the timer summary \ No newline at end of file From e67151f71171b09ab223d492889f43ac8e7c3949 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 6 Nov 2024 18:20:07 +0100 Subject: [PATCH 066/115] adaptive mesh refinement testing --- examples/elixir_rainy_euler_bubble_amr.jl | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_amr.jl b/examples/elixir_rainy_euler_bubble_amr.jl index 45624771..252bf506 100644 --- a/examples/elixir_rainy_euler_bubble_amr.jl +++ b/examples/elixir_rainy_euler_bubble_amr.jl @@ -223,7 +223,7 @@ boundary_conditions = (x_neg = boundary_condition_periodic, surface_flux = flux_lax_friedrichs #volume_integral = VolumeIntegralFluxDifferencing(flux_chandrashekar) -polydeg = 2 +polydeg = 1 basis = LobattoLegendreBasis(polydeg) solver = DGSEM(basis, surface_flux)#, volume_integral) @@ -274,15 +274,12 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, amr_callback, save_solution, stepsize_callback) -# positivity limiter necessary for this tough example stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) ############################################################################### # run the simulation # use adaptive time stepping based on error estimates -sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limiter!), - maxiters = 1.0e7, - dt = 1.0, - save_everystep = false, callback = callbacks); +sol = solve(ode, SSPRK43(stage_limiter!); + ode_default_options()..., callback = callbacks); summary_callback() # print the timer summary \ No newline at end of file From 026d7676f793fb8a01df04e5a02911eee11565cf Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Mon, 18 Nov 2024 00:30:06 +0100 Subject: [PATCH 067/115] rain testing --- examples/elixir_rainy_euler_bubble.jl | 24 ++++++++++---------- examples/elixir_rainy_euler_bubble_amr.jl | 6 ++--- src/callbacks_stage/nonlinear_solve_dg2d.jl | 8 ++++--- src/equations/compressible_rainy_euler_2d.jl | 18 +++++++++------ 4 files changed, 31 insertions(+), 25 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble.jl b/examples/elixir_rainy_euler_bubble.jl index ca2d08e3..08b2cfde 100644 --- a/examples/elixir_rainy_euler_bubble.jl +++ b/examples/elixir_rainy_euler_bubble.jl @@ -7,12 +7,13 @@ using TrixiAtmo: source_terms_rainy, saturation_residual, flux_chandrashekar, flux_LMARS, source_terms_no_phase_change using NLsolve: nlsolve +#using Plots # domain coordinates_min = ( 0.0, 0.0) -coordinates_max = (3600.0, 2400.0) +coordinates_max = (2400.0, 2400.0) # hydrostatic dry potential temperature @@ -112,7 +113,7 @@ end function AtmosphereLayers(equations::CompressibleRainyEulerEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) # constants - humidity_rel0 = 0.2 # hydrostatic relative humidity + humidity_rel0 = 0.45 # hydrostatic relative humidity surface_pressure = 8.5e4 # surface layer with initial guesses for rho_dry, rho_vapour and temperature @@ -155,11 +156,12 @@ function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerE ref_L = equations.ref_latent_heat_vap_temp # problem specific constants - humidity_rel_bar = 0.2 # background relative humidity field + humidity_rel_bar = 0.45 # background relative humidity field + humidity_max = 1.0 # bubble parameters radius_outer, radius_inner = 300.0, 200.0 # radii of humidity bubble - x_center, z_center = 1800.0, 800.0 # center of humidity bubble + x_center, z_center = 1200.0, 800.0 # center of humidity bubble # radius relative to bubble center r = sqrt((x[1] - x_center)^2 + (x[2] - z_center)^2) @@ -170,10 +172,10 @@ function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerE humidity = humidity_rel_bar elseif (r > radius_inner) # outer layers of the bubble - humidity = humidity_rel_bar + (1.0 - humidity_rel_bar) * cos(pi * (r - radius_inner) / (2.0 * (radius_outer - radius_inner)))^2 + humidity = humidity_rel_bar + (humidity_max - humidity_rel_bar) * cos(pi * (r - radius_inner) / (2.0 * (radius_outer - radius_inner)))^2 else # inner layer - humidity = 1.0 + humidity = humidity_max end # get atmosphere layer and height information @@ -219,7 +221,7 @@ boundary_conditions = (x_neg = boundary_condition_periodic, y_neg = boundary_condition_slip_wall, y_pos = boundary_condition_slip_wall) -polydeg = 2 +polydeg = 1 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_lax_friedrichs @@ -227,7 +229,7 @@ surface_flux = flux_lax_friedrichs solver = DGSEM(basis, surface_flux)#, volume_integral) -cells_per_dimension = (400, 200) +cells_per_dimension = (200, 200) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = (true, false)) @@ -270,9 +272,7 @@ stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacob ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limiter!), - maxiters = 1.0e7, - dt = 1.0, - save_everystep = false, callback = callbacks); +sol = solve(ode, SSPRK43(stage_limiter!); ode_default_options()..., + maxiters = 1.0e7, save_everystep = false, callback = callbacks); summary_callback() \ No newline at end of file diff --git a/examples/elixir_rainy_euler_bubble_amr.jl b/examples/elixir_rainy_euler_bubble_amr.jl index 252bf506..68257764 100644 --- a/examples/elixir_rainy_euler_bubble_amr.jl +++ b/examples/elixir_rainy_euler_bubble_amr.jl @@ -231,7 +231,7 @@ solver = DGSEM(basis, surface_flux)#, volume_integral) mesh = TreeMesh(coordinates_min, coordinates_max, initial_refinement_level = 8, periodicity = (true, false), - n_cells_max = 10_000_000) + n_cells_max = 1_000_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, source_terms = source_terms_rainy, solver, @@ -261,11 +261,11 @@ amr_indicator = IndicatorMax(semi, variable=rain_density) amr_controller = ControllerThreeLevel(semi, amr_indicator, base_level = 8, med_level = 10, med_threshold = 1e-6, - max_level = 12, max_threshold = 5e-5) + max_level = 11, max_threshold = 5e-5) amr_callback = AMRCallback(semi, amr_controller, interval = 1, - adapt_initial_condition = true, + adapt_initial_condition = false, adapt_initial_condition_only_refine = true) stepsize_callback = StepsizeCallback(cfl = 1.0) diff --git a/src/callbacks_stage/nonlinear_solve_dg2d.jl b/src/callbacks_stage/nonlinear_solve_dg2d.jl index 544a0234..4a00d9f9 100644 --- a/src/callbacks_stage/nonlinear_solve_dg2d.jl +++ b/src/callbacks_stage/nonlinear_solve_dg2d.jl @@ -1,4 +1,4 @@ -using Trixi: get_node_vars, @batch, get_inverse_jacobian, set_node_vars! +using Trixi: get_node_vars, @batch, get_inverse_jacobian, set_node_vars!, get_node_coords using LinearAlgebra using StaticArrays @@ -124,9 +124,11 @@ function nonlinear_solve_dg_2d!(u, residual, jacobian, variables_index_vector, t u_node = get_node_vars(u, equations, dg, i, j, element) guess = SVector(u_node[7], u_node[8], u_node[9]) + x_node = get_node_coords(cache.elements.node_coordinates, equations, dg, i, j, element) + # keep rain positive - if (u_node[3] < 0.0) - u[3, i, j, element] = 0.0 + if (u_node[3] < 0.0 || x_node[2] < 50.0) + u[3, i, j, element] = 0.0 end if (u_node[3] > rain_threshold) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 0383e461..5eb4cf2c 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -296,7 +296,6 @@ end error("rho vapour less than zero") end if ( rho_cloud < 0.0 ) - display(rho_cloud) error("rho cloud less than zero") end @@ -505,8 +504,13 @@ end S_auto_conversion = 0.001 * rho_cloud S_accretion = 1.72 * rho_cloud * rho_rain^(0.875) S_rain = S_auto_conversion + S_accretion - S_evaporation + S_groundwater = 0.0 + #= + if (x[2] < 100.0) + S_groundwater = rho_rain * (1 - (x[2] * 0.01)^2) + end=# - return SVector(0.0, -S_rain, S_rain, 0.0, + return SVector(0.0, -S_rain, S_rain - S_groundwater, 0.0, -rho * g, -rho_v2 * g, 0.0, 0.0, 0.0) end @@ -562,10 +566,9 @@ end else v_ll = abs(v2_ll) v_rr = abs(v2_rr) - v_rr += abs(v_r_rr) end - - return max(v_ll, v_rr) + max(v_sound_ll, v_sound_rr) + # experimental + return max(v_ll, v_rr) + max(v_sound_ll, v_sound_rr) + max(abs(v_r_ll), abs(v_r_rr)) end @@ -877,8 +880,9 @@ end f_rhov2 = (f_dry + f_moist + f_rain) * v2_avg + normal_direction[2] * p_int #- rho_rain_mean * vr_dot_n_avg * v2_avg f_energy = (( c_vd * inv_temperature_mean - K_avg) * f_dry + (ref_L + c_vv * inv_temperature_mean - K_avg) * f_vapour + - ( c_l * inv_temperature_mean - K_avg) * (f_cloud + f_rain) + v1_avg * f_rhov1 + v2_avg * f_rhov2) - + ( c_l * inv_temperature_mean - K_avg) * (f_cloud + f_rain) + v1_avg * f_rhov1 + v2_avg * f_rhov2) #- + #( c_l * inv_temperature_mean + K_avg) * rho_rain_mean * vr_dot_n_avg + return SVector(f_dry, f_moist, f_rain, f_rhov1, f_rhov2, f_energy, 0.0, 0.0, 0.0) end From 0f0fcf868071ea2e0b83eb85819f7211f1c8ce78 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Mon, 18 Nov 2024 00:33:59 +0100 Subject: [PATCH 068/115] added a template (copy of rainy euler) for possible implementation with potential temperature --- ...le_rainy_euler_potential_temperature_2d.jl | 802 ++++++++++++++++++ 1 file changed, 802 insertions(+) create mode 100644 src/equations/compressible_rainy_euler_potential_temperature_2d.jl diff --git a/src/equations/compressible_rainy_euler_potential_temperature_2d.jl b/src/equations/compressible_rainy_euler_potential_temperature_2d.jl new file mode 100644 index 00000000..422a0f39 --- /dev/null +++ b/src/equations/compressible_rainy_euler_potential_temperature_2d.jl @@ -0,0 +1,802 @@ +using Trixi +using NLsolve: nlsolve +import Trixi: varnames, + cons2prim, cons2entropy, + flux, flux_chandrashekar, + max_abs_speeds, max_abs_speed_naive, + boundary_condition_slip_wall + + + +### Implementation similar to: +# Sabine Doppler, Philip L. Lederer, Joachim Schöberl, Henry von Wahl, +# A discontinuous Galerkin approach for atmospheric flows with implicit condensation, +# Journal of Computational Physics, +# Volume 499, +# 2024, +# 112713, +# ISSN 0021-9991 + + + +@muladd begin + +### equation, parameters and constants ### + +struct CompressibleRainyEulerEquations2D{RealT <: Real} <: AbstractCompressibleRainyEulerEquations{2, 9} + # Specific heat capacities: + c_liquid_water ::RealT + c_dry_air_const_pressure ::RealT + c_dry_air_const_volume ::RealT + c_vapour_const_pressure ::RealT + c_vapour_const_volume ::RealT + + # Gas constants: + R_dry_air ::RealT + R_vapour ::RealT + eps ::RealT + + # Reference values: + ref_saturation_pressure ::RealT + ref_temperature ::RealT + ref_latent_heat_vap_temp ::RealT + ref_pressure ::RealT + + # Other: + gravity ::RealT + rain_water_distr ::RealT + v_mean_rain ::RealT +end + + +function CompressibleRainyEulerEquations2D(; RealT = Float64) + # Specific heat capacities: + c_liquid_water = 4186.0 + c_dry_air_const_pressure = 1004.0 + c_dry_air_const_volume = 717.0 + c_vapour_const_pressure = 1885.0 + c_vapour_const_volume = 1424.0 + + # Gas constants: + R_dry_air = c_dry_air_const_pressure - c_dry_air_const_volume + R_vapour = c_vapour_const_pressure - c_vapour_const_volume + eps = R_dry_air / R_vapour + + # Reference values: + ref_saturation_pressure = 610.7 # This needs to be adjusted if ref_temperature is changed! + ref_temperature = 273.15 + ref_latent_heat_vap_temp = 2.5e6#3147620.0 + ref_pressure = 1e5 + + # Other: + gravity = 9.81 + rain_water_distr = 8e6 + v_mean_rain = 130.0 + + return CompressibleRainyEulerEquations2D{RealT}(c_liquid_water, c_dry_air_const_pressure, c_dry_air_const_volume, + c_vapour_const_pressure, c_vapour_const_volume, R_dry_air, + R_vapour, eps, ref_saturation_pressure, ref_temperature, + ref_latent_heat_vap_temp, ref_pressure, gravity, + rain_water_distr, v_mean_rain) +end + + + +### conversion ### + +@inline function cons2prim(u, equations::CompressibleRainyEulerEquations2D) + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + + # energy density + energy = energy_density(u, equations) + + # nonlinear system + rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) + + return SVector(rho_dry, rho_moist, rho_rain, v1, v2, energy, rho_vapour, rho_cloud, temperature) +end + + +@inline function cons2entropy(u, equations::CompressibleRainyEulerEquations2D) + #TODO + return SVector(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) +end + + +# adapted from compressible_moist_euler_2d.jl +@inline function cons2eq_pot_temp(u, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_pd = equations.c_dry_air_const_pressure + c_pv = equations.c_vapour_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + ref_p = equations.ref_pressure + ref_temp = equations.ref_temperature + ref_L = equations.ref_latent_heat_vap_temp + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + + # energy density + energy = energy_density(u, equations) + + # nonlinear system + rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) + + # pressure + p = pressure(u, equations) + + p_v = rho_vapour * R_v * temperature + p_d = p - p_v + T_C = temperature - ref_temp + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + H = p_v / p_vs + r_v = rho_vapour / rho_dry + r_c = rho_cloud / rho_dry + r_r = rho_rain / rho_dry + L_v = ref_L + (c_pv - c_l) * temperature + c_p = c_pd + (r_v + r_c + r_r) * c_l + + # equivalent potential temperature + eq_pot = (temperature * (ref_p / p_d)^(R_d / c_p) * H^(-r_v * R_v / c_p) * + exp(L_v * r_v * inv(c_p * temperature))) + + return SVector(rho, r_v, r_c, r_r, v1, v2, eq_pot, p) +end + + +@inline function cons2nonlinearsystemsol(u, equations::CompressibleRainyEulerEquations2D) + # constants + c_vd = equations.c_dry_air_const_volume + #ref_temp = equations.ref_temperature + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + + # energy density + energy = energy_density(u, equations) + + # recover temperature explicitly from energy when other variables are zero + if (rho_moist == 0.0 && rho_rain == 0.0) + # energy density definition without ref_temp for dry case + energy_kinetic = 0.5 * (v1^2 + v2^2) * rho + temperature = (energy - energy_kinetic) / (c_vd * rho) #+ ref_temp + + if (temperature < 0.0) + error("temp negative") + end + + return SVector(0.0, 0.0, temperature) + else + # experimental and overly simple positivity check + rho_vapour = u[7] + rho_cloud = u[8] + temperature = u[9] + + if (rho_vapour < 0.0 && isapprox(rho_vapour, 0.0, atol = 1e-15)) + rho_vapour = 0.0 + end + + if (rho_cloud < 0.0 && isapprox(rho_cloud, 0.0, atol = 1e-15)) + rho_cloud = 0.0 + end + + return SVector(rho_vapour, rho_cloud, temperature) + end +end + + +# for convenience +@inline function cons2speeds(u, equations::CompressibleRainyEulerEquations2D) + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + + # get speed of sound + v_sound = speed_of_sound(u, equations)[1] + + # get terminal velocity rain + v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) + + return SVector(v1, v2, v_sound, v_r) +end + + + +### varnames ### + +varnames(::typeof(cons2cons), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_moist", "rho_rain", + "rho_v1", "rho_v2", + "potential_temperature", + "rho_vapour", "rho_cloud", "temperature") + + +varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_moist", "rho_rain", + "v1", "v2", + "energy_density", + "rho_vapour", "rho_cloud", "temperature") + +varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquations2D) = ("rho", "r_vapour", + "r_cloud", "r_rain", + "v1", "v2", "eq_pot_temp", + "pressure") + + + +### physics variables ### + +@inline function densities(u, equations::CompressibleRainyEulerEquations2D) + # densities + rho_dry = u[1] + rho_moist = u[2] + rho_rain = u[3] + rho = rho_dry + rho_moist + rho_rain + rho_inv = inv(rho) + + return SVector(rho_dry, rho_moist, rho_rain, rho, rho_inv) +end + +@inline function rain_density(u, equations::CompressibleRainyEulerEquations2D) + return u[3] +end + +@inline function velocities(u, rho_inv, equations::CompressibleRainyEulerEquations2D) + return SVector(u[4] * rho_inv, u[5] * rho_inv) +end + + +@inline function energy_density(u, equations::CompressibleRainyEulerEquations2D) + return u[6] +end + + +@inline function pressure(u, equations::CompressibleRainyEulerEquations2D) + # constants + R_d = equations.R_dry_air + R_v = equations.R_vapour + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) + + p = (R_d * rho_dry + R_v * rho_vapour) * temperature + + return p +end + + +@inline function speed_of_sound(u, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + + # densities + rho_dry, _, rho_rain, _, rho_inv = densities(u, equations) + + # recover rho_vapour, rho_cloud, temperature from nonlinear system + rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) + if ( rho_vapour < 0.0 ) + error("rho vapour less than zero") + end + if ( rho_cloud < 0.0 ) + #display(rho_cloud) + error("rho cloud less than zero") + end + + # formula + p = pressure(u, equations) + q_v = rho_vapour / rho_dry + q_l = (rho_cloud + rho_rain) / rho_dry + gamma_m = 1 + (R_d + R_v * q_v) / (c_vd + c_vv * q_v + c_l * q_l) + + if (rho_inv < 0.0) + error("rho less than zero") + elseif (p < 0.0) + error("pressure less than zero") + end + + v_sound = sqrt(gamma_m * p * rho_inv) + + return SVector(v_sound, gamma_m) +end + + +@inline function terminal_velocity_rain(rho_moist, rho_rain, equations::CompressibleRainyEulerEquations2D) + # constants + N_0 = equations.rain_water_distr + v_0 = equations.v_mean_rain + + # formula ( \Gamma(4.5) / 6 ~= 1.9386213994279082 ) + if ( rho_rain > 0.0) + v_terminal_rain = v_0 * 1.9386213994279082 * (rho_rain / (pi * (rho_moist + rho_rain) * N_0))^(0.125) + else + v_terminal_rain = 0.0 + end + + return v_terminal_rain +end + + +@inline function saturation_vapour_pressure(temperature, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_pv = equations.c_vapour_const_pressure + R_v = equations.R_vapour + ref_s_p = equations.ref_saturation_pressure + ref_temp = equations.ref_temperature + ref_L = equations.ref_latent_heat_vap_temp + + # testing + if (temperature < 0.0) + display(temperature) + error("temp less than zero") + end + + # Clausius Clapeyron formula + p_vapour_saturation = ref_s_p * (temperature / ref_temp)^((c_pv - c_l) / R_v) + p_vapour_saturation *= exp(((ref_L - (c_pv - c_l) * ref_temp) / R_v) * (1 / ref_temp - 1 / temperature)) + + return p_vapour_saturation +end + + +@inline function saturation_vapour_pressure_derivative(temperature, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_pv = equations.c_vapour_const_pressure + R_v = equations.R_vapour + ref_s_p = equations.ref_saturation_pressure + ref_temp = equations.ref_temperature + ref_L = equations.ref_latent_heat_vap_temp + + # testing + if (temperature < 0.0) + display(temperature) + error("temp less than zero") + end + + const_1 = (c_pv - c_l) / R_v + const_2 = (ref_L - (c_pv - c_l) * ref_temp) / R_v + + p_vapour_saturation_derivative = ref_s_p / (ref_temp^const_1) + p_vapour_saturation_derivative *= (const_1 * temperature^(const_1 - 1) + const_2 * temperature^(const_1 - 2)) + p_vapour_saturation_derivative *= exp(const_2 * (1 / ref_temp - 1 / temperature)) + + return p_vapour_saturation_derivative +end + + + +### pde discretization ### + +@inline function flux(u, orientation::Integer, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + + #densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + # recover rho_vapour, rho_cloud, temperature from nonlinear system + rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) + + # pressure + p = pressure(u, equations) + + # energy density + energy = energy_density(u, equations) + + # flux for orientation cases + if (orientation == 1) + # "mass" + f1 = rho_dry * v1 + f2 = rho_moist * v1 + f3 = rho_rain * v1 + + # "momentum" + f4 = rho * v1 * v1 + p + f5 = rho * v1 * v2 + + # "energy" + f6 = (energy + p) * v1 + + else + # "mass" + f1 = rho_dry * v2 + f2 = rho_moist * v2 + f3 = rho_rain * (v2 - v_r) + + # "momentum" + f4 = rho * v1 * v2 - rho_rain * v_r * v1 + f5 = rho * v2 * v2 + p - rho_rain * v_r * v2 + + # "energy" + f6 = (energy + p) * v2 - (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r + end + + return SVector(f1, f2, f3, f4, f5, f6, + 0.0, 0.0, 0.0) +end + + +@inline function flux(u, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + # recover rho_vapour, rho_cloud, temperature from nonlinear system + rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) + + # normal velocities + v_normal = v1 * normal_direction[1] + v2 * normal_direction[2] + v_r_normal = v_r * normal_direction[2] + + # pressure + p = pressure(u, equations) + + # energy density + energy = energy_density(u, equations) + + # flux + # "mass" + f1 = rho_dry * v_normal + f2 = rho_moist * v_normal + f3 = rho_rain * (v_normal - v_r_normal) + + # "momentum" + f4 = rho * v_normal * v1 + p * normal_direction[1] - rho_rain * v_r_normal * v1 + f5 = rho * v_normal * v2 + p * normal_direction[2] - rho_rain * v_r_normal * v2 + + # "energy" + f6 = (energy + p) * v_normal - (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r_normal + + return SVector(f1, f2, f3, f4, f5, f6, + 0.0, 0.0, 0.0) +end + + +# no Coriolis term +@inline function source_terms_rainy(u, x, t, equations::CompressibleRainyEulerEquations2D) + # constants + R_v = equations.R_vapour + ref_temp = equations.ref_temperature + g = equations.gravity + + # name needed variables + rho_v2 = u[5] + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + # recover rho_vapour, rho_cloud, temperature from nonlinear system + rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) + + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + + # source terms phase change + S_evaporation = (3.86e-3 - 9.41e-5 * (temperature - ref_temp)) * (1 + 9.1 * rho_rain^(0.1875)) + S_evaporation *= (rho_vs - rho_vapour) * rho_rain^(0.5) + S_auto_conversion = 0.001 * rho_cloud + S_accretion = 1.72 * rho_cloud * rho_rain^(0.875) + S_rain = S_auto_conversion + S_accretion - S_evaporation + S_groundwater = 0.0 + #= + if (x[2] < 100.0) + S_groundwater = rho_rain * (1 - (x[2] * 0.01)^2) + end=# + + return SVector(0.0, -S_rain, S_rain - S_groundwater, 0.0, + -rho * g, -rho_v2 * g, 0.0, 0.0, 0.0) +end + + +# no phase changes and no Coriolis term +@inline function source_terms_no_phase_change(u, x, t, equations::CompressibleRainyEulerEquations2D) + # constants + g = equations.gravity + + # name needed variables + rho_v2 = u[5] + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + return SVector(0.0, 0.0, 0.0, 0.0, + -g * rho, -g * rho_v2, 0.0, 0.0, 0.0) +end + + +@inline function max_abs_speeds(u, equations::CompressibleRainyEulerEquations2D) + # name needed variables + v1, v2, v_sound, v_r = cons2speeds(u, equations) + + return SVector((abs(v1) + v_sound), (abs(v2) + v_sound + abs(v_r))) +end + + +@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) + # name needed variables + v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) + v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) + + # calculate upper bounds for left and right speed + v_ll_max = abs(v1_ll * normal_direction[1] + v2_ll * normal_direction[2]) + v_ll_max += abs( v_r_ll * normal_direction[2]) + + v_rr_max = abs(v1_rr * normal_direction[1] + v2_rr * normal_direction[2]) + v_rr_max += abs( v_r_rr * normal_direction[2]) + + return max(v_ll_max, v_rr_max) + max(v_sound_ll, v_sound_rr) * norm(normal_direction) +end + + +@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::CompressibleRainyEulerEquations2D) + # name needed variables + v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) + v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) + + if (orientation == 1) + v_ll = abs(v1_ll) + v_rr = abs(v1_rr) + else + v_ll = abs(v2_ll) + v_rr = abs(v2_rr) + end + + return max(v_ll, v_rr) + max(v_sound_ll, v_sound_rr) + max(abs(v_r_ll), abs(v_r_rr)) +end + + +### boundary conditions ### + +# adapted from compressible_moist_euler_2d.jl which was probably adapted from compressible_euler_2d.jl +@inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, x, t, + surface_flux_function, equations::CompressibleRainyEulerEquations2D) + + norm_ = norm(normal_direction) + # Normalize the vector without using `normalize` since we need to multiply by the `norm_` later + normal = normal_direction / norm_ + + # rotate the internal solution state + u_local = rotate_to_x(u_inner, normal, equations) + + # name needed variables + rho_v1 = u_local[4] + + # densities + rho_dry_local, rho_moist_local, rho_rain_local, rho_local, rho_inv_local = densities(u_local, equations) + + # velocities + v_normal = rho_v1 * rho_inv_local + v_sound, gamma = speed_of_sound(u_local, equations) + + # pressure + p_local = pressure(u_local, equations) + + # Get the solution of the pressure Riemann problem + # See Section 6.3.3 of + # Eleuterio F. Toro (2009) + # Riemann Solvers and Numerical Methods for Fluid Dynamics: A Practical Introduction + # [DOI: 10.1007/b79761](https://doi.org/10.1007/b79761) + if v_normal <= 0.0 + p_star = p_local * + (1.0 + 0.5 * (gamma - 1) * v_normal / v_sound)^(2.0 * gamma * + inv(gamma - 1)) + else # v_normal > 0.0 + A = 2.0 / ((gamma + 1) * rho_local) + B = p_local * (gamma - 1) / (gamma + 1) + p_star = p_local + + 0.5 * v_normal / A * + (v_normal + sqrt(v_normal^2 + 4.0 * A * (p_local + B))) + end + + # For the slip wall we directly set the flux as the normal velocity is zero + return SVector(0.0, 0.0, 0.0, + p_star * normal[1] * norm_, + p_star * normal[2] * norm_, + 0.0, 0.0, 0.0, 0.0) +end + + +# same as in compressible_euler_2d.jl +@inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, direction, x, t, + surface_flux_function, equations::CompressibleRainyEulerEquations2D) + # flip sign of normal to make it outward pointing, then flip the sign of the normal flux back + # to be inward pointing on the -x and -y sides due to the orientation convention used by StructuredMesh + if isodd(direction) + boundary_flux = -boundary_condition_slip_wall(u_inner, -normal_direction, + x, t, surface_flux_function, + equations) + else + boundary_flux = boundary_condition_slip_wall(u_inner, normal_direction, + x, t, surface_flux_function, + equations) + end + + return boundary_flux +end + + +# same as in compressible_euler_2d.jl +@inline function rotate_to_x(u, normal_vector, equations::CompressibleRainyEulerEquations2D) + # cos and sin of the angle between the x-axis and the normalized normal_vector are + # the normalized vector's x and y coordinates respectively (see unit circle). + c = normal_vector[1] + s = normal_vector[2] + + return SVector(u[1], u[2], u[3], + c * u[4] + s * u[5], + -s * u[4] + c * u[5], + u[6], u[7], u[8], u[9]) +end + + +# should be used together with TreeMesh (adapted from compressible_euler_2d.jl) +@inline function boundary_condition_slip_wall(u_inner, orientation, direction, x, t, surface_flux_function, + equations::CompressibleRainyEulerEquations2D) + # get the appropriate normal vector from the orientation + RealT = eltype(u_inner) + if orientation == 1 + normal_direction = SVector(one(RealT), zero(RealT)) + else # orientation == 2 + normal_direction = SVector(zero(RealT), one(RealT)) + end + + # compute and return the flux using `boundary_condition_slip_wall` routine above + return boundary_condition_slip_wall(u_inner, normal_direction, direction, + x, t, surface_flux_function, equations) +end + + +### Nonlinear System Residual ### + +# in preparation for a callback to solve the nonlinear system +@inline function saturation_residual(u, guess, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + + # energy density + energy = energy_density(u, equations) + + # define residual + residual1 = (c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain)) * guess[3] + residual1 += guess[1] * L_ref + residual1 -= (energy - rho * 0.5 * (v1^2 + v2^2)) + + residual2 = min(saturation_vapour_pressure(guess[3], equations) / (R_v * guess[3]), rho_moist) + residual2 -= guess[1] + residual2 *= 1e7 + + residual3 = rho_moist + residual3 -= guess[1] + guess[2] + residual3 *= 1e7 + + return SVector(residual1, residual2, residual3) +end + + + +@inline function saturation_residual_jacobian(u, guess, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + # saturation + svp = saturation_vapour_pressure(guess[3], equations) + svp_t = saturation_vapour_pressure_derivative(guess[3], equations) + + # define jacobian + J_11 = c_vv * guess[3] + L_ref + J_12 = c_l * guess[3] + J_13 = c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain) + + J_21 = -1e7 + J_22 = 0.0 + + if (svp / (R_v * guess[3]) < rho_moist) + J_23 = (svp_t * guess[3] - svp) / (R_v * guess[3]^2) * 1e7 + else + J_23 = 0.0 + end + + J_31 = -1e7 + J_32 = -1e7 + J_33 = 0.0 + + return SMatrix{3, 3}(J_11, J_21, J_31, J_12, J_22, J_32, J_13, J_23, J_33) +end + + +# TODO Careful with rain != 0.0 does not really work (bad physics) +# fluxes adapted from compressible_moist_euler_2d.jl + +# Low Mach number approximate Riemann solver (LMARS) from +# X. Chen, N. Andronova, B. Van Leer, J. E. Penner, J. P. Boyd, C. Jablonowski, S. +# Lin, A Control-Volume Model of the Compressible Euler Equations with a Vertical Lagrangian +# Coordinate Monthly Weather Review Vol. 141.7, pages 2526–2544, 2013, +# https://journals.ametsoc.org/view/journals/mwre/141/7/mwr-d-12-00129.1.xml. +@inline function flux_LMARS(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) + # constants + a = 360.0 + + # densities + rho_dry_ll, rho_moist_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) + rho_dry_rr, rho_moist_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) + + # pressure + p_ll = pressure(u_ll, equations) + p_rr = pressure(u_rr, equations) + + # velocities + v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) + v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) + + v_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] + v_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] + norm_ = norm(normal_direction) + + # diffusion parameter 0.0 < beta <= 1.0 + beta = 1.0 + + # interface flux components + rho = 0.5 * (rho_ll + rho_rr) + p_interface = 0.5 * (p_ll + p_rr) - beta * 0.5 * a * rho * (v_rr - v_ll) / norm_ + v_interface = 0.5 * (v_ll + v_rr) - beta * 1 / (2 * a * rho) * (p_rr - p_ll) * norm_ + + if (v_interface > 0) + f1, f2, f3, f4, f5, f6, _, _, _ = u_ll * v_interface + f6 += p_ll * v_interface + else + f1, f2, f3, f4, f5, f6, _, _, _ = u_rr * v_interface + f6 += p_rr * v_interface + end + + return SVector(f1, f2, f3, + f4 + p_interface * normal_direction[1], + f5 + p_interface * normal_direction[2], + f6, 0.0, 0.0, 0.0) +end + +end #muladd \ No newline at end of file From 773d8cbad3223fdf4266be6d9fbf8af4ba4ac34c Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 19 Nov 2024 02:09:40 +0100 Subject: [PATCH 069/115] added rainy bubble with diffusion --- .../elixir_rainy_euler_bubble_diffusion.jl | 289 ++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 examples/elixir_rainy_euler_bubble_diffusion.jl diff --git a/examples/elixir_rainy_euler_bubble_diffusion.jl b/examples/elixir_rainy_euler_bubble_diffusion.jl new file mode 100644 index 00000000..4c7f37a6 --- /dev/null +++ b/examples/elixir_rainy_euler_bubble_diffusion.jl @@ -0,0 +1,289 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: source_terms_rainy, saturation_residual, + saturation_residual_jacobian, NonlinearSolveDG, + cons2eq_pot_temp, saturation_vapour_pressure, + flux_chandrashekar, flux_LMARS, + source_terms_no_phase_change, + boundary_condition_laplace +using NLsolve: nlsolve +#using Plots + + + +# domain +coordinates_min = ( 0.0, 0.0) +coordinates_max = (2400.0, 2400.0) + + +# hydrostatic dry potential temperature +function theta_d(z, equations::CompressibleRainyEulerEquations2D) + # constants + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + ref_pressure = equations.ref_pressure + + # problem specific constants + surface_temperature = 283.0 + surface_pressure = 8.5e4 + stratification = 1.3e-5 + + # dry potential temperature at surface + Theta0 = surface_temperature * (ref_pressure / surface_pressure)^(R_d / c_pd) + # at height z + theta_d = Theta0 * exp(stratification * z) + + return theta_d +end + + +# hydrostatic base state residual +function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equations::CompressibleRainyEulerEquations2D) + # equations constants + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure + g = equations.gravity + + function hydrostatic_residual!(residual, guess) + # variables + pressure, rho_dry, rho_vapour, temperature = guess + + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + + # pressure derivative residual approximation + residual[1] = (pressure - pressure_lower) / dz + (rho_dry + rho_vapour) * g + + # pressure residual + residual[2] = pressure - temperature * (rho_dry * R_d + rho_vapour * R_v) + + # hydrostatic dry potential temperature residual + residual[3] = theta_d(z, equations) - temperature * (ref_pressure / pressure)^(R_d / c_pd) + + # humidity residual + residual[4] = rho_vs * (rho_dry + rho_vapour / eps) * humidity_rel0 + residual[4] -= rho_vapour * (rho_dry + rho_vs / eps) + residual[4] *= 1000.0 + end + + return hydrostatic_residual! +end + + +function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equations::CompressibleRainyEulerEquations2D) + # equations constants + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure + + function perturbation_residual!(residual, guess) + # variables + rho_dry, rho_vapour, temperature = guess + + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + pressure = (rho_dry * R_d + rho_vapour * R_v) * temperature + + # humidity residual + residual[1] = rho_vs * (rho_dry + rho_vapour / eps) * H_init + residual[1] -= rho_vapour * (rho_dry + rho_vs / eps) + residual[1] *= 30.0 + + # hydrostatic dry potential temperature residual + residual[2] = theta_d(z, equations) - temperature * (ref_pressure / pressure_hydrostatic)^(R_d / c_pd) + + # pressure residual + residual[3] = pressure_hydrostatic - pressure + end + + return perturbation_residual! +end + + +# for approximating the dz pressure gradient +struct AtmosphereLayers{RealT <: Real} + layer_data ::Matrix{RealT} + total_height ::RealT + precision ::RealT +end + + +function AtmosphereLayers(equations::CompressibleRainyEulerEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) + # constants + humidity_rel0 = 0.2 # hydrostatic relative humidity + surface_pressure = 8.5e4 + + # surface layer with initial guesses for rho_dry, rho_vapour and temperature + surface_layer = [surface_pressure, 1.4, 0.04, 300.0] + + # allocate layer_data + n = convert(Int, total_height / precision) + layer_data = zeros(RealT, n + 1, 4) + + # solve (slightly above) surface layer + dz = 0.01 + z = 0.01 + residual_function! = generate_hydrostatic_residual(surface_pressure, humidity_rel0, z, dz, equations) + layer_data[1, :] .= nlsolve(residual_function!, surface_layer).zero + + # adjust to chosen precision + dz = precision + + # iterate up the atmosphere + for i in (1:n) + z += dz + residual_function! = generate_hydrostatic_residual(layer_data[i, 1], humidity_rel0, z, dz, equations) + guess = deepcopy(layer_data[i, :]) + layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, iterations = 20).zero + end + + return AtmosphereLayers{RealT}(layer_data, total_height, precision) +end + + +# create layers for initial condition +equations = CompressibleRainyEulerEquations2D() +layers = AtmosphereLayers(equations) + + +function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerEquations2D; atmosphere_layers = layers) + # equations constants + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + ref_L = equations.ref_latent_heat_vap_temp + + # problem specific constants + humidity_rel_bar = 0.2 # background relative humidity field + humidity_max = 1.0 + + # bubble parameters + radius_outer, radius_inner = 300.0, 200.0 # radii of humidity bubble + x_center, z_center = 1200.0, 800.0 # center of humidity bubble + + # radius relative to bubble center + r = sqrt((x[1] - x_center)^2 + (x[2] - z_center)^2) + + # humidity definition + if (r > radius_outer) + # outside the bubble + humidity = humidity_rel_bar + elseif (r > radius_inner) + # outer layers of the bubble + humidity = humidity_rel_bar + (humidity_max - humidity_rel_bar) * cos(pi * (r - radius_inner) / (2.0 * (radius_outer - radius_inner)))^2 + else + # inner layer + humidity = humidity_max + end + + # get atmosphere layer and height information + @unpack layer_data, total_height, precision = atmosphere_layers + dz = precision + z = x[2] + n = convert(Int, floor((z + eps()) / dz)) + 1 + z_lower = (n - 1) * dz + z_upper = n * dz + + if (z_lower == total_height) + z_upper = z_lower + dz + n = n - 1 + end + + # check height consistency + if (z > total_height && !(isapprox(z, total_height))) + error("The atmosphere does not match the simulation domain") + end + + # get hydrostatic pressures and approximate between lower and upper data point + pressure_hydrostatic_lower = layer_data[n, 1] + pressure_hydrostatic_upper = layer_data[n + 1, 1] + pressure_hydrostatic = (pressure_hydrostatic_upper * (z - z_lower) + pressure_hydrostatic_lower * (z_upper - z)) / dz + + # solve perturbation + residual_function! = generate_perturbation_residual(pressure_hydrostatic, humidity, z, equations) + rho_dry, rho_vapour, temperature = nlsolve(residual_function!, layer_data[n, 2:4], ftol = 1e-9, iterations = 20).zero + + energy_density = (c_vd * rho_dry + c_vv * rho_vapour) * temperature + rho_vapour * ref_L + + return SVector(rho_dry, rho_vapour, 0.0, 0.0, 0.0, energy_density, rho_vapour, 0.0, temperature) +end + + + +############################################################################### +# semidiscretization of the compressible rainy Euler equations + +diffusivity = 0.4 +equations_parabolic = LaplaceDiffusion2D(diffusivity, equations) + + +boundary_conditions = (x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_slip_wall, + y_pos = boundary_condition_slip_wall) + +boundary_conditions_parabolic = ( + x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_laplace, + y_pos = boundary_condition_laplace) + + +polydeg = 1 +basis = LobattoLegendreBasis(polydeg) + +surface_flux = flux_lax_friedrichs +#volume_integral = VolumeIntegralFluxDifferencing(flux_chandrashekar) + +solver = DGSEM(basis, surface_flux)#, volume_integral) + +initial_condition = initial_condition_bubble_rainy +source_terms = source_terms_rainy + +mesh = TreeMesh(coordinates_min, coordinates_max, initial_refinement_level = 7, periodicity = (true, false), n_cells_max = 1_000_000) + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; source_terms, + boundary_conditions = (boundary_conditions, boundary_conditions_parabolic)) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 600.0) + +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 + +# entropy? +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:entropy_conservation_error,)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + output_directory = "out", + solution_variables = cons2eq_pot_temp) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) + +stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) + +############################################################################### +# run the simulation +sol = solve(ode, SSPRK43(stage_limiter!); ode_default_options()..., + maxiters = 1.0e7, save_everystep = false, callback = callbacks); + +summary_callback() \ No newline at end of file From d03bf4794fc4aea08391eedee96360c0b7a9fef2 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 19 Nov 2024 02:10:46 +0100 Subject: [PATCH 070/115] added boundary condition for laplace diffusion --- src/equations/compressible_rainy_euler_2d.jl | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 5eb4cf2c..722223e0 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -4,7 +4,8 @@ import Trixi: varnames, cons2prim, cons2entropy, flux, flux_chandrashekar, max_abs_speeds, max_abs_speed_naive, - boundary_condition_slip_wall + boundary_condition_slip_wall, + LaplaceDiffusion2D @@ -673,6 +674,18 @@ end end +# for parabolic terms (LaplaceDiffusion2D) +@inline function boundary_condition_laplace(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Trixi.Gradient, + equations_parabolic::LaplaceDiffusion2D) + return u_inner +end + +@inline function boundary_condition_laplace(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Trixi.Divergence, + equations_parabolic::LaplaceDiffusion2D) + return flux_inner +end + + ### Nonlinear System Residual ### # in preparation for a callback to solve the nonlinear system From 01947345262bcfa444947d147bdcb0bbdcb7696b Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 19 Nov 2024 02:11:24 +0100 Subject: [PATCH 071/115] added DGMulti example (work in progress) --- ...ixir_rainy_euler_bubble_no_rain_dgmulti.jl | 293 ++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100644 examples/elixir_rainy_euler_bubble_no_rain_dgmulti.jl diff --git a/examples/elixir_rainy_euler_bubble_no_rain_dgmulti.jl b/examples/elixir_rainy_euler_bubble_no_rain_dgmulti.jl new file mode 100644 index 00000000..bef45702 --- /dev/null +++ b/examples/elixir_rainy_euler_bubble_no_rain_dgmulti.jl @@ -0,0 +1,293 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: source_terms_no_phase_change, saturation_residual, + saturation_residual_jacobian, NonlinearSolveDG, + cons2eq_pot_temp, flux_LMARS, flux_chandrashekar +using NLsolve: nlsolve + + + +# Initial condition from elixir_moist_euler_bubble.jl +function moist_state(y, dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) + + @unpack p_0, g, c_pd, c_pv, c_vd, c_vv, R_d, R_v, c_pl, L_00 = equations + + (p, rho, T, r_t, r_v, rho_qv, theta_e) = y + p0 = y0[1] + + F = zeros(7, 1) + rho_d = rho / (1 + r_t) + p_d = R_d * rho_d * T + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + L = L_00 - (c_pl - c_pv) * T + + F[1] = (p - p0) / dz + g * rho + F[2] = p - (R_d * rho_d + R_v * rho_qv) * T + # H = 1 is assumed + F[3] = (theta_e - + T * (p_d / p_0)^(-R_d / (c_pd + c_pl * r_t)) * + exp(L * r_v / ((c_pd + c_pl * r_t) * T))) + F[4] = r_t - r_t0 + F[5] = rho_qv - rho_d * r_v + F[6] = theta_e - theta_e0 + a = p_vs / (R_v * T) - rho_qv + b = rho - rho_qv - rho_d + # H=1 => phi=0 + F[7] = a + b - sqrt(a * a + b * b) + + return F +end + +function generate_function_of_y(dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) + function function_of_y(y) + return moist_state(y, dz, y0, r_t0, theta_e0, equations) + end +end + +struct AtmosphereLayers{RealT <: Real} + equations::CompressibleMoistEulerEquations2D + # structure: 1--> i-layer (z = total_height/precision *(i-1)), 2--> rho, rho_theta, rho_qv, rho_ql + layer_data::Matrix{RealT} + total_height::RealT + preciseness::Int + layers::Int + ground_state::NTuple{2, RealT} + equivalent_potential_temperature::RealT + mixing_ratios::NTuple{2, RealT} +end + +function AtmosphereLayers(equations; total_height = 10010.0, preciseness = 10, + ground_state = (1.4, 100000.0), + equivalent_potential_temperature = 320, + mixing_ratios = (0.02, 0.02), RealT = Float64) + + @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl = equations + rho0, p0 = ground_state + r_t0, r_v0 = mixing_ratios + theta_e0 = equivalent_potential_temperature + + rho_qv0 = rho0 * r_v0 + T0 = theta_e0 + y0 = [p0, rho0, T0, r_t0, r_v0, rho_qv0, theta_e0] + + n = convert(Int, total_height / preciseness) + dz = 0.01 + layer_data = zeros(RealT, n + 1, 4) + + F = generate_function_of_y(dz, y0, r_t0, theta_e0, equations) + sol = nlsolve(F, y0) + p, rho, T, r_t, r_v, rho_qv, theta_e = sol.zero + + rho_d = rho / (1 + r_t) + rho_ql = rho - rho_d - rho_qv + kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * (p0 / p)^kappa_M * T * (1 + (R_v / R_d) * r_v) / (1 + r_t) + + layer_data[1, :] = [rho, rho_theta, rho_qv, rho_ql] + for i in (1:n) + y0 = deepcopy(sol.zero) + dz = preciseness + F = generate_function_of_y(dz, y0, r_t0, theta_e0, equations) + sol = nlsolve(F, y0) + p, rho, T, r_t, r_v, rho_qv, theta_e = sol.zero + + rho_d = rho / (1 + r_t) + rho_ql = rho - rho_d - rho_qv + kappa_M = (R_d * rho_d + R_v * rho_qv) / + (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * (p0 / p)^kappa_M * T * (1 + (R_v / R_d) * r_v) / (1 + r_t) + + layer_data[i + 1, :] = [rho, rho_theta, rho_qv, rho_ql] + end + + return AtmosphereLayers{RealT}(equations, layer_data, total_height, dz, n, ground_state, + theta_e0, mixing_ratios) +end + +# Moist bubble test case from paper: +# G.H. Bryan, J.M. Fritsch, A Benchmark Simulation for Moist Nonhydrostatic Numerical +# Models, MonthlyWeather Review Vol.130, 2917–2928, 2002, +# https://journals.ametsoc.org/view/journals/mwre/130/12/1520-0493_2002_130_2917_absfmn_2.0.co_2.xml. +function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, atmosphere_layers::AtmosphereLayers) + @unpack layer_data, preciseness, total_height = atmosphere_layers + dz = preciseness + z = x[2] + if (z > total_height && !(isapprox(z, total_height))) + error("The atmosphere does not match the simulation domain") + end + n = convert(Int, floor((z + eps()) / dz)) + 1 + z_l = (n - 1) * dz + (rho_l, rho_theta_l, rho_qv_l, rho_ql_l) = layer_data[n, :] + z_r = n * dz + if (z_l == total_height) + z_r = z_l + dz + n = n - 1 + end + (rho_r, rho_theta_r, rho_qv_r, rho_ql_r) = layer_data[n + 1, :] + rho = (rho_r * (z - z_l) + rho_l * (z_r - z)) / dz + rho_theta = rho * (rho_theta_r / rho_r * (z - z_l) + rho_theta_l / rho_l * (z_r - z)) / + dz + rho_qv = rho * (rho_qv_r / rho_r * (z - z_l) + rho_qv_l / rho_l * (z_r - z)) / dz + rho_ql = rho * (rho_ql_r / rho_r * (z - z_l) + rho_ql_l / rho_l * (z_r - z)) / dz + + rho, rho_e, rho_qv, rho_ql, T_loc = perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, + equations::CompressibleMoistEulerEquations2D) + + v1 = 0.0 + v2 = 0.0 + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_E = rho_e + 1 / 2 * rho * (v1^2 + v2^2) + + return SVector(rho - rho_qv - rho_ql, rho_qv + rho_ql, 0.0, rho_v1, rho_v2, rho_E, rho_qv, rho_ql, T_loc) +end + +function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, + equations::CompressibleMoistEulerEquations2D) + @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl, L_00 = equations + xc = 10000.0 + zc = 2000.0 + rc = 2000.0 + Δθ = 2.0 + + r = sqrt((x[1] - xc)^2 + (x[2] - zc)^2) + rho_d = rho - rho_qv - rho_ql + kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + p_loc = p_0 * (R_d * rho_theta / p_0)^(1 / (1 - kappa_M)) + T_loc = p_loc / (R_d * rho_d + R_v * rho_qv) + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv + + # Assume pressure stays constant + if (r < rc && Δθ > 0) + # Calculate background density potential temperature + θ_dens = rho_theta / rho * (p_loc / p_0)^(kappa_M - kappa) + # Calculate perturbed density potential temperature + θ_dens_new = θ_dens * (1 + Δθ * cospi(0.5 * r / rc)^2 / 300) + rt = (rho_qv + rho_ql) / rho_d + rv = rho_qv / rho_d + # Calculate moist potential temperature + θ_loc = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rv) + # Adjust varuables until the temperature is met + if rt > 0 + while true + T_loc = θ_loc * (p_loc / p_0)^kappa + T_C = T_loc - 273.15 + # SaturVapor + pvs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + rho_d_new = (p_loc - pvs) / (R_d * T_loc) + rvs = pvs / (R_v * rho_d_new * T_loc) + θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) + if abs(θ_new - θ_loc) <= θ_loc * 1.0e-12 + break + else + θ_loc = θ_new + end + end + else + rvs = 0 + T_loc = θ_loc * (p_loc / p_0)^kappa + rho_d_new = p_loc / (R_d * T_loc) + θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) + end + # test + #T_loc = θ_new * (p_loc / p_0)^kappa + # + rho_qv = rvs * rho_d_new + rho_ql = (rt - rvs) * rho_d_new + rho = rho_d_new * (1 + rt) + rho_d = rho - rho_qv - rho_ql + kappa_M = (R_d * rho_d + R_v * rho_qv) / + (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * θ_dens_new * (p_loc / p_0)^(kappa - kappa_M) + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv + end + return SVector(rho, rho_e, rho_qv, rho_ql, T_loc) +end + +# Create background atmosphere data set +atmosphere_data = AtmosphereLayers(CompressibleMoistEulerEquations2D()) + +# Create the initial condition with the initial data set +function initial_condition_moist(x, t, equations::CompressibleRainyEulerEquations2D) + return initial_condition_moist_bubble(x, t, CompressibleMoistEulerEquations2D(), atmosphere_data) +end + + + +############################################################################### +# semidiscretization of the compressible rainy Euler equations + +equations = CompressibleRainyEulerEquations2D() + +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 = 3 +basis = LobattoLegendreBasis(polydeg) + +surface_flux = flux_lax_friedrichs +#surface_flux = flux_LMARS +#volume_flux = flux_chandrashekar + +#volume_integral = VolumeIntegralFluxDifferencing(volume_flux) + +solver = DGMulti(polydeg=polydeg, element_type = Quad(), approximation_type = GaussSBP(), + surface_integral = SurfaceIntegralWeakForm(surface_flux), + volume_integral = VolumeIntegralWeakForm()) + +coordinates_min = ( 0.0, 0.0) +coordinates_max = (20_000.0, 10_000.0) + +cells_per_dimension = (200, 100) +mesh = DGMultiMesh(solver, cells_per_dimension; coordinates_min, coordinates_max, periodicity = (true, false)) + +semi = SemidiscretizationHyperbolic(mesh, equations, + initial_condition_moist, solver, + source_terms = source_terms_no_phase_change, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 1000.0) + +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 + +# entropy? +#analysis_callback = AnalysisCallback(semi, interval = analysis_interval, +# extra_analysis_errors = (:entropy_conservation_error,)) + +alive_callback = AliveCallback(analysis_interval = 1000) + +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + output_directory = "out", + solution_variables = cons2eq_pot_temp) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + #analysis_callback, + alive_callback, + save_solution, + stepsize_callback) + +stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) + +############################################################################### +# run the simulation +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limiter!), + maxiters = 1.0e7, + dt = 1.0, + save_everystep = false, callback = callbacks); + +summary_callback() \ No newline at end of file From a76e26fe8bdece128ab652c327b69d9084ddf78f Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 20 Nov 2024 21:24:57 +0100 Subject: [PATCH 072/115] diffusion adjustments --- examples/elixir_rainy_euler_bubble_diffusion.jl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_diffusion.jl b/examples/elixir_rainy_euler_bubble_diffusion.jl index 4c7f37a6..0c3357df 100644 --- a/examples/elixir_rainy_euler_bubble_diffusion.jl +++ b/examples/elixir_rainy_euler_bubble_diffusion.jl @@ -192,6 +192,10 @@ function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerE n = n - 1 end + if (n == 0) + n = 1 + end + # check height consistency if (z > total_height && !(isapprox(z, total_height))) error("The atmosphere does not match the simulation domain") @@ -216,7 +220,7 @@ end ############################################################################### # semidiscretization of the compressible rainy Euler equations -diffusivity = 0.4 +diffusivity = 0.6 equations_parabolic = LaplaceDiffusion2D(diffusivity, equations) @@ -243,7 +247,7 @@ solver = DGSEM(basis, surface_flux)#, volume_integral) initial_condition = initial_condition_bubble_rainy source_terms = source_terms_rainy -mesh = TreeMesh(coordinates_min, coordinates_max, initial_refinement_level = 7, periodicity = (true, false), n_cells_max = 1_000_000) +mesh = TreeMesh(coordinates_min, coordinates_max, initial_refinement_level = 8, periodicity = (true, false), n_cells_max = 1_000_000) semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; source_terms, boundary_conditions = (boundary_conditions, boundary_conditions_parabolic)) From dea0087208e95b58d24dd17e8ed563e0a4c85801 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 20 Nov 2024 21:25:25 +0100 Subject: [PATCH 073/115] potential temperature (work in progress) --- .../elixir_dry_potential_euler_bubble.jl | 125 ++++++++ .../elixir_moist_potential_euler_bubble.jl | 292 ++++++++++++++++++ src/TrixiAtmo.jl | 3 +- src/callbacks_stage/nonlinear_solve_dg2d.jl | 2 +- ...le_rainy_euler_potential_temperature_2d.jl | 288 +++++++++-------- src/equations/equations.jl | 3 +- 6 files changed, 565 insertions(+), 148 deletions(-) create mode 100644 examples/potential_temperature_elixirs/elixir_dry_potential_euler_bubble.jl create mode 100644 examples/potential_temperature_elixirs/elixir_moist_potential_euler_bubble.jl diff --git a/examples/potential_temperature_elixirs/elixir_dry_potential_euler_bubble.jl b/examples/potential_temperature_elixirs/elixir_dry_potential_euler_bubble.jl new file mode 100644 index 00000000..9f6e0b2e --- /dev/null +++ b/examples/potential_temperature_elixirs/elixir_dry_potential_euler_bubble.jl @@ -0,0 +1,125 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: source_terms_no_phase_change, flux_LMARS + + + +# copied from elixir_euler_warm_bubble.jl for quick tests +function initial_condition_bubble_dry(x, t, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) + g = equations.gravity + c_p = equations.c_dry_air_const_pressure + c_v = equations.c_dry_air_const_volume + + # center of perturbation + center_x = 10000.0 + center_z = 2000.0 + # radius of perturbation + radius = 2000.0 + # 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.0 + potential_temperature_perturbation = 0.0 + if r <= radius + potential_temperature_perturbation = 2 * cospi(0.5 * 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.0 # 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 = 0.0 + v2 = 0.0 + #E = c_v * T + 0.5 * (v1^2 + v2^2) + + return SVector(rho, 0.0, 0.0, rho * v1, rho * v2, rho * potential_temperature, 0.0, 0.0, 0.0) +end + + + +############################################################################### +# semidiscretization of the compressible rainy Euler equations + +equations = CompressibleRainyEulerPotentialTemperatureEquations2D() + +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 = 3 +basis = LobattoLegendreBasis(polydeg) + +surface_flux = flux_LMARS + +solver = DGSEM(basis, surface_flux) + +coordinates_min = ( 0.0, 0.0) +coordinates_max = (20_000.0, 10_000.0) + +cells_per_dimension = (64, 32) + +periodicity = (true, false) + +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, + periodicity = periodicity) + +initial_condition = initial_condition_bubble_dry +source_terms = source_terms_no_phase_change + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 1100.0) + +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 + +# entropy? +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:entropy_conservation_error,)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + output_directory = "out", + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) + +############################################################################### +# run the simulation +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + maxiters = 1.0e7, + dt = 1.0, + save_everystep = false, callback = callbacks); + +summary_callback() \ No newline at end of file diff --git a/examples/potential_temperature_elixirs/elixir_moist_potential_euler_bubble.jl b/examples/potential_temperature_elixirs/elixir_moist_potential_euler_bubble.jl new file mode 100644 index 00000000..673c1a19 --- /dev/null +++ b/examples/potential_temperature_elixirs/elixir_moist_potential_euler_bubble.jl @@ -0,0 +1,292 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: source_terms_no_phase_change, saturation_residual, + saturation_residual_jacobian, NonlinearSolveDG, + cons2eq_pot_temp, flux_LMARS, flux_chandrashekar +using NLsolve: nlsolve + + + +# Initial condition from elixir_moist_euler_bubble.jl +function moist_state(y, dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) + + @unpack p_0, g, c_pd, c_pv, c_vd, c_vv, R_d, R_v, c_pl, L_00 = equations + + (p, rho, T, r_t, r_v, rho_qv, theta_e) = y + p0 = y0[1] + + F = zeros(7, 1) + rho_d = rho / (1 + r_t) + p_d = R_d * rho_d * T + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + L = L_00 - (c_pl - c_pv) * T + + F[1] = (p - p0) / dz + g * rho + F[2] = p - (R_d * rho_d + R_v * rho_qv) * T + # H = 1 is assumed + F[3] = (theta_e - + T * (p_d / p_0)^(-R_d / (c_pd + c_pl * r_t)) * + exp(L * r_v / ((c_pd + c_pl * r_t) * T))) + F[4] = r_t - r_t0 + F[5] = rho_qv - rho_d * r_v + F[6] = theta_e - theta_e0 + a = p_vs / (R_v * T) - rho_qv + b = rho - rho_qv - rho_d + # H=1 => phi=0 + F[7] = a + b - sqrt(a * a + b * b) + + return F +end + +function generate_function_of_y(dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) + function function_of_y(y) + return moist_state(y, dz, y0, r_t0, theta_e0, equations) + end +end + +struct AtmosphereLayers{RealT <: Real} + equations::CompressibleMoistEulerEquations2D + # structure: 1--> i-layer (z = total_height/precision *(i-1)), 2--> rho, rho_theta, rho_qv, rho_ql + layer_data::Matrix{RealT} + total_height::RealT + preciseness::Int + layers::Int + ground_state::NTuple{2, RealT} + equivalent_potential_temperature::RealT + mixing_ratios::NTuple{2, RealT} +end + +function AtmosphereLayers(equations; total_height = 10010.0, preciseness = 10, + ground_state = (1.4, 100000.0), + equivalent_potential_temperature = 320, + mixing_ratios = (0.02, 0.02), RealT = Float64) + + @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl = equations + rho0, p0 = ground_state + r_t0, r_v0 = mixing_ratios + theta_e0 = equivalent_potential_temperature + + rho_qv0 = rho0 * r_v0 + T0 = theta_e0 + y0 = [p0, rho0, T0, r_t0, r_v0, rho_qv0, theta_e0] + + n = convert(Int, total_height / preciseness) + dz = 0.01 + layer_data = zeros(RealT, n + 1, 4) + + F = generate_function_of_y(dz, y0, r_t0, theta_e0, equations) + sol = nlsolve(F, y0) + p, rho, T, r_t, r_v, rho_qv, theta_e = sol.zero + + rho_d = rho / (1 + r_t) + rho_ql = rho - rho_d - rho_qv + kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * (p0 / p)^kappa_M * T * (1 + (R_v / R_d) * r_v) / (1 + r_t) + + layer_data[1, :] = [rho, rho_theta, rho_qv, rho_ql] + for i in (1:n) + y0 = deepcopy(sol.zero) + dz = preciseness + F = generate_function_of_y(dz, y0, r_t0, theta_e0, equations) + sol = nlsolve(F, y0) + p, rho, T, r_t, r_v, rho_qv, theta_e = sol.zero + + rho_d = rho / (1 + r_t) + rho_ql = rho - rho_d - rho_qv + kappa_M = (R_d * rho_d + R_v * rho_qv) / + (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * (p0 / p)^kappa_M * T * (1 + (R_v / R_d) * r_v) / (1 + r_t) + + layer_data[i + 1, :] = [rho, rho_theta, rho_qv, rho_ql] + end + + return AtmosphereLayers{RealT}(equations, layer_data, total_height, dz, n, ground_state, + theta_e0, mixing_ratios) +end + +# Moist bubble test case from paper: +# G.H. Bryan, J.M. Fritsch, A Benchmark Simulation for Moist Nonhydrostatic Numerical +# Models, MonthlyWeather Review Vol.130, 2917–2928, 2002, +# https://journals.ametsoc.org/view/journals/mwre/130/12/1520-0493_2002_130_2917_absfmn_2.0.co_2.xml. +function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, atmosphere_layers::AtmosphereLayers) + @unpack layer_data, preciseness, total_height = atmosphere_layers + dz = preciseness + z = x[2] + if (z > total_height && !(isapprox(z, total_height))) + error("The atmosphere does not match the simulation domain") + end + n = convert(Int, floor((z + eps()) / dz)) + 1 + z_l = (n - 1) * dz + (rho_l, rho_theta_l, rho_qv_l, rho_ql_l) = layer_data[n, :] + z_r = n * dz + if (z_l == total_height) + z_r = z_l + dz + n = n - 1 + end + (rho_r, rho_theta_r, rho_qv_r, rho_ql_r) = layer_data[n + 1, :] + rho = (rho_r * (z - z_l) + rho_l * (z_r - z)) / dz + rho_theta = rho * (rho_theta_r / rho_r * (z - z_l) + rho_theta_l / rho_l * (z_r - z)) / + dz + rho_qv = rho * (rho_qv_r / rho_r * (z - z_l) + rho_qv_l / rho_l * (z_r - z)) / dz + rho_ql = rho * (rho_ql_r / rho_r * (z - z_l) + rho_ql_l / rho_l * (z_r - z)) / dz + + rho, rho_e, rho_qv, rho_ql, T_loc = perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, + equations::CompressibleMoistEulerEquations2D) + + v1 = 0.0 + v2 = 0.0 + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_E = rho_e + 1 / 2 * rho * (v1^2 + v2^2) + + return SVector(rho - rho_qv - rho_ql, rho_qv + rho_ql, 0.0, rho_v1, rho_v2, rho_E, rho_qv, rho_ql, T_loc) +end + +function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, + equations::CompressibleMoistEulerEquations2D) + @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl, L_00 = equations + xc = 10000.0 + zc = 2000.0 + rc = 2000.0 + Δθ = 2.0 + + r = sqrt((x[1] - xc)^2 + (x[2] - zc)^2) + rho_d = rho - rho_qv - rho_ql + kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + p_loc = p_0 * (R_d * rho_theta / p_0)^(1 / (1 - kappa_M)) + T_loc = p_loc / (R_d * rho_d + R_v * rho_qv) + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv + + # Assume pressure stays constant + if (r < rc && Δθ > 0) + # Calculate background density potential temperature + θ_dens = rho_theta / rho * (p_loc / p_0)^(kappa_M - kappa) + # Calculate perturbed density potential temperature + θ_dens_new = θ_dens * (1 + Δθ * cospi(0.5 * r / rc)^2 / 300) + rt = (rho_qv + rho_ql) / rho_d + rv = rho_qv / rho_d + # Calculate moist potential temperature + θ_loc = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rv) + # Adjust varuables until the temperature is met + if rt > 0 + while true + T_loc = θ_loc * (p_loc / p_0)^kappa + T_C = T_loc - 273.15 + # SaturVapor + pvs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + rho_d_new = (p_loc - pvs) / (R_d * T_loc) + rvs = pvs / (R_v * rho_d_new * T_loc) + θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) + if abs(θ_new - θ_loc) <= θ_loc * 1.0e-12 + break + else + θ_loc = θ_new + end + end + else + rvs = 0 + T_loc = θ_loc * (p_loc / p_0)^kappa + rho_d_new = p_loc / (R_d * T_loc) + θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) + end + # test + #T_loc = θ_new * (p_loc / p_0)^kappa + # + rho_qv = rvs * rho_d_new + rho_ql = (rt - rvs) * rho_d_new + rho = rho_d_new * (1 + rt) + rho_d = rho - rho_qv - rho_ql + kappa_M = (R_d * rho_d + R_v * rho_qv) / + (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * θ_dens_new * (p_loc / p_0)^(kappa - kappa_M) + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv + end + return SVector(rho, rho_e, rho_qv, rho_ql, T_loc) +end + +# Create background atmosphere data set +atmosphere_data = AtmosphereLayers(CompressibleMoistEulerEquations2D()) + +# Create the initial condition with the initial data set +function initial_condition_moist(x, t, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) + return initial_condition_moist_bubble(x, t, CompressibleMoistEulerEquations2D(), atmosphere_data) +end + + + +############################################################################### +# semidiscretization of the compressible rainy Euler equations + +equations = CompressibleRainyEulerPotentialTemperatureEquations2D() + +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 = 3 +basis = LobattoLegendreBasis(polydeg) + +#surface_flux = flux_lax_friedrichs +surface_flux = flux_LMARS +#volume_flux = flux_chandrashekar + +#volume_integral = VolumeIntegralFluxDifferencing(volume_flux) + +solver = DGSEM(basis, surface_flux)#, volume_integral) + +coordinates_min = ( 0.0, 0.0) +coordinates_max = (20_000.0, 10_000.0) + +cells_per_dimension = (65, 32) +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, + periodicity = (true, false)) + +semi = SemidiscretizationHyperbolic(mesh, equations, + initial_condition_moist, solver, + source_terms = source_terms_no_phase_change, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 1000.0) + +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 + +# entropy? +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:entropy_conservation_error,)) + +alive_callback = AliveCallback(analysis_interval = 1000) + +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + output_directory = "out", + solution_variables = cons2eq_pot_temp) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) + +stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) + +############################################################################### +# run the simulation +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limiter!), + maxiters = 1.0e7, + dt = 1.0, + save_everystep = false, callback = callbacks); + +summary_callback() \ No newline at end of file diff --git a/src/TrixiAtmo.jl b/src/TrixiAtmo.jl index 4974fa4d..14b569b3 100644 --- a/src/TrixiAtmo.jl +++ b/src/TrixiAtmo.jl @@ -21,7 +21,8 @@ bar() = false baz() = Trixi.examples_dir() include("equations/equations.jl") -export CompressibleMoistEulerEquations2D, CompressibleRainyEulerEquations2D +export CompressibleMoistEulerEquations2D, CompressibleRainyEulerEquations2D, + CompressibleRainyEulerPotentialTemperatureEquations2D include("callbacks_stage/callbacks_stage.jl") export NonlinearSolveDG diff --git a/src/callbacks_stage/nonlinear_solve_dg2d.jl b/src/callbacks_stage/nonlinear_solve_dg2d.jl index 4a00d9f9..4f87c854 100644 --- a/src/callbacks_stage/nonlinear_solve_dg2d.jl +++ b/src/callbacks_stage/nonlinear_solve_dg2d.jl @@ -7,7 +7,7 @@ using StaticArrays @muladd begin function nonlinear_solve_dg_2d!(u, residual, jacobian, variables_index_vector, tolerance, - equations::CompressibleRainyEulerEquations2D, dg::DGSEM, cache, mesh) + equations::AbstractCompressibleRainyEulerEquations, dg::DGSEM, cache, mesh) max_iterations = 20 rain_threshold = 1e-4 #=threshold = 0.0 diff --git a/src/equations/compressible_rainy_euler_potential_temperature_2d.jl b/src/equations/compressible_rainy_euler_potential_temperature_2d.jl index 422a0f39..6e593905 100644 --- a/src/equations/compressible_rainy_euler_potential_temperature_2d.jl +++ b/src/equations/compressible_rainy_euler_potential_temperature_2d.jl @@ -17,13 +17,13 @@ import Trixi: varnames, # 112713, # ISSN 0021-9991 - +### WARNING: Potential temperature implementation does not include rainFALL yet. @muladd begin ### equation, parameters and constants ### -struct CompressibleRainyEulerEquations2D{RealT <: Real} <: AbstractCompressibleRainyEulerEquations{2, 9} +struct CompressibleRainyEulerPotentialTemperatureEquations2D{RealT <: Real} <: AbstractCompressibleRainyEulerEquations{2, 9} # Specific heat capacities: c_liquid_water ::RealT c_dry_air_const_pressure ::RealT @@ -49,7 +49,7 @@ struct CompressibleRainyEulerEquations2D{RealT <: Real} <: AbstractCompressibleR end -function CompressibleRainyEulerEquations2D(; RealT = Float64) +function CompressibleRainyEulerPotentialTemperatureEquations2D(; RealT = Float64) # Specific heat capacities: c_liquid_water = 4186.0 c_dry_air_const_pressure = 1004.0 @@ -73,7 +73,7 @@ function CompressibleRainyEulerEquations2D(; RealT = Float64) rain_water_distr = 8e6 v_mean_rain = 130.0 - return CompressibleRainyEulerEquations2D{RealT}(c_liquid_water, c_dry_air_const_pressure, c_dry_air_const_volume, + return CompressibleRainyEulerPotentialTemperatureEquations2D{RealT}(c_liquid_water, c_dry_air_const_pressure, c_dry_air_const_volume, c_vapour_const_pressure, c_vapour_const_volume, R_dry_air, R_vapour, eps, ref_saturation_pressure, ref_temperature, ref_latent_heat_vap_temp, ref_pressure, gravity, @@ -84,7 +84,7 @@ end ### conversion ### -@inline function cons2prim(u, equations::CompressibleRainyEulerEquations2D) +@inline function cons2prim(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) @@ -101,14 +101,14 @@ end end -@inline function cons2entropy(u, equations::CompressibleRainyEulerEquations2D) +@inline function cons2entropy(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) #TODO return SVector(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) end # adapted from compressible_moist_euler_2d.jl -@inline function cons2eq_pot_temp(u, equations::CompressibleRainyEulerEquations2D) +@inline function cons2eq_pot_temp(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # constants c_l = equations.c_liquid_water c_pd = equations.c_dry_air_const_pressure @@ -125,9 +125,6 @@ end # velocity v1, v2 = velocities(u, rho_inv, equations) - # energy density - energy = energy_density(u, equations) - # nonlinear system rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) @@ -153,52 +150,26 @@ end end -@inline function cons2nonlinearsystemsol(u, equations::CompressibleRainyEulerEquations2D) - # constants - c_vd = equations.c_dry_air_const_volume - #ref_temp = equations.ref_temperature - - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - - # velocity - v1, v2 = velocities(u, rho_inv, equations) - - # energy density - energy = energy_density(u, equations) - - # recover temperature explicitly from energy when other variables are zero - if (rho_moist == 0.0 && rho_rain == 0.0) - # energy density definition without ref_temp for dry case - energy_kinetic = 0.5 * (v1^2 + v2^2) * rho - temperature = (energy - energy_kinetic) / (c_vd * rho) #+ ref_temp - - if (temperature < 0.0) - error("temp negative") - end - - return SVector(0.0, 0.0, temperature) - else - # experimental and overly simple positivity check - rho_vapour = u[7] - rho_cloud = u[8] - temperature = u[9] +@inline function cons2nonlinearsystemsol(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) + # experimental and simple positivity check + rho_vapour = u[7] + rho_cloud = u[8] + temperature = u[9] - if (rho_vapour < 0.0 && isapprox(rho_vapour, 0.0, atol = 1e-15)) - rho_vapour = 0.0 - end - - if (rho_cloud < 0.0 && isapprox(rho_cloud, 0.0, atol = 1e-15)) - rho_cloud = 0.0 - end + if (rho_vapour < 0.0 && isapprox(rho_vapour, 0.0, atol = 1e-15)) + rho_vapour = 0.0 + end - return SVector(rho_vapour, rho_cloud, temperature) + if (rho_cloud < 0.0 && isapprox(rho_cloud, 0.0, atol = 1e-15)) + rho_cloud = 0.0 end + + return SVector(rho_vapour, rho_cloud, temperature) end # for convenience -@inline function cons2speeds(u, equations::CompressibleRainyEulerEquations2D) +@inline function cons2speeds(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) @@ -218,18 +189,18 @@ end ### varnames ### -varnames(::typeof(cons2cons), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_moist", "rho_rain", +varnames(::typeof(cons2cons), ::CompressibleRainyEulerPotentialTemperatureEquations2D) = ("rho_dry", "rho_moist", "rho_rain", "rho_v1", "rho_v2", - "potential_temperature", + "potential_temperature_density", "rho_vapour", "rho_cloud", "temperature") -varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_moist", "rho_rain", +varnames(::typeof(cons2prim), ::CompressibleRainyEulerPotentialTemperatureEquations2D) = ("rho_dry", "rho_moist", "rho_rain", "v1", "v2", "energy_density", "rho_vapour", "rho_cloud", "temperature") -varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquations2D) = ("rho", "r_vapour", +varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerPotentialTemperatureEquations2D) = ("rho", "r_vapour", "r_cloud", "r_rain", "v1", "v2", "eq_pot_temp", "pressure") @@ -238,7 +209,7 @@ varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquations2D) = ("rh ### physics variables ### -@inline function densities(u, equations::CompressibleRainyEulerEquations2D) +@inline function densities(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # densities rho_dry = u[1] rho_moist = u[2] @@ -249,37 +220,76 @@ varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquations2D) = ("rh return SVector(rho_dry, rho_moist, rho_rain, rho, rho_inv) end -@inline function rain_density(u, equations::CompressibleRainyEulerEquations2D) +@inline function rain_density(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) return u[3] end -@inline function velocities(u, rho_inv, equations::CompressibleRainyEulerEquations2D) +@inline function velocities(u, rho_inv, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) return SVector(u[4] * rho_inv, u[5] * rho_inv) end -@inline function energy_density(u, equations::CompressibleRainyEulerEquations2D) - return u[6] +@inline function energy_density(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + c_l = equations.c_liquid_water + ref_L = equations.ref_latent_heat_vap_temp + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + + inner_energy_density = (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * temperature + inner_energy_density += rho_vapour * ref_L + kinetic_energy_density = 0.5 * rho * (v1^2 + v2^2) + + return inner_energy_density + kinetic_energy_density end -@inline function pressure(u, equations::CompressibleRainyEulerEquations2D) +@inline function pressure(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # constants - R_d = equations.R_dry_air - R_v = equations.R_vapour + c_pd = equations.c_dry_air_const_pressure + c_vd = equations.c_dry_air_const_volume + c_pv = equations.c_vapour_const_pressure + c_vv = equations.c_vapour_const_volume + c_l = equations.c_liquid_water + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure # densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) - - p = (R_d * rho_dry + R_v * rho_vapour) * temperature + rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) + + # potential temperature density + rho_pot_temp = potential_temperature_density(u, equations) + + r_v = rho_vapour / rho_dry + r_l = (rho_cloud + rho_rain) / rho_dry + + kappa_m = (R_d + r_v * R_v) / (c_pd + r_v * c_pv + r_l * c_l) + + rho_theta = rho_pot_temp * (rho_dry + rho_vapour / eps) * rho_inv + + p = ((R_d * rho_theta) / (ref_pressure^kappa_m))^(1 / (1 - kappa_m)) return p end -@inline function speed_of_sound(u, equations::CompressibleRainyEulerEquations2D) +@inline function potential_temperature_density(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) + return u[6] +end + + +@inline function speed_of_sound(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # constants c_l = equations.c_liquid_water c_vd = equations.c_dry_air_const_volume @@ -318,7 +328,7 @@ end end -@inline function terminal_velocity_rain(rho_moist, rho_rain, equations::CompressibleRainyEulerEquations2D) +@inline function terminal_velocity_rain(rho_moist, rho_rain, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # constants N_0 = equations.rain_water_distr v_0 = equations.v_mean_rain @@ -334,7 +344,7 @@ end end -@inline function saturation_vapour_pressure(temperature, equations::CompressibleRainyEulerEquations2D) +@inline function saturation_vapour_pressure(temperature, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # constants c_l = equations.c_liquid_water c_pv = equations.c_vapour_const_pressure @@ -357,7 +367,7 @@ end end -@inline function saturation_vapour_pressure_derivative(temperature, equations::CompressibleRainyEulerEquations2D) +@inline function saturation_vapour_pressure_derivative(temperature, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # constants c_l = equations.c_liquid_water c_pv = equations.c_vapour_const_pressure @@ -386,25 +396,25 @@ end ### pde discretization ### -@inline function flux(u, orientation::Integer, equations::CompressibleRainyEulerEquations2D) +@inline function flux(u, orientation::Integer, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # constants - c_l = equations.c_liquid_water + #c_l = equations.c_liquid_water #densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) # recover rho_vapour, rho_cloud, temperature from nonlinear system - rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) + #rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) # velocity v1, v2 = velocities(u, rho_inv, equations) - v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) + #v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) # pressure p = pressure(u, equations) - # energy density - energy = energy_density(u, equations) + # potential temperature density + rho_pot_temp = potential_temperature_density(u, equations) # flux for orientation cases if (orientation == 1) @@ -417,21 +427,20 @@ end f4 = rho * v1 * v1 + p f5 = rho * v1 * v2 - # "energy" - f6 = (energy + p) * v1 - + # "potential temperature" + f6 = rho_pot_temp * v1 else # "mass" f1 = rho_dry * v2 f2 = rho_moist * v2 - f3 = rho_rain * (v2 - v_r) + f3 = rho_rain * v2 #- v_r) # "momentum" - f4 = rho * v1 * v2 - rho_rain * v_r * v1 - f5 = rho * v2 * v2 + p - rho_rain * v_r * v2 + f4 = rho * v1 * v2 #- rho_rain * v_r * v1 + f5 = rho * v2 * v2 + p #- rho_rain * v_r * v2 # "energy" - f6 = (energy + p) * v2 - (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r + f6 = rho_pot_temp * v2 #- (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r end return SVector(f1, f2, f3, f4, f5, f6, @@ -439,42 +448,42 @@ end end -@inline function flux(u, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) +@inline function flux(u, normal_direction::AbstractVector, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # constants - c_l = equations.c_liquid_water + #c_l = equations.c_liquid_water # densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) # recover rho_vapour, rho_cloud, temperature from nonlinear system - rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) + #rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) # velocity v1, v2 = velocities(u, rho_inv, equations) - v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) + #v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) # normal velocities v_normal = v1 * normal_direction[1] + v2 * normal_direction[2] - v_r_normal = v_r * normal_direction[2] + #v_r_normal = v_r * normal_direction[2] # pressure p = pressure(u, equations) - # energy density - energy = energy_density(u, equations) + # potential temperature density + rho_pot_temp = potential_temperature_density(u, equations) # flux # "mass" f1 = rho_dry * v_normal f2 = rho_moist * v_normal - f3 = rho_rain * (v_normal - v_r_normal) + f3 = rho_rain * v_normal #- v_r_normal) # "momentum" - f4 = rho * v_normal * v1 + p * normal_direction[1] - rho_rain * v_r_normal * v1 - f5 = rho * v_normal * v2 + p * normal_direction[2] - rho_rain * v_r_normal * v2 + f4 = rho * v_normal * v1 + p * normal_direction[1] #- rho_rain * v_r_normal * v1 + f5 = rho * v_normal * v2 + p * normal_direction[2] #- rho_rain * v_r_normal * v2 # "energy" - f6 = (energy + p) * v_normal - (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r_normal + f6 = rho_pot_temp * v_normal #- (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r_normal return SVector(f1, f2, f3, f4, f5, f6, 0.0, 0.0, 0.0) @@ -482,7 +491,7 @@ end # no Coriolis term -@inline function source_terms_rainy(u, x, t, equations::CompressibleRainyEulerEquations2D) +@inline function source_terms_rainy(u, x, t, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # constants R_v = equations.R_vapour ref_temp = equations.ref_temperature @@ -517,22 +526,19 @@ end # no phase changes and no Coriolis term -@inline function source_terms_no_phase_change(u, x, t, equations::CompressibleRainyEulerEquations2D) +@inline function source_terms_no_phase_change(u, x, t, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # constants g = equations.gravity - - # name needed variables - rho_v2 = u[5] # densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) return SVector(0.0, 0.0, 0.0, 0.0, - -g * rho, -g * rho_v2, 0.0, 0.0, 0.0) + -g * rho, 0.0, 0.0, 0.0, 0.0) end -@inline function max_abs_speeds(u, equations::CompressibleRainyEulerEquations2D) +@inline function max_abs_speeds(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # name needed variables v1, v2, v_sound, v_r = cons2speeds(u, equations) @@ -540,36 +546,36 @@ end end -@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) +@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # name needed variables v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) # calculate upper bounds for left and right speed v_ll_max = abs(v1_ll * normal_direction[1] + v2_ll * normal_direction[2]) - v_ll_max += abs( v_r_ll * normal_direction[2]) + #v_ll_max += abs( v_r_ll * normal_direction[2]) v_rr_max = abs(v1_rr * normal_direction[1] + v2_rr * normal_direction[2]) - v_rr_max += abs( v_r_rr * normal_direction[2]) + #v_rr_max += abs( v_r_rr * normal_direction[2]) return max(v_ll_max, v_rr_max) + max(v_sound_ll, v_sound_rr) * norm(normal_direction) end -@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::CompressibleRainyEulerEquations2D) +@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # name needed variables v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) if (orientation == 1) - v_ll = abs(v1_ll) - v_rr = abs(v1_rr) + v_ll = abs(v1_ll) + v_rr = abs(v1_rr) else - v_ll = abs(v2_ll) - v_rr = abs(v2_rr) + v_ll = abs(v2_ll) + v_rr = abs(v2_rr) end - return max(v_ll, v_rr) + max(v_sound_ll, v_sound_rr) + max(abs(v_r_ll), abs(v_r_rr)) + return max(v_ll, v_rr) + max(v_sound_ll, v_sound_rr) #+ max(abs(v_r_ll), abs(v_r_rr)) end @@ -577,7 +583,7 @@ end # adapted from compressible_moist_euler_2d.jl which was probably adapted from compressible_euler_2d.jl @inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, x, t, - surface_flux_function, equations::CompressibleRainyEulerEquations2D) + surface_flux_function, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) norm_ = norm(normal_direction) # Normalize the vector without using `normalize` since we need to multiply by the `norm_` later @@ -626,7 +632,7 @@ end # same as in compressible_euler_2d.jl @inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, direction, x, t, - surface_flux_function, equations::CompressibleRainyEulerEquations2D) + surface_flux_function, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # flip sign of normal to make it outward pointing, then flip the sign of the normal flux back # to be inward pointing on the -x and -y sides due to the orientation convention used by StructuredMesh if isodd(direction) @@ -644,7 +650,7 @@ end # same as in compressible_euler_2d.jl -@inline function rotate_to_x(u, normal_vector, equations::CompressibleRainyEulerEquations2D) +@inline function rotate_to_x(u, normal_vector, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # cos and sin of the angle between the x-axis and the normalized normal_vector are # the normalized vector's x and y coordinates respectively (see unit circle). c = normal_vector[1] @@ -659,7 +665,7 @@ end # should be used together with TreeMesh (adapted from compressible_euler_2d.jl) @inline function boundary_condition_slip_wall(u_inner, orientation, direction, x, t, surface_flux_function, - equations::CompressibleRainyEulerEquations2D) + equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # get the appropriate normal vector from the orientation RealT = eltype(u_inner) if orientation == 1 @@ -677,48 +683,38 @@ end ### Nonlinear System Residual ### # in preparation for a callback to solve the nonlinear system -@inline function saturation_residual(u, guess, equations::CompressibleRainyEulerEquations2D) +@inline function saturation_residual(u, guess, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_v = equations.R_vapour - L_ref = equations.ref_latent_heat_vap_temp + R_v = equations.R_vapour + eps = equations.eps # densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - # velocity - v1, v2 = velocities(u, rho_inv, equations) - - # energy density - energy = energy_density(u, equations) + # potential temperature density + rho_pot_temp = potential_temperature_density(u, equations) # define residual - residual1 = (c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain)) * guess[3] - residual1 += guess[1] * L_ref - residual1 -= (energy - rho * 0.5 * (v1^2 + v2^2)) + residual1 = guess[3] * (rho_dry + guess[1] / eps) / (rho_dry + guess[1] + guess[2] + rho_rain) + residual1 -= rho_pot_temp * rho_inv residual2 = min(saturation_vapour_pressure(guess[3], equations) / (R_v * guess[3]), rho_moist) residual2 -= guess[1] - residual2 *= 1e7 + residual2 *= 1e4 residual3 = rho_moist residual3 -= guess[1] + guess[2] - residual3 *= 1e7 + residual3 *= 1e4 return SVector(residual1, residual2, residual3) end -@inline function saturation_residual_jacobian(u, guess, equations::CompressibleRainyEulerEquations2D) +@inline function saturation_residual_jacobian(u, guess, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_v = equations.R_vapour - L_ref = equations.ref_latent_heat_vap_temp + R_v = equations.R_vapour + eps = equations.eps # densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) @@ -727,22 +723,26 @@ end svp = saturation_vapour_pressure(guess[3], equations) svp_t = saturation_vapour_pressure_derivative(guess[3], equations) + # helper variables + rho_help = rho_dry + guess[1] + guess[2] + rho_rain + inv_eps = inv(eps) + # define jacobian - J_11 = c_vv * guess[3] + L_ref - J_12 = c_l * guess[3] - J_13 = c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain) + J_11 = guess[3] * ((inv_eps - 1) * rho_dry + inv_eps * (guess[2] + rho_rain)) / (rho_help^2) + J_12 = -guess[3] * (rho_dry + guess[1] * inv_eps) / (rho_help^2) + J_13 = (rho_dry + guess[1] * inv_eps) / rho_help - J_21 = -1e7 + J_21 = -1e4 J_22 = 0.0 if (svp / (R_v * guess[3]) < rho_moist) - J_23 = (svp_t * guess[3] - svp) / (R_v * guess[3]^2) * 1e7 + J_23 = (svp_t * guess[3] - svp) / (R_v * guess[3]^2) * 1e4 else J_23 = 0.0 end - J_31 = -1e7 - J_32 = -1e7 + J_31 = -1e4 + J_32 = -1e4 J_33 = 0.0 return SMatrix{3, 3}(J_11, J_21, J_31, J_12, J_22, J_32, J_13, J_23, J_33) @@ -757,9 +757,9 @@ end # Lin, A Control-Volume Model of the Compressible Euler Equations with a Vertical Lagrangian # Coordinate Monthly Weather Review Vol. 141.7, pages 2526–2544, 2013, # https://journals.ametsoc.org/view/journals/mwre/141/7/mwr-d-12-00129.1.xml. -@inline function flux_LMARS(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) +@inline function flux_LMARS(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) # constants - a = 360.0 + a = 340.0 # densities rho_dry_ll, rho_moist_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) @@ -787,10 +787,8 @@ end if (v_interface > 0) f1, f2, f3, f4, f5, f6, _, _, _ = u_ll * v_interface - f6 += p_ll * v_interface else f1, f2, f3, f4, f5, f6, _, _, _ = u_rr * v_interface - f6 += p_rr * v_interface end return SVector(f1, f2, f3, diff --git a/src/equations/equations.jl b/src/equations/equations.jl index ea2f5c7a..17cae95f 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -7,4 +7,5 @@ abstract type AbstractCompressibleRainyEulerEquations{NDIMS, NVARS} <: AbstractEquations{NDIMS, NVARS} end include("compressible_rainy_euler_2d.jl") -include("compressible_moist_euler_2d_lucas.jl") \ No newline at end of file +include("compressible_moist_euler_2d_lucas.jl") +include("compressible_rainy_euler_potential_temperature_2d.jl") \ No newline at end of file From 1de9058235576683d6e516982b765a792385b6b3 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:44:24 +0100 Subject: [PATCH 074/115] added moist potential temperature case from Oswald and Marco, changed pressure and L_00 --- ...uler_potential_temperature_moist_bubble.jl | 304 +++++++++ src/TrixiAtmo.jl | 3 +- ...le_moist_euler_potential_temperature_2d.jl | 637 ++++++++++++++++++ src/equations/equations.jl | 3 +- 4 files changed, 945 insertions(+), 2 deletions(-) create mode 100644 examples/elixir_moist_euler_potential_temperature_moist_bubble.jl create mode 100644 src/equations/compressible_moist_euler_potential_temperature_2d.jl diff --git a/examples/elixir_moist_euler_potential_temperature_moist_bubble.jl b/examples/elixir_moist_euler_potential_temperature_moist_bubble.jl new file mode 100644 index 00000000..72c8f10a --- /dev/null +++ b/examples/elixir_moist_euler_potential_temperature_moist_bubble.jl @@ -0,0 +1,304 @@ +using OrdinaryDiffEq +using Trixi, TrixiAtmo +using Plots +using TrixiAtmo: cons2aeqpot, saturation_pressure, source_terms_moist_bubble, + flux_LMARS, flux_shima_etal, flux_theta +using NLsolve: nlsolve + +############################################################################### +# semidiscretization of the compressible moist Euler equations + +equations = CompressibleMoistEulerPotentialTemperatureEquations2D() + +function moist_state(y, dz, y0, r_t0, theta_e0, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + @unpack p_0, g, c_pd, c_pv, c_vd, c_vv, R_d, R_v, c_pl, L_00 = equations + (p, rho, T, r_t, r_v, rho_qv, theta_e) = y + p0 = y0[1] + + F = zeros(7, 1) + rho_d = rho / (1 + r_t) + p_d = R_d * rho_d * T + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + L = L_00 - (c_pl - c_pv) * T + + F[1] = (p - p0) / dz + g * rho + F[2] = p - (R_d * rho_d + R_v * rho_qv) * T + # H = 1 is assumed + F[3] = (theta_e - + T * (p_d / p_0)^(-R_d / (c_pd + c_pl * r_t)) * + exp(L * r_v / ((c_pd + c_pl * r_t) * T))) + F[4] = r_t - r_t0 + F[5] = rho_qv - rho_d * r_v + F[6] = theta_e - theta_e0 + a = p_vs / (R_v * T) - rho_qv + b = rho - rho_qv - rho_d + # H=1 => phi=0 + F[7] = a + b - sqrt(a * a + b * b) + + return F +end + +function generate_function_of_y(dz, y0, r_t0, theta_e0, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + function function_of_y(y) + return moist_state(y, dz, y0, r_t0, theta_e0, equations) + end +end + +struct AtmosphereLayers{RealT <: Real} + equations::CompressibleMoistEulerPotentialTemperatureEquations2D + # structure: 1--> i-layer (z = total_height/precision *(i-1)), 2--> rho, rho_theta, rho_qv, rho_ql + layer_data::Matrix{RealT} + total_height::RealT + preciseness::Int + layers::Int + ground_state::NTuple{2, RealT} + equivalent_potential_temperature::RealT + mixing_ratios::NTuple{2, RealT} +end + +function AtmosphereLayers(equations; total_height = 10010.0, preciseness = 10, + ground_state = (1.4, 100000.0), + equivalent_potential_temperature = 320, + mixing_ratios = (0.02, 0.02), RealT = Float64) + @unpack p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl = equations + kappa = 1- inv(equations.gamma) + rho0, p0 = ground_state + r_t0, r_v0 = mixing_ratios + theta_e0 = equivalent_potential_temperature + + rho_qv0 = rho0 * r_v0 + T0 = theta_e0 + y0 = [p0, rho0, T0, r_t0, r_v0, rho_qv0, theta_e0] + + n = convert(Int, total_height / preciseness) + dz = 0.01 + layer_data = zeros(RealT, n + 1, 4) + + F = generate_function_of_y(dz, y0, r_t0, theta_e0, equations) + sol = nlsolve(F, y0) + p, rho, T, r_t, r_v, rho_qv, theta_e = sol.zero + + rho_d = rho / (1 + r_t) + rho_ql = rho - rho_d - rho_qv + kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * (p0 / p)^kappa_M * T * (1 + (R_v / R_d) * r_v) / (1 + r_t) + + layer_data[1, :] = [rho, rho_theta, rho_qv, rho_ql] + for i in (1:n) + y0 = deepcopy(sol.zero) + dz = preciseness + F = generate_function_of_y(dz, y0, r_t0, theta_e0, equations) + sol = nlsolve(F, y0) + p, rho, T, r_t, r_v, rho_qv, theta_e = sol.zero + + rho_d = rho / (1 + r_t) + rho_ql = rho - rho_d - rho_qv + kappa_M = (R_d * rho_d + R_v * rho_qv) / + (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * (p0 / p)^kappa_M * T * (1 + (R_v / R_d) * r_v) / (1 + r_t) + + layer_data[i + 1, :] = [rho, rho_theta, rho_qv, rho_ql] + end + + return AtmosphereLayers{RealT}(equations, layer_data, total_height, dz, n, ground_state, + theta_e0, mixing_ratios) +end + +# Moist bubble test case from paper: +# G.H. Bryan, J.M. Fritsch, A Benchmark Simulation for Moist Nonhydrostatic Numerical +# Models, MonthlyWeather Review Vol.130, 2917–2928, 2002, +# https://journals.ametsoc.org/view/journals/mwre/130/12/1520-0493_2002_130_2917_absfmn_2.0.co_2.xml. +function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerPotentialTemperatureEquations2D, + atmosphere_layers::AtmosphereLayers) + @unpack layer_data, preciseness, total_height = atmosphere_layers + dz = preciseness + z = x[2] + if (z > total_height && !(isapprox(z, total_height))) + error("The atmosphere does not match the simulation domain") + end + n = convert(Int, floor((z + eps()) / dz)) + 1 + z_l = (n - 1) * dz + (rho_l, rho_theta_l, rho_qv_l, rho_ql_l) = layer_data[n, :] + z_r = n * dz + if (z_l == total_height) + z_r = z_l + dz + n = n - 1 + end + (rho_r, rho_theta_r, rho_qv_r, rho_ql_r) = layer_data[n + 1, :] + rho = (rho_r * (z - z_l) + rho_l * (z_r - z)) / dz + rho_theta = rho * (rho_theta_r / rho_r * (z - z_l) + rho_theta_l / rho_l * (z_r - z)) / + dz + rho_qv = rho * (rho_qv_r / rho_r * (z - z_l) + rho_qv_l / rho_l * (z_r - z)) / dz + rho_ql = rho * (rho_ql_r / rho_r * (z - z_l) + rho_ql_l / rho_l * (z_r - z)) / dz + + rho, rho_e, rho_qv, rho_ql = perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + + v1 = 0.0 + v2 = 0.0 + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_E = rho_e + 1 / 2 * rho * (v1^2 + v2^2) + + return SVector(rho, rho_v1, rho_v2, rho_theta, rho_qv, rho_ql) +end + +function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + @unpack p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl, L_00 = equations + kappa = 1 - inv(equations.gamma) + xc = 10000.0 + zc = 2000.0 + rc = 2000.0 + Δθ = 2.0 + + r = sqrt((x[1] - xc)^2 + (x[2] - zc)^2) + rho_d = rho - rho_qv - rho_ql + kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + p_loc = p_0 * (R_d * rho_theta / p_0)^(1 / (1 - kappa_M)) + T_loc = p_loc / (R_d * rho_d + R_v * rho_qv) + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv + + p_v = rho_qv * R_v * T_loc + p_d = p_loc - p_v + T_C = T_loc - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + H = p_v / p_vs + r_v = rho_qv / rho_d + r_l = rho_ql / rho_d + r_t = r_v + r_l + + # equivalent potential temperature + a = T_loc * (p_0 / p_d)^(R_d / (c_pd + r_t * c_pl)) + b = H^(-r_v * R_v / c_pd) + L_v = L_00 + (c_pv - c_pl) * T_loc + c = exp(L_v * r_v / ((c_pd + r_t * c_pl) * T_loc)) + aeq_pot = (a * b * c) # TODO: this is not used. remove? + + # Assume pressure stays constant + if (r < rc && Δθ > 0) + # Calculate background density potential temperature + θ_dens = rho_theta / rho * (p_loc / p_0)^(kappa_M - kappa) + # Calculate perturbed density potential temperature + θ_dens_new = θ_dens * (1 + Δθ * cospi(0.5 * r / rc)^2 / 300) + rt = (rho_qv + rho_ql) / rho_d + rv = rho_qv / rho_d + # Calculate moist potential temperature + θ_loc = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rv) + # Adjust varuables until the temperature is met + if rt > 0 + while true + T_loc = θ_loc * (p_loc / p_0)^kappa + T_C = T_loc - 273.15 + # SaturVapor + pvs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + rho_d_new = (p_loc - pvs) / (R_d * T_loc) + rvs = pvs / (R_v * rho_d_new * T_loc) + θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) + if abs(θ_new - θ_loc) <= θ_loc * 1.0e-12 + break + else + θ_loc = θ_new + end + end + else + rvs = 0 + T_loc = θ_loc * (p_loc / p_0)^kappa + rho_d_new = p_loc / (R_d * T_loc) + θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) + end + rho_qv = rvs * rho_d_new + rho_ql = (rt - rvs) * rho_d_new + rho = rho_d_new * (1 + rt) + rho_d = rho - rho_qv - rho_ql + kappa_M = (R_d * rho_d + R_v * rho_qv) / + (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * θ_dens_new * (p_loc / p_0)^(kappa - kappa_M) + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv + end + return SVector(rho, rho_e, rho_qv, rho_ql) +end + +# Create background atmosphere data set +atmosphere_data = AtmosphereLayers(equations) + +# Create the initial condition with the initial data set +function initial_condition_moist(x, t, equations) + return initial_condition_moist_bubble(x, t, equations, atmosphere_data) +end + +initial_condition = initial_condition_moist + +boundary_conditions = (x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_slip_wall, + y_pos = boundary_condition_slip_wall) + +source_term = source_terms_moist_bubble + +############################################################################### +# Get the DG approximation space + +polydeg = 3 +basis = LobattoLegendreBasis(polydeg) + +surface_flux = flux_lax_friedrichs +#volume_flux = flux_theta +#volume_integral = VolumeIntegralFluxDifferencing(volume_flux) + +solver = DGSEM(basis, surface_flux)#, volume_integral) +#solver = DGSEM(basis, surface_flux) +coordinates_min = (0.0, 0.0) +coordinates_max = (20000.0, 10000.0) + +cells_per_dimension = (64, 32) + +# Create curved mesh with 64 x 32 elements +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, + periodicity = (true, false)) + +############################################################################### +# create the semi discretization object + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_conditions, + source_terms = source_term) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 1000.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 +solution_variables = cons2aeqpot + +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + solution_variables = solution_variables) + +stepsize_callback = StepsizeCallback(cfl = 0.2) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) + +############################################################################### +# run the simulation + +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); +summary_callback() # print the timer summary diff --git a/src/TrixiAtmo.jl b/src/TrixiAtmo.jl index 14b569b3..d59ff1eb 100644 --- a/src/TrixiAtmo.jl +++ b/src/TrixiAtmo.jl @@ -22,7 +22,8 @@ baz() = Trixi.examples_dir() include("equations/equations.jl") export CompressibleMoistEulerEquations2D, CompressibleRainyEulerEquations2D, - CompressibleRainyEulerPotentialTemperatureEquations2D + CompressibleRainyEulerPotentialTemperatureEquations2D, + CompressibleMoistEulerPotentialTemperatureEquations2D include("callbacks_stage/callbacks_stage.jl") export NonlinearSolveDG diff --git a/src/equations/compressible_moist_euler_potential_temperature_2d.jl b/src/equations/compressible_moist_euler_potential_temperature_2d.jl new file mode 100644 index 00000000..8acb2c53 --- /dev/null +++ b/src/equations/compressible_moist_euler_potential_temperature_2d.jl @@ -0,0 +1,637 @@ +# Implemented by Lucas Gemein +# https://github.com/NichtLucas/Trixi.jl/tree/thesis_gemein_2022 + +using Trixi +using Trixi: ln_mean, inv_ln_mean +import Trixi: varnames, flux_chandrashekar, boundary_condition_slip_wall, + cons2prim, cons2entropy, max_abs_speed_naive, max_abs_speeds, + entropy, energy_total, flux, stolarsky_mean + +@muladd begin +#! format: noindent +struct CompressibleMoistEulerPotentialTemperatureEquations2D{RealT <: Real} <: + AbstractCompressibleMoistEulerEquations{2, 6} + p_0::RealT # constant reference pressure 1000 hPa(100000 Pa) + c_pd::RealT # dry air constant + c_vd::RealT # dry air constant + R_d::RealT # dry air gas constant + c_pv::RealT # moist air constant + c_vv::RealT # moist air constant + R_v::RealT # moist air gas constant + c_pl::RealT # liqid water constant + g::RealT # gravitation constant + inv_gamma_minus_one::RealT # ratio of the gas constant R_d + gamma::RealT # = inv(kappa- 1); can be used to write slow divisions as fast multiplications + L_00::RealT # latent heat of evaporation at 0 K + K::RealT +end + +function CompressibleMoistEulerPotentialTemperatureEquations2D(; g = 9.81, RealT = Float64) + p_0 = 100000.0 + c_pd = 1004.0 + c_vd = 717.0 + R_d = c_pd - c_vd + c_pv = 1885.0 + c_vv = 1424.0 + R_v = c_pv - c_vv + c_pl = 4186.0 + gamma = c_pd / c_vd # = 1/(1 - kappa) + inv_gamma_minus_one = inv(1 - gamma) + K = + L_00 = 2.5e6 #+ (c_pl - c_pv)*273.15 + K = p_0 * (R_d / p_0)^gamma + return CompressibleMoistEulerPotentialTemperatureEquations2D{RealT}(p_0, c_pd, c_vd, R_d, c_pv, c_vv, + R_v, c_pl, g, inv_gamma_minus_one, gamma, L_00, K) +end + +@inline function pressure(u, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + @unpack p_0, R_d, R_v, c_pd, c_pv, c_pl, c_vd, c_vv = equations + rho, rho_v1, rho_v2, rho_theta, rho_v, rho_l = u + + rho_d = rho - (rho_v + rho_l) + + kappa_M = (R_d * rho_d + R_v * rho_v) / (c_pd * rho_d + c_pv * rho_v + c_pl * rho_l) + p = p_0 * (R_d * rho_theta / p_0)^(1 / (1 - kappa_M)) + + return p +end + +# Calculate 1D flux for a single point. +@inline function flux(u, orientation::Integer, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + rho, rho_v1, rho_v2, rho_theta, rho_qv, rho_qc = u + v1 = rho_v1 / rho + v2 = rho_v2 / rho + qv = rho_qv / rho + qc = rho_qc / rho + p = pressure(u, equations) + if orientation == 1 + f1 = rho_v1 + f2 = rho_v1 * v1 + p + f3 = rho_v1 * v2 + f4 = rho_theta * v1 + f5 = rho_v1 * qv + f6 = rho_v1 * qc + else + f1 = rho_v2 + f2 = rho_v2 * v1 + f3 = rho_v2 * v2 + p + f4 = rho_theta * v2 + f5 = rho_v2 * qv + f6 = rho_v2 * qc + end + return SVector(f1, f2, f3, f4, f5, f6) +end + +# Calculate 1D flux for a single point in the normal direction. +# Note, this directional vector is not normalized. +@inline function flux(u, normal_direction::AbstractVector, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + rho, rho_v1, rho_v2, rho_theta, rho_qv, rho_qc = u + v1 = rho_v1 / rho + v2 = rho_v2 / rho + qv = rho_qv / rho + qc = rho_qc / rho + p = pressure(u, equations) + v_normal = v1 * normal_direction[1] + v2 * normal_direction[2] + rho_v_normal = rho * v_normal + f1 = rho_v_normal + f2 = (rho_v_normal) * v1 + p * normal_direction[1] + f3 = (rho_v_normal) * v2 + p * normal_direction[2] + f4 = (rho_theta) * v_normal + f5 = rho_v_normal * qv + f6 = (rho_v_normal) * qc + return SVector(f1, f2, f3, f4, f5, f6) +end + +# Slip-wall boundary condition +# Determine the boundary numerical surface flux for a slip wall condition. +# Imposes a zero normal velocity at the wall. +@inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, + x, t, + surface_flux_function, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + @unpack c_pd, c_pv, c_pl, c_vd, c_vv = equations + norm_ = norm(normal_direction) + # Normalize the vector without using `normalize` since we need to multiply by the `norm_` later + normal = normal_direction / norm_ + + # rotate the internal solution state + u_local = rotate_to_x(u_inner, normal, equations) + + # compute the primitive variables + rho_local, v_normal, v_tangent, p_local, qv_local, ql_local = cons2prim(u_local, + equations) + qd_local = 1 - qv_local - ql_local + gamma = (qd_local * c_pd + qv_local * c_pv + ql_local * c_pl) * + inv(qd_local * c_vd + qv_local * c_vv + ql_local * c_pl) + # Get the solution of the pressure Riemann problem + # See Section 6.3.3 of + # Eleuterio F. Toro (2009) + # Riemann Solvers and Numerical Methods for Fluid Dynamics: A Practical Introduction + # [DOI: 10.1007/b79761](https://doi.org/10.1007/b79761) + if v_normal <= 0.0 + sound_speed = sqrt(gamma * p_local / rho_local) # local sound speed + p_star = p_local * + (1.0 + 0.5 * (gamma - 1) * v_normal / sound_speed)^(2.0 * gamma * + inv(gamma - 1)) + else # v_normal > 0.0 + A = 2.0 / ((gamma + 1) * rho_local) + B = p_local * (gamma - 1) / (gamma + 1) + p_star = p_local + + 0.5 * v_normal / A * + (v_normal + sqrt(v_normal^2 + 4.0 * A * (p_local + B))) + end + + # For the slip wall we directly set the flux as the normal velocity is zero + return SVector(zero(eltype(u_inner)), + p_star * normal[1], + p_star * normal[2], + zero(eltype(u_inner)), + zero(eltype(u_inner)), + zero(eltype(u_inner))) * norm_ +end + +# Fix sign for structured mesh. +@inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, + direction, x, t, + surface_flux_function, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + # flip sign of normal to make it outward pointing, then flip the sign of the normal flux back + # to be inward pointing on the -x and -y sides due to the orientation convention used by StructuredMesh + if isodd(direction) + boundary_flux = -boundary_condition_slip_wall(u_inner, -normal_direction, + x, t, surface_flux_function, + equations) + else + boundary_flux = boundary_condition_slip_wall(u_inner, normal_direction, + x, t, surface_flux_function, + equations) + end + + return boundary_flux +end + +# Rotate momentum flux. The same as in compressible Euler. +@inline function rotate_to_x(u, normal_vector::AbstractVector, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + # cos and sin of the angle between the x-axis and the normalized normal_vector are + # the normalized vector's x and y coordinates respectively (see unit circle). + c = normal_vector[1] + s = normal_vector[2] + + # Apply the 2D rotation matrix with normal and tangent directions of the form + # [ 1 0 0 0; + # 0 n_1 n_2 0; + # 0 t_1 t_2 0; + # 0 0 0 1 ] + # where t_1 = -n_2 and t_2 = n_1 + + return SVector(u[1], + c * u[2] + s * u[3], + -s * u[2] + c * u[3], + u[4], u[5], u[6]) +end + +# Recreates the convergence test initial condition from compressible euler 2D. +function initial_condition_warm_bubble(x, t, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + @unpack R_d, R_v, c_vd, c_vv, c_pl, L_00 = equations + xc = 0 + zc = 2000 + r = sqrt((x[1] - xc)^2 + (x[2] - zc)^2) + rc = 2000 + theta_ref = 300 + qv_ref = 0 + qc_ref = 0 + Δtheta = 0 + Δqv = 0 + Δqc = 0 + + if r <= rc + Δtheta = 2 * cospi(0.5*r/rc)^2 + end + + #Perturbed state: + theta = theta_ref + Δtheta # potential temperature + π_exner = 1 - equation._grav / (equation.c_pd * theta) * x[2] # exner pressure + rho = equation.p_0 / (equation.R_d * theta) * (π_exner)^(equation.c_vd / equation.R_d) # density + + v1 = 20 + v2 = 0 + qv = 0 + qc = 0 + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_theta = rho * theta + rho_qv = rho * qv + rho_qc = rho * qc + + return SVector(rho, rho_v1, rho_v2, rho_e, rho_qv, rho_qc) +end + + + +# Gravity source term +@inline function source_terms_gravity(u, x, t, + equations::CompressibleMoistEulerEquations2D) + @unpack g = equations + rho, _, _, _, _, _ = u + + return SVector(zero(eltype(u)), zero(eltype(u)), + -g * rho, + zero(eltype(u)), zero(eltype(u)), zero(eltype(u))) +end + +# Rayleigh damping sponge source term form A. Sridhar et al., +# Large-eddy simulations with ClimateMachine: a new open-sourcecode for +# atmospheric simulations on GPUs and CPUs, 2 Oct 2021, doi: 10.5194/gmd-15-6259-2022, +# https://arxiv.org/abs/2110.00853 [physics.ao-ph] . +@inline function source_terms_nonhydrostatic_rayleigh_sponge(u, x, t, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + rho, rho_v1, rho_v2, rho_theta, rho_qv, rho_ql = u + v1 = rho_v1 / rho + v2 = rho_v2 / rho + z = x[2] + + # relaxed background velocity + vr1, vr2 = (10.0, 0.0) + # damping threshold + z_s = 9000.0 + # boundary top + z_top = 16000.0 + # positive even power with default value 2 + gamma = 2.0 + # relaxation coefficient > 0 + alpha = 0.5 + + tau_s = zero(eltype(u)) + if z > z_s + tau_s = alpha * sin(0.5 * (z - z_s) * inv(z_top - z_s))^(gamma) + end + + return SVector(zero(eltype(u)), + -tau_s * rho * (v1 - vr1), + -tau_s * rho * (v2 - vr2), + zero(eltype(u)), zero(eltype(u)), zero(eltype(u))) +end + +function source_terms_moist_bubble(u, x, t, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + + rho, rho_v1, rho_v2, rho_theta, rho_qv, rho_qc = u + RelCloud = 1 + rho_d = rho - rho_qv - rho_qc + c_pml = equations.c_pd * rho_d + equations.c_pv * rho_qv + equations.c_pl * rho_qc + c_vml = equations.c_vd * rho_d + equations.c_vv * rho_qv + equations.c_pl * rho_qc + R_m = equations.R_d * rho_d + equations.R_v * rho_qv + kappa_M = R_m / c_pml + p = pressure(u, equations) + T = p / R_m + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + a = p_vs / (equations.R_v * T) - rho_qv + b = rho_qc + rho_q_cond = RelCloud * (a + b - sqrt(a * a + b * b)) + L = equations.L_00 - (equations.c_pl - equations.c_pv) * T + du4 = rho_theta * ((-L / (c_pml * T) - log(p / equations.p_0) * kappa_M * (equations.R_v / R_m - equations.c_pv / c_pml) + + equations.R_v / R_m) * rho_q_cond + (log(p / equations.p_0) * kappa_M * (equations.c_pl / c_pml)) * (-rho_q_cond)) + + du5 = rho_q_cond + du6 = -rho_q_cond + + return SVector(zero(eltype(u)), zero(eltype(u)), -equations.g*rho, du4, du5, du6) +end + +@inline function flux_shima_etal(u_ll, u_rr, orientation, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + # Unpack left and right state + rho_ll, rho_v1_ll, rho_v2_ll, rho_theta_ll, rho_qv_ll, rho_qc_ll = u_ll + rho_rr, rho_v1_rr, rho_v2_rr, rho_theta_rr, rho_qv_rr, rho_qc_rr = u_rr + + p_ll = equations.K * (rho_theta_ll)^equations.gamma + p_rr = equations.K * (rho_theta_rr)^equations.gamma + + p_avg = 0.5*(p_ll + p_rr) + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + theta_ll = rho_theta_ll / rho_ll + qv_ll = rho_qv_ll / rho_ll + qc_ll = rho_qc_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + theta_rr = rho_theta_rr / rho_rr + qv_rr = rho_qv_rr / rho_rr + qc_rr = rho_qc_rr / rho_rr + + # Average each factor of products in flux + rho_avg = 1/2 * (rho_ll + rho_rr) + v1_avg = 1/2 * ( v1_ll + v1_rr) + v2_avg = 1/2 * ( v2_ll + v2_rr) + theta_avg = 1/2 * ( theta_ll + theta_rr) + qv_avg = 1/2 * ( qv_ll + qv_rr) + qc_avg = 1/2 * ( qc_ll + qc_rr) + + # Calculate fluxes depending on orientation + if orientation == 1 + f1 = rho_avg * v1_avg + f2 = rho_avg * v1_avg * v1_avg + p_avg + f3 = rho_avg * v1_avg * v2_avg + f4 = rho_avg * v1_avg * theta_avg + f5 = rho_avg * v1_avg * qv_avg + f6 = rho_avg * v1_avg * qc_avg + else + f1 = rho_avg * v2_avg + f2 = rho_avg * v2_avg * v1_avg + f3 = rho_avg * v2_avg * v2_avg + p_avg + f4 = rho_avg * v2_avg * theta_avg + f5 = rho_avg * v2_avg * qv_avg + f6 = rho_avg * v2_avg * qc_avg + end + + return SVector(f1, f2, f3, f4, f5, f6) + end + + @inline function flux_theta(u_ll, u_rr, orientation, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + # Unpack left and right state + rho_ll, rho_v1_ll, rho_v2_ll, rho_theta_ll, rho_qv_ll, rho_qc_ll = u_ll + rho_rr, rho_v1_rr, rho_v2_rr, rho_theta_rr, rho_qv_rr, rho_qc_rr = u_rr + + p_ll = equations.K * (rho_theta_ll)^equations.gamma + p_rr = equations.K * (rho_theta_rr)^equations.gamma + rho_avg = ln_mean(rho_ll, rho_rr) + + gammamean = stolarsky_mean(rho_theta_ll, rho_theta_rr, equations.gamma) + + rho_qv_mean = 0.0 + if (!(rho_qv_ll == 0.0) && !(rho_qv_rr == 0.0)) + #rho_qv_mean = stolarsky_mean(rho_qv_ll, rho_qv_rr, equations.gamma) + rho_qv_mean = ln_mean(rho_qv_ll, rho_qv_rr) + end + rho_qc_mean = 0.0 + if (!(rho_qc_ll == 0.0) && !(rho_qc_rr == 0.0)) + #rho_qc_mean = stolarsky_mean(rho_qc_ll, rho_qc_rr, equations.gamma) + rho_qc_mean = ln_mean(rho_qc_ll, rho_qc_rr) + end + + p_avg = 0.5*(p_ll + p_rr) + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + theta_ll = rho_theta_ll / rho_ll + qv_ll = rho_qv_ll / rho_ll + qc_ll = rho_qc_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + theta_rr = rho_theta_rr / rho_rr + qv_rr = rho_qv_rr / rho_rr + qc_rr = rho_qc_rr / rho_rr + + # Average each factor of products in flux + v1_avg = 1/2 * ( v1_ll + v1_rr) + v2_avg = 1/2 * ( v2_ll + v2_rr) + theta_avg = 1/2 * ( theta_ll + theta_rr) + qv_avg = 1/2 * ( qv_ll + qv_rr) + qc_avg = 1/2 * ( qc_ll + qc_rr) + + # Calculate fluxes depending on orientation + if orientation == 1 + f1 = rho_avg * v1_avg + f2 = f1 * v1_avg + p_avg + f3 = f1 * v2_avg + f4 = gammamean * v1_avg + f5 = rho_qv_mean * v1_avg + f6 = rho_qc_mean * v1_avg + else + f1 = rho_avg * v2_avg + f2 = f1 * v1_avg + f3 = f1 * v2_avg + p_avg + f4 = gammamean * v2_avg + f5 = rho_qv_mean * v2_avg + f6 = rho_qc_mean * v2_avg + end + + return SVector(f1, f2, f3, f4, f5, f6) + end + + +# Low Mach number approximate Riemann solver (LMARS) from +# X. Chen, N. Andronova, B. Van Leer, J. E. Penner, J. P. Boyd, C. Jablonowski, S. +# Lin, A Control-Volume Model of the Compressible Euler Equations with a Vertical Lagrangian +# Coordinate Monthly Weather Review Vol. 141.7, pages 2526–2544, 2013, +# https://journals.ametsoc.org/view/journals/mwre/141/7/mwr-d-12-00129.1.xml. +@inline function flux_LMARS(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + a = 360.0 + # Unpack left and right state + rho_ll, rho_v1_ll, rho_v2_ll, rho_theta_ll, rho_qv_ll, rho_ql_ll = u_ll + rho_rr, rho_v1_rr, rho_v2_rr, rho_theta_rr, rho_qv_rr, rho_ql_rr = u_rr + p_ll = equations.K * (rho_theta_ll)^equations.gamma + p_rr = equations.K * (rho_theta_rr)^equations.gamma + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + + v_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] + v_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] + + # diffusion parameter <= 1 + beta = 1 + + # Compute the necessary interface flux components + norm_ = norm(normal_direction) + + rho = 0.5 * (rho_ll + rho_rr) + p_interface = 0.5 * (p_ll + p_rr) - beta * 0.5 * a * rho * (v_rr - v_ll) / norm_ + v_interface = 0.5 * (v_ll + v_rr) - beta * 1 / (2 * a * rho) * (p_rr - p_ll) * norm_ + + if (v_interface > 0) + f1, f2, f3, f4, f5, f6 = u_ll * v_interface + else + f1, f2, f3, f4, f5, f6 = u_rr * v_interface + end + + return SVector(f1, + f2 + p_interface * normal_direction[1], + f3 + p_interface * normal_direction[2], + f4, f5, f6) +end + +# Convert conservative variables to primitive. +@inline function cons2prim(u, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + rho, rho_v1, rho_v2, rho_theta, rho_qv, rho_ql = u + v1 = rho_v1 / rho + v2 = rho_v2 / rho + p = pressure(u, equations) + qv = rho_qv / rho + ql = rho_ql / rho + + return SVector(rho, v1, v2, p, qv, ql) +end + +# Convert conservative variables to entropy +@inline function cons2entropy(u, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + @unpack R_d, R_v, c_pd, c_pv, c_pl, L_00 = equations + rho, rho_v1, rho_v2, rho_theta, rho_qv, rho_qc = u + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v_square = v1^2 + v2^2 + p = pressure(u, equations) + s = log(p) - equations.gamma*log(rho) + rho_p = rho / p + + w1 = (equations.gamma - s) / (equations.gamma-1) - 0.5 * rho_p * v_square + w2 = rho_p * v1 + w3 = rho_p * v2 + w4 = -rho_p + w5 = rho_p * rho_qv / rho + w6 = rho_p * rho_qc / rho + + return SVector(w1, w2, w3, w4, w5, w6) +end + +# Convert primitive to conservative variables. +@inline function prim2cons(prim, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + rho, v1, v2, p, qv, ql = prim + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_qv = rho * qv + rho_ql = rho * ql + rho_theta = (p / equations.K)^(1 / equations.gamma) # TODO + return SVector(rho, rho_v1, rho_v2, rho_theta, rho_qv, rho_ql) +end + + +@inline function density(u, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + rho = u[1] + return rho +end + +@inline function density_dry(u, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + rho_qd = u[1] - (u[5] + u[6]) + return rho_qd +end + +@inline function density_vapor(u, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + rho_qv = u[5] + return rho_qv +end + + + + + +# Calculate kinetic energy for a conservative state `cons`. +@inline function energy_kinetic(u, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + rho, rho_v1, rho_v2, rho_theta, rho_qv, rho_ql = u + return (rho_v1^2 + rho_v2^2) / (2 * rho) +end + + +@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + @unpack c_pd, c_pv, c_pl, c_vd, c_vv = equations + rho_ll, v1_ll, v2_ll, p_ll, qv_ll, ql_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr, p_rr, qv_rr, ql_rr = cons2prim(u_rr, equations) + qd_ll = 1 - qv_ll - ql_ll + qd_rr = 1 - qv_rr - ql_rr + # Get the density and gas gamma + gamma_ll = (qd_ll * c_pd + qv_ll * c_pv + ql_ll * c_pl) * + inv(qd_ll * c_vd + qv_ll * c_vv + ql_ll * c_pl) + gamma_rr = (qd_rr * c_pd + qv_rr * c_pv + ql_rr * c_pl) * + inv(qd_rr * c_vd + qv_rr * c_vv + ql_rr * c_pl) + + # Compute the sound speeds on the left and right + v_mag_ll = sqrt(v1_ll^2 + v2_ll^2) + c_ll = sqrt(gamma_ll * p_ll / rho_ll) + v_mag_rr = sqrt(v1_rr^2 + v2_rr^2) + c_rr = sqrt(gamma_rr * p_rr / rho_rr) + + return max(v_mag_ll, v_mag_rr) + max(c_ll, c_rr) +end + +# Adjusted version of LLF dissipation from compressible euler. +@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + @unpack c_pd, c_pv, c_pl, c_vd, c_vv = equations + rho_ll, v1_ll, v2_ll, p_ll, qv_ll, ql_ll = cons2prim(u_ll, equations) + rho_rr, v1_rr, v2_rr, p_rr, qv_rr, ql_rr = cons2prim(u_rr, equations) + qd_ll = 1 - qv_ll - ql_ll + qd_rr = 1 - qv_rr - ql_rr + # Get the density and gas gamma + gamma_ll = (qd_ll * c_pd + qv_ll * c_pv + ql_ll * c_pl) * + inv(qd_ll * c_vd + qv_ll * c_vv + ql_ll * c_pl) + gamma_rr = (qd_rr * c_pd + qv_rr * c_pv + ql_rr * c_pl) * + inv(qd_rr * c_vd + qv_rr * c_vv + ql_rr * c_pl) + # Calculate normal velocities and sound speed + # left + v_ll = (v1_ll * normal_direction[1] + + + v2_ll * normal_direction[2]) + c_ll = sqrt(gamma_ll * p_ll / rho_ll) + # right + v_rr = (v1_rr * normal_direction[1] + + + v2_rr * normal_direction[2]) + c_rr = sqrt(gamma_rr * p_rr / rho_rr) + + return max(abs(v_ll), abs(v_rr)) + max(c_ll, c_rr) * norm(normal_direction) +end + +# Adjusted version of lambda_max from compressible euler. +@inline function max_abs_speeds(u, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + @unpack c_pd, c_pv, c_pl, c_vd, c_vv = equations + rho, v1, v2, p, qv, ql = cons2prim(u, equations) + qd = 1 - qv - ql + + gamma = (qd * c_pd + qv * c_pv + ql * c_pl) * inv(qd * c_vd + qv * c_vv + ql * c_pl) + c = sqrt(gamma * p / rho) + + return (abs(v1) + c, abs(v2) + c) +end + +@inline function cons2aeqpot(u, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + @unpack c_pd, c_pv, c_pl, R_d, R_v, p_0, L_00 = equations + rho, rho_v1, rho_v2, rho_theta, rho_qv, rho_ql = u + rho_d = rho - rho_qv - rho_ql + p = pressure(u, equations) + T = p / (equations.R_d * rho_d + equations.R_v * rho_qv) + p_v = rho_qv * R_v * T + p_d = p - p_v + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + H = p_v / p_vs + r_v = rho_qv / rho_d + r_l = rho_ql / rho_d + r_t = r_v + r_l + L_v = L_00 + (c_pv - c_pl) * T + c_p = c_pd + r_t * c_pl + + # equivalent potential temperature + aeq_pot = (T * (p_0 / p_d)^(R_d / c_p) * H^(-r_v * R_v / c_p) * + exp(L_v * r_v * inv(c_p * T))) + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + + pot1 = rho + pot2 = v1 + pot3 = v2 + pot4 = aeq_pot + pot5 = r_v + pot6 = r_t + return SVector(pot1, pot2, pot3, pot4, pot5, pot6) +end + +varnames(::typeof(cons2aeqpot), ::CompressibleMoistEulerPotentialTemperatureEquations2D) = ("rho", "v1", + "v2", + "aeqpottemp", + "rv", "rt") + + +varnames(::typeof(cons2cons), ::CompressibleMoistEulerPotentialTemperatureEquations2D) = ("rho", "rho_v1", + "rho_v2", "rho_theta", + "rho_qv", + "rho_ql") +varnames(::typeof(cons2prim), ::CompressibleMoistEulerPotentialTemperatureEquations2D) = ("rho", "v1", "v2", + "p", "qv", "ql") +end # @muladd diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 17cae95f..81a4306f 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -8,4 +8,5 @@ abstract type AbstractCompressibleRainyEulerEquations{NDIMS, NVARS} <: include("compressible_rainy_euler_2d.jl") include("compressible_moist_euler_2d_lucas.jl") -include("compressible_rainy_euler_potential_temperature_2d.jl") \ No newline at end of file +include("compressible_rainy_euler_potential_temperature_2d.jl") +include("compressible_moist_euler_potential_temperature_2d.jl") \ No newline at end of file From 91344ac1956cea56f6aed0b4a268a60719b432d3 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:57:43 +0100 Subject: [PATCH 075/115] fixes --- ...le_moist_euler_potential_temperature_2d.jl | 109 ------------------ 1 file changed, 109 deletions(-) diff --git a/src/equations/compressible_moist_euler_potential_temperature_2d.jl b/src/equations/compressible_moist_euler_potential_temperature_2d.jl index 8acb2c53..105aa7fa 100644 --- a/src/equations/compressible_moist_euler_potential_temperature_2d.jl +++ b/src/equations/compressible_moist_euler_potential_temperature_2d.jl @@ -302,115 +302,6 @@ function source_terms_moist_bubble(u, x, t, equations::CompressibleMoistEulerPot return SVector(zero(eltype(u)), zero(eltype(u)), -equations.g*rho, du4, du5, du6) end -@inline function flux_shima_etal(u_ll, u_rr, orientation, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) - # Unpack left and right state - rho_ll, rho_v1_ll, rho_v2_ll, rho_theta_ll, rho_qv_ll, rho_qc_ll = u_ll - rho_rr, rho_v1_rr, rho_v2_rr, rho_theta_rr, rho_qv_rr, rho_qc_rr = u_rr - - p_ll = equations.K * (rho_theta_ll)^equations.gamma - p_rr = equations.K * (rho_theta_rr)^equations.gamma - - p_avg = 0.5*(p_ll + p_rr) - v1_ll = rho_v1_ll / rho_ll - v2_ll = rho_v2_ll / rho_ll - theta_ll = rho_theta_ll / rho_ll - qv_ll = rho_qv_ll / rho_ll - qc_ll = rho_qc_ll / rho_ll - v1_rr = rho_v1_rr / rho_rr - v2_rr = rho_v2_rr / rho_rr - theta_rr = rho_theta_rr / rho_rr - qv_rr = rho_qv_rr / rho_rr - qc_rr = rho_qc_rr / rho_rr - - # Average each factor of products in flux - rho_avg = 1/2 * (rho_ll + rho_rr) - v1_avg = 1/2 * ( v1_ll + v1_rr) - v2_avg = 1/2 * ( v2_ll + v2_rr) - theta_avg = 1/2 * ( theta_ll + theta_rr) - qv_avg = 1/2 * ( qv_ll + qv_rr) - qc_avg = 1/2 * ( qc_ll + qc_rr) - - # Calculate fluxes depending on orientation - if orientation == 1 - f1 = rho_avg * v1_avg - f2 = rho_avg * v1_avg * v1_avg + p_avg - f3 = rho_avg * v1_avg * v2_avg - f4 = rho_avg * v1_avg * theta_avg - f5 = rho_avg * v1_avg * qv_avg - f6 = rho_avg * v1_avg * qc_avg - else - f1 = rho_avg * v2_avg - f2 = rho_avg * v2_avg * v1_avg - f3 = rho_avg * v2_avg * v2_avg + p_avg - f4 = rho_avg * v2_avg * theta_avg - f5 = rho_avg * v2_avg * qv_avg - f6 = rho_avg * v2_avg * qc_avg - end - - return SVector(f1, f2, f3, f4, f5, f6) - end - - @inline function flux_theta(u_ll, u_rr, orientation, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) - # Unpack left and right state - rho_ll, rho_v1_ll, rho_v2_ll, rho_theta_ll, rho_qv_ll, rho_qc_ll = u_ll - rho_rr, rho_v1_rr, rho_v2_rr, rho_theta_rr, rho_qv_rr, rho_qc_rr = u_rr - - p_ll = equations.K * (rho_theta_ll)^equations.gamma - p_rr = equations.K * (rho_theta_rr)^equations.gamma - rho_avg = ln_mean(rho_ll, rho_rr) - - gammamean = stolarsky_mean(rho_theta_ll, rho_theta_rr, equations.gamma) - - rho_qv_mean = 0.0 - if (!(rho_qv_ll == 0.0) && !(rho_qv_rr == 0.0)) - #rho_qv_mean = stolarsky_mean(rho_qv_ll, rho_qv_rr, equations.gamma) - rho_qv_mean = ln_mean(rho_qv_ll, rho_qv_rr) - end - rho_qc_mean = 0.0 - if (!(rho_qc_ll == 0.0) && !(rho_qc_rr == 0.0)) - #rho_qc_mean = stolarsky_mean(rho_qc_ll, rho_qc_rr, equations.gamma) - rho_qc_mean = ln_mean(rho_qc_ll, rho_qc_rr) - end - - p_avg = 0.5*(p_ll + p_rr) - v1_ll = rho_v1_ll / rho_ll - v2_ll = rho_v2_ll / rho_ll - theta_ll = rho_theta_ll / rho_ll - qv_ll = rho_qv_ll / rho_ll - qc_ll = rho_qc_ll / rho_ll - v1_rr = rho_v1_rr / rho_rr - v2_rr = rho_v2_rr / rho_rr - theta_rr = rho_theta_rr / rho_rr - qv_rr = rho_qv_rr / rho_rr - qc_rr = rho_qc_rr / rho_rr - - # Average each factor of products in flux - v1_avg = 1/2 * ( v1_ll + v1_rr) - v2_avg = 1/2 * ( v2_ll + v2_rr) - theta_avg = 1/2 * ( theta_ll + theta_rr) - qv_avg = 1/2 * ( qv_ll + qv_rr) - qc_avg = 1/2 * ( qc_ll + qc_rr) - - # Calculate fluxes depending on orientation - if orientation == 1 - f1 = rho_avg * v1_avg - f2 = f1 * v1_avg + p_avg - f3 = f1 * v2_avg - f4 = gammamean * v1_avg - f5 = rho_qv_mean * v1_avg - f6 = rho_qc_mean * v1_avg - else - f1 = rho_avg * v2_avg - f2 = f1 * v1_avg - f3 = f1 * v2_avg + p_avg - f4 = gammamean * v2_avg - f5 = rho_qv_mean * v2_avg - f6 = rho_qc_mean * v2_avg - end - - return SVector(f1, f2, f3, f4, f5, f6) - end - # Low Mach number approximate Riemann solver (LMARS) from # X. Chen, N. Andronova, B. Van Leer, J. E. Penner, J. P. Boyd, C. Jablonowski, S. From 5566e0ce06f41000fabc32e934b74004db6975cd Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Thu, 21 Nov 2024 20:22:54 +0100 Subject: [PATCH 076/115] adjusted LMARS --- ...oist_euler_potential_temperature_moist_bubble.jl | 13 +++++-------- ...ressible_moist_euler_potential_temperature_2d.jl | 4 ++-- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/examples/elixir_moist_euler_potential_temperature_moist_bubble.jl b/examples/elixir_moist_euler_potential_temperature_moist_bubble.jl index 72c8f10a..1f85a698 100644 --- a/examples/elixir_moist_euler_potential_temperature_moist_bubble.jl +++ b/examples/elixir_moist_euler_potential_temperature_moist_bubble.jl @@ -2,7 +2,7 @@ using OrdinaryDiffEq using Trixi, TrixiAtmo using Plots using TrixiAtmo: cons2aeqpot, saturation_pressure, source_terms_moist_bubble, - flux_LMARS, flux_shima_etal, flux_theta + flux_LMARS using NLsolve: nlsolve ############################################################################### @@ -245,16 +245,13 @@ source_term = source_terms_moist_bubble polydeg = 3 basis = LobattoLegendreBasis(polydeg) -surface_flux = flux_lax_friedrichs -#volume_flux = flux_theta -#volume_integral = VolumeIntegralFluxDifferencing(volume_flux) +surface_flux = flux_LMARS -solver = DGSEM(basis, surface_flux)#, volume_integral) -#solver = DGSEM(basis, surface_flux) +solver = DGSEM(basis, surface_flux) coordinates_min = (0.0, 0.0) coordinates_max = (20000.0, 10000.0) -cells_per_dimension = (64, 32) +cells_per_dimension = (201, 100) # Create curved mesh with 64 x 32 elements mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, @@ -287,7 +284,7 @@ save_solution = SaveSolutionCallback(interval = 1000, save_final_solution = true, solution_variables = solution_variables) -stepsize_callback = StepsizeCallback(cfl = 0.2) +stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, diff --git a/src/equations/compressible_moist_euler_potential_temperature_2d.jl b/src/equations/compressible_moist_euler_potential_temperature_2d.jl index 105aa7fa..02eae587 100644 --- a/src/equations/compressible_moist_euler_potential_temperature_2d.jl +++ b/src/equations/compressible_moist_euler_potential_temperature_2d.jl @@ -314,8 +314,8 @@ end # Unpack left and right state rho_ll, rho_v1_ll, rho_v2_ll, rho_theta_ll, rho_qv_ll, rho_ql_ll = u_ll rho_rr, rho_v1_rr, rho_v2_rr, rho_theta_rr, rho_qv_rr, rho_ql_rr = u_rr - p_ll = equations.K * (rho_theta_ll)^equations.gamma - p_rr = equations.K * (rho_theta_rr)^equations.gamma + p_ll = pressure(u_ll, equations) + p_rr = pressure(u_rr, equations) v1_ll = rho_v1_ll / rho_ll v2_ll = rho_v2_ll / rho_ll v1_rr = rho_v1_rr / rho_rr From f81d4055f1321140218c287ea73cbaa950d85a71 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Sun, 24 Nov 2024 21:52:43 +0100 Subject: [PATCH 077/115] fixed DGMulti example --- ...ixir_rainy_euler_bubble_no_rain_dgmulti.jl | 119 ++++++++++-------- 1 file changed, 66 insertions(+), 53 deletions(-) diff --git a/examples/elixir_rainy_euler_bubble_no_rain_dgmulti.jl b/examples/elixir_rainy_euler_bubble_no_rain_dgmulti.jl index bef45702..8bf8fde9 100644 --- a/examples/elixir_rainy_euler_bubble_no_rain_dgmulti.jl +++ b/examples/elixir_rainy_euler_bubble_no_rain_dgmulti.jl @@ -1,27 +1,27 @@ using OrdinaryDiffEq using Trixi using TrixiAtmo -using TrixiAtmo: source_terms_no_phase_change, saturation_residual, +using TrixiAtmo: source_terms_moist_bubble, saturation_residual, saturation_residual_jacobian, NonlinearSolveDG, cons2eq_pot_temp, flux_LMARS, flux_chandrashekar using NLsolve: nlsolve -# Initial condition from elixir_moist_euler_bubble.jl -function moist_state(y, dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) +equations = CompressibleMoistEulerEquations2D() +function moist_state(y, dz, y0, r_t0, theta_e0, + equations::CompressibleMoistEulerEquations2D) @unpack p_0, g, c_pd, c_pv, c_vd, c_vv, R_d, R_v, c_pl, L_00 = equations - (p, rho, T, r_t, r_v, rho_qv, theta_e) = y p0 = y0[1] - F = zeros(7, 1) + F = zeros(7, 1) rho_d = rho / (1 + r_t) - p_d = R_d * rho_d * T - T_C = T - 273.15 - p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) - L = L_00 - (c_pl - c_pv) * T + p_d = R_d * rho_d * T + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + L = L_00 - (c_pl - c_pv) * T F[1] = (p - p0) / dz + g * rho F[2] = p - (R_d * rho_d + R_v * rho_qv) * T @@ -32,15 +32,16 @@ function moist_state(y, dz, y0, r_t0, theta_e0, equations::CompressibleMoistEule F[4] = r_t - r_t0 F[5] = rho_qv - rho_d * r_v F[6] = theta_e - theta_e0 - a = p_vs / (R_v * T) - rho_qv - b = rho - rho_qv - rho_d + a = p_vs / (R_v * T) - rho_qv + b = rho - rho_qv - rho_d # H=1 => phi=0 F[7] = a + b - sqrt(a * a + b * b) return F end -function generate_function_of_y(dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) +function generate_function_of_y(dz, y0, r_t0, theta_e0, + equations::CompressibleMoistEulerEquations2D) function function_of_y(y) return moist_state(y, dz, y0, r_t0, theta_e0, equations) end @@ -62,7 +63,6 @@ function AtmosphereLayers(equations; total_height = 10010.0, preciseness = 10, ground_state = (1.4, 100000.0), equivalent_potential_temperature = 320, mixing_ratios = (0.02, 0.02), RealT = Float64) - @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl = equations rho0, p0 = ground_state r_t0, r_v0 = mixing_ratios @@ -110,7 +110,8 @@ end # G.H. Bryan, J.M. Fritsch, A Benchmark Simulation for Moist Nonhydrostatic Numerical # Models, MonthlyWeather Review Vol.130, 2917–2928, 2002, # https://journals.ametsoc.org/view/journals/mwre/130/12/1520-0493_2002_130_2917_absfmn_2.0.co_2.xml. -function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, atmosphere_layers::AtmosphereLayers) +function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, + atmosphere_layers::AtmosphereLayers) @unpack layer_data, preciseness, total_height = atmosphere_layers dz = preciseness z = x[2] @@ -132,7 +133,7 @@ function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerE rho_qv = rho * (rho_qv_r / rho_r * (z - z_l) + rho_qv_l / rho_l * (z_r - z)) / dz rho_ql = rho * (rho_ql_r / rho_r * (z - z_l) + rho_ql_l / rho_l * (z_r - z)) / dz - rho, rho_e, rho_qv, rho_ql, T_loc = perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, + rho, rho_e, rho_qv, rho_ql = perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, equations::CompressibleMoistEulerEquations2D) v1 = 0.0 @@ -141,7 +142,7 @@ function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerE rho_v2 = rho * v2 rho_E = rho_e + 1 / 2 * rho * (v1^2 + v2^2) - return SVector(rho - rho_qv - rho_ql, rho_qv + rho_ql, 0.0, rho_v1, rho_v2, rho_E, rho_qv, rho_ql, T_loc) + return SVector(rho, rho_v1, rho_v2, rho_E, rho_qv, rho_ql) end function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, @@ -159,6 +160,22 @@ function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, T_loc = p_loc / (R_d * rho_d + R_v * rho_qv) rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv + p_v = rho_qv * R_v * T_loc + p_d = p_loc - p_v + T_C = T_loc - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + H = p_v / p_vs + r_v = rho_qv / rho_d + r_l = rho_ql / rho_d + r_t = r_v + r_l + + # equivalent potential temperature + a = T_loc * (p_0 / p_d)^(R_d / (c_pd + r_t * c_pl)) + b = H^(-r_v * R_v / c_pd) + L_v = L_00 + (c_pv - c_pl) * T_loc + c = exp(L_v * r_v / ((c_pd + r_t * c_pl) * T_loc)) + aeq_pot = (a * b * c) # TODO: this is not used. remove? + # Assume pressure stays constant if (r < rc && Δθ > 0) # Calculate background density potential temperature @@ -191,9 +208,6 @@ function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, rho_d_new = p_loc / (R_d * T_loc) θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) end - # test - #T_loc = θ_new * (p_loc / p_0)^kappa - # rho_qv = rvs * rho_d_new rho_ql = (rt - rvs) * rho_d_new rho = rho_d_new * (1 + rt) @@ -203,51 +217,54 @@ function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, rho_theta = rho * θ_dens_new * (p_loc / p_0)^(kappa - kappa_M) rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv end - return SVector(rho, rho_e, rho_qv, rho_ql, T_loc) + return SVector(rho, rho_e, rho_qv, rho_ql) end # Create background atmosphere data set -atmosphere_data = AtmosphereLayers(CompressibleMoistEulerEquations2D()) +atmosphere_data = AtmosphereLayers(equations) # Create the initial condition with the initial data set -function initial_condition_moist(x, t, equations::CompressibleRainyEulerEquations2D) - return initial_condition_moist_bubble(x, t, CompressibleMoistEulerEquations2D(), atmosphere_data) +function initial_condition_moist(x, t, equations) + return initial_condition_moist_bubble(x, t, equations, atmosphere_data) end +############################################################################### +# semidiscretization of the compressible moist Euler equations +initial_condition = initial_condition_moist -############################################################################### -# semidiscretization of the compressible rainy Euler equations +# tag different boundary segments +left(x, tol = 50 * eps()) = abs(x[1] - coordinates_min[1]) < tol +right(x, tol = 50 * eps()) = abs(x[1] - coordinates_max[1]) < tol +bottom(x, tol = 50 * eps()) = abs(x[2] - coordinates_min[2]) < tol +top(x, tol = 50 * eps()) = abs(x[2] - coordinates_max[2]) < tol -equations = CompressibleRainyEulerEquations2D() +is_on_boundary = Dict(:left => left, :right => right, :top => top, :bottom => bottom) -boundary_conditions = (x_neg = boundary_condition_periodic, - x_pos = boundary_condition_periodic, - y_neg = boundary_condition_slip_wall, - y_pos = boundary_condition_slip_wall) +boundary_conditions = (; :left => boundary_condition_periodic, + :top => boundary_condition_slip_wall, + :bottom => boundary_condition_slip_wall, + :right => boundary_condition_periodic) -polydeg = 3 +polydeg = 1 basis = LobattoLegendreBasis(polydeg) -surface_flux = flux_lax_friedrichs -#surface_flux = flux_LMARS #volume_flux = flux_chandrashekar - #volume_integral = VolumeIntegralFluxDifferencing(volume_flux) -solver = DGMulti(polydeg=polydeg, element_type = Quad(), approximation_type = GaussSBP(), - surface_integral = SurfaceIntegralWeakForm(surface_flux), - volume_integral = VolumeIntegralWeakForm()) +solver = DGMulti(polydeg=polydeg, element_type = Quad(), approximation_type = GaussSBP(), #TODO + surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), + volume_integral = VolumeIntegralWeakForm()) #TODO coordinates_min = ( 0.0, 0.0) coordinates_max = (20_000.0, 10_000.0) cells_per_dimension = (200, 100) -mesh = DGMultiMesh(solver, cells_per_dimension; coordinates_min, coordinates_max, periodicity = (true, false)) +mesh = DGMultiMesh(solver, cells_per_dimension; coordinates_min, coordinates_max, is_on_boundary, periodicity = (true, false)) semi = SemidiscretizationHyperbolic(mesh, equations, - initial_condition_moist, solver, - source_terms = source_terms_no_phase_change, + initial_condition, solver; + source_terms = source_terms_moist_bubble, boundary_conditions = boundary_conditions) ############################################################################### @@ -261,31 +278,27 @@ summary_callback = SummaryCallback() analysis_interval = 1000 -# entropy? -#analysis_callback = AnalysisCallback(semi, interval = analysis_interval, -# extra_analysis_errors = (:entropy_conservation_error,)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(solver)) alive_callback = AliveCallback(analysis_interval = 1000) -save_solution = SaveSolutionCallback(interval = 1000, - save_initial_solution = true, - save_final_solution = true, - output_directory = "out", - solution_variables = cons2eq_pot_temp) +#save_solution = SaveSolutionCallback(interval = 1000, + #save_initial_solution = true, + #save_final_solution = true, + #output_directory = "out", + #solution_variables = cons2eq_pot_temp) stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, - #analysis_callback, + analysis_callback, alive_callback, - save_solution, + #save_solution, stepsize_callback) -stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) - ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limiter!), +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), maxiters = 1.0e7, dt = 1.0, save_everystep = false, callback = callbacks); From bb8bb5194b75daa36538a3d9ea0078a1f4cf376b Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:07:13 +0100 Subject: [PATCH 078/115] added rainy equations DGMulti example and clarified elixir names --- ...ixir_moist_euler_bubble_no_rain_dgmulti.jl | 303 ++++++++++++++++++ ...ixir_rainy_euler_bubble_no_rain_dgmulti.jl | 75 ++--- src/callbacks_stage/nonlinear_solve_dg2d.jl | 133 ++------ 3 files changed, 364 insertions(+), 147 deletions(-) create mode 100644 examples/elixir_moist_euler_bubble_no_rain_dgmulti.jl diff --git a/examples/elixir_moist_euler_bubble_no_rain_dgmulti.jl b/examples/elixir_moist_euler_bubble_no_rain_dgmulti.jl new file mode 100644 index 00000000..bcc31189 --- /dev/null +++ b/examples/elixir_moist_euler_bubble_no_rain_dgmulti.jl @@ -0,0 +1,303 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: source_terms_moist_bubble, saturation_residual, + saturation_residual_jacobian, NonlinearSolveDG, + cons2eq_pot_temp, flux_LMARS, flux_chandrashekar +using NLsolve: nlsolve + + + +equations = CompressibleMoistEulerEquations2D() + +function moist_state(y, dz, y0, r_t0, theta_e0, + equations::CompressibleMoistEulerEquations2D) + @unpack p_0, g, c_pd, c_pv, c_vd, c_vv, R_d, R_v, c_pl, L_00 = equations + (p, rho, T, r_t, r_v, rho_qv, theta_e) = y + p0 = y0[1] + + F = zeros(7, 1) + rho_d = rho / (1 + r_t) + p_d = R_d * rho_d * T + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + L = L_00 - (c_pl - c_pv) * T + + F[1] = (p - p0) / dz + g * rho + F[2] = p - (R_d * rho_d + R_v * rho_qv) * T + # H = 1 is assumed + F[3] = (theta_e - + T * (p_d / p_0)^(-R_d / (c_pd + c_pl * r_t)) * + exp(L * r_v / ((c_pd + c_pl * r_t) * T))) + F[4] = r_t - r_t0 + F[5] = rho_qv - rho_d * r_v + F[6] = theta_e - theta_e0 + a = p_vs / (R_v * T) - rho_qv + b = rho - rho_qv - rho_d + # H=1 => phi=0 + F[7] = a + b - sqrt(a * a + b * b) + + return F +end + +function generate_function_of_y(dz, y0, r_t0, theta_e0, + equations::CompressibleMoistEulerEquations2D) + function function_of_y(y) + return moist_state(y, dz, y0, r_t0, theta_e0, equations) + end +end + +struct AtmosphereLayers{RealT <: Real} + equations::CompressibleMoistEulerEquations2D + # structure: 1--> i-layer (z = total_height/precision *(i-1)), 2--> rho, rho_theta, rho_qv, rho_ql + layer_data::Matrix{RealT} + total_height::RealT + preciseness::Int + layers::Int + ground_state::NTuple{2, RealT} + equivalent_potential_temperature::RealT + mixing_ratios::NTuple{2, RealT} +end + +function AtmosphereLayers(equations; total_height = 10010.0, preciseness = 10, + ground_state = (1.4, 100000.0), + equivalent_potential_temperature = 320, + mixing_ratios = (0.02, 0.02), RealT = Float64) + @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl = equations + rho0, p0 = ground_state + r_t0, r_v0 = mixing_ratios + theta_e0 = equivalent_potential_temperature + + rho_qv0 = rho0 * r_v0 + T0 = theta_e0 + y0 = [p0, rho0, T0, r_t0, r_v0, rho_qv0, theta_e0] + + n = convert(Int, total_height / preciseness) + dz = 0.01 + layer_data = zeros(RealT, n + 1, 4) + + F = generate_function_of_y(dz, y0, r_t0, theta_e0, equations) + sol = nlsolve(F, y0) + p, rho, T, r_t, r_v, rho_qv, theta_e = sol.zero + + rho_d = rho / (1 + r_t) + rho_ql = rho - rho_d - rho_qv + kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * (p0 / p)^kappa_M * T * (1 + (R_v / R_d) * r_v) / (1 + r_t) + + layer_data[1, :] = [rho, rho_theta, rho_qv, rho_ql] + for i in (1:n) + y0 = deepcopy(sol.zero) + dz = preciseness + F = generate_function_of_y(dz, y0, r_t0, theta_e0, equations) + sol = nlsolve(F, y0) + p, rho, T, r_t, r_v, rho_qv, theta_e = sol.zero + + rho_d = rho / (1 + r_t) + rho_ql = rho - rho_d - rho_qv + kappa_M = (R_d * rho_d + R_v * rho_qv) / + (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * (p0 / p)^kappa_M * T * (1 + (R_v / R_d) * r_v) / (1 + r_t) + + layer_data[i + 1, :] = [rho, rho_theta, rho_qv, rho_ql] + end + + return AtmosphereLayers{RealT}(equations, layer_data, total_height, dz, n, ground_state, + theta_e0, mixing_ratios) +end + +# Moist bubble test case from paper: +# G.H. Bryan, J.M. Fritsch, A Benchmark Simulation for Moist Nonhydrostatic Numerical +# Models, MonthlyWeather Review Vol.130, 2917–2928, 2002, +# https://journals.ametsoc.org/view/journals/mwre/130/12/1520-0493_2002_130_2917_absfmn_2.0.co_2.xml. +function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, + atmosphere_layers::AtmosphereLayers) + @unpack layer_data, preciseness, total_height = atmosphere_layers + dz = preciseness + z = x[2] + if (z > total_height && !(isapprox(z, total_height))) + error("The atmosphere does not match the simulation domain") + end + n = convert(Int, floor((z + eps()) / dz)) + 1 + z_l = (n - 1) * dz + (rho_l, rho_theta_l, rho_qv_l, rho_ql_l) = layer_data[n, :] + z_r = n * dz + if (z_l == total_height) + z_r = z_l + dz + n = n - 1 + end + (rho_r, rho_theta_r, rho_qv_r, rho_ql_r) = layer_data[n + 1, :] + rho = (rho_r * (z - z_l) + rho_l * (z_r - z)) / dz + rho_theta = rho * (rho_theta_r / rho_r * (z - z_l) + rho_theta_l / rho_l * (z_r - z)) / + dz + rho_qv = rho * (rho_qv_r / rho_r * (z - z_l) + rho_qv_l / rho_l * (z_r - z)) / dz + rho_ql = rho * (rho_ql_r / rho_r * (z - z_l) + rho_ql_l / rho_l * (z_r - z)) / dz + + rho, rho_e, rho_qv, rho_ql = perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, + equations::CompressibleMoistEulerEquations2D) + + v1 = 0.0 + v2 = 0.0 + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_E = rho_e + 1 / 2 * rho * (v1^2 + v2^2) + + return SVector(rho, rho_v1, rho_v2, rho_E, rho_qv, rho_ql) +end + +function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, + equations::CompressibleMoistEulerEquations2D) + @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl, L_00 = equations + xc = 10000.0 + zc = 2000.0 + rc = 2000.0 + Δθ = 2.0 + + r = sqrt((x[1] - xc)^2 + (x[2] - zc)^2) + rho_d = rho - rho_qv - rho_ql + kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + p_loc = p_0 * (R_d * rho_theta / p_0)^(1 / (1 - kappa_M)) + T_loc = p_loc / (R_d * rho_d + R_v * rho_qv) + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv + + p_v = rho_qv * R_v * T_loc + p_d = p_loc - p_v + T_C = T_loc - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + H = p_v / p_vs + r_v = rho_qv / rho_d + r_l = rho_ql / rho_d + r_t = r_v + r_l + + # equivalent potential temperature + a = T_loc * (p_0 / p_d)^(R_d / (c_pd + r_t * c_pl)) + b = H^(-r_v * R_v / c_pd) + L_v = L_00 + (c_pv - c_pl) * T_loc + c = exp(L_v * r_v / ((c_pd + r_t * c_pl) * T_loc)) + aeq_pot = (a * b * c) # TODO: this is not used. remove? + + # Assume pressure stays constant + if (r < rc && Δθ > 0) + # Calculate background density potential temperature + θ_dens = rho_theta / rho * (p_loc / p_0)^(kappa_M - kappa) + # Calculate perturbed density potential temperature + θ_dens_new = θ_dens * (1 + Δθ * cospi(0.5 * r / rc)^2 / 300) + rt = (rho_qv + rho_ql) / rho_d + rv = rho_qv / rho_d + # Calculate moist potential temperature + θ_loc = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rv) + # Adjust varuables until the temperature is met + if rt > 0 + while true + T_loc = θ_loc * (p_loc / p_0)^kappa + T_C = T_loc - 273.15 + # SaturVapor + pvs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + rho_d_new = (p_loc - pvs) / (R_d * T_loc) + rvs = pvs / (R_v * rho_d_new * T_loc) + θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) + if abs(θ_new - θ_loc) <= θ_loc * 1.0e-12 + break + else + θ_loc = θ_new + end + end + else + rvs = 0 + T_loc = θ_loc * (p_loc / p_0)^kappa + rho_d_new = p_loc / (R_d * T_loc) + θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) + end + rho_qv = rvs * rho_d_new + rho_ql = (rt - rvs) * rho_d_new + rho = rho_d_new * (1 + rt) + rho_d = rho - rho_qv - rho_ql + kappa_M = (R_d * rho_d + R_v * rho_qv) / + (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * θ_dens_new * (p_loc / p_0)^(kappa - kappa_M) + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv + end + return SVector(rho, rho_e, rho_qv, rho_ql) +end + +# Create background atmosphere data set +atmosphere_data = AtmosphereLayers(equations) + +# Create the initial condition with the initial data set +function initial_condition_moist(x, t, equations) + return initial_condition_moist_bubble(x, t, equations, atmosphere_data) +end + +############################################################################### +# semidiscretization of the compressible moist Euler equations + +initial_condition = initial_condition_moist + +# tag different boundary segments +left(x, tol = 50 * eps()) = abs(x[1] - coordinates_min[1]) < tol +right(x, tol = 50 * eps()) = abs(x[1] - coordinates_max[1]) < tol +bottom(x, tol = 50 * eps()) = abs(x[2] - coordinates_min[2]) < tol +top(x, tol = 50 * eps()) = abs(x[2] - coordinates_max[2]) < tol + +is_on_boundary = Dict(:left => left, :right => right, :top => top, :bottom => bottom) + +boundary_conditions = (; :left => boundary_condition_periodic, + :top => boundary_condition_slip_wall, + :bottom => boundary_condition_slip_wall, + :right => boundary_condition_periodic) + +#volume_flux = flux_chandrashekar +#volume_integral = VolumeIntegralFluxDifferencing(volume_flux) + +solver = DGMulti(polydeg = 1, element_type = Quad(), approximation_type = GaussSBP(), + surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), + volume_integral = VolumeIntegralWeakForm()) + +coordinates_min = ( 0.0, 0.0) +coordinates_max = (20_000.0, 10_000.0) + +cells_per_dimension = (200, 100) +mesh = DGMultiMesh(solver, cells_per_dimension; coordinates_min, coordinates_max, is_on_boundary, periodicity = (true, false)) + +semi = SemidiscretizationHyperbolic(mesh, equations, + initial_condition, solver; + source_terms = source_terms_moist_bubble, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 1000.0) + +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 + +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(solver)) + +alive_callback = AliveCallback(analysis_interval = 1000) + +#save_solution = SaveSolutionCallback(interval = 1000, + #save_initial_solution = true, + #save_final_solution = true, + #output_directory = "out", + #solution_variables = cons2eq_pot_temp) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + #save_solution, + stepsize_callback) + +############################################################################### +# run the simulation +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + maxiters = 1.0e7, + dt = 1.0, + save_everystep = false, callback = callbacks); + +summary_callback() \ No newline at end of file diff --git a/examples/elixir_rainy_euler_bubble_no_rain_dgmulti.jl b/examples/elixir_rainy_euler_bubble_no_rain_dgmulti.jl index 8bf8fde9..5567a940 100644 --- a/examples/elixir_rainy_euler_bubble_no_rain_dgmulti.jl +++ b/examples/elixir_rainy_euler_bubble_no_rain_dgmulti.jl @@ -1,27 +1,27 @@ using OrdinaryDiffEq using Trixi using TrixiAtmo -using TrixiAtmo: source_terms_moist_bubble, saturation_residual, +using TrixiAtmo: source_terms_no_phase_change, saturation_residual, saturation_residual_jacobian, NonlinearSolveDG, cons2eq_pot_temp, flux_LMARS, flux_chandrashekar using NLsolve: nlsolve -equations = CompressibleMoistEulerEquations2D() +# Initial condition from elixir_moist_euler_bubble.jl +function moist_state(y, dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) -function moist_state(y, dz, y0, r_t0, theta_e0, - equations::CompressibleMoistEulerEquations2D) @unpack p_0, g, c_pd, c_pv, c_vd, c_vv, R_d, R_v, c_pl, L_00 = equations + (p, rho, T, r_t, r_v, rho_qv, theta_e) = y p0 = y0[1] - F = zeros(7, 1) + F = zeros(7, 1) rho_d = rho / (1 + r_t) - p_d = R_d * rho_d * T - T_C = T - 273.15 - p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) - L = L_00 - (c_pl - c_pv) * T + p_d = R_d * rho_d * T + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + L = L_00 - (c_pl - c_pv) * T F[1] = (p - p0) / dz + g * rho F[2] = p - (R_d * rho_d + R_v * rho_qv) * T @@ -32,16 +32,15 @@ function moist_state(y, dz, y0, r_t0, theta_e0, F[4] = r_t - r_t0 F[5] = rho_qv - rho_d * r_v F[6] = theta_e - theta_e0 - a = p_vs / (R_v * T) - rho_qv - b = rho - rho_qv - rho_d + a = p_vs / (R_v * T) - rho_qv + b = rho - rho_qv - rho_d # H=1 => phi=0 F[7] = a + b - sqrt(a * a + b * b) return F end -function generate_function_of_y(dz, y0, r_t0, theta_e0, - equations::CompressibleMoistEulerEquations2D) +function generate_function_of_y(dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) function function_of_y(y) return moist_state(y, dz, y0, r_t0, theta_e0, equations) end @@ -63,6 +62,7 @@ function AtmosphereLayers(equations; total_height = 10010.0, preciseness = 10, ground_state = (1.4, 100000.0), equivalent_potential_temperature = 320, mixing_ratios = (0.02, 0.02), RealT = Float64) + @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl = equations rho0, p0 = ground_state r_t0, r_v0 = mixing_ratios @@ -110,8 +110,7 @@ end # G.H. Bryan, J.M. Fritsch, A Benchmark Simulation for Moist Nonhydrostatic Numerical # Models, MonthlyWeather Review Vol.130, 2917–2928, 2002, # https://journals.ametsoc.org/view/journals/mwre/130/12/1520-0493_2002_130_2917_absfmn_2.0.co_2.xml. -function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, - atmosphere_layers::AtmosphereLayers) +function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, atmosphere_layers::AtmosphereLayers) @unpack layer_data, preciseness, total_height = atmosphere_layers dz = preciseness z = x[2] @@ -133,7 +132,7 @@ function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerE rho_qv = rho * (rho_qv_r / rho_r * (z - z_l) + rho_qv_l / rho_l * (z_r - z)) / dz rho_ql = rho * (rho_ql_r / rho_r * (z - z_l) + rho_ql_l / rho_l * (z_r - z)) / dz - rho, rho_e, rho_qv, rho_ql = perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, + rho, rho_e, rho_qv, rho_ql, T_loc = perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, equations::CompressibleMoistEulerEquations2D) v1 = 0.0 @@ -142,7 +141,7 @@ function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerE rho_v2 = rho * v2 rho_E = rho_e + 1 / 2 * rho * (v1^2 + v2^2) - return SVector(rho, rho_v1, rho_v2, rho_E, rho_qv, rho_ql) + return SVector(rho - rho_qv - rho_ql, rho_qv + rho_ql, 0.0, rho_v1, rho_v2, rho_E, rho_qv, rho_ql, T_loc) end function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, @@ -160,22 +159,6 @@ function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, T_loc = p_loc / (R_d * rho_d + R_v * rho_qv) rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv - p_v = rho_qv * R_v * T_loc - p_d = p_loc - p_v - T_C = T_loc - 273.15 - p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) - H = p_v / p_vs - r_v = rho_qv / rho_d - r_l = rho_ql / rho_d - r_t = r_v + r_l - - # equivalent potential temperature - a = T_loc * (p_0 / p_d)^(R_d / (c_pd + r_t * c_pl)) - b = H^(-r_v * R_v / c_pd) - L_v = L_00 + (c_pv - c_pl) * T_loc - c = exp(L_v * r_v / ((c_pd + r_t * c_pl) * T_loc)) - aeq_pot = (a * b * c) # TODO: this is not used. remove? - # Assume pressure stays constant if (r < rc && Δθ > 0) # Calculate background density potential temperature @@ -208,6 +191,9 @@ function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, rho_d_new = p_loc / (R_d * T_loc) θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) end + # test + #T_loc = θ_new * (p_loc / p_0)^kappa + # rho_qv = rvs * rho_d_new rho_ql = (rt - rvs) * rho_d_new rho = rho_d_new * (1 + rt) @@ -217,20 +203,22 @@ function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, rho_theta = rho * θ_dens_new * (p_loc / p_0)^(kappa - kappa_M) rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv end - return SVector(rho, rho_e, rho_qv, rho_ql) + return SVector(rho, rho_e, rho_qv, rho_ql, T_loc) end # Create background atmosphere data set -atmosphere_data = AtmosphereLayers(equations) +atmosphere_data = AtmosphereLayers(CompressibleMoistEulerEquations2D()) # Create the initial condition with the initial data set -function initial_condition_moist(x, t, equations) - return initial_condition_moist_bubble(x, t, equations, atmosphere_data) +function initial_condition_moist(x, t, equations::CompressibleRainyEulerEquations2D) + return initial_condition_moist_bubble(x, t, CompressibleMoistEulerEquations2D(), atmosphere_data) end ############################################################################### # semidiscretization of the compressible moist Euler equations +equations = CompressibleRainyEulerEquations2D() + initial_condition = initial_condition_moist # tag different boundary segments @@ -246,15 +234,12 @@ boundary_conditions = (; :left => boundary_condition_periodic, :bottom => boundary_condition_slip_wall, :right => boundary_condition_periodic) -polydeg = 1 -basis = LobattoLegendreBasis(polydeg) - #volume_flux = flux_chandrashekar #volume_integral = VolumeIntegralFluxDifferencing(volume_flux) -solver = DGMulti(polydeg=polydeg, element_type = Quad(), approximation_type = GaussSBP(), #TODO +solver = DGMulti(polydeg = 1, element_type = Quad(), approximation_type = GaussSBP(), surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), - volume_integral = VolumeIntegralWeakForm()) #TODO + volume_integral = VolumeIntegralWeakForm()) coordinates_min = ( 0.0, 0.0) coordinates_max = (20_000.0, 10_000.0) @@ -264,7 +249,7 @@ mesh = DGMultiMesh(solver, cells_per_dimension; coordinates_min, coordinates_max semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver; - source_terms = source_terms_moist_bubble, + source_terms = source_terms_no_phase_change, boundary_conditions = boundary_conditions) ############################################################################### @@ -296,9 +281,11 @@ callbacks = CallbackSet(summary_callback, #save_solution, stepsize_callback) +stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) + ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limiter!), maxiters = 1.0e7, dt = 1.0, save_everystep = false, callback = callbacks); diff --git a/src/callbacks_stage/nonlinear_solve_dg2d.jl b/src/callbacks_stage/nonlinear_solve_dg2d.jl index 4f87c854..483d86a9 100644 --- a/src/callbacks_stage/nonlinear_solve_dg2d.jl +++ b/src/callbacks_stage/nonlinear_solve_dg2d.jl @@ -1,4 +1,4 @@ -using Trixi: get_node_vars, @batch, get_inverse_jacobian, set_node_vars!, get_node_coords +using Trixi: get_node_vars, @batch, get_inverse_jacobian, set_node_vars!, get_node_coords, each_quad_node_global using LinearAlgebra using StaticArrays @@ -16,108 +16,6 @@ function nonlinear_solve_dg_2d!(u, residual, jacobian, variables_index_vector, t # iterate over every DGSEM element @batch for element in eachelement(dg, cache) - #= positivity preserving limiter zhang shu test determine minimum value - value_min = typemax(eltype(u)) - for j in eachnode(dg), i in eachnode(dg) - u_node = get_node_vars(u, equations, dg, i, j, element) - value_min = min(value_min, u_node[3]) - end - - # detect if limiting is necessary - if (value_min < threshold) - # compute mean value - u_mean = zero(get_node_vars(u, equations, dg, 1, 1, element)) - total_volume = zero(eltype(u)) - for j in eachnode(dg), i in eachnode(dg) - volume_jacobian = abs(inv(get_inverse_jacobian(inverse_jacobian, mesh, - i, j, element))) - u_node = get_node_vars(u, equations, dg, i, j, element) - u_mean += u_node * weights[i] * weights[j] * volume_jacobian - total_volume += weights[i] * weights[j] * volume_jacobian - end - - # normalize with the total volume - u_mean = u_mean / total_volume - - # We compute the value directly with the mean values, as we assume that - # Jensen's inequality holds (e.g. pressure for compressible Euler equations). - value_mean = u_mean[3] - theta = (value_mean - threshold) / (value_mean - value_min) - for j in eachnode(dg), i in eachnode(dg) - u_node = get_node_vars(u, equations, dg, i, j, element) - set_node_vars!(u, theta * u_node + (1 - theta) * u_mean, - equations, dg, i, j, element) - end - end - - # positivity preserving limiter zhang shu test determine minimum value - value_min = typemax(eltype(u)) - for j in eachnode(dg), i in eachnode(dg) - u_node = get_node_vars(u, equations, dg, i, j, element) - value_min = min(value_min, u_node[2]) - end - - # detect if limiting is necessary - if (value_min < 1e-5) - # compute mean value - u_mean = zero(get_node_vars(u, equations, dg, 1, 1, element)) - total_volume = zero(eltype(u)) - for j in eachnode(dg), i in eachnode(dg) - volume_jacobian = abs(inv(get_inverse_jacobian(inverse_jacobian, mesh, - i, j, element))) - u_node = get_node_vars(u, equations, dg, i, j, element) - u_mean += u_node * weights[i] * weights[j] * volume_jacobian - total_volume += weights[i] * weights[j] * volume_jacobian - end - - # normalize with the total volume - u_mean = u_mean / total_volume - - # We compute the value directly with the mean values, as we assume that - # Jensen's inequality holds (e.g. pressure for compressible Euler equations). - value_mean = u_mean[2] - theta = (value_mean - 1e-5) / (value_mean - value_min) - for j in eachnode(dg), i in eachnode(dg) - u_node = get_node_vars(u, equations, dg, i, j, element) - set_node_vars!(u, theta * u_node + (1 - theta) * u_mean, - equations, dg, i, j, element) - end - end - - # positivity preserving limiter zhang shu test determine minimum value - value_min = typemax(eltype(u)) - for j in eachnode(dg), i in eachnode(dg) - u_node = get_node_vars(u, equations, dg, i, j, element) - value_min = min(value_min, u_node[1]) - end - - # detect if limiting is necessary - if (value_min < 1e-5) - # compute mean value - u_mean = zero(get_node_vars(u, equations, dg, 1, 1, element)) - total_volume = zero(eltype(u)) - for j in eachnode(dg), i in eachnode(dg) - volume_jacobian = abs(inv(get_inverse_jacobian(inverse_jacobian, mesh, - i, j, element))) - u_node = get_node_vars(u, equations, dg, i, j, element) - u_mean += u_node * weights[i] * weights[j] * volume_jacobian - total_volume += weights[i] * weights[j] * volume_jacobian - end - - # normalize with the total volume - u_mean = u_mean / total_volume - - # We compute the value directly with the mean values, as we assume that - # Jensen's inequality holds (e.g. pressure for compressible Euler equations). - value_mean = u_mean[1] - theta = (value_mean - 1e-5) / (value_mean - value_min) - for j in eachnode(dg), i in eachnode(dg) - u_node = get_node_vars(u, equations, dg, i, j, element) - set_node_vars!(u, theta * u_node + (1 - theta) * u_mean, - equations, dg, i, j, element) - end - end =# - # iterate over every node for j in eachnode(dg), i in eachnode(dg) @@ -161,4 +59,33 @@ function nonlinear_solve_dg_2d!(u, residual, jacobian, variables_index_vector, t end end + +function nonlinear_solve_dg_2d!(u, residual, jacobian, variables_index_vector, tolerance, + equations::AbstractCompressibleRainyEulerEquations, dg::DGMulti, cache, mesh::DGMultiMesh) + max_iterations = 20 + @unpack u_values = cache + + # iterate over every node + for j in each_quad_node_global(mesh, dg, cache) + + u_node = u_values[j] + guess = SVector(u_node[7], u_node[8], u_node[9]) + + # newton method + for iteration in range(1, max_iterations) + res_vector = residual(u_node, guess, equations) + + if (maximum(abs.(res_vector)) < tolerance) + break + end + + jac_matrix = jacobian(u_node, guess, equations) + guess += - jac_matrix \ res_vector + end + + u_values[j] = SVector(u_node[1], u_node[2], u_node[3], u_node[4], u_node[5], + u_node[6], guess[1], guess[2], guess[3]) + end +end + end # muladd end \ No newline at end of file From d72ef2f448e20549e198dfb6b655b9221a05ddbd Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 3 Dec 2024 21:25:20 +0100 Subject: [PATCH 079/115] added plots and rainy bubble dgmulti example --- ...ixir_moist_euler_bubble_no_rain_dgmulti.jl | 20 +- ...ixir_rainy_euler_bubble_no_rain_dgmulti.jl | 7 +- ...elixir_rainy_euler_rainy_bubble_dgmulti.jl | 288 ++++++++++++++++++ src/equations/compressible_rainy_euler_2d.jl | 14 +- 4 files changed, 314 insertions(+), 15 deletions(-) create mode 100644 examples/elixir_rainy_euler_rainy_bubble_dgmulti.jl diff --git a/examples/elixir_moist_euler_bubble_no_rain_dgmulti.jl b/examples/elixir_moist_euler_bubble_no_rain_dgmulti.jl index bcc31189..6c1a1bd5 100644 --- a/examples/elixir_moist_euler_bubble_no_rain_dgmulti.jl +++ b/examples/elixir_moist_euler_bubble_no_rain_dgmulti.jl @@ -3,8 +3,9 @@ using Trixi using TrixiAtmo using TrixiAtmo: source_terms_moist_bubble, saturation_residual, saturation_residual_jacobian, NonlinearSolveDG, - cons2eq_pot_temp, flux_LMARS, flux_chandrashekar + cons2aeqpot, flux_LMARS, flux_chandrashekar using NLsolve: nlsolve +using Plots @@ -246,12 +247,12 @@ boundary_conditions = (; :left => boundary_condition_periodic, :bottom => boundary_condition_slip_wall, :right => boundary_condition_periodic) -#volume_flux = flux_chandrashekar -#volume_integral = VolumeIntegralFluxDifferencing(volume_flux) - -solver = DGMulti(polydeg = 1, element_type = Quad(), approximation_type = GaussSBP(), - surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), - volume_integral = VolumeIntegralWeakForm()) +solver = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = GaussSBP(), + surface_integral = SurfaceIntegralWeakForm(flux_LMARS), + volume_integral = VolumeIntegralWeakForm(), + #volume_integral = VolumeIntegralFluxDifferencing(flux_chandrashekar); + #quad_rule_vol = Trixi.RefElemData(Quad(), 3) + ) coordinates_min = ( 0.0, 0.0) coordinates_max = (20_000.0, 10_000.0) @@ -300,4 +301,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, save_everystep = false, callback = callbacks); -summary_callback() \ No newline at end of file +summary_callback() + +pd = PlotData2D(sol; solution_variables = cons2aeqpot); +plot(pd["aeqpottemp"], c = :vik, dpi = 1000) \ No newline at end of file diff --git a/examples/elixir_rainy_euler_bubble_no_rain_dgmulti.jl b/examples/elixir_rainy_euler_bubble_no_rain_dgmulti.jl index 5567a940..1dbb560f 100644 --- a/examples/elixir_rainy_euler_bubble_no_rain_dgmulti.jl +++ b/examples/elixir_rainy_euler_bubble_no_rain_dgmulti.jl @@ -5,7 +5,7 @@ using TrixiAtmo: source_terms_no_phase_change, saturation_residual, saturation_residual_jacobian, NonlinearSolveDG, cons2eq_pot_temp, flux_LMARS, flux_chandrashekar using NLsolve: nlsolve - +using Plots # Initial condition from elixir_moist_euler_bubble.jl @@ -290,4 +290,7 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limite dt = 1.0, save_everystep = false, callback = callbacks); -summary_callback() \ No newline at end of file +summary_callback() + +pd = PlotData2D(sol; solution_variables = cons2eq_pot_temp); +plot(pd["eq_pot_temp"], c = :vik, dpi = 1000) \ No newline at end of file diff --git a/examples/elixir_rainy_euler_rainy_bubble_dgmulti.jl b/examples/elixir_rainy_euler_rainy_bubble_dgmulti.jl new file mode 100644 index 00000000..7d42979a --- /dev/null +++ b/examples/elixir_rainy_euler_rainy_bubble_dgmulti.jl @@ -0,0 +1,288 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: source_terms_rainy, saturation_residual, + saturation_residual_jacobian, NonlinearSolveDG, + cons2eq_pot_temp, saturation_vapour_pressure, + flux_chandrashekar, flux_LMARS, + source_terms_no_phase_change +using NLsolve: nlsolve +using Plots + + + +# domain +coordinates_min = ( 0.0, 0.0) +coordinates_max = (2400.0, 2400.0) + + +# hydrostatic dry potential temperature +function theta_d(z, equations::CompressibleRainyEulerEquations2D) + # constants + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + ref_pressure = equations.ref_pressure + + # problem specific constants + surface_temperature = 283.0 + surface_pressure = 8.5e4 + stratification = 1.3e-5 + + # dry potential temperature at surface + Theta0 = surface_temperature * (ref_pressure / surface_pressure)^(R_d / c_pd) + # at height z + theta_d = Theta0 * exp(stratification * z) + + return theta_d +end + + +# hydrostatic base state residual +function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equations::CompressibleRainyEulerEquations2D) + # equations constants + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure + g = equations.gravity + + function hydrostatic_residual!(residual, guess) + # variables + pressure, rho_dry, rho_vapour, temperature = guess + + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + + # pressure derivative residual approximation + residual[1] = (pressure - pressure_lower) / dz + (rho_dry + rho_vapour) * g + + # pressure residual + residual[2] = pressure - temperature * (rho_dry * R_d + rho_vapour * R_v) + + # hydrostatic dry potential temperature residual + residual[3] = theta_d(z, equations) - temperature * (ref_pressure / pressure)^(R_d / c_pd) + + # humidity residual + residual[4] = rho_vs * (rho_dry + rho_vapour / eps) * humidity_rel0 + residual[4] -= rho_vapour * (rho_dry + rho_vs / eps) + residual[4] *= 1000.0 + end + + return hydrostatic_residual! +end + + +function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equations::CompressibleRainyEulerEquations2D) + # equations constants + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure + + function perturbation_residual!(residual, guess) + # variables + rho_dry, rho_vapour, temperature = guess + + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + pressure = (rho_dry * R_d + rho_vapour * R_v) * temperature + + # humidity residual + residual[1] = rho_vs * (rho_dry + rho_vapour / eps) * H_init + residual[1] -= rho_vapour * (rho_dry + rho_vs / eps) + residual[1] *= 30.0 + + # hydrostatic dry potential temperature residual + residual[2] = theta_d(z, equations) - temperature * (ref_pressure / pressure_hydrostatic)^(R_d / c_pd) + + # pressure residual + residual[3] = pressure_hydrostatic - pressure + end + + return perturbation_residual! +end + + +# for approximating the dz pressure gradient +struct AtmosphereLayers{RealT <: Real} + layer_data ::Matrix{RealT} + total_height ::RealT + precision ::RealT +end + + +function AtmosphereLayers(equations::CompressibleRainyEulerEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) + # constants + humidity_rel0 = 0.45 # hydrostatic relative humidity + surface_pressure = 8.5e4 + + # surface layer with initial guesses for rho_dry, rho_vapour and temperature + surface_layer = [surface_pressure, 1.4, 0.04, 300.0] + + # allocate layer_data + n = convert(Int, total_height / precision) + layer_data = zeros(RealT, n + 1, 4) + + # solve (slightly above) surface layer + dz = 0.01 + z = 0.01 + residual_function! = generate_hydrostatic_residual(surface_pressure, humidity_rel0, z, dz, equations) + layer_data[1, :] .= nlsolve(residual_function!, surface_layer).zero + + # adjust to chosen precision + dz = precision + + # iterate up the atmosphere + for i in (1:n) + z += dz + residual_function! = generate_hydrostatic_residual(layer_data[i, 1], humidity_rel0, z, dz, equations) + guess = deepcopy(layer_data[i, :]) + layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, iterations = 20).zero + end + + return AtmosphereLayers{RealT}(layer_data, total_height, precision) +end + + +# create layers for initial condition +equations = CompressibleRainyEulerEquations2D() +layers = AtmosphereLayers(equations) + + +function initial_condition_rainy_bubble(x, t, equations::CompressibleRainyEulerEquations2D; atmosphere_layers = layers) + # equations constants + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + ref_L = equations.ref_latent_heat_vap_temp + + # problem specific constants + humidity_rel_bar = 0.45 # background relative humidity field + humidity_max = 1.0 + + # bubble parameters + radius_outer, radius_inner = 300.0, 200.0 # radii of humidity bubble + x_center, z_center = 1200.0, 800.0 # center of humidity bubble + + # radius relative to bubble center + r = sqrt((x[1] - x_center)^2 + (x[2] - z_center)^2) + + # humidity definition + if (r > radius_outer) + # outside the bubble + humidity = humidity_rel_bar + elseif (r > radius_inner) + # outer layers of the bubble + humidity = humidity_rel_bar + (humidity_max - humidity_rel_bar) * cos(pi * (r - radius_inner) / (2.0 * (radius_outer - radius_inner)))^2 + else + # inner layer + humidity = humidity_max + end + + # get atmosphere layer and height information + @unpack layer_data, total_height, precision = atmosphere_layers + dz = precision + z = x[2] + n = convert(Int, floor((z + eps()) / dz)) + 1 + z_lower = (n - 1) * dz + z_upper = n * dz + + if (z_lower == total_height) + z_upper = z_lower + dz + n = n - 1 + end + + # check height consistency + if (z > total_height && !(isapprox(z, total_height))) + error("The atmosphere does not match the simulation domain") + end + + # get hydrostatic pressures and approximate between lower and upper data point + pressure_hydrostatic_lower = layer_data[n, 1] + pressure_hydrostatic_upper = layer_data[n + 1, 1] + pressure_hydrostatic = (pressure_hydrostatic_upper * (z - z_lower) + pressure_hydrostatic_lower * (z_upper - z)) / dz + + # solve perturbation + residual_function! = generate_perturbation_residual(pressure_hydrostatic, humidity, z, equations) + rho_dry, rho_vapour, temperature = nlsolve(residual_function!, layer_data[n, 2:4], ftol = 1e-9, iterations = 20).zero + + energy_density = (c_vd * rho_dry + c_vv * rho_vapour) * temperature + rho_vapour * ref_L + + return SVector(rho_dry, rho_vapour, 0.0, 0.0, 0.0, energy_density, rho_vapour, 0.0, temperature) +end + + +############################################################################### +# semidiscretization of the compressible moist Euler equations + +equations = CompressibleRainyEulerEquations2D() + +initial_condition = initial_condition_rainy_bubble + +# tag different boundary segments +left(x, tol = 50 * eps()) = abs(x[1] - coordinates_min[1]) < tol +right(x, tol = 50 * eps()) = abs(x[1] - coordinates_max[1]) < tol +bottom(x, tol = 50 * eps()) = abs(x[2] - coordinates_min[2]) < tol +top(x, tol = 50 * eps()) = abs(x[2] - coordinates_max[2]) < tol + +is_on_boundary = Dict(:left => left, :right => right, :top => top, :bottom => bottom) + +boundary_conditions = (; :left => boundary_condition_periodic, + :top => boundary_condition_slip_wall, + :bottom => boundary_condition_slip_wall, + :right => boundary_condition_periodic) + +#volume_flux = flux_chandrashekar +#volume_integral = VolumeIntegralFluxDifferencing(volume_flux) + +solver = DGMulti(polydeg = 1, element_type = Quad(), approximation_type = GaussSBP(), + surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), + volume_integral = VolumeIntegralWeakForm()) + +cells_per_dimension = (100, 100) +mesh = DGMultiMesh(solver, cells_per_dimension; coordinates_min, coordinates_max, is_on_boundary, periodicity = (true, false)) + +semi = SemidiscretizationHyperbolic(mesh, equations, + initial_condition, solver; + source_terms = source_terms_rainy, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 1000.0) + +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 + +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(solver)) + +alive_callback = AliveCallback(analysis_interval = 1000) + +#save_solution = SaveSolutionCallback(interval = 1000, + #save_initial_solution = true, + #save_final_solution = true, + #output_directory = "out", + #solution_variables = cons2eq_pot_temp) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + #save_solution, + stepsize_callback) + +stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) + +############################################################################### +# run the simulation +sol = solve(ode, SSPRK43(stage_limiter!); ode_default_options()..., + maxiters = 1.0e7, save_everystep = false, callback = callbacks); + +summary_callback() + +pd = PlotData2D(sol; solution_variables = cons2eq_pot_temp); +plot(pd["eq_pot_temp"], c = :vik, dpi = 1000) \ No newline at end of file diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 722223e0..407f7bfe 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -150,7 +150,11 @@ end eq_pot = (temperature * (ref_p / p_d)^(R_d / c_p) * H^(-r_v * R_v / c_p) * exp(L_v * r_v * inv(c_p * temperature))) - return SVector(rho, r_v, r_c, r_r, v1, v2, eq_pot, p) + #TODO + s_dry, s_vapour, s_cloud, s_rain, _, _, _, _, _ = cons2entropy(u, equations) + entropy = s_dry + s_vapour + s_cloud + s_rain + + return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, v1, v2, eq_pot, p, entropy) end @@ -230,8 +234,8 @@ varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "energy_density", "rho_vapour", "rho_cloud", "temperature") -varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquations2D) = ("rho", "r_vapour", - "r_cloud", "r_rain", +varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_vapour", + "rho_cloud", "rho_rain", "v1", "v2", "eq_pot_temp", "pressure") @@ -506,10 +510,10 @@ end S_accretion = 1.72 * rho_cloud * rho_rain^(0.875) S_rain = S_auto_conversion + S_accretion - S_evaporation S_groundwater = 0.0 - #= + if (x[2] < 100.0) S_groundwater = rho_rain * (1 - (x[2] * 0.01)^2) - end=# + end return SVector(0.0, -S_rain, S_rain - S_groundwater, 0.0, -rho * g, -rho_v2 * g, 0.0, 0.0, 0.0) From de1972b475d502202c641391ae27430af2885291 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 3 Dec 2024 21:25:43 +0100 Subject: [PATCH 080/115] fixed dgmulti solver --- src/callbacks_stage/nonlinear_solve_dg2d.jl | 40 ++++++++++++--------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/src/callbacks_stage/nonlinear_solve_dg2d.jl b/src/callbacks_stage/nonlinear_solve_dg2d.jl index 483d86a9..2f3528da 100644 --- a/src/callbacks_stage/nonlinear_solve_dg2d.jl +++ b/src/callbacks_stage/nonlinear_solve_dg2d.jl @@ -1,4 +1,4 @@ -using Trixi: get_node_vars, @batch, get_inverse_jacobian, set_node_vars!, get_node_coords, each_quad_node_global +using Trixi: get_node_vars, @batch, get_inverse_jacobian, set_node_vars!, get_node_coords, each_quad_node using LinearAlgebra using StaticArrays @@ -63,28 +63,36 @@ end function nonlinear_solve_dg_2d!(u, residual, jacobian, variables_index_vector, tolerance, equations::AbstractCompressibleRainyEulerEquations, dg::DGMulti, cache, mesh::DGMultiMesh) max_iterations = 20 - @unpack u_values = cache - + # iterate over every node - for j in each_quad_node_global(mesh, dg, cache) + @batch for element in eachelement(mesh, dg) + for j in each_quad_node(mesh, dg) + + u_node = u[j, element] + + # keep rain positive + if (u_node[3] < 0.0) + u_node = SVector(u_node[1], u_node[2], 0.0, u_node[4], u_node[5], u_node[6], + u_node[7], u_node[8], u_node[9]) + end - u_node = u_values[j] - guess = SVector(u_node[7], u_node[8], u_node[9]) + guess = SVector(u_node[7], u_node[8], u_node[9]) + + # newton method + for iteration in range(1, max_iterations) + res_vector = residual(u_node, guess, equations) - # newton method - for iteration in range(1, max_iterations) - res_vector = residual(u_node, guess, equations) + if (maximum(abs.(res_vector)) < tolerance) + break + end - if (maximum(abs.(res_vector)) < tolerance) - break + jac_matrix = jacobian(u_node, guess, equations) + guess += - jac_matrix \ res_vector end - jac_matrix = jacobian(u_node, guess, equations) - guess += - jac_matrix \ res_vector + u[j, element] = SVector(u_node[1], u_node[2], u_node[3], u_node[4], u_node[5], u_node[6], + guess[1], guess[2], guess[3]) end - - u_values[j] = SVector(u_node[1], u_node[2], u_node[3], u_node[4], u_node[5], - u_node[6], guess[1], guess[2], guess[3]) end end From e3e9e100996fc36956ee19037c76a7af4661195b Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 3 Dec 2024 21:26:45 +0100 Subject: [PATCH 081/115] attempted adding entropy2cons --- .../compressible_moist_euler_2d_lucas.jl | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/equations/compressible_moist_euler_2d_lucas.jl b/src/equations/compressible_moist_euler_2d_lucas.jl index aae3eaf1..c8cf6f86 100644 --- a/src/equations/compressible_moist_euler_2d_lucas.jl +++ b/src/equations/compressible_moist_euler_2d_lucas.jl @@ -559,6 +559,42 @@ end return inv(T) * SVector(w1, w2, w3, w4, w5, w6) end +@inline function entropy2cons(w, equations::CompressibleMoistEulerEquations2D) + @unpack R_d, R_v, c_pd, c_pv, c_pl, c_vd, c_vv, L_00 = equations + + v1 = w[2] + v2 = w[3] + v_square = v1^2 + v2^2 + + T_inv = - w[4] + T = -inv(w[4]) + + g_d = w[1] + 0.5* v_square + g_v = w[5] + g_d + g_l = w[6] + g_d + + s_d = -( g_d * T_inv - c_pd) + s_v = -((g_v - L_00) * T_inv - c_pv) + s_l = -( g_l * T_inv - c_pl) + + if (s_d != 0.0) + rho_d = exp(s_d - c_pd * log(T) + R_d * log(R_d * T)) + end + if (s_v != 0.0) + rho_v = exp(s_v - c_pv * log(T) + R_v * log(R_v * T)) + end + if (s_l != 0.0) + rho_l = 0.0#TODO no information in cons2entropy???? + end + + rho = rho_d + rho_v + rho_l + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_E = (c_vd * rho_d + c_vv * rho_v + c_l * rho_l) * T + rho_v * L_00 + 0.5 * rho * v_square + + return SVector(rho, rho_v1, rho_v2, rho_E, rho_v, rho_l) +end + # Convert primitive to conservative variables. @inline function prim2cons(prim, equations::CompressibleMoistEulerEquations2D) rho, v1, v2, p, qv, ql = prim From f135408d18abf543763a828fee911f5ff506ea9b Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Fri, 6 Dec 2024 15:56:23 +0100 Subject: [PATCH 082/115] fixed varnames of cons2eq_pot_temp --- src/equations/compressible_rainy_euler_2d.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 407f7bfe..c7b26871 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -237,7 +237,7 @@ varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_vapour", "rho_cloud", "rho_rain", "v1", "v2", "eq_pot_temp", - "pressure") + "pressure", "entropy") From 7a5a22a58b61f93ce0a609676048436ed32cd328 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 11 Dec 2024 16:05:37 +0100 Subject: [PATCH 083/115] changed folder structure and renamed some elixirs for clarity --- .../energy/elixir_rainy_euler_dry_bubble.jl} | 0 .../elixir_dry_potential_euler_bubble.jl | 0 ...lixir_moist_euler_moist_bubble_dgmulti.jl} | 5 +- .../elixir_rainy_euler_moist_bubble.jl} | 0 ...lixir_rainy_euler_moist_bubble_dgmulti.jl} | 0 ...uler_potential_temperature_moist_bubble.jl | 0 .../elixir_moist_potential_euler_bubble.jl | 292 ------------------ .../elixir_rainy_euler_rainy_bubble.jl} | 10 +- .../elixir_rainy_euler_rainy_bubble_amr.jl} | 0 ...elixir_rainy_euler_rainy_bubble_dgmulti.jl | 10 +- ...xir_rainy_euler_rainy_bubble_diffusion.jl} | 8 +- 11 files changed, 17 insertions(+), 308 deletions(-) rename examples/{elixir_rainy_euler_bubble_dry.jl => dry_bubble_elixirs/energy/elixir_rainy_euler_dry_bubble.jl} (100%) rename examples/{potential_temperature_elixirs => dry_bubble_elixirs/potential_temperature}/elixir_dry_potential_euler_bubble.jl (100%) rename examples/{elixir_moist_euler_bubble_no_rain_dgmulti.jl => moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl} (98%) rename examples/{elixir_rainy_euler_bubble_no_rain.jl => moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl} (100%) rename examples/{elixir_rainy_euler_bubble_no_rain_dgmulti.jl => moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble_dgmulti.jl} (100%) rename examples/{ => moist_bubble_elixirs/potential_temperature}/elixir_moist_euler_potential_temperature_moist_bubble.jl (100%) delete mode 100644 examples/potential_temperature_elixirs/elixir_moist_potential_euler_bubble.jl rename examples/{elixir_rainy_euler_bubble.jl => rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl} (97%) rename examples/{elixir_rainy_euler_bubble_amr.jl => rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_amr.jl} (100%) rename examples/{ => rainy_bubble_elixirs}/elixir_rainy_euler_rainy_bubble_dgmulti.jl (98%) rename examples/{elixir_rainy_euler_bubble_diffusion.jl => rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl} (98%) diff --git a/examples/elixir_rainy_euler_bubble_dry.jl b/examples/dry_bubble_elixirs/energy/elixir_rainy_euler_dry_bubble.jl similarity index 100% rename from examples/elixir_rainy_euler_bubble_dry.jl rename to examples/dry_bubble_elixirs/energy/elixir_rainy_euler_dry_bubble.jl diff --git a/examples/potential_temperature_elixirs/elixir_dry_potential_euler_bubble.jl b/examples/dry_bubble_elixirs/potential_temperature/elixir_dry_potential_euler_bubble.jl similarity index 100% rename from examples/potential_temperature_elixirs/elixir_dry_potential_euler_bubble.jl rename to examples/dry_bubble_elixirs/potential_temperature/elixir_dry_potential_euler_bubble.jl diff --git a/examples/elixir_moist_euler_bubble_no_rain_dgmulti.jl b/examples/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl similarity index 98% rename from examples/elixir_moist_euler_bubble_no_rain_dgmulti.jl rename to examples/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl index 6c1a1bd5..091ab7ad 100644 --- a/examples/elixir_moist_euler_bubble_no_rain_dgmulti.jl +++ b/examples/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl @@ -6,6 +6,7 @@ using TrixiAtmo: source_terms_moist_bubble, saturation_residual, cons2aeqpot, flux_LMARS, flux_chandrashekar using NLsolve: nlsolve using Plots +using StartUpDG @@ -247,11 +248,11 @@ boundary_conditions = (; :left => boundary_condition_periodic, :bottom => boundary_condition_slip_wall, :right => boundary_condition_periodic) -solver = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = GaussSBP(), +solver = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = StartUpDG.Polynomial{MultidimensionalQuadrature}(), surface_integral = SurfaceIntegralWeakForm(flux_LMARS), volume_integral = VolumeIntegralWeakForm(), #volume_integral = VolumeIntegralFluxDifferencing(flux_chandrashekar); - #quad_rule_vol = Trixi.RefElemData(Quad(), 3) + quad_rule_vol = StartUpDG.RefElemData(Quad(), 3) ) coordinates_min = ( 0.0, 0.0) diff --git a/examples/elixir_rainy_euler_bubble_no_rain.jl b/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl similarity index 100% rename from examples/elixir_rainy_euler_bubble_no_rain.jl rename to examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl diff --git a/examples/elixir_rainy_euler_bubble_no_rain_dgmulti.jl b/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble_dgmulti.jl similarity index 100% rename from examples/elixir_rainy_euler_bubble_no_rain_dgmulti.jl rename to examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble_dgmulti.jl diff --git a/examples/elixir_moist_euler_potential_temperature_moist_bubble.jl b/examples/moist_bubble_elixirs/potential_temperature/elixir_moist_euler_potential_temperature_moist_bubble.jl similarity index 100% rename from examples/elixir_moist_euler_potential_temperature_moist_bubble.jl rename to examples/moist_bubble_elixirs/potential_temperature/elixir_moist_euler_potential_temperature_moist_bubble.jl diff --git a/examples/potential_temperature_elixirs/elixir_moist_potential_euler_bubble.jl b/examples/potential_temperature_elixirs/elixir_moist_potential_euler_bubble.jl deleted file mode 100644 index 673c1a19..00000000 --- a/examples/potential_temperature_elixirs/elixir_moist_potential_euler_bubble.jl +++ /dev/null @@ -1,292 +0,0 @@ -using OrdinaryDiffEq -using Trixi -using TrixiAtmo -using TrixiAtmo: source_terms_no_phase_change, saturation_residual, - saturation_residual_jacobian, NonlinearSolveDG, - cons2eq_pot_temp, flux_LMARS, flux_chandrashekar -using NLsolve: nlsolve - - - -# Initial condition from elixir_moist_euler_bubble.jl -function moist_state(y, dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) - - @unpack p_0, g, c_pd, c_pv, c_vd, c_vv, R_d, R_v, c_pl, L_00 = equations - - (p, rho, T, r_t, r_v, rho_qv, theta_e) = y - p0 = y0[1] - - F = zeros(7, 1) - rho_d = rho / (1 + r_t) - p_d = R_d * rho_d * T - T_C = T - 273.15 - p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) - L = L_00 - (c_pl - c_pv) * T - - F[1] = (p - p0) / dz + g * rho - F[2] = p - (R_d * rho_d + R_v * rho_qv) * T - # H = 1 is assumed - F[3] = (theta_e - - T * (p_d / p_0)^(-R_d / (c_pd + c_pl * r_t)) * - exp(L * r_v / ((c_pd + c_pl * r_t) * T))) - F[4] = r_t - r_t0 - F[5] = rho_qv - rho_d * r_v - F[6] = theta_e - theta_e0 - a = p_vs / (R_v * T) - rho_qv - b = rho - rho_qv - rho_d - # H=1 => phi=0 - F[7] = a + b - sqrt(a * a + b * b) - - return F -end - -function generate_function_of_y(dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) - function function_of_y(y) - return moist_state(y, dz, y0, r_t0, theta_e0, equations) - end -end - -struct AtmosphereLayers{RealT <: Real} - equations::CompressibleMoistEulerEquations2D - # structure: 1--> i-layer (z = total_height/precision *(i-1)), 2--> rho, rho_theta, rho_qv, rho_ql - layer_data::Matrix{RealT} - total_height::RealT - preciseness::Int - layers::Int - ground_state::NTuple{2, RealT} - equivalent_potential_temperature::RealT - mixing_ratios::NTuple{2, RealT} -end - -function AtmosphereLayers(equations; total_height = 10010.0, preciseness = 10, - ground_state = (1.4, 100000.0), - equivalent_potential_temperature = 320, - mixing_ratios = (0.02, 0.02), RealT = Float64) - - @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl = equations - rho0, p0 = ground_state - r_t0, r_v0 = mixing_ratios - theta_e0 = equivalent_potential_temperature - - rho_qv0 = rho0 * r_v0 - T0 = theta_e0 - y0 = [p0, rho0, T0, r_t0, r_v0, rho_qv0, theta_e0] - - n = convert(Int, total_height / preciseness) - dz = 0.01 - layer_data = zeros(RealT, n + 1, 4) - - F = generate_function_of_y(dz, y0, r_t0, theta_e0, equations) - sol = nlsolve(F, y0) - p, rho, T, r_t, r_v, rho_qv, theta_e = sol.zero - - rho_d = rho / (1 + r_t) - rho_ql = rho - rho_d - rho_qv - kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) - rho_theta = rho * (p0 / p)^kappa_M * T * (1 + (R_v / R_d) * r_v) / (1 + r_t) - - layer_data[1, :] = [rho, rho_theta, rho_qv, rho_ql] - for i in (1:n) - y0 = deepcopy(sol.zero) - dz = preciseness - F = generate_function_of_y(dz, y0, r_t0, theta_e0, equations) - sol = nlsolve(F, y0) - p, rho, T, r_t, r_v, rho_qv, theta_e = sol.zero - - rho_d = rho / (1 + r_t) - rho_ql = rho - rho_d - rho_qv - kappa_M = (R_d * rho_d + R_v * rho_qv) / - (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) - rho_theta = rho * (p0 / p)^kappa_M * T * (1 + (R_v / R_d) * r_v) / (1 + r_t) - - layer_data[i + 1, :] = [rho, rho_theta, rho_qv, rho_ql] - end - - return AtmosphereLayers{RealT}(equations, layer_data, total_height, dz, n, ground_state, - theta_e0, mixing_ratios) -end - -# Moist bubble test case from paper: -# G.H. Bryan, J.M. Fritsch, A Benchmark Simulation for Moist Nonhydrostatic Numerical -# Models, MonthlyWeather Review Vol.130, 2917–2928, 2002, -# https://journals.ametsoc.org/view/journals/mwre/130/12/1520-0493_2002_130_2917_absfmn_2.0.co_2.xml. -function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, atmosphere_layers::AtmosphereLayers) - @unpack layer_data, preciseness, total_height = atmosphere_layers - dz = preciseness - z = x[2] - if (z > total_height && !(isapprox(z, total_height))) - error("The atmosphere does not match the simulation domain") - end - n = convert(Int, floor((z + eps()) / dz)) + 1 - z_l = (n - 1) * dz - (rho_l, rho_theta_l, rho_qv_l, rho_ql_l) = layer_data[n, :] - z_r = n * dz - if (z_l == total_height) - z_r = z_l + dz - n = n - 1 - end - (rho_r, rho_theta_r, rho_qv_r, rho_ql_r) = layer_data[n + 1, :] - rho = (rho_r * (z - z_l) + rho_l * (z_r - z)) / dz - rho_theta = rho * (rho_theta_r / rho_r * (z - z_l) + rho_theta_l / rho_l * (z_r - z)) / - dz - rho_qv = rho * (rho_qv_r / rho_r * (z - z_l) + rho_qv_l / rho_l * (z_r - z)) / dz - rho_ql = rho * (rho_ql_r / rho_r * (z - z_l) + rho_ql_l / rho_l * (z_r - z)) / dz - - rho, rho_e, rho_qv, rho_ql, T_loc = perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, - equations::CompressibleMoistEulerEquations2D) - - v1 = 0.0 - v2 = 0.0 - rho_v1 = rho * v1 - rho_v2 = rho * v2 - rho_E = rho_e + 1 / 2 * rho * (v1^2 + v2^2) - - return SVector(rho - rho_qv - rho_ql, rho_qv + rho_ql, 0.0, rho_v1, rho_v2, rho_E, rho_qv, rho_ql, T_loc) -end - -function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, - equations::CompressibleMoistEulerEquations2D) - @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl, L_00 = equations - xc = 10000.0 - zc = 2000.0 - rc = 2000.0 - Δθ = 2.0 - - r = sqrt((x[1] - xc)^2 + (x[2] - zc)^2) - rho_d = rho - rho_qv - rho_ql - kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) - p_loc = p_0 * (R_d * rho_theta / p_0)^(1 / (1 - kappa_M)) - T_loc = p_loc / (R_d * rho_d + R_v * rho_qv) - rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv - - # Assume pressure stays constant - if (r < rc && Δθ > 0) - # Calculate background density potential temperature - θ_dens = rho_theta / rho * (p_loc / p_0)^(kappa_M - kappa) - # Calculate perturbed density potential temperature - θ_dens_new = θ_dens * (1 + Δθ * cospi(0.5 * r / rc)^2 / 300) - rt = (rho_qv + rho_ql) / rho_d - rv = rho_qv / rho_d - # Calculate moist potential temperature - θ_loc = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rv) - # Adjust varuables until the temperature is met - if rt > 0 - while true - T_loc = θ_loc * (p_loc / p_0)^kappa - T_C = T_loc - 273.15 - # SaturVapor - pvs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) - rho_d_new = (p_loc - pvs) / (R_d * T_loc) - rvs = pvs / (R_v * rho_d_new * T_loc) - θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) - if abs(θ_new - θ_loc) <= θ_loc * 1.0e-12 - break - else - θ_loc = θ_new - end - end - else - rvs = 0 - T_loc = θ_loc * (p_loc / p_0)^kappa - rho_d_new = p_loc / (R_d * T_loc) - θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) - end - # test - #T_loc = θ_new * (p_loc / p_0)^kappa - # - rho_qv = rvs * rho_d_new - rho_ql = (rt - rvs) * rho_d_new - rho = rho_d_new * (1 + rt) - rho_d = rho - rho_qv - rho_ql - kappa_M = (R_d * rho_d + R_v * rho_qv) / - (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) - rho_theta = rho * θ_dens_new * (p_loc / p_0)^(kappa - kappa_M) - rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv - end - return SVector(rho, rho_e, rho_qv, rho_ql, T_loc) -end - -# Create background atmosphere data set -atmosphere_data = AtmosphereLayers(CompressibleMoistEulerEquations2D()) - -# Create the initial condition with the initial data set -function initial_condition_moist(x, t, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - return initial_condition_moist_bubble(x, t, CompressibleMoistEulerEquations2D(), atmosphere_data) -end - - - -############################################################################### -# semidiscretization of the compressible rainy Euler equations - -equations = CompressibleRainyEulerPotentialTemperatureEquations2D() - -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 = 3 -basis = LobattoLegendreBasis(polydeg) - -#surface_flux = flux_lax_friedrichs -surface_flux = flux_LMARS -#volume_flux = flux_chandrashekar - -#volume_integral = VolumeIntegralFluxDifferencing(volume_flux) - -solver = DGSEM(basis, surface_flux)#, volume_integral) - -coordinates_min = ( 0.0, 0.0) -coordinates_max = (20_000.0, 10_000.0) - -cells_per_dimension = (65, 32) -mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, - periodicity = (true, false)) - -semi = SemidiscretizationHyperbolic(mesh, equations, - initial_condition_moist, solver, - source_terms = source_terms_no_phase_change, - boundary_conditions = boundary_conditions) - -############################################################################### -# ODE solvers, callbacks etc. - -tspan = (0.0, 1000.0) - -ode = semidiscretize(semi, tspan) - -summary_callback = SummaryCallback() - -analysis_interval = 1000 - -# entropy? -analysis_callback = AnalysisCallback(semi, interval = analysis_interval, - extra_analysis_errors = (:entropy_conservation_error,)) - -alive_callback = AliveCallback(analysis_interval = 1000) - -save_solution = SaveSolutionCallback(interval = 1000, - save_initial_solution = true, - save_final_solution = true, - output_directory = "out", - solution_variables = cons2eq_pot_temp) - -stepsize_callback = StepsizeCallback(cfl = 1.0) - -callbacks = CallbackSet(summary_callback, - analysis_callback, - alive_callback, - save_solution, - stepsize_callback) - -stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) - -############################################################################### -# run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limiter!), - maxiters = 1.0e7, - dt = 1.0, - save_everystep = false, callback = callbacks); - -summary_callback() \ No newline at end of file diff --git a/examples/elixir_rainy_euler_bubble.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl similarity index 97% rename from examples/elixir_rainy_euler_bubble.jl rename to examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl index 08b2cfde..4e516905 100644 --- a/examples/elixir_rainy_euler_bubble.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl @@ -113,7 +113,7 @@ end function AtmosphereLayers(equations::CompressibleRainyEulerEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) # constants - humidity_rel0 = 0.45 # hydrostatic relative humidity + humidity_rel0 = 0.2 # hydrostatic relative humidity surface_pressure = 8.5e4 # surface layer with initial guesses for rho_dry, rho_vapour and temperature @@ -156,7 +156,7 @@ function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerE ref_L = equations.ref_latent_heat_vap_temp # problem specific constants - humidity_rel_bar = 0.45 # background relative humidity field + humidity_rel_bar = 0.2 # background relative humidity field humidity_max = 1.0 # bubble parameters @@ -225,16 +225,16 @@ polydeg = 1 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_lax_friedrichs -#volume_integral = VolumeIntegralFluxDifferencing(flux_chandrashekar) +volume_integral = VolumeIntegralFluxDifferencing(flux_chandrashekar) -solver = DGSEM(basis, surface_flux)#, volume_integral) +solver = DGSEM(basis, surface_flux, volume_integral) cells_per_dimension = (200, 200) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = (true, false)) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_bubble_rainy, solver, - source_terms = source_terms_rainy, + source_terms = source_terms_no_phase_change, boundary_conditions = boundary_conditions) ############################################################################### diff --git a/examples/elixir_rainy_euler_bubble_amr.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_amr.jl similarity index 100% rename from examples/elixir_rainy_euler_bubble_amr.jl rename to examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_amr.jl diff --git a/examples/elixir_rainy_euler_rainy_bubble_dgmulti.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_dgmulti.jl similarity index 98% rename from examples/elixir_rainy_euler_rainy_bubble_dgmulti.jl rename to examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_dgmulti.jl index 7d42979a..de44c2f5 100644 --- a/examples/elixir_rainy_euler_rainy_bubble_dgmulti.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_dgmulti.jl @@ -113,7 +113,7 @@ end function AtmosphereLayers(equations::CompressibleRainyEulerEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) # constants - humidity_rel0 = 0.45 # hydrostatic relative humidity + humidity_rel0 = 0.2 # hydrostatic relative humidity surface_pressure = 8.5e4 # surface layer with initial guesses for rho_dry, rho_vapour and temperature @@ -156,7 +156,7 @@ function initial_condition_rainy_bubble(x, t, equations::CompressibleRainyEulerE ref_L = equations.ref_latent_heat_vap_temp # problem specific constants - humidity_rel_bar = 0.45 # background relative humidity field + humidity_rel_bar = 0.2 # background relative humidity field humidity_max = 1.0 # bubble parameters @@ -235,7 +235,7 @@ boundary_conditions = (; :left => boundary_condition_periodic, #volume_integral = VolumeIntegralFluxDifferencing(volume_flux) solver = DGMulti(polydeg = 1, element_type = Quad(), approximation_type = GaussSBP(), - surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), + surface_integral = SurfaceIntegralWeakForm(flux_LMARS), volume_integral = VolumeIntegralWeakForm()) cells_per_dimension = (100, 100) @@ -243,13 +243,13 @@ mesh = DGMultiMesh(solver, cells_per_dimension; coordinates_min, coordinates_max semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver; - source_terms = source_terms_rainy, + source_terms = source_terms_no_phase_change, boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 1000.0) +tspan = (0.0, 600.0) ode = semidiscretize(semi, tspan) diff --git a/examples/elixir_rainy_euler_bubble_diffusion.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl similarity index 98% rename from examples/elixir_rainy_euler_bubble_diffusion.jl rename to examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl index 0c3357df..73c775e1 100644 --- a/examples/elixir_rainy_euler_bubble_diffusion.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl @@ -220,7 +220,7 @@ end ############################################################################### # semidiscretization of the compressible rainy Euler equations -diffusivity = 0.6 +diffusivity = 1.5 equations_parabolic = LaplaceDiffusion2D(diffusivity, equations) @@ -236,7 +236,7 @@ boundary_conditions_parabolic = ( y_pos = boundary_condition_laplace) -polydeg = 1 +polydeg = 2 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_lax_friedrichs @@ -247,7 +247,7 @@ solver = DGSEM(basis, surface_flux)#, volume_integral) initial_condition = initial_condition_bubble_rainy source_terms = source_terms_rainy -mesh = TreeMesh(coordinates_min, coordinates_max, initial_refinement_level = 8, periodicity = (true, false), n_cells_max = 1_000_000) +mesh = TreeMesh(coordinates_min, coordinates_max, initial_refinement_level = 6, periodicity = (true, false), n_cells_max = 1_000_000) semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; source_terms, boundary_conditions = (boundary_conditions, boundary_conditions_parabolic)) @@ -255,7 +255,7 @@ semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabol ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 600.0) +tspan = (0.0, 1000.0) ode = semidiscretize(semi, tspan) From a3650e325703c4087cb077aa6376a6b1a91e6064 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 11 Dec 2024 16:07:02 +0100 Subject: [PATCH 084/115] added StartUpDG for testing overintegration --- Project.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Project.toml b/Project.toml index 7e5479f7..3cca6486 100644 --- a/Project.toml +++ b/Project.toml @@ -7,6 +7,7 @@ version = "0.1.0-DEV" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" +StartUpDG = "472ebc20-7c99-4d4b-9470-8fde4e9faa0f" Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Trixi = "a7f1ee26-1774-49b1-8366-f1abc58fbfcb" From bee087858edde622bc94963cbf012f0335704767 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:58:35 +0100 Subject: [PATCH 085/115] LMARS rain testing --- .../elixir_rainy_euler_rainy_bubble.jl | 10 ++--- src/equations/compressible_rainy_euler_2d.jl | 39 +++++++++++++++---- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl index 4e516905..447f50b9 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl @@ -224,17 +224,17 @@ boundary_conditions = (x_neg = boundary_condition_periodic, polydeg = 1 basis = LobattoLegendreBasis(polydeg) -surface_flux = flux_lax_friedrichs -volume_integral = VolumeIntegralFluxDifferencing(flux_chandrashekar) +surface_flux = flux_LMARS +#volume_integral = VolumeIntegralFluxDifferencing(flux_chandrashekar) -solver = DGSEM(basis, surface_flux, volume_integral) +solver = DGSEM(basis, surface_flux)#, volume_integral) -cells_per_dimension = (200, 200) +cells_per_dimension = (100, 100) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = (true, false)) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_bubble_rainy, solver, - source_terms = source_terms_no_phase_change, + source_terms = source_terms_rainy, boundary_conditions = boundary_conditions) ############################################################################### diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index c7b26871..4807478a 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -775,12 +775,15 @@ end # https://journals.ametsoc.org/view/journals/mwre/141/7/mwr-d-12-00129.1.xml. @inline function flux_LMARS(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) # constants - a = 360.0 + a = 360.0 + c_l = equations.c_liquid_water # densities rho_dry_ll, rho_moist_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) rho_dry_rr, rho_moist_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) + rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) + # pressure p_ll = pressure(u_ll, equations) p_rr = pressure(u_rr, equations) @@ -789,24 +792,46 @@ end v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) + v_r_ll = terminal_velocity_rain(rho_moist_ll, rho_rain_ll, equations) * normal_direction[2] + v_r_rr = terminal_velocity_rain(rho_moist_rr, rho_rain_rr, equations) * normal_direction[2] + v_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] v_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] norm_ = norm(normal_direction) + v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) + v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) + + v_r_avg = 0.5 * (v_r_ll + v_r_rr) + + # temperature + _, _, temperature_ll = cons2nonlinearsystemsol(u_ll, equations) + _, _, temperature_rr = cons2nonlinearsystemsol(u_rr, equations) + # diffusion parameter 0.0 < beta <= 1.0 beta = 1.0 # interface flux components rho = 0.5 * (rho_ll + rho_rr) - p_interface = 0.5 * (p_ll + p_rr) - beta * 0.5 * a * rho * (v_rr - v_ll) / norm_ - v_interface = 0.5 * (v_ll + v_rr) - beta * 1 / (2 * a * rho) * (p_rr - p_ll) * norm_ + p_interface = 0.5 * (p_ll + p_rr) - beta * 0.5 * a * rho * (v_rr - v_ll) / norm_ + v_interface = 0.5 * (v_ll + v_rr) - beta * 1 / (2 * a * rho) * (p_rr - p_ll) * norm_ + v_r_interface = v_interface - v_r_avg + + energy_rain_term = (c_l * 0.5 * (temperature_ll + temperature_rr) + 0.5 * (v1_square_avg + v2_square_avg)) + energy_rain_term *= rho_rain_avg * v_r_avg if (v_interface > 0) - f1, f2, f3, f4, f5, f6, _, _, _ = u_ll * v_interface - f6 += p_ll * v_interface + f1, f2, _, f4, f5, f6, _, _, _ = u_ll * v_interface + f4 -= rho_rain_avg * v_r_avg * 0.5 * (v1_ll + v1_rr) + f5 -= rho_rain_avg * v_r_avg * 0.5 * (v2_ll + v2_rr) + f6 += p_ll * v_interface - energy_rain_term + f3 = u_ll[3] * v_r_interface else - f1, f2, f3, f4, f5, f6, _, _, _ = u_rr * v_interface - f6 += p_rr * v_interface + f1, f2, _, f4, f5, f6, _, _, _ = u_rr * v_interface + f4 -= rho_rain_avg * v_r_avg * 0.5 * (v1_ll + v1_rr) + f5 -= rho_rain_avg * v_r_avg * 0.5 * (v2_ll + v2_rr) + f6 += p_rr * v_interface - energy_rain_term + f3 = u_rr[3] * v_r_interface end return SVector(f1, f2, f3, From 24eeac12170420061c4e082bb8c115d9185f90ef Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Sun, 26 Jan 2025 21:22:40 +0100 Subject: [PATCH 086/115] DGMulti testing --- .../energy/elixir_moist_euler_moist_bubble_dgmulti.jl | 2 +- .../elixir_rainy_euler_rainy_bubble_dgmulti.jl | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl b/examples/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl index 091ab7ad..c4d121df 100644 --- a/examples/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl +++ b/examples/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl @@ -252,7 +252,7 @@ solver = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = StartU surface_integral = SurfaceIntegralWeakForm(flux_LMARS), volume_integral = VolumeIntegralWeakForm(), #volume_integral = VolumeIntegralFluxDifferencing(flux_chandrashekar); - quad_rule_vol = StartUpDG.RefElemData(Quad(), 3) + quad_rule_vol = StartUpDG.quad_nodes(Quad(), 6) ) coordinates_min = ( 0.0, 0.0) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_dgmulti.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_dgmulti.jl index de44c2f5..7e5b1e98 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_dgmulti.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_dgmulti.jl @@ -235,7 +235,7 @@ boundary_conditions = (; :left => boundary_condition_periodic, #volume_integral = VolumeIntegralFluxDifferencing(volume_flux) solver = DGMulti(polydeg = 1, element_type = Quad(), approximation_type = GaussSBP(), - surface_integral = SurfaceIntegralWeakForm(flux_LMARS), + surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), volume_integral = VolumeIntegralWeakForm()) cells_per_dimension = (100, 100) @@ -243,13 +243,13 @@ mesh = DGMultiMesh(solver, cells_per_dimension; coordinates_min, coordinates_max semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver; - source_terms = source_terms_no_phase_change, + source_terms = source_terms_rainy, boundary_conditions = boundary_conditions) ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 600.0) +tspan = (0.0, 300.0) ode = semidiscretize(semi, tspan) From 8bbb8c2947969eb4bbf26f7bd3a5d0e5f4dd121d Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Sun, 26 Jan 2025 21:22:56 +0100 Subject: [PATCH 087/115] rain ec flux testing --- .../elixir_rainy_euler_rainy_bubble.jl | 8 +- src/equations/compressible_rainy_euler_2d.jl | 184 +++++++++++++----- 2 files changed, 144 insertions(+), 48 deletions(-) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl index 447f50b9..f06377aa 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl @@ -4,7 +4,7 @@ using TrixiAtmo using TrixiAtmo: source_terms_rainy, saturation_residual, saturation_residual_jacobian, NonlinearSolveDG, cons2eq_pot_temp, saturation_vapour_pressure, - flux_chandrashekar, flux_LMARS, + flux_chandrashekar, flux_LMARS, flux_ec_rain_log, source_terms_no_phase_change using NLsolve: nlsolve #using Plots @@ -224,10 +224,10 @@ boundary_conditions = (x_neg = boundary_condition_periodic, polydeg = 1 basis = LobattoLegendreBasis(polydeg) -surface_flux = flux_LMARS -#volume_integral = VolumeIntegralFluxDifferencing(flux_chandrashekar) +surface_flux = flux_lax_friedrichs +volume_integral = VolumeIntegralFluxDifferencing(flux_ec_rain_log) -solver = DGSEM(basis, surface_flux)#, volume_integral) +solver = DGSEM(basis, surface_flux, volume_integral) cells_per_dimension = (100, 100) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 4807478a..61f2e5e9 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -102,8 +102,18 @@ end end +# converts consverved to entropy variables @inline function cons2entropy(u, equations::CompressibleRainyEulerEquations2D) - #TODO + # constants + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + c_l = equations.c_liquid_water + R_d = equations.R_dry_air + R_v = equations.R_vapour + + # + + return SVector(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) end @@ -765,25 +775,20 @@ end end -# TODO Careful with rain != 0.0 does not really work (bad physics) -# fluxes adapted from compressible_moist_euler_2d.jl - # Low Mach number approximate Riemann solver (LMARS) from # X. Chen, N. Andronova, B. Van Leer, J. E. Penner, J. P. Boyd, C. Jablonowski, S. # Lin, A Control-Volume Model of the Compressible Euler Equations with a Vertical Lagrangian # Coordinate Monthly Weather Review Vol. 141.7, pages 2526–2544, 2013, # https://journals.ametsoc.org/view/journals/mwre/141/7/mwr-d-12-00129.1.xml. +# adapted from compressible_moist_euler_2d.jl, does NOT work with rain! @inline function flux_LMARS(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) # constants - a = 360.0 - c_l = equations.c_liquid_water + a = 360.0 # densities rho_dry_ll, rho_moist_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) rho_dry_rr, rho_moist_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) - rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) - # pressure p_ll = pressure(u_ll, equations) p_rr = pressure(u_rr, equations) @@ -792,49 +797,31 @@ end v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) - v_r_ll = terminal_velocity_rain(rho_moist_ll, rho_rain_ll, equations) * normal_direction[2] - v_r_rr = terminal_velocity_rain(rho_moist_rr, rho_rain_rr, equations) * normal_direction[2] - v_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] v_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] norm_ = norm(normal_direction) - v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) - v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) - - v_r_avg = 0.5 * (v_r_ll + v_r_rr) - # temperature - _, _, temperature_ll = cons2nonlinearsystemsol(u_ll, equations) - _, _, temperature_rr = cons2nonlinearsystemsol(u_rr, equations) + rho_vapour_ll, _, temperature_ll = cons2nonlinearsystemsol(u_ll, equations) + rho_vapour_rr, _, temperature_rr = cons2nonlinearsystemsol(u_rr, equations) # diffusion parameter 0.0 < beta <= 1.0 beta = 1.0 # interface flux components rho = 0.5 * (rho_ll + rho_rr) - p_interface = 0.5 * (p_ll + p_rr) - beta * 0.5 * a * rho * (v_rr - v_ll) / norm_ - v_interface = 0.5 * (v_ll + v_rr) - beta * 1 / (2 * a * rho) * (p_rr - p_ll) * norm_ - v_r_interface = v_interface - v_r_avg - - energy_rain_term = (c_l * 0.5 * (temperature_ll + temperature_rr) + 0.5 * (v1_square_avg + v2_square_avg)) - energy_rain_term *= rho_rain_avg * v_r_avg + p_interface = 0.5 * (p_ll + p_rr) - beta * 0.5 * a * rho * (v_rr - v_ll) / norm_ + v_interface = 0.5 * (v_ll + v_rr) - beta * 1 / (2 * a * rho) * (p_rr - p_ll) * norm_ if (v_interface > 0) f1, f2, _, f4, f5, f6, _, _, _ = u_ll * v_interface - f4 -= rho_rain_avg * v_r_avg * 0.5 * (v1_ll + v1_rr) - f5 -= rho_rain_avg * v_r_avg * 0.5 * (v2_ll + v2_rr) - f6 += p_ll * v_interface - energy_rain_term - f3 = u_ll[3] * v_r_interface + f6 += p_ll * v_interface else f1, f2, _, f4, f5, f6, _, _, _ = u_rr * v_interface - f4 -= rho_rain_avg * v_r_avg * 0.5 * (v1_ll + v1_rr) - f5 -= rho_rain_avg * v_r_avg * 0.5 * (v2_ll + v2_rr) - f6 += p_rr * v_interface - energy_rain_term - f3 = u_rr[3] * v_r_interface + f6 += p_rr * v_interface end - return SVector(f1, f2, f3, + return SVector(f1, f2, 0.0, f4 + p_interface * normal_direction[1], f5 + p_interface * normal_direction[2], f6, 0.0, 0.0, 0.0) @@ -845,6 +832,7 @@ end # A. Gouasmi, K. Duraisamy, S. M. Murman, Formulation of Entropy-Stable schemes for the # multicomponent compressible Euler equations, 4 Feb 2020, doi:10.1016/j.cma.2020.112912, # https://arxiv.org/abs/1904.00972 [math.NA]. +# Adapted from compressible_moist_euler_2d.jl, careful, does NOT work for rain! @inline function flux_chandrashekar(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) # constants c_l = equations.c_liquid_water @@ -864,8 +852,6 @@ end # velocities v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) - #vr_ll = terminal_velocity_rain(rho_moist_ll, rho_rain_ll, equations) - #vr_rr = terminal_velocity_rain(rho_moist_rr, rho_rain_rr, equations) # mean values rho_dry_mean = 0.0 @@ -904,26 +890,136 @@ end rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) inv_temperature_avg = 0.5 * (inv(temperature_ll) + inv(temperature_rr)) v_dot_n_avg = normal_direction[1] * v1_avg + normal_direction[2] * v2_avg - #vr_avg = 0.5 * (vr_ll + vr_rr) - #vr_square_avg = 0.5 * ((v2_ll - vr_ll)^2 + (v2_rr - vr_rr)^2) - #vr_dot_n_avg = normal_direction[2] * vr_avg p_int = inv(inv_temperature_avg) * (R_d * rho_dry_avg + R_v * rho_vapour_avg + R_q * (rho_cloud_avg + rho_rain_avg)) K_avg = 0.5 * (v1_square_avg + v2_square_avg) - #K2_avg = 0.5 * (v1_square_avg + (vr_square_avg)) # assemble the flux f_dry = rho_dry_mean * v_dot_n_avg - f_rain = rho_rain_mean * (v_dot_n_avg) #- vr_dot_n_avg) + f_rain = rho_rain_mean * v_dot_n_avg f_vapour = rho_vapour_mean * v_dot_n_avg f_cloud = rho_cloud_mean * v_dot_n_avg f_moist = (rho_vapour_mean + rho_cloud_mean) * v_dot_n_avg - f_rhov1 = (f_dry + f_moist + f_rain) * v1_avg + normal_direction[1] * p_int #- rho_rain_mean * vr_dot_n_avg * v1_avg - f_rhov2 = (f_dry + f_moist + f_rain) * v2_avg + normal_direction[2] * p_int #- rho_rain_mean * vr_dot_n_avg * v2_avg + f_rhov1 = (f_dry + f_moist + f_rain) * v1_avg + normal_direction[1] * p_int + f_rhov2 = (f_dry + f_moist + f_rain) * v2_avg + normal_direction[2] * p_int f_energy = (( c_vd * inv_temperature_mean - K_avg) * f_dry + (ref_L + c_vv * inv_temperature_mean - K_avg) * f_vapour + - ( c_l * inv_temperature_mean - K_avg) * (f_cloud + f_rain) + v1_avg * f_rhov1 + v2_avg * f_rhov2) #- - #( c_l * inv_temperature_mean + K_avg) * rho_rain_mean * vr_dot_n_avg + ( c_l * inv_temperature_mean - K_avg) * (f_cloud + f_rain) + v1_avg * f_rhov1 + v2_avg * f_rhov2) + + return SVector(f_dry, f_moist, f_rain, f_rhov1, f_rhov2, f_energy, 0.0, 0.0, 0.0) +end + + +@inline function flux_ec_rain_log(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp + + # densities and temperatures + rho_dry_ll, rho_moist_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) + rho_dry_rr, rho_moist_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) + rho_vapour_ll, rho_cloud_ll, temperature_ll = cons2nonlinearsystemsol(u_ll, equations) + rho_vapour_rr, rho_cloud_rr, temperature_rr = cons2nonlinearsystemsol(u_rr, equations) + inv_temperature_ll = 1/temperature_ll + inv_temperature_rr = 1/temperature_rr + + # velocities + v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) + v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) + vr_ll = terminal_velocity_rain(rho_moist_ll, rho_rain_ll, equations) + vr_rr = terminal_velocity_rain(rho_moist_rr, rho_rain_rr, equations) + + # energy_density + E_ll = energy_density(u_ll, equations) + E_rr = energy_density(u_rr, equations) + + # pressures + p_ll = pressure(u_ll, equations) + p_rr = pressure(u_rr, equations) + + # velocity averages + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) + v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) + v_square_avg = v1_square_avg + v2_square_avg + v_dot_n_avg = normal_direction[1] * v1_avg + normal_direction[2] * v2_avg + vr_normal_avg = 0.5 * normal_direction[2] * (vr_ll + vr_rr) + + # density averages + rho_dry_avg = 0.5 * (rho_dry_ll + rho_dry_rr) + rho_vapour_avg = 0.5 * (rho_vapour_ll + rho_vapour_rr) + rho_cloud_avg = 0.5 * (rho_cloud_ll + rho_cloud_rr) + rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) + + # density log means + rho_dry_log = 0.0 + rho_vapour_log = 0.0 + rho_cloud_log = 0.0 + rho_rain_log = 0.0 + + if (!(rho_dry_ll == 0.0) && !(rho_dry_rr == 0.0)) + rho_dry_log = ln_mean(rho_dry_ll, rho_dry_rr) + end + + if (!(rho_vapour_ll == 0.0) && !(rho_vapour_rr == 0.0)) + rho_vapour_log = ln_mean(rho_vapour_ll, rho_vapour_rr) + end + + if (!(rho_cloud_ll == 0.0) && !(rho_cloud_rr == 0.0)) + rho_cloud_log = ln_mean(rho_cloud_ll, rho_cloud_rr) + end + + if (!(rho_rain_ll == 0.0) && !(rho_rain_rr == 0.0)) + rho_rain_log = ln_mean(rho_rain_ll, rho_rain_rr) + end + + # other averages + p_avg = 0.5 * (p_ll + p_rr) + E_avg = 0.5 * (E_ll + E_rr) + temperature_avg = 0.5 * (temperature_ll + temperature_rr) + inv_temperature_avg = 0.5 * (inv_temperature_ll + inv_temperature_rr) + temperature_log = ln_mean(temperature_ll, temperature_rr) + inv_temperature_log = ln_mean(inv_temperature_ll, inv_temperature_rr) + + # jumps + rho_dry_jump = rho_dry_rr - rho_dry_ll + rho_vapour_jump = rho_vapour_rr - rho_vapour_ll + rho_cloud_jump = rho_cloud_rr - rho_cloud_ll + rho_rain_jump = rho_rain_rr - rho_rain_ll + temperature_jump = temperature_rr - temperature_ll + inv_temperature_jump = inv_temperature_rr - inv_temperature_ll + v_normal_jump = (v1_rr - v1_ll) * normal_direction[1] + (v2_rr - v2_ll) * normal_direction[2] + v_jump = sqrt(v1_rr^2 + v2_rr^2) - sqrt(v1_ll^2 + v2_ll^2) + + # help variables + s_help = inv(inv_temperature_log) + f_vapour = rho_vapour_log * v_dot_n_avg + f_cloud = rho_cloud_avg * v_dot_n_avg + + # flux + f_dry = rho_dry_log * v_dot_n_avg + f_rain = rho_rain_avg * (v_dot_n_avg - vr_normal_avg) + f_moist = f_vapour + f_cloud + f_rho = f_dry + f_moist + f_rain + + # TODO check velocities and normal directions + f_rhov1 = f_rho * v1_avg + p_avg * normal_direction[1] + f_rhov2 = f_rho * v2_avg + p_avg * normal_direction[2] + + if (temperature_jump != 0.0) + v_temp_jump = v_jump / inv_temperature_jump + f_energy = (c_vd * s_help - 0.5 * v_square_avg) * f_dry + (c_vv * s_help - 0.5 * v_square_avg + L_ref) * f_vapour + + (c_l * s_help - 0.5 * v_square_avg) * (f_cloud + f_rain) + + (v_temp_jump * inv_temperature_avg + v_dot_n_avg) * p_avg + + v_square_avg * f_rho - (R_d * rho_dry_avg + R_v * rho_vapour_avg) * v_temp_jump + else + f_energy = 0.0 + end return SVector(f_dry, f_moist, f_rain, f_rhov1, f_rhov2, f_energy, 0.0, 0.0, 0.0) end From 0196d35e06344311fd2f23d8d5e7de8e7322bed9 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Mon, 27 Jan 2025 22:18:37 +0100 Subject: [PATCH 088/115] ec flux update and further testing --- .../elixir_rainy_euler_rainy_bubble.jl | 6 +- src/equations/compressible_rainy_euler_2d.jl | 60 +++++++++++++------ 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl index f06377aa..95179ec0 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl @@ -4,7 +4,7 @@ using TrixiAtmo using TrixiAtmo: source_terms_rainy, saturation_residual, saturation_residual_jacobian, NonlinearSolveDG, cons2eq_pot_temp, saturation_vapour_pressure, - flux_chandrashekar, flux_LMARS, flux_ec_rain_log, + flux_chandrashekar, flux_LMARS, flux_ec_rain, source_terms_no_phase_change using NLsolve: nlsolve #using Plots @@ -221,11 +221,11 @@ boundary_conditions = (x_neg = boundary_condition_periodic, y_neg = boundary_condition_slip_wall, y_pos = boundary_condition_slip_wall) -polydeg = 1 +polydeg = 4 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_lax_friedrichs -volume_integral = VolumeIntegralFluxDifferencing(flux_ec_rain_log) +volume_integral = VolumeIntegralFluxDifferencing(flux_ec_rain) solver = DGSEM(basis, surface_flux, volume_integral) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 61f2e5e9..7911e523 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -105,16 +105,34 @@ end # converts consverved to entropy variables @inline function cons2entropy(u, equations::CompressibleRainyEulerEquations2D) # constants - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - c_l = equations.c_liquid_water - R_d = equations.R_dry_air - R_v = equations.R_vapour + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + c_l = equations.c_liquid_water + R_d = equations.R_dry_air + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + # nonlinear system + rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) + ln_temperature = log(temperature) + inv_temperature = inv(temperature) - # + # velocity + v1, v2 = velocities(u, rho_inv, equations) + v_squared_temp = 0.5 * (v1^2 + v2^2) * inv_temperature + omega_dry = c_vd * ln_temperature - R_d * log(rho_dry) + v_squared_temp - c_vd - R_d + omega_vapour = c_vv * ln_temperature - R_v * log(rho_vapour) + v_squared_temp - c_vv - R_v - L_ref * inv_temperature + omega_liquid = c_l * ln_temperature + v_squared_temp - c_l + omega_momentum_1 = -v1 * inv_temperature + omega_momentum_2 = -v2 * inv_temperature + omega_energy = inv_temperature - return SVector(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + return SVector(omega_dry, omega_vapour + omega_liquid, omega_liquid, + omega_momentum_1, omega_momentum_2, omega_energy, 0.0, 0.0, 0.0) end @@ -161,8 +179,7 @@ end exp(L_v * r_v * inv(c_p * temperature))) #TODO - s_dry, s_vapour, s_cloud, s_rain, _, _, _, _, _ = cons2entropy(u, equations) - entropy = s_dry + s_vapour + s_cloud + s_rain + entropy = 0.0 return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, v1, v2, eq_pot, p, entropy) end @@ -212,7 +229,7 @@ end end -# for convenience +# for convenience TODO rename @inline function cons2speeds(u, equations::CompressibleRainyEulerEquations2D) # densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) @@ -852,6 +869,8 @@ end # velocities v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) + vr_ll = terminal_velocity_rain(rho_moist_ll, rho_rain_ll, equations) + vr_rr = terminal_velocity_rain(rho_moist_rr, rho_rain_rr, equations) # mean values rho_dry_mean = 0.0 @@ -893,10 +912,12 @@ end p_int = inv(inv_temperature_avg) * (R_d * rho_dry_avg + R_v * rho_vapour_avg + R_q * (rho_cloud_avg + rho_rain_avg)) K_avg = 0.5 * (v1_square_avg + v2_square_avg) + vr_normal_avg = 0.5 * normal_direction[2] * (vr_ll + vr_rr) + rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) # assemble the flux f_dry = rho_dry_mean * v_dot_n_avg - f_rain = rho_rain_mean * v_dot_n_avg + f_rain = rho_rain_avg * (v_dot_n_avg - vr_normal_avg) f_vapour = rho_vapour_mean * v_dot_n_avg f_cloud = rho_cloud_mean * v_dot_n_avg f_moist = (rho_vapour_mean + rho_cloud_mean) * v_dot_n_avg @@ -910,7 +931,7 @@ end end -@inline function flux_ec_rain_log(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) +@inline function flux_ec_rain(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) # constants c_l = equations.c_liquid_water c_vd = equations.c_dry_air_const_volume @@ -994,29 +1015,30 @@ end temperature_jump = temperature_rr - temperature_ll inv_temperature_jump = inv_temperature_rr - inv_temperature_ll v_normal_jump = (v1_rr - v1_ll) * normal_direction[1] + (v2_rr - v2_ll) * normal_direction[2] - v_jump = sqrt(v1_rr^2 + v2_rr^2) - sqrt(v1_ll^2 + v2_ll^2) + v_jump = v1_rr - v1_ll + v2_rr - v2_ll # help variables s_help = inv(inv_temperature_log) - f_vapour = rho_vapour_log * v_dot_n_avg - f_cloud = rho_cloud_avg * v_dot_n_avg - - # flux + + # density flux + f_vapour = rho_vapour_log * v_dot_n_avg + f_cloud = rho_cloud_avg * v_dot_n_avg f_dry = rho_dry_log * v_dot_n_avg f_rain = rho_rain_avg * (v_dot_n_avg - vr_normal_avg) f_moist = f_vapour + f_cloud f_rho = f_dry + f_moist + f_rain - # TODO check velocities and normal directions + # momentum flux f_rhov1 = f_rho * v1_avg + p_avg * normal_direction[1] f_rhov2 = f_rho * v2_avg + p_avg * normal_direction[2] + # energy flux if (temperature_jump != 0.0) v_temp_jump = v_jump / inv_temperature_jump f_energy = (c_vd * s_help - 0.5 * v_square_avg) * f_dry + (c_vv * s_help - 0.5 * v_square_avg + L_ref) * f_vapour + (c_l * s_help - 0.5 * v_square_avg) * (f_cloud + f_rain) + (v_temp_jump * inv_temperature_avg + v_dot_n_avg) * p_avg + - v_square_avg * f_rho - (R_d * rho_dry_avg + R_v * rho_vapour_avg) * v_temp_jump + (v1_avg^2 + v2_avg^2) * f_rho - (R_d * rho_dry_avg + R_v * rho_vapour_avg) * v_temp_jump else f_energy = 0.0 end From 94b60b447a5192af43d69e44128166b6975a9619 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 28 Jan 2025 19:03:40 +0100 Subject: [PATCH 089/115] removed obsolete limiting case --- src/callbacks_stage/nonlinear_solve_dg2d.jl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/callbacks_stage/nonlinear_solve_dg2d.jl b/src/callbacks_stage/nonlinear_solve_dg2d.jl index 2f3528da..75c5b29c 100644 --- a/src/callbacks_stage/nonlinear_solve_dg2d.jl +++ b/src/callbacks_stage/nonlinear_solve_dg2d.jl @@ -29,10 +29,6 @@ function nonlinear_solve_dg_2d!(u, residual, jacobian, variables_index_vector, t u[3, i, j, element] = 0.0 end - if (u_node[3] > rain_threshold) - u[3, i, j, element] = rain_threshold * 0.1 - end - # newton method for iteration in range(1, max_iterations) res_vector = residual(u_node, guess, equations) From 57e491d0d5389c18af1ccc284f2e43a1d4d583ea Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 28 Jan 2025 19:04:54 +0100 Subject: [PATCH 090/115] energy density ec flux rain case improvement and formatting changes --- src/equations/compressible_rainy_euler_2d.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 7911e523..714ab046 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -945,8 +945,8 @@ end rho_dry_rr, rho_moist_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) rho_vapour_ll, rho_cloud_ll, temperature_ll = cons2nonlinearsystemsol(u_ll, equations) rho_vapour_rr, rho_cloud_rr, temperature_rr = cons2nonlinearsystemsol(u_rr, equations) - inv_temperature_ll = 1/temperature_ll - inv_temperature_rr = 1/temperature_rr + inv_temperature_ll = inv(temperature_ll) + inv_temperature_rr = inv(temperature_rr) # velocities v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) @@ -1033,7 +1033,7 @@ end f_rhov2 = f_rho * v2_avg + p_avg * normal_direction[2] # energy flux - if (temperature_jump != 0.0) + if !(isapprox(temperature_jump, 0.0, atol=1e-13)) v_temp_jump = v_jump / inv_temperature_jump f_energy = (c_vd * s_help - 0.5 * v_square_avg) * f_dry + (c_vv * s_help - 0.5 * v_square_avg + L_ref) * f_vapour + (c_l * s_help - 0.5 * v_square_avg) * (f_cloud + f_rain) + From e70064cd8ea5ea3a0963c2f4ffcf4eb87defaf6a Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Thu, 30 Jan 2025 16:41:28 +0100 Subject: [PATCH 091/115] diffusion and ec flux testing --- .../elixir_rainy_euler_rainy_bubble_diffusion.jl | 11 ++++++----- src/equations/compressible_rainy_euler_2d.jl | 8 ++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl index 73c775e1..e27b59fd 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl @@ -6,7 +6,8 @@ using TrixiAtmo: source_terms_rainy, saturation_residual, cons2eq_pot_temp, saturation_vapour_pressure, flux_chandrashekar, flux_LMARS, source_terms_no_phase_change, - boundary_condition_laplace + boundary_condition_laplace, + flux_ec_rain using NLsolve: nlsolve #using Plots @@ -220,7 +221,7 @@ end ############################################################################### # semidiscretization of the compressible rainy Euler equations -diffusivity = 1.5 +diffusivity = 0.5 equations_parabolic = LaplaceDiffusion2D(diffusivity, equations) @@ -236,13 +237,13 @@ boundary_conditions_parabolic = ( y_pos = boundary_condition_laplace) -polydeg = 2 +polydeg = 3 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_lax_friedrichs -#volume_integral = VolumeIntegralFluxDifferencing(flux_chandrashekar) +volume_integral = VolumeIntegralFluxDifferencing(flux_ec_rain) -solver = DGSEM(basis, surface_flux)#, volume_integral) +solver = DGSEM(basis, surface_flux, volume_integral) initial_condition = initial_condition_bubble_rainy source_terms = source_terms_rainy diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 714ab046..53b21003 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -1046,4 +1046,12 @@ end return SVector(f_dry, f_moist, f_rain, f_rhov1, f_rhov2, f_energy, 0.0, 0.0, 0.0) end +@inline function flux_ec_rain(u_ll, u_rr, orientation::Int, equations::CompressibleRainyEulerEquations2D) + if (orientation == 1) + return flux_ec_rain(u_ll, u_rr, SVector(1, 0), equations) + else + return flux_ec_rain(u_ll, u_rr, SVector(0, 1), equations) + end +end + end # muladd end \ No newline at end of file From d72a27d4d15743739c2d2795d60e2e6af711e682 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Sun, 2 Feb 2025 00:13:31 +0100 Subject: [PATCH 092/115] added explicit rainy euler equations for testing --- ...lixir_rainy_euler_explicit_moist_bubble.jl | 290 ++++++ ...lixir_rainy_euler_explicit_rainy_bubble.jl | 280 ++++++ ...y_euler_explicit_rainy_bubble_diffusion.jl | 295 ++++++ src/TrixiAtmo.jl | 3 +- src/callbacks_stage/callbacks_stage.jl | 1 + src/callbacks_stage/rain_limiter_dg.jl | 23 + src/callbacks_stage/rain_limiter_dg2d.jl | 34 + .../compressible_rainy_euler_explicit_2d.jl | 952 ++++++++++++++++++ src/equations/equations.jl | 3 +- 9 files changed, 1879 insertions(+), 2 deletions(-) create mode 100644 examples/moist_bubble_elixirs/energy/elixir_rainy_euler_explicit_moist_bubble.jl create mode 100644 examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl create mode 100644 examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl create mode 100644 src/callbacks_stage/rain_limiter_dg.jl create mode 100644 src/callbacks_stage/rain_limiter_dg2d.jl create mode 100644 src/equations/compressible_rainy_euler_explicit_2d.jl diff --git a/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_explicit_moist_bubble.jl b/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_explicit_moist_bubble.jl new file mode 100644 index 00000000..401d5704 --- /dev/null +++ b/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_explicit_moist_bubble.jl @@ -0,0 +1,290 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: source_terms_moist, saturation_residual, + saturation_residual_jacobian, NonlinearSolveDG, + cons2eq_pot_temp, flux_LMARS, flux_ec_rain +using NLsolve: nlsolve + + + +# Initial condition from elixir_moist_euler_bubble.jl +function moist_state(y, dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) + + @unpack p_0, g, c_pd, c_pv, c_vd, c_vv, R_d, R_v, c_pl, L_00 = equations + + (p, rho, T, r_t, r_v, rho_qv, theta_e) = y + p0 = y0[1] + + F = zeros(7, 1) + rho_d = rho / (1 + r_t) + p_d = R_d * rho_d * T + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + L = L_00 - (c_pl - c_pv) * T + + F[1] = (p - p0) / dz + g * rho + F[2] = p - (R_d * rho_d + R_v * rho_qv) * T + # H = 1 is assumed + F[3] = (theta_e - + T * (p_d / p_0)^(-R_d / (c_pd + c_pl * r_t)) * + exp(L * r_v / ((c_pd + c_pl * r_t) * T))) + F[4] = r_t - r_t0 + F[5] = rho_qv - rho_d * r_v + F[6] = theta_e - theta_e0 + a = p_vs / (R_v * T) - rho_qv + b = rho - rho_qv - rho_d + # H=1 => phi=0 + F[7] = a + b - sqrt(a * a + b * b) + + return F +end + +function generate_function_of_y(dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) + function function_of_y(y) + return moist_state(y, dz, y0, r_t0, theta_e0, equations) + end +end + +struct AtmosphereLayers{RealT <: Real} + equations::CompressibleMoistEulerEquations2D + # structure: 1--> i-layer (z = total_height/precision *(i-1)), 2--> rho, rho_theta, rho_qv, rho_ql + layer_data::Matrix{RealT} + total_height::RealT + preciseness::Int + layers::Int + ground_state::NTuple{2, RealT} + equivalent_potential_temperature::RealT + mixing_ratios::NTuple{2, RealT} +end + +function AtmosphereLayers(equations; total_height = 10010.0, preciseness = 10, + ground_state = (1.4, 100000.0), + equivalent_potential_temperature = 320, + mixing_ratios = (0.02, 0.02), RealT = Float64) + + @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl = equations + rho0, p0 = ground_state + r_t0, r_v0 = mixing_ratios + theta_e0 = equivalent_potential_temperature + + rho_qv0 = rho0 * r_v0 + T0 = theta_e0 + y0 = [p0, rho0, T0, r_t0, r_v0, rho_qv0, theta_e0] + + n = convert(Int, total_height / preciseness) + dz = 0.01 + layer_data = zeros(RealT, n + 1, 4) + + F = generate_function_of_y(dz, y0, r_t0, theta_e0, equations) + sol = nlsolve(F, y0) + p, rho, T, r_t, r_v, rho_qv, theta_e = sol.zero + + rho_d = rho / (1 + r_t) + rho_ql = rho - rho_d - rho_qv + kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * (p0 / p)^kappa_M * T * (1 + (R_v / R_d) * r_v) / (1 + r_t) + + layer_data[1, :] = [rho, rho_theta, rho_qv, rho_ql] + for i in (1:n) + y0 = deepcopy(sol.zero) + dz = preciseness + F = generate_function_of_y(dz, y0, r_t0, theta_e0, equations) + sol = nlsolve(F, y0) + p, rho, T, r_t, r_v, rho_qv, theta_e = sol.zero + + rho_d = rho / (1 + r_t) + rho_ql = rho - rho_d - rho_qv + kappa_M = (R_d * rho_d + R_v * rho_qv) / + (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * (p0 / p)^kappa_M * T * (1 + (R_v / R_d) * r_v) / (1 + r_t) + + layer_data[i + 1, :] = [rho, rho_theta, rho_qv, rho_ql] + end + + return AtmosphereLayers{RealT}(equations, layer_data, total_height, dz, n, ground_state, + theta_e0, mixing_ratios) +end + +# Moist bubble test case from paper: +# G.H. Bryan, J.M. Fritsch, A Benchmark Simulation for Moist Nonhydrostatic Numerical +# Models, MonthlyWeather Review Vol.130, 2917–2928, 2002, +# https://journals.ametsoc.org/view/journals/mwre/130/12/1520-0493_2002_130_2917_absfmn_2.0.co_2.xml. +function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, atmosphere_layers::AtmosphereLayers) + @unpack layer_data, preciseness, total_height = atmosphere_layers + dz = preciseness + z = x[2] + if (z > total_height && !(isapprox(z, total_height))) + error("The atmosphere does not match the simulation domain") + end + n = convert(Int, floor((z + eps()) / dz)) + 1 + z_l = (n - 1) * dz + (rho_l, rho_theta_l, rho_qv_l, rho_ql_l) = layer_data[n, :] + z_r = n * dz + if (z_l == total_height) + z_r = z_l + dz + n = n - 1 + end + (rho_r, rho_theta_r, rho_qv_r, rho_ql_r) = layer_data[n + 1, :] + rho = (rho_r * (z - z_l) + rho_l * (z_r - z)) / dz + rho_theta = rho * (rho_theta_r / rho_r * (z - z_l) + rho_theta_l / rho_l * (z_r - z)) / + dz + rho_qv = rho * (rho_qv_r / rho_r * (z - z_l) + rho_qv_l / rho_l * (z_r - z)) / dz + rho_ql = rho * (rho_ql_r / rho_r * (z - z_l) + rho_ql_l / rho_l * (z_r - z)) / dz + + rho, rho_e, rho_qv, rho_ql, T_loc = perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, + equations::CompressibleMoistEulerEquations2D) + + v1 = 0.0 + v2 = 0.0 + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_E = rho_e + 1 / 2 * rho * (v1^2 + v2^2) + + return SVector(rho - rho_qv - rho_ql, rho_qv, rho_ql, 0.0, rho_v1, rho_v2, rho_E) +end + +function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, + equations::CompressibleMoistEulerEquations2D) + @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl, L_00 = equations + xc = 10000.0 + zc = 2000.0 + rc = 2000.0 + Δθ = 2.0 + + r = sqrt((x[1] - xc)^2 + (x[2] - zc)^2) + rho_d = rho - rho_qv - rho_ql + kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + p_loc = p_0 * (R_d * rho_theta / p_0)^(1 / (1 - kappa_M)) + T_loc = p_loc / (R_d * rho_d + R_v * rho_qv) + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv + + # Assume pressure stays constant + if (r < rc && Δθ > 0) + # Calculate background density potential temperature + θ_dens = rho_theta / rho * (p_loc / p_0)^(kappa_M - kappa) + # Calculate perturbed density potential temperature + θ_dens_new = θ_dens * (1 + Δθ * cospi(0.5 * r / rc)^2 / 300) + rt = (rho_qv + rho_ql) / rho_d + rv = rho_qv / rho_d + # Calculate moist potential temperature + θ_loc = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rv) + # Adjust varuables until the temperature is met + if rt > 0 + while true + T_loc = θ_loc * (p_loc / p_0)^kappa + T_C = T_loc - 273.15 + # SaturVapor + pvs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + rho_d_new = (p_loc - pvs) / (R_d * T_loc) + rvs = pvs / (R_v * rho_d_new * T_loc) + θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) + if abs(θ_new - θ_loc) <= θ_loc * 1.0e-12 + break + else + θ_loc = θ_new + end + end + else + rvs = 0 + T_loc = θ_loc * (p_loc / p_0)^kappa + rho_d_new = p_loc / (R_d * T_loc) + θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) + end + # test + #T_loc = θ_new * (p_loc / p_0)^kappa + # + rho_qv = rvs * rho_d_new + rho_ql = (rt - rvs) * rho_d_new + rho = rho_d_new * (1 + rt) + rho_d = rho - rho_qv - rho_ql + kappa_M = (R_d * rho_d + R_v * rho_qv) / + (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * θ_dens_new * (p_loc / p_0)^(kappa - kappa_M) + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv + end + return SVector(rho, rho_e, rho_qv, rho_ql, T_loc) +end + +# Create background atmosphere data set +atmosphere_data = AtmosphereLayers(CompressibleMoistEulerEquations2D()) + +# Create the initial condition with the initial data set +function initial_condition_moist(x, t, equations::CompressibleRainyEulerEquationsExplicit2D) + return initial_condition_moist_bubble(x, t, CompressibleMoistEulerEquations2D(), atmosphere_data) +end + + + +############################################################################### +# semidiscretization of the compressible rainy Euler equations + +equations = CompressibleRainyEulerEquationsExplicit2D() + +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 = 3 +basis = LobattoLegendreBasis(polydeg) + +#surface_flux = flux_lax_friedrichs +surface_flux = flux_LMARS +volume_flux = flux_ec_rain + +volume_integral = VolumeIntegralFluxDifferencing(volume_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + +coordinates_min = ( 0.0, 0.0) +coordinates_max = (20_000.0, 10_000.0) + +cells_per_dimension = (65, 32) +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, + periodicity = (true, false)) + +semi = SemidiscretizationHyperbolic(mesh, equations, + initial_condition_moist, solver, + source_terms = source_terms_moist, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 1000.0) + +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 + + +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:entropy_conservation_error,)) + +alive_callback = AliveCallback(analysis_interval = 1000) + +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + output_directory = "out", + solution_variables = cons2eq_pot_temp) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) + +############################################################################### +# run the simulation +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + maxiters = 1.0e7, + dt = 1.0, + save_everystep = false, callback = callbacks); + +summary_callback() \ No newline at end of file diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl new file mode 100644 index 00000000..82398349 --- /dev/null +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl @@ -0,0 +1,280 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: source_terms_rainy, saturation_residual, + saturation_residual_jacobian, RainLimiterDG, + cons2eq_pot_temp, saturation_vapour_pressure, + flux_chandrashekar, flux_LMARS, flux_ec_rain, + source_terms_no_phase_change +using NLsolve: nlsolve +#using Plots + + + +# domain +coordinates_min = ( 0.0, 0.0) +coordinates_max = (2400.0, 2400.0) + + +# hydrostatic dry potential temperature +function theta_d(z, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + ref_pressure = equations.ref_pressure + + # problem specific constants + surface_temperature = 283.0 + surface_pressure = 8.5e4 + stratification = 1.3e-5 + + # dry potential temperature at surface + Theta0 = surface_temperature * (ref_pressure / surface_pressure)^(R_d / c_pd) + # at height z + theta_d = Theta0 * exp(stratification * z) + + return theta_d +end + + +# hydrostatic base state residual +function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equations::CompressibleRainyEulerEquationsExplicit2D) + # equations constants + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure + g = equations.gravity + + function hydrostatic_residual!(residual, guess) + # variables + pressure, rho_dry, rho_vapour, temperature = guess + + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + + # pressure derivative residual approximation + residual[1] = (pressure - pressure_lower) / dz + (rho_dry + rho_vapour) * g + + # pressure residual + residual[2] = pressure - temperature * (rho_dry * R_d + rho_vapour * R_v) + + # hydrostatic dry potential temperature residual + residual[3] = theta_d(z, equations) - temperature * (ref_pressure / pressure)^(R_d / c_pd) + + # humidity residual + residual[4] = rho_vs * (rho_dry + rho_vapour / eps) * humidity_rel0 + residual[4] -= rho_vapour * (rho_dry + rho_vs / eps) + residual[4] *= 1000.0 + end + + return hydrostatic_residual! +end + + +function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equations::CompressibleRainyEulerEquationsExplicit2D) + # equations constants + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure + + function perturbation_residual!(residual, guess) + # variables + rho_dry, rho_vapour, temperature = guess + + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + pressure = (rho_dry * R_d + rho_vapour * R_v) * temperature + + # humidity residual + residual[1] = rho_vs * (rho_dry + rho_vapour / eps) * H_init + residual[1] -= rho_vapour * (rho_dry + rho_vs / eps) + residual[1] *= 30.0 + + # hydrostatic dry potential temperature residual + residual[2] = theta_d(z, equations) - temperature * (ref_pressure / pressure_hydrostatic)^(R_d / c_pd) + + # pressure residual + residual[3] = pressure_hydrostatic - pressure + end + + return perturbation_residual! +end + + +# for approximating the dz pressure gradient +struct AtmosphereLayers{RealT <: Real} + layer_data ::Matrix{RealT} + total_height ::RealT + precision ::RealT +end + + +function AtmosphereLayers(equations::CompressibleRainyEulerEquationsExplicit2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) + # constants + humidity_rel0 = 0.2 # hydrostatic relative humidity + surface_pressure = 8.5e4 + + # surface layer with initial guesses for rho_dry, rho_vapour and temperature + surface_layer = [surface_pressure, 1.4, 0.04, 300.0] + + # allocate layer_data + n = convert(Int, total_height / precision) + layer_data = zeros(RealT, n + 1, 4) + + # solve (slightly above) surface layer + dz = 0.01 + z = 0.01 + residual_function! = generate_hydrostatic_residual(surface_pressure, humidity_rel0, z, dz, equations) + layer_data[1, :] .= nlsolve(residual_function!, surface_layer).zero + + # adjust to chosen precision + dz = precision + + # iterate up the atmosphere + for i in (1:n) + z += dz + residual_function! = generate_hydrostatic_residual(layer_data[i, 1], humidity_rel0, z, dz, equations) + guess = deepcopy(layer_data[i, :]) + layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, iterations = 20).zero + end + + return AtmosphereLayers{RealT}(layer_data, total_height, precision) +end + + +# create layers for initial condition +equations = CompressibleRainyEulerEquationsExplicit2D() +layers = AtmosphereLayers(equations) + + +function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerEquationsExplicit2D; atmosphere_layers = layers) + # equations constants + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + ref_L = equations.ref_latent_heat_vap_temp + + # problem specific constants + humidity_rel_bar = 0.2 # background relative humidity field + humidity_max = 1.0 + + # bubble parameters + radius_outer, radius_inner = 300.0, 200.0 # radii of humidity bubble + x_center, z_center = 1200.0, 800.0 # center of humidity bubble + + # radius relative to bubble center + r = sqrt((x[1] - x_center)^2 + (x[2] - z_center)^2) + + # humidity definition + if (r > radius_outer) + # outside the bubble + humidity = humidity_rel_bar + elseif (r > radius_inner) + # outer layers of the bubble + humidity = humidity_rel_bar + (humidity_max - humidity_rel_bar) * cos(pi * (r - radius_inner) / (2.0 * (radius_outer - radius_inner)))^2 + else + # inner layer + humidity = humidity_max + end + + # get atmosphere layer and height information + @unpack layer_data, total_height, precision = atmosphere_layers + dz = precision + z = x[2] + n = convert(Int, floor((z + eps()) / dz)) + 1 + z_lower = (n - 1) * dz + z_upper = n * dz + + if (z_lower == total_height) + z_upper = z_lower + dz + n = n - 1 + end + + # check height consistency + if (z > total_height && !(isapprox(z, total_height))) + error("The atmosphere does not match the simulation domain") + end + + # get hydrostatic pressures and approximate between lower and upper data point + pressure_hydrostatic_lower = layer_data[n, 1] + pressure_hydrostatic_upper = layer_data[n + 1, 1] + pressure_hydrostatic = (pressure_hydrostatic_upper * (z - z_lower) + pressure_hydrostatic_lower * (z_upper - z)) / dz + + # solve perturbation + residual_function! = generate_perturbation_residual(pressure_hydrostatic, humidity, z, equations) + rho_dry, rho_vapour, temperature = nlsolve(residual_function!, layer_data[n, 2:4], ftol = 1e-9, iterations = 20).zero + + energy_density = (c_vd * rho_dry + c_vv * rho_vapour) * temperature + rho_vapour * ref_L + + return SVector(rho_dry, rho_vapour, 0.0, 0.0, 0.0, 0.0, energy_density) +end + + + +############################################################################### +# semidiscretization of the compressible rainy Euler equations + + +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 = 1 +basis = LobattoLegendreBasis(polydeg) + +surface_flux = flux_lax_friedrichs +volume_integral = VolumeIntegralFluxDifferencing(flux_ec_rain) + +solver = DGSEM(basis, surface_flux, volume_integral) + +cells_per_dimension = (100, 100) +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, + periodicity = (true, false)) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition_bubble_rainy, solver, + source_terms = source_terms_rainy, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 600.0) + +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 + +# entropy? +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:entropy_conservation_error,)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + output_directory = "out", + solution_variables = cons2eq_pot_temp) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) + +topography(x_1) = 0.0 + +stage_limiter! = RainLimiterDG(topography) + +############################################################################### +# run the simulation +sol = solve(ode, SSPRK43(stage_limiter!); ode_default_options()..., + maxiters = 1.0e7, save_everystep = false, callback = callbacks); + +summary_callback() \ No newline at end of file diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl new file mode 100644 index 00000000..9db5f46c --- /dev/null +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl @@ -0,0 +1,295 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: source_terms_rainy, saturation_residual, + saturation_residual_jacobian, RainLimiterDG, + cons2eq_pot_temp, saturation_vapour_pressure, + flux_chandrashekar, flux_LMARS, + source_terms_no_phase_change, + boundary_condition_laplace, + flux_ec_rain +using NLsolve: nlsolve +#using Plots + + + +# domain +coordinates_min = ( 0.0, 0.0) +coordinates_max = (2400.0, 2400.0) + + +# hydrostatic dry potential temperature +function theta_d(z, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + ref_pressure = equations.ref_pressure + + # problem specific constants + surface_temperature = 283.0 + surface_pressure = 8.5e4 + stratification = 1.3e-5 + + # dry potential temperature at surface + Theta0 = surface_temperature * (ref_pressure / surface_pressure)^(R_d / c_pd) + # at height z + theta_d = Theta0 * exp(stratification * z) + + return theta_d +end + + +# hydrostatic base state residual +function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equations::CompressibleRainyEulerEquationsExplicit2D) + # equations constants + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure + g = equations.gravity + + function hydrostatic_residual!(residual, guess) + # variables + pressure, rho_dry, rho_vapour, temperature = guess + + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + + # pressure derivative residual approximation + residual[1] = (pressure - pressure_lower) / dz + (rho_dry + rho_vapour) * g + + # pressure residual + residual[2] = pressure - temperature * (rho_dry * R_d + rho_vapour * R_v) + + # hydrostatic dry potential temperature residual + residual[3] = theta_d(z, equations) - temperature * (ref_pressure / pressure)^(R_d / c_pd) + + # humidity residual + residual[4] = rho_vs * (rho_dry + rho_vapour / eps) * humidity_rel0 + residual[4] -= rho_vapour * (rho_dry + rho_vs / eps) + residual[4] *= 1000.0 + end + + return hydrostatic_residual! +end + + +function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equations::CompressibleRainyEulerEquationsExplicit2D) + # equations constants + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure + + function perturbation_residual!(residual, guess) + # variables + rho_dry, rho_vapour, temperature = guess + + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + pressure = (rho_dry * R_d + rho_vapour * R_v) * temperature + + # humidity residual + residual[1] = rho_vs * (rho_dry + rho_vapour / eps) * H_init + residual[1] -= rho_vapour * (rho_dry + rho_vs / eps) + residual[1] *= 30.0 + + # hydrostatic dry potential temperature residual + residual[2] = theta_d(z, equations) - temperature * (ref_pressure / pressure_hydrostatic)^(R_d / c_pd) + + # pressure residual + residual[3] = pressure_hydrostatic - pressure + end + + return perturbation_residual! +end + + +# for approximating the dz pressure gradient +struct AtmosphereLayers{RealT <: Real} + layer_data ::Matrix{RealT} + total_height ::RealT + precision ::RealT +end + + +function AtmosphereLayers(equations::CompressibleRainyEulerEquationsExplicit2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) + # constants + humidity_rel0 = 0.2 # hydrostatic relative humidity + surface_pressure = 8.5e4 + + # surface layer with initial guesses for rho_dry, rho_vapour and temperature + surface_layer = [surface_pressure, 1.4, 0.04, 300.0] + + # allocate layer_data + n = convert(Int, total_height / precision) + layer_data = zeros(RealT, n + 1, 4) + + # solve (slightly above) surface layer + dz = 0.01 + z = 0.01 + residual_function! = generate_hydrostatic_residual(surface_pressure, humidity_rel0, z, dz, equations) + layer_data[1, :] .= nlsolve(residual_function!, surface_layer).zero + + # adjust to chosen precision + dz = precision + + # iterate up the atmosphere + for i in (1:n) + z += dz + residual_function! = generate_hydrostatic_residual(layer_data[i, 1], humidity_rel0, z, dz, equations) + guess = deepcopy(layer_data[i, :]) + layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, iterations = 20).zero + end + + return AtmosphereLayers{RealT}(layer_data, total_height, precision) +end + + +# create layers for initial condition +equations = CompressibleRainyEulerEquationsExplicit2D() +layers = AtmosphereLayers(equations) + + +function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerEquationsExplicit2D; atmosphere_layers = layers) + # equations constants + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + ref_L = equations.ref_latent_heat_vap_temp + + # problem specific constants + humidity_rel_bar = 0.2 # background relative humidity field + humidity_max = 1.0 + + # bubble parameters + radius_outer, radius_inner = 300.0, 200.0 # radii of humidity bubble + x_center, z_center = 1200.0, 800.0 # center of humidity bubble + + # radius relative to bubble center + r = sqrt((x[1] - x_center)^2 + (x[2] - z_center)^2) + + # humidity definition + if (r > radius_outer) + # outside the bubble + humidity = humidity_rel_bar + elseif (r > radius_inner) + # outer layers of the bubble + humidity = humidity_rel_bar + (humidity_max - humidity_rel_bar) * cos(pi * (r - radius_inner) / (2.0 * (radius_outer - radius_inner)))^2 + else + # inner layer + humidity = humidity_max + end + + # get atmosphere layer and height information + @unpack layer_data, total_height, precision = atmosphere_layers + dz = precision + z = x[2] + n = convert(Int, floor((z + eps()) / dz)) + 1 + z_lower = (n - 1) * dz + z_upper = n * dz + + if (z_lower == total_height) + z_upper = z_lower + dz + n = n - 1 + end + + if (n == 0) + n = 1 + end + + # check height consistency + if (z > total_height && !(isapprox(z, total_height))) + error("The atmosphere does not match the simulation domain") + end + + # get hydrostatic pressures and approximate between lower and upper data point + pressure_hydrostatic_lower = layer_data[n, 1] + pressure_hydrostatic_upper = layer_data[n + 1, 1] + pressure_hydrostatic = (pressure_hydrostatic_upper * (z - z_lower) + pressure_hydrostatic_lower * (z_upper - z)) / dz + + # solve perturbation + residual_function! = generate_perturbation_residual(pressure_hydrostatic, humidity, z, equations) + rho_dry, rho_vapour, temperature = nlsolve(residual_function!, layer_data[n, 2:4], ftol = 1e-9, iterations = 20).zero + + energy_density = (c_vd * rho_dry + c_vv * rho_vapour) * temperature + rho_vapour * ref_L + + return SVector(rho_dry, rho_vapour, 0.0, 0.0, 0.0, 0.0, energy_density) +end + + + +############################################################################### +# semidiscretization of the compressible rainy Euler equations + +diffusivity = 0.5 +equations_parabolic = LaplaceDiffusion2D(diffusivity, equations) + + +boundary_conditions = (x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_slip_wall, + y_pos = boundary_condition_slip_wall) + +boundary_conditions_parabolic = ( + x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_laplace, + y_pos = boundary_condition_laplace) + + +polydeg = 3 +basis = LobattoLegendreBasis(polydeg) + +surface_flux = flux_lax_friedrichs +volume_integral = VolumeIntegralFluxDifferencing(flux_ec_rain) + +solver = DGSEM(basis, surface_flux, volume_integral) + +initial_condition = initial_condition_bubble_rainy +source_terms = source_terms_rainy + +mesh = TreeMesh(coordinates_min, coordinates_max, initial_refinement_level = 6, periodicity = (true, false), n_cells_max = 1_000_000) + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; source_terms, + boundary_conditions = (boundary_conditions, boundary_conditions_parabolic)) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 600.0) + +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 + +# entropy? +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:entropy_conservation_error,)) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + output_directory = "out", + solution_variables = cons2eq_pot_temp) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) +topography(x_1) = 0.0 + +stage_limiter! = RainLimiterDG(topography) + +############################################################################### +# run the simulation +sol = solve(ode, SSPRK43(stage_limiter!); ode_default_options()..., + maxiters = 1.0e7, save_everystep = false, callback = callbacks); + +summary_callback() \ No newline at end of file diff --git a/src/TrixiAtmo.jl b/src/TrixiAtmo.jl index d59ff1eb..9f02ac67 100644 --- a/src/TrixiAtmo.jl +++ b/src/TrixiAtmo.jl @@ -23,7 +23,8 @@ baz() = Trixi.examples_dir() include("equations/equations.jl") export CompressibleMoistEulerEquations2D, CompressibleRainyEulerEquations2D, CompressibleRainyEulerPotentialTemperatureEquations2D, - CompressibleMoistEulerPotentialTemperatureEquations2D + CompressibleMoistEulerPotentialTemperatureEquations2D, + CompressibleRainyEulerEquationsExplicit2D include("callbacks_stage/callbacks_stage.jl") export NonlinearSolveDG diff --git a/src/callbacks_stage/callbacks_stage.jl b/src/callbacks_stage/callbacks_stage.jl index 4be1d434..3e756c20 100644 --- a/src/callbacks_stage/callbacks_stage.jl +++ b/src/callbacks_stage/callbacks_stage.jl @@ -1,3 +1,4 @@ @muladd begin include("nonlinear_solve_dg.jl") + include("rain_limiter_dg.jl") end \ No newline at end of file diff --git a/src/callbacks_stage/rain_limiter_dg.jl b/src/callbacks_stage/rain_limiter_dg.jl new file mode 100644 index 00000000..fc2dcdbe --- /dev/null +++ b/src/callbacks_stage/rain_limiter_dg.jl @@ -0,0 +1,23 @@ +using Trixi: wrap_array, TimerOutputs, @trixi_timeit, timer + + + +@muladd begin + +struct RainLimiterDG + topography::Function +end + + +function (limiter!::RainLimiterDG)(u_ode, integrator, semi::AbstractSemidiscretization, t) + u = wrap_array(u_ode, semi) + + @trixi_timeit timer() "rain limiter" begin + rain_limiter_dg2d!(u, limiter!.topography, semi.equations, semi.solver, semi.cache, semi.mesh) + end +end + + +include("rain_limiter_dg2d.jl") + +end \ No newline at end of file diff --git a/src/callbacks_stage/rain_limiter_dg2d.jl b/src/callbacks_stage/rain_limiter_dg2d.jl new file mode 100644 index 00000000..5fae9a15 --- /dev/null +++ b/src/callbacks_stage/rain_limiter_dg2d.jl @@ -0,0 +1,34 @@ +using Trixi: get_node_vars, @batch, set_node_vars!, get_node_coords, each_quad_node +using LinearAlgebra +using StaticArrays + + + +@muladd begin + +function rain_limiter_dg2d!(u, topography, + equations::AbstractCompressibleRainyEulerEquations, dg::DGSEM, cache, mesh) + + # iterate over every DGSEM element + @batch for element in eachelement(dg, cache) + # iterate over every node + for j in eachnode(dg), i in eachnode(dg) + + u_node = get_node_vars(u, equations, dg, i, j, element) + + x_node = get_node_coords(cache.elements.node_coordinates, equations, dg, i, j, element) + + # keep rho_rain positive + if (u_node[4] < 0.0 || (x_node[2] + topography(x_node[1])) < 50.0) + u[4, i, j, element] = 0.0 + end + + # keep rho_cloud positive + if (u_node[3] < 0.0) + u[3, i, j, element] = 0.0 + end + end + end +end + +end #muladd end \ No newline at end of file diff --git a/src/equations/compressible_rainy_euler_explicit_2d.jl b/src/equations/compressible_rainy_euler_explicit_2d.jl new file mode 100644 index 00000000..a056825d --- /dev/null +++ b/src/equations/compressible_rainy_euler_explicit_2d.jl @@ -0,0 +1,952 @@ +using Trixi +using NLsolve: nlsolve +import Trixi: varnames, + cons2prim, cons2entropy, + flux, flux_chandrashekar, + max_abs_speeds, max_abs_speed_naive, + boundary_condition_slip_wall + + + +### Implementation similar to: +# Sabine Doppler, Philip L. Lederer, Joachim Schöberl, Henry von Wahl, +# A discontinuous Galerkin approach for atmospheric flows with implicit condensation, +# Journal of Computational Physics, +# Volume 499, +# 2024, +# 112713, +# ISSN 0021-9991 + + + +@muladd begin + +### equation, parameters and constants ### + +struct CompressibleRainyEulerEquationsExplicit2D{RealT <: Real} <: AbstractCompressibleRainyEulerEquations{2, 7} + # Specific heat capacities: + c_liquid_water ::RealT + c_dry_air_const_pressure ::RealT + c_dry_air_const_volume ::RealT + c_vapour_const_pressure ::RealT + c_vapour_const_volume ::RealT + + # Gas constants: + R_dry_air ::RealT + R_vapour ::RealT + eps ::RealT + + # Reference values: + ref_saturation_pressure ::RealT + ref_temperature ::RealT + ref_latent_heat_vap_temp ::RealT + ref_pressure ::RealT + + # Other: + gravity ::RealT + rain_water_distr ::RealT + v_mean_rain ::RealT +end + + +function CompressibleRainyEulerEquationsExplicit2D(; RealT = Float64) + # Specific heat capacities: + c_liquid_water = 4186.0 + c_dry_air_const_pressure = 1004.0 + c_dry_air_const_volume = 717.0 + c_vapour_const_pressure = 1885.0 + c_vapour_const_volume = 1424.0 + + # Gas constants: + R_dry_air = c_dry_air_const_pressure - c_dry_air_const_volume + R_vapour = c_vapour_const_pressure - c_vapour_const_volume + eps = R_dry_air / R_vapour + + # Reference values: + ref_saturation_pressure = 610.7 # This needs to be adjusted if ref_temperature is changed! + ref_temperature = 273.15 + ref_latent_heat_vap_temp = 2.5e6#3147620.0 + ref_pressure = 1e5 + + # Other: + gravity = 9.81 + rain_water_distr = 8e6 + v_mean_rain = 130.0 + + return CompressibleRainyEulerEquationsExplicit2D{RealT}(c_liquid_water, c_dry_air_const_pressure, c_dry_air_const_volume, + c_vapour_const_pressure, c_vapour_const_volume, R_dry_air, + R_vapour, eps, ref_saturation_pressure, ref_temperature, + ref_latent_heat_vap_temp, ref_pressure, gravity, + rain_water_distr, v_mean_rain) +end + + + +### conversion ### + +@inline function cons2prim(u, equations::CompressibleRainyEulerEquationsExplicit2D) + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + + # energy density + energy = energy_density(u, equations) + + return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, v1, v2, energy) +end + + +# converts consverved to entropy variables +@inline function cons2entropy(u, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + c_l = equations.c_liquid_water + R_d = equations.R_dry_air + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp + + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + + # nonlinear system + temperature = get_temperature(u, equations) + ln_temperature = log(temperature) + inv_temperature = inv(temperature) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + v_squared_temp = 0.5 * (v1^2 + v2^2) * inv_temperature + + omega_dry = c_vd * ln_temperature - R_d * log(rho_dry) + v_squared_temp - c_vd - R_d + omega_vapour = c_vv * ln_temperature - R_v * log(rho_vapour) + v_squared_temp - c_vv - R_v - L_ref * inv_temperature + omega_liquid = c_l * ln_temperature + v_squared_temp - c_l + omega_momentum_1 = -v1 * inv_temperature + omega_momentum_2 = -v2 * inv_temperature + omega_energy = inv_temperature + + return SVector(omega_dry, omega_vapour, omega_liquid, omega_liquid, + omega_momentum_1, omega_momentum_2, omega_energy) +end + + +# adapted from compressible_moist_euler_2d.jl +@inline function cons2eq_pot_temp(u, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + c_l = equations.c_liquid_water + c_pd = equations.c_dry_air_const_pressure + c_pv = equations.c_vapour_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + ref_p = equations.ref_pressure + ref_temp = equations.ref_temperature + ref_L = equations.ref_latent_heat_vap_temp + + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + + # nonlinear system + temperature = get_temperature(u, equations) + + # pressure + p = pressure(u, equations) + + p_v = rho_vapour * R_v * temperature + p_d = p - p_v + p_vs = saturation_vapour_pressure(temperature, equations) + H = p_v / p_vs + r_v = rho_vapour / rho_dry + r_c = rho_cloud / rho_dry + r_r = rho_rain / rho_dry + L_v = ref_L + (c_pv - c_l) * temperature + c_p = c_pd + (r_v + r_c + r_r) * c_l + + # equivalent potential temperature + eq_pot = (temperature * (ref_p / p_d)^(R_d / c_p) * H^(-r_v * R_v / c_p) * + exp(L_v * r_v * inv(c_p * temperature))) + + return SVector(rho, r_v, r_c, r_r, v1, v2, eq_pot, p) +end + + +# for convenience TODO rename +@inline function cons2speeds(u, equations::CompressibleRainyEulerEquationsExplicit2D) + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + + # get speed of sound + v_sound = speed_of_sound(u, equations)[1] + + # get terminal velocity rain + v_r = terminal_velocity_rain(rho_vapour + rho_cloud, rho_rain, equations) + + return SVector(v1, v2, v_sound, v_r) +end + + + +### varnames ### + +varnames(::typeof(cons2cons), ::CompressibleRainyEulerEquationsExplicit2D) = ("rho_dry", "rho_moist", "rho_rain", + "rho_v1", "rho_v2", + "energy_density", + "rho_vapour", "rho_cloud", "temperature") + + +varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquationsExplicit2D) = ("rho_dry", "rho_moist", "rho_rain", + "v1", "v2", + "energy_density", + "rho_vapour", "rho_cloud", "temperature") + +varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquationsExplicit2D) = ("rho_dry", "rho_vapour", + "rho_cloud", "rho_rain", + "v1", "v2", "eq_pot_temp", + "pressure", "entropy") + + + +### physics variables ### + +@inline function densities(u, equations::CompressibleRainyEulerEquationsExplicit2D) + # densities + rho_dry = u[1] + rho_vapour = u[2] + rho_cloud = u[3] + rho_rain = u[4] + rho = rho_dry + rho_vapour + rho_cloud + rho_rain + rho_inv = inv(rho) + + return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv) +end + +@inline function rain_density(u, equations::CompressibleRainyEulerEquationsExplicit2D) + return u[4] +end + +@inline function velocities(u, rho_inv, equations::CompressibleRainyEulerEquationsExplicit2D) + return SVector(u[5] * rho_inv, u[6] * rho_inv) +end + + +@inline function energy_density(u, equations::CompressibleRainyEulerEquationsExplicit2D) + return u[7] +end + + +@inline function pressure(u, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + R_d = equations.R_dry_air + R_v = equations.R_vapour + + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + + temperature = get_temperature(u, equations) + + p = (R_d * rho_dry + R_v * rho_vapour) * temperature + + return p +end + + +@inline function speed_of_sound(u, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + + if ( rho_vapour < 0.0 ) + error("rho vapour less than zero") + end + if ( rho_cloud < 0.0 ) + error("rho cloud less than zero") + end + + # formula + p = pressure(u, equations) + q_v = rho_vapour / rho_dry + q_l = (rho_cloud + rho_rain) / rho_dry + gamma_m = 1 + (R_d + R_v * q_v) / (c_vd + c_vv * q_v + c_l * q_l) + + if (rho_inv < 0.0) + error("rho less than zero") + elseif (p < 0.0) + error("pressure less than zero") + end + + v_sound = sqrt(gamma_m * p * rho_inv) + + return SVector(v_sound, gamma_m) +end + + +@inline function get_temperature(u, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + L_ref = equations.ref_latent_heat_vap_temp + + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + + # energy density + energy = energy_density(u, equations::CompressibleRainyEulerEquationsExplicit2D) + + return (energy - L_ref * rho_vapour - 0.5 * rho * (v1^2 + v2^2)) / (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) +end + + +@inline function terminal_velocity_rain(rho_moist, rho_rain, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + N_0 = equations.rain_water_distr + v_0 = equations.v_mean_rain + + # formula ( \Gamma(4.5) / 6 ~= 1.9386213994279082 ) + if ( rho_rain > 0.0) + v_terminal_rain = v_0 * 1.9386213994279082 * (rho_rain / (pi * (rho_moist + rho_rain) * N_0))^(0.125) + else + v_terminal_rain = 0.0 + end + + return v_terminal_rain +end + + +@inline function saturation_vapour_pressure(temperature, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + c_l = equations.c_liquid_water + c_pv = equations.c_vapour_const_pressure + R_v = equations.R_vapour + ref_s_p = equations.ref_saturation_pressure + ref_temp = equations.ref_temperature + ref_L = equations.ref_latent_heat_vap_temp + + # testing + if (temperature < 0.0) + display(temperature) + error("temp less than zero") + end + + # Clausius Clapeyron formula + p_vapour_saturation = ref_s_p * (temperature / ref_temp)^((c_pv - c_l) / R_v) + p_vapour_saturation *= exp(((ref_L - (c_pv - c_l) * ref_temp) / R_v) * (1 / ref_temp - 1 / temperature)) + + return p_vapour_saturation +end + + +# adapted from compressible_moist_euler_2d.jl +@inline function moist_air_phase_change(u, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + R_v = equations.R_vapour + + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + + # temperature + temperature = get_temperature(u, equations) + + # saturation vapor pressure + p_vs = saturation_vapour_pressure(temperature, equations) + + # saturation density of vapor + rho_star_qv = p_vs / (R_v * temperature) + + # Fisher-Burgmeister-Function + a = rho_star_qv - rho_vapour + b = rho_cloud + + # saturation control factor + # < 1: stronger saturation effect + # > 1: weaker saturation effect + C = 1.0 + + return (a + b - sqrt(a^2 + b^2)) * C +end + + + +### pde discretization ### + +@inline function flux(u, orientation::Integer, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + c_l = equations.c_liquid_water + + #densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + + # recover rho_vapour, rho_cloud, temperature from nonlinear system + temperature = get_temperature(u, equations) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + v_r = terminal_velocity_rain(rho_vapour + rho_cloud, rho_rain, equations) + + # pressure + p = pressure(u, equations) + + # energy density + energy = energy_density(u, equations) + + # flux for orientation cases + if (orientation == 1) + # "mass" + f1 = rho_dry * v1 + f2 = rho_vapour * v1 + f3 = rho_cloud * v1 + f4 = rho_rain * v1 + + # "momentum" + f5 = rho * v1 * v1 + p + f6 = rho * v1 * v2 + + # "energy" + f7 = (energy + p) * v1 + + else + # "mass" + f1 = rho_dry * v2 + f2 = rho_vapour * v2 + f3 = rho_cloud * v2 + f4 = rho_rain * (v2 - v_r) + + # "momentum" + f5 = rho * v1 * v2 - rho_rain * v_r * v1 + f6 = rho * v2 * v2 + p - rho_rain * v_r * v2 + + # "energy" + f7 = (energy + p) * v2 - (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r + end + + return SVector(f1, f2, f3, f4, f5, f6, f7) +end + + +@inline function flux(u, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + c_l = equations.c_liquid_water + + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + + # recover rho_vapour, rho_cloud, temperature from nonlinear system + temperature = get_temperature(u, equations) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + v_r = terminal_velocity_rain(rho_vapour + rho_cloud, rho_rain, equations) + + # normal velocities + v_normal = v1 * normal_direction[1] + v2 * normal_direction[2] + v_r_normal = v_r * normal_direction[2] + + # pressure + p = pressure(u, equations) + + # energy density + energy = energy_density(u, equations) + + # flux + # "mass" + f1 = rho_dry * v_normal + f2 = rho_vapour * v_normal + f3 = rho_cloud * v_normal + f4 = rho_rain * (v_normal - v_r_normal) + + # "momentum" + f5 = rho * v_normal * v1 + p * normal_direction[1] - rho_rain * v_r_normal * v1 + f6 = rho * v_normal * v2 + p * normal_direction[2] - rho_rain * v_r_normal * v2 + + # "energy" + f7 = (energy + p) * v_normal - (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r_normal + + return SVector(f1, f2, f3, f4, f5, f6, f7) +end + + +# no Coriolis term +@inline function source_terms_rainy(u, x, t, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + R_v = equations.R_vapour + ref_temp = equations.ref_temperature + g = equations.gravity + + # name needed variables + rho_v2 = u[6] + + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + + # temperature + temperature = get_temperature(u, equations) + + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + Q_ph = moist_air_phase_change(u, equations) + + # source terms phase change + S_evaporation = (3.86e-3 - 9.41e-5 * (temperature - ref_temp)) * (1 + 9.1 * rho_rain^(0.1875)) + S_evaporation *= (rho_vs - rho_vapour) * rho_rain^(0.5) + S_auto_conversion = 0.001 * rho_cloud + S_accretion = 1.72 * rho_cloud * rho_rain^(0.875) + S_rain = S_auto_conversion + S_accretion - S_evaporation + S_groundwater = 0.0 + + if (x[2] < 100.0) + S_groundwater = rho_rain * (1 - (x[2] * 0.01)^2) + end + + return SVector(0.0, Q_ph + S_evaporation, -Q_ph - S_auto_conversion - S_accretion, S_rain - S_groundwater, 0.0, + -rho * g, -rho_v2 * g) +end + + +# no Coriolis term +@inline function source_terms_moist(u, x, t, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + g = equations.gravity + + # name needed variables + rho_v2 = u[6] + + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + + Q_ph = phase_change_term(u, equations) + + return SVector(0.0, Q_ph, -Q_ph, 0.0, 0.0, + -rho * g, -rho_v2 * g) +end + + +# no phase changes and no Coriolis term +@inline function source_terms_no_phase_change(u, x, t, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + g = equations.gravity + + # name needed variables + rho_v2 = u[6] + + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + + return SVector(0.0, 0.0, 0.0, 0.0, 0.0, -g * rho, -g * rho_v2) +end + + +@inline function max_abs_speeds(u, equations::CompressibleRainyEulerEquationsExplicit2D) + # name needed variables + v1, v2, v_sound, v_r = cons2speeds(u, equations) + + return SVector((abs(v1) + v_sound), (abs(v2) + v_sound + abs(v_r))) +end + + +@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquationsExplicit2D) + # name needed variables + v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) + v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) + + # calculate upper bounds for left and right speed + v_ll_max = abs(v1_ll * normal_direction[1] + v2_ll * normal_direction[2]) + v_ll_max += abs( v_r_ll * normal_direction[2]) + + v_rr_max = abs(v1_rr * normal_direction[1] + v2_rr * normal_direction[2]) + v_rr_max += abs( v_r_rr * normal_direction[2]) + + return max(v_ll_max, v_rr_max) + max(v_sound_ll, v_sound_rr) * norm(normal_direction) +end + + +@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::CompressibleRainyEulerEquationsExplicit2D) + # name needed variables + v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) + v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) + + if (orientation == 1) + v_ll = abs(v1_ll) + v_rr = abs(v1_rr) + else + v_ll = abs(v2_ll) + v_rr = abs(v2_rr) + end + # experimental + return max(v_ll, v_rr) + max(v_sound_ll, v_sound_rr) + max(abs(v_r_ll), abs(v_r_rr)) +end + + +### boundary conditions ### + +# adapted from compressible_moist_euler_2d.jl which was probably adapted from compressible_euler_2d.jl +@inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, x, t, + surface_flux_function, equations::CompressibleRainyEulerEquationsExplicit2D) + + norm_ = norm(normal_direction) + # Normalize the vector without using `normalize` since we need to multiply by the `norm_` later + normal = normal_direction / norm_ + + # rotate the internal solution state + u_local = rotate_to_x(u_inner, normal, equations) + + # name needed variables + rho_v1 = u_local[5] + + # densities + rho_dry_local, rho_vapour_local, rho_cloud_local, rho_rain_local, rho_local, rho_inv_local = densities(u_local, equations) + + # velocities + v_normal = rho_v1 * rho_inv_local + v_sound, gamma = speed_of_sound(u_local, equations) + + # pressure + p_local = pressure(u_local, equations) + + # Get the solution of the pressure Riemann problem + # See Section 6.3.3 of + # Eleuterio F. Toro (2009) + # Riemann Solvers and Numerical Methods for Fluid Dynamics: A Practical Introduction + # [DOI: 10.1007/b79761](https://doi.org/10.1007/b79761) + if v_normal <= 0.0 + p_star = p_local * + (1.0 + 0.5 * (gamma - 1) * v_normal / v_sound)^(2.0 * gamma * + inv(gamma - 1)) + else # v_normal > 0.0 + A = 2.0 / ((gamma + 1) * rho_local) + B = p_local * (gamma - 1) / (gamma + 1) + p_star = p_local + + 0.5 * v_normal / A * + (v_normal + sqrt(v_normal^2 + 4.0 * A * (p_local + B))) + end + + # For the slip wall we directly set the flux as the normal velocity is zero + return SVector(0.0, 0.0, 0.0, 0.0, + p_star * normal[1] * norm_, + p_star * normal[2] * norm_, + 0.0) +end + + +# same as in compressible_euler_2d.jl +@inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, direction, x, t, + surface_flux_function, equations::CompressibleRainyEulerEquationsExplicit2D) + # flip sign of normal to make it outward pointing, then flip the sign of the normal flux back + # to be inward pointing on the -x and -y sides due to the orientation convention used by StructuredMesh + if isodd(direction) + boundary_flux = -boundary_condition_slip_wall(u_inner, -normal_direction, + x, t, surface_flux_function, + equations) + else + boundary_flux = boundary_condition_slip_wall(u_inner, normal_direction, + x, t, surface_flux_function, + equations) + end + + return boundary_flux +end + + +# same as in compressible_euler_2d.jl +@inline function rotate_to_x(u, normal_vector, equations::CompressibleRainyEulerEquationsExplicit2D) + # cos and sin of the angle between the x-axis and the normalized normal_vector are + # the normalized vector's x and y coordinates respectively (see unit circle). + c = normal_vector[1] + s = normal_vector[2] + + return SVector(u[1], u[2], u[3], u[4], + c * u[5] + s * u[6], + -s * u[5] + c * u[6], + u[7]) +end + + +# should be used together with TreeMesh (adapted from compressible_euler_2d.jl) +@inline function boundary_condition_slip_wall(u_inner, orientation, direction, x, t, surface_flux_function, + equations::CompressibleRainyEulerEquationsExplicit2D) + # get the appropriate normal vector from the orientation + RealT = eltype(u_inner) + if orientation == 1 + normal_direction = SVector(one(RealT), zero(RealT)) + else # orientation == 2 + normal_direction = SVector(zero(RealT), one(RealT)) + end + + # compute and return the flux using `boundary_condition_slip_wall` routine above + return boundary_condition_slip_wall(u_inner, normal_direction, direction, + x, t, surface_flux_function, equations) +end + + +#= for parabolic terms (LaplaceDiffusion2D) +@inline function boundary_condition_laplace(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Trixi.Gradient, + equations_parabolic::LaplaceDiffusion2D) + return u_inner +end + +@inline function boundary_condition_laplace(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Trixi.Divergence, + equations_parabolic::LaplaceDiffusion2D) + return flux_inner +end=# + + +# Low Mach number approximate Riemann solver (LMARS) from +# X. Chen, N. Andronova, B. Van Leer, J. E. Penner, J. P. Boyd, C. Jablonowski, S. +# Lin, A Control-Volume Model of the Compressible Euler Equations with a Vertical Lagrangian +# Coordinate Monthly Weather Review Vol. 141.7, pages 2526–2544, 2013, +# https://journals.ametsoc.org/view/journals/mwre/141/7/mwr-d-12-00129.1.xml. +# adapted from compressible_moist_euler_2d.jl, does NOT work with rain! +@inline function flux_LMARS(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + a = 360.0 + + # densities + rho_dry_ll, rho_vapour_ll, rho_cloud_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) + rho_dry_rr, rho_vapour_rr, rho_cloud_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) + + # pressure + p_ll = pressure(u_ll, equations) + p_rr = pressure(u_rr, equations) + + # velocities + v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) + v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) + + v_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] + v_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] + norm_ = norm(normal_direction) + + # diffusion parameter 0.0 < beta <= 1.0 + beta = 1.0 + + # interface flux components + rho = 0.5 * (rho_ll + rho_rr) + p_interface = 0.5 * (p_ll + p_rr) - beta * 0.5 * a * rho * (v_rr - v_ll) / norm_ + v_interface = 0.5 * (v_ll + v_rr) - beta * 1 / (2 * a * rho) * (p_rr - p_ll) * norm_ + + if (v_interface > 0) + f1, f2, f3, _, f5, f6, f7 = u_ll * v_interface + f7 += p_ll * v_interface + else + f1, f2, f3, _, f5, f6, f7 = u_rr * v_interface + f7 += p_rr * v_interface + end + + return SVector(f1, f2, f3, 0.0, + f5 + p_interface * normal_direction[1], + f6 + p_interface * normal_direction[2], + f7) +end + + +# Adjusted EC flux in a normal direction with R_q=0. This is based on +# A. Gouasmi, K. Duraisamy, S. M. Murman, Formulation of Entropy-Stable schemes for the +# multicomponent compressible Euler equations, 4 Feb 2020, doi:10.1016/j.cma.2020.112912, +# https://arxiv.org/abs/1904.00972 [math.NA]. +# Adapted from compressible_moist_euler_2d.jl, careful, does NOT work for rain! +@inline function flux_chandrashekar(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + ref_L = equations.ref_latent_heat_vap_temp + R_q = 0.0 + + # densities and temperatures + rho_dry_ll, rho_vapour_ll, rho_cloud_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) + rho_dry_rr, rho_vapour_rr, rho_cloud_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) + temperature_ll = get_temperature(u_ll, equations) + temperature_rr = get_temperature(u_rr, equations) + + # velocities + v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) + v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) + vr_ll = terminal_velocity_rain(rho_vapour_ll + rho_cloud_ll, rho_rain_ll, equations) + vr_rr = terminal_velocity_rain(rho_vapour_rr + rho_cloud_rr, rho_rain_rr, equations) + + # mean values + rho_dry_mean = 0.0 + rho_vapour_mean = 0.0 + rho_cloud_mean = 0.0 + rho_rain_mean = 0.0 + inv_temperature_mean = 0.0 + + if (!(rho_dry_ll == 0.0) && !(rho_dry_rr == 0.0)) + rho_dry_mean = ln_mean(rho_dry_ll, rho_dry_rr) + end + + if (!(rho_vapour_ll == 0.0) && !(rho_vapour_rr == 0.0)) + rho_vapour_mean = ln_mean(rho_vapour_ll, rho_vapour_rr) + end + + if (!(rho_cloud_ll == 0.0) && !(rho_cloud_rr == 0.0)) + rho_cloud_mean = ln_mean(rho_cloud_ll, rho_cloud_rr) + end + + if (!(rho_rain_ll == 0.0) && !(rho_rain_rr == 0.0)) + rho_rain_mean = ln_mean(rho_rain_ll, rho_rain_rr) + end + + if (!(inv(temperature_ll) == 0.0) && !(inv(temperature_rr) == 0.0)) + inv_temperature_mean = inv_ln_mean(inv(temperature_ll), inv(temperature_rr)) + end + + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) + v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) + rho_dry_avg = 0.5 * (rho_dry_ll + rho_dry_rr) + rho_vapour_avg = 0.5 * (rho_vapour_ll + rho_vapour_rr) + rho_cloud_avg = 0.5 * (rho_cloud_ll + rho_cloud_rr) + rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) + inv_temperature_avg = 0.5 * (inv(temperature_ll) + inv(temperature_rr)) + v_dot_n_avg = normal_direction[1] * v1_avg + normal_direction[2] * v2_avg + + p_int = inv(inv_temperature_avg) * (R_d * rho_dry_avg + R_v * rho_vapour_avg + R_q * (rho_cloud_avg + rho_rain_avg)) + K_avg = 0.5 * (v1_square_avg + v2_square_avg) + vr_normal_avg = 0.5 * normal_direction[2] * (vr_ll + vr_rr) + rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) + + # assemble the flux + f_dry = rho_dry_mean * v_dot_n_avg + f_vapour = rho_vapour_mean * v_dot_n_avg + f_cloud = rho_cloud_mean * v_dot_n_avg + f_rain = rho_rain_avg * (v_dot_n_avg - vr_normal_avg) + f_rhov1 = (f_dry + f_vapour + f_cloud + f_rain) * v1_avg + normal_direction[1] * p_int + f_rhov2 = (f_dry + f_vapour + f_cloud + f_rain) * v2_avg + normal_direction[2] * p_int + f_energy = (( c_vd * inv_temperature_mean - K_avg) * f_dry + + (ref_L + c_vv * inv_temperature_mean - K_avg) * f_vapour + + ( c_l * inv_temperature_mean - K_avg) * (f_cloud + f_rain) + v1_avg * f_rhov1 + v2_avg * f_rhov2) + + return SVector(f_dry, f_vapour, f_cloud, f_rain, f_rhov1, f_rhov2, f_energy) +end + + +@inline function flux_ec_rain(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp + + # densities and temperatures + rho_dry_ll, rho_vapour_ll, rho_cloud_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) + rho_dry_rr, rho_vapour_rr, rho_cloud_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) + temperature_ll = get_temperature(u_ll, equations) + temperature_rr = get_temperature(u_rr, equations) + inv_temperature_ll = inv(temperature_ll) + inv_temperature_rr = inv(temperature_rr) + + # velocities + v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) + v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) + vr_ll = terminal_velocity_rain(rho_vapour_ll + rho_cloud_ll, rho_rain_ll, equations) + vr_rr = terminal_velocity_rain(rho_vapour_rr + rho_cloud_rr, rho_rain_rr, equations) + + # pressures + p_ll = pressure(u_ll, equations) + p_rr = pressure(u_rr, equations) + + # velocity averages + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) + v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) + v_square_avg = v1_square_avg + v2_square_avg + v_dot_n_avg = normal_direction[1] * v1_avg + normal_direction[2] * v2_avg + vr_normal_avg = 0.5 * normal_direction[2] * (vr_ll + vr_rr) + + # density averages + rho_dry_avg = 0.5 * (rho_dry_ll + rho_dry_rr) + rho_vapour_avg = 0.5 * (rho_vapour_ll + rho_vapour_rr) + rho_cloud_avg = 0.5 * (rho_cloud_ll + rho_cloud_rr) + rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) + + # density log means + rho_dry_log = 0.0 + rho_vapour_log = 0.0 + rho_cloud_log = 0.0 + rho_rain_log = 0.0 + + if (!(rho_dry_ll == 0.0) && !(rho_dry_rr == 0.0)) + rho_dry_log = ln_mean(rho_dry_ll, rho_dry_rr) + end + + if (!(rho_vapour_ll == 0.0) && !(rho_vapour_rr == 0.0)) + rho_vapour_log = ln_mean(rho_vapour_ll, rho_vapour_rr) + end + + if (!(rho_cloud_ll == 0.0) && !(rho_cloud_rr == 0.0)) + rho_cloud_log = ln_mean(rho_cloud_ll, rho_cloud_rr) + end + + if (!(rho_rain_ll == 0.0) && !(rho_rain_rr == 0.0)) + rho_rain_log = ln_mean(rho_rain_ll, rho_rain_rr) + end + + # other averages + p_avg = 0.5 * (p_ll + p_rr) + inv_temperature_avg = 0.5 * (inv_temperature_ll + inv_temperature_rr) + inv_temperature_log = ln_mean(inv_temperature_ll, inv_temperature_rr) + + # jumps + temperature_jump = temperature_rr - temperature_ll + inv_temperature_jump = inv_temperature_rr - inv_temperature_ll + v_jump = v1_rr - v1_ll + v2_rr - v2_ll + + # help variables + s_help = inv(inv_temperature_log) + + # density flux + f_vapour = rho_vapour_log * v_dot_n_avg + f_cloud = rho_cloud_avg * v_dot_n_avg + f_dry = rho_dry_log * v_dot_n_avg + f_rain = rho_rain_avg * (v_dot_n_avg - vr_normal_avg) + f_moist = f_vapour + f_cloud + f_rho = f_dry + f_moist + f_rain + + # momentum flux + f_rhov1 = f_rho * v1_avg + p_avg * normal_direction[1] + f_rhov2 = f_rho * v2_avg + p_avg * normal_direction[2] + + # energy flux + if !(isapprox(temperature_jump, 0.0, atol=1e-13)) + v_temp_jump = v_jump / inv_temperature_jump + f_energy = (c_vd * s_help - 0.5 * v_square_avg) * f_dry + (c_vv * s_help - 0.5 * v_square_avg + L_ref) * f_vapour + + (c_l * s_help - 0.5 * v_square_avg) * (f_cloud + f_rain) + + (v_temp_jump * inv_temperature_avg + v_dot_n_avg) * p_avg + + (v1_avg^2 + v2_avg^2) * f_rho - (R_d * rho_dry_avg + R_v * rho_vapour_avg) * v_temp_jump + else + f_energy = 0.0 + end + + return SVector(f_dry, f_vapour, f_cloud, f_rain, f_rhov1, f_rhov2, f_energy) +end + +@inline function flux_ec_rain(u_ll, u_rr, orientation::Int, equations::CompressibleRainyEulerEquationsExplicit2D) + if (orientation == 1) + return flux_ec_rain(u_ll, u_rr, SVector(1, 0), equations) + else + return flux_ec_rain(u_ll, u_rr, SVector(0, 1), equations) + end +end + +end # muladd end \ No newline at end of file diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 81a4306f..11fdbdcd 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -9,4 +9,5 @@ abstract type AbstractCompressibleRainyEulerEquations{NDIMS, NVARS} <: include("compressible_rainy_euler_2d.jl") include("compressible_moist_euler_2d_lucas.jl") include("compressible_rainy_euler_potential_temperature_2d.jl") -include("compressible_moist_euler_potential_temperature_2d.jl") \ No newline at end of file +include("compressible_moist_euler_potential_temperature_2d.jl") +include("compressible_rainy_euler_explicit_2d.jl") \ No newline at end of file From 3af24d5f4404628f71523c7a2bfb741f93966975 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 12 Feb 2025 19:31:40 +0100 Subject: [PATCH 093/115] convergence test update with results --- .../convergence_test_rainy_dry.jl | 49 +++++++++++++++++-- .../convergence_test_rainy_no_rain.jl | 29 ++++++++++- 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/examples/convergence_test_elixirs/convergence_test_rainy_dry.jl b/examples/convergence_test_elixirs/convergence_test_rainy_dry.jl index 40ca7f83..30dfd846 100644 --- a/examples/convergence_test_elixirs/convergence_test_rainy_dry.jl +++ b/examples/convergence_test_elixirs/convergence_test_rainy_dry.jl @@ -69,7 +69,7 @@ solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) coordinates_min = (0.0, 0.0) coordinates_max = (2.0, 2.0) -cells_per_dimension = (16, 16) +cells_per_dimension = (8, 8) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) @@ -109,5 +109,48 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), save_everystep = false, callback = callbacks); summary_callback() # print the timer summary -# For copy-paste convenience: -#convergence_test("TrixiAtmo.jl/examples/convergence_test_elixirs/convergence_test_rainy_dry.jl", 4) \ No newline at end of file + +#= For copy-paste convenience: +#convergence_test("TrixiAtmo.jl/examples/convergence_test_elixirs/convergence_test_rainy_dry.jl", 5) + +#################################################################################################### +l2 +rho_dry rho_moist rho_rain rho_v1 rho_v2 energy_density rho_vapour rho_cloud temperature +error EOC error EOC error EOC error EOC error EOC error EOC error EOC error EOC error +EOC +2.80e-05 - 0.00e+00 - 0.00e+00 - 2.90e-05 - 2.90e-05 - 9.66e-05 - 0.00e+00 - 0.00e+00 - 0.00e+00 +- +9.30e-07 4.91 0.00e+00 NaN 0.00e+00 NaN 1.42e-06 4.36 1.42e-06 4.36 4.82e-06 4.32 0.00e+00 NaN 0.00e+00 NaN 0.00e+00 +NaN +7.00e-08 3.73 0.00e+00 NaN 0.00e+00 NaN 9.51e-08 3.90 9.51e-08 3.90 3.29e-07 3.87 0.00e+00 NaN 0.00e+00 NaN 0.00e+00 +NaN +4.64e-09 3.92 0.00e+00 NaN 0.00e+00 NaN 6.08e-09 3.97 6.08e-09 3.97 2.12e-08 3.95 0.00e+00 NaN 0.00e+00 NaN 0.00e+00 +NaN +2.93e-10 3.98 0.00e+00 NaN 0.00e+00 NaN 3.82e-10 3.99 3.82e-10 3.99 1.33e-09 3.99 0.00e+00 NaN 0.00e+00 NaN 0.00e+00 +NaN + +mean 4.14 mean NaN mean NaN mean 4.05 mean 4.05 mean 4.04 mean NaN mean NaN mean +NaN +---------------------------------------------------------------------------------------------------- +linf +rho_dry rho_moist rho_rain rho_v1 rho_v2 energy_density rho_vapour rho_cloud temperature +error EOC error EOC error EOC error EOC error EOC error EOC error EOC error EOC error +EOC +1.97e-04 - 0.00e+00 - 0.00e+00 - 2.02e-04 - 2.02e-04 - 8.91e-04 - 0.00e+00 - 0.00e+00 - 0.00e+00 +- +9.62e-06 4.36 0.00e+00 NaN 0.00e+00 NaN 1.17e-05 4.10 1.17e-05 4.10 4.89e-05 4.19 0.00e+00 NaN 0.00e+00 NaN 0.00e+00 +NaN +6.24e-07 3.95 0.00e+00 NaN 0.00e+00 NaN 7.49e-07 3.97 7.49e-07 3.97 3.23e-06 3.92 0.00e+00 NaN 0.00e+00 NaN 0.00e+00 +NaN +4.06e-08 3.94 0.00e+00 NaN 0.00e+00 NaN 4.97e-08 3.91 4.97e-08 3.91 2.10e-07 3.94 0.00e+00 NaN 0.00e+00 NaN 0.00e+00 +NaN +2.55e-09 3.99 0.00e+00 NaN 0.00e+00 NaN 3.19e-09 3.96 3.19e-09 3.96 1.34e-08 3.97 0.00e+00 NaN 0.00e+00 NaN 0.00e+00 +NaN + +mean 4.06 mean NaN mean NaN mean 3.99 mean 3.99 mean 4.00 mean NaN mean NaN mean +NaN +---------------------------------------------------------------------------------------------------- +Dict{Symbol, Any} with 3 entries: + :variables => ("rho_dry", "rho_moist", "rho_rain", "rho_v1", "rho_v2", "energy_density", "rho_vapour", "rho_cloud", "temperature") + :l2 => [4.13577, NaN, NaN, 4.05385, 4.05385, 4.03601, NaN, NaN, NaN] + :linf => [4.05911, NaN, NaN, 3.9867, 3.98669, 4.00476, NaN, NaN, NaN]=# \ No newline at end of file diff --git a/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl b/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl index b704e2a9..f78284ca 100644 --- a/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl +++ b/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl @@ -163,4 +163,31 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limite summary_callback() # print the timer summary # For copy-paste convenience: -#convergence_test("TrixiAtmo.jl/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl", 4) \ No newline at end of file +#convergence_test("TrixiAtmo.jl/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl", 4) +#= +#################################################################################################### +l2 +rho_dry rho_moist rho_rain rho_v1 rho_v2 energy_density rho_vapour rho_cloud temperature +error EOC error EOC error EOC error EOC error EOC error EOC error EOC error EOC error EOC +8.26e-07 - 1.87e-05 - 0.00e+00 - 7.47e-03 - 7.47e-03 - 1.92e+01 - 2.62e-08 - 1.87e-05 - 3.23e-04 - +4.38e-08 4.24 9.63e-07 4.28 0.00e+00 NaN 2.13e-04 5.13 2.13e-04 5.13 1.01e+00 4.25 8.68e-10 4.91 9.63e-07 4.28 1.07e-05 4.91 +2.69e-09 4.02 5.86e-08 4.04 0.00e+00 NaN 7.04e-06 4.92 7.04e-06 4.92 6.23e-02 4.03 3.61e-11 4.59 5.86e-08 4.04 4.46e-07 4.58 +1.68e-10 4.01 3.61e-09 4.02 0.00e+00 NaN 2.78e-07 4.66 2.78e-07 4.66 3.87e-03 4.01 1.06e-12 5.09 3.61e-09 4.02 1.32e-08 5.08 + +mean 4.09 mean 4.11 mean NaN mean 4.90 mean 4.90 mean 4.09 mean 4.86 mean 4.11 mean +4.86 +---------------------------------------------------------------------------------------------------- +linf +rho_dry rho_moist rho_rain rho_v1 rho_v2 energy_density rho_vapour rho_cloud temperature +error EOC error EOC error EOC error EOC error EOC error EOC error EOC error EOC error EOC +6.66e-06 - 1.45e-04 - 0.00e+00 - 1.55e-02 - 1.55e-02 - 1.54e+02 - 1.24e-07 - 1.45e-04 - 1.54e-03 - +3.51e-07 4.25 8.00e-06 4.18 0.00e+00 NaN 4.91e-04 4.98 4.91e-04 4.98 8.24e+00 4.23 3.85e-09 5.01 8.00e-06 4.18 4.78e-05 5.01 +1.92e-08 4.19 4.16e-07 4.26 0.00e+00 NaN 1.81e-05 4.76 1.81e-05 4.76 4.46e-01 4.21 1.58e-10 4.61 4.16e-07 4.26 1.94e-06 4.62 +1.17e-09 4.03 2.53e-08 4.04 0.00e+00 NaN 8.48e-07 4.42 8.48e-07 4.42 2.72e-02 4.04 5.63e-12 4.81 2.53e-08 4.04 6.94e-08 4.81 + +mean 4.16 mean 4.16 mean NaN mean 4.72 mean 4.72 mean 4.16 mean 4.81 mean 4.16 mean 4.81 +---------------------------------------------------------------------------------------------------- +Dict{Symbol, Any} with 3 entries: + :variables => ("rho_dry", "rho_moist", "rho_rain", "rho_v1", "rho_v2", "energy_density", "rho_vapour", "rho_cloud", "temperature") + :l2 => [4.08874, 4.11293, NaN, 4.90375, 4.90375, 4.09297, 4.86169, 4.11317, 4.85982] + :linf => [4.1567, 4.161, NaN, 4.71912, 4.71912, 4.15581, 4.8092, 4.16105, 4.81099]=# \ No newline at end of file From 0c06d2709fc1130cc15197e163856200aa0eda86 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 12 Feb 2025 19:33:17 +0100 Subject: [PATCH 094/115] introduced boundary_condition_simple_slip_wall for compatibilty with rain --- ...ixir_rainy_euler_rainy_bubble_diffusion.jl | 7 +-- src/equations/compressible_rainy_euler_2d.jl | 52 ++++++++++++++++--- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl index e27b59fd..27e893bf 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl @@ -7,6 +7,7 @@ using TrixiAtmo: source_terms_rainy, saturation_residual, flux_chandrashekar, flux_LMARS, source_terms_no_phase_change, boundary_condition_laplace, + boundary_condition_simple_slip_wall, flux_ec_rain using NLsolve: nlsolve #using Plots @@ -227,8 +228,8 @@ equations_parabolic = LaplaceDiffusion2D(diffusivity, equations) boundary_conditions = (x_neg = boundary_condition_periodic, x_pos = boundary_condition_periodic, - y_neg = boundary_condition_slip_wall, - y_pos = boundary_condition_slip_wall) + y_neg = boundary_condition_simple_slip_wall, + y_pos = boundary_condition_simple_slip_wall) boundary_conditions_parabolic = ( x_neg = boundary_condition_periodic, @@ -256,7 +257,7 @@ semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabol ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 1000.0) +tspan = (0.0, 600.0) ode = semidiscretize(semi, tspan) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 53b21003..6122badf 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -536,13 +536,8 @@ end S_auto_conversion = 0.001 * rho_cloud S_accretion = 1.72 * rho_cloud * rho_rain^(0.875) S_rain = S_auto_conversion + S_accretion - S_evaporation - S_groundwater = 0.0 - - if (x[2] < 100.0) - S_groundwater = rho_rain * (1 - (x[2] * 0.01)^2) - end - return SVector(0.0, -S_rain, S_rain - S_groundwater, 0.0, + return SVector(0.0, -S_rain, S_rain, 0.0, -rho * g, -rho_v2 * g, 0.0, 0.0, 0.0) end @@ -1054,4 +1049,47 @@ end end end -end # muladd end \ No newline at end of file +end # muladd end + + +# adapted from ShallowWaterEquations2D (Recommended with rain!) +@inline function boundary_condition_simple_slip_wall(u_inner, normal_direction::AbstractVector, x, t, surface_flux_function, + equations::CompressibleRainyEulerEquations2D) + # normalize the outward pointing direction + normal = normal_direction / norm(normal_direction) + + # compute the normal velocity + u_normal = normal[1] * u_inner[2] + normal[2] * u_inner[5] + + # create the "external" boundary solution state + u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], + u_inner[4] - 2 * u_normal * normal[5], + u_inner[5] - 2 * u_normal * normal[4], + u_inner[6], u_inner[7], u_inner[8], u_inner[9]) + + # calculate the boundary flux + flux = surface_flux_function(u_inner, u_boundary, normal_direction, equations) + + return flux +end + + +# adapted from ShallowWaterEquations2D (Recommended with rain!) +@inline function boundary_condition_simple_slip_wall(u_inner, orientation, direction, x, t, surface_flux_function, + equations::CompressibleRainyEulerEquations2D) + ## get the appropriate normal vector from the orientation + if orientation == 1 + u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], -u_inner[4], u_inner[5], u_inner[6], u_inner[7], u_inner[8], u_inner[9]) + else # orientation == 2 + u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], u_inner[4], -u_inner[5], u_inner[6], u_inner[7], u_inner[8], u_inner[9]) + end + + # Calculate boundary flux + if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary + flux = surface_flux_function(u_inner, u_boundary, orientation, equations) + else # u_boundary is "left" of boundary, u_inner is "right" of boundary + flux = surface_flux_function(u_boundary, u_inner, orientation, equations) + end + + return flux +end \ No newline at end of file From 9771cc65a8d1eb362942e0abe614311fee2464a9 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 12 Feb 2025 19:34:07 +0100 Subject: [PATCH 095/115] removed rain-cutting experimental cases --- src/callbacks_stage/nonlinear_solve_dg2d.jl | 4 +--- src/callbacks_stage/rain_limiter_dg2d.jl | 4 +--- src/equations/compressible_rainy_euler_explicit_2d.jl | 7 +------ 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/callbacks_stage/nonlinear_solve_dg2d.jl b/src/callbacks_stage/nonlinear_solve_dg2d.jl index 75c5b29c..1317e0d5 100644 --- a/src/callbacks_stage/nonlinear_solve_dg2d.jl +++ b/src/callbacks_stage/nonlinear_solve_dg2d.jl @@ -22,10 +22,8 @@ function nonlinear_solve_dg_2d!(u, residual, jacobian, variables_index_vector, t u_node = get_node_vars(u, equations, dg, i, j, element) guess = SVector(u_node[7], u_node[8], u_node[9]) - x_node = get_node_coords(cache.elements.node_coordinates, equations, dg, i, j, element) - # keep rain positive - if (u_node[3] < 0.0 || x_node[2] < 50.0) + if (u_node[3] < 0.0) u[3, i, j, element] = 0.0 end diff --git a/src/callbacks_stage/rain_limiter_dg2d.jl b/src/callbacks_stage/rain_limiter_dg2d.jl index 5fae9a15..6619bccc 100644 --- a/src/callbacks_stage/rain_limiter_dg2d.jl +++ b/src/callbacks_stage/rain_limiter_dg2d.jl @@ -16,10 +16,8 @@ function rain_limiter_dg2d!(u, topography, u_node = get_node_vars(u, equations, dg, i, j, element) - x_node = get_node_coords(cache.elements.node_coordinates, equations, dg, i, j, element) - # keep rho_rain positive - if (u_node[4] < 0.0 || (x_node[2] + topography(x_node[1])) < 50.0) + if (u_node[4] < 0.0) u[4, i, j, element] = 0.0 end diff --git a/src/equations/compressible_rainy_euler_explicit_2d.jl b/src/equations/compressible_rainy_euler_explicit_2d.jl index a056825d..f3b0fbb2 100644 --- a/src/equations/compressible_rainy_euler_explicit_2d.jl +++ b/src/equations/compressible_rainy_euler_explicit_2d.jl @@ -506,13 +506,8 @@ end S_auto_conversion = 0.001 * rho_cloud S_accretion = 1.72 * rho_cloud * rho_rain^(0.875) S_rain = S_auto_conversion + S_accretion - S_evaporation - S_groundwater = 0.0 - - if (x[2] < 100.0) - S_groundwater = rho_rain * (1 - (x[2] * 0.01)^2) - end - return SVector(0.0, Q_ph + S_evaporation, -Q_ph - S_auto_conversion - S_accretion, S_rain - S_groundwater, 0.0, + return SVector(0.0, Q_ph + S_evaporation, -Q_ph - S_auto_conversion - S_accretion, S_rain, 0.0, -rho * g, -rho_v2 * g) end From fbd1526e08aa9ed459a99c58e5d9c626a319e913 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Fri, 21 Feb 2025 23:14:40 +0100 Subject: [PATCH 096/115] removed unnecessary parameter from rain limiter --- src/callbacks_stage/rain_limiter_dg.jl | 3 +-- src/callbacks_stage/rain_limiter_dg2d.jl | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/callbacks_stage/rain_limiter_dg.jl b/src/callbacks_stage/rain_limiter_dg.jl index fc2dcdbe..13b54d6e 100644 --- a/src/callbacks_stage/rain_limiter_dg.jl +++ b/src/callbacks_stage/rain_limiter_dg.jl @@ -5,7 +5,6 @@ using Trixi: wrap_array, TimerOutputs, @trixi_timeit, timer @muladd begin struct RainLimiterDG - topography::Function end @@ -13,7 +12,7 @@ function (limiter!::RainLimiterDG)(u_ode, integrator, semi::AbstractSemidiscreti u = wrap_array(u_ode, semi) @trixi_timeit timer() "rain limiter" begin - rain_limiter_dg2d!(u, limiter!.topography, semi.equations, semi.solver, semi.cache, semi.mesh) + rain_limiter_dg2d!(u, semi.equations, semi.solver, semi.cache, semi.mesh) end end diff --git a/src/callbacks_stage/rain_limiter_dg2d.jl b/src/callbacks_stage/rain_limiter_dg2d.jl index 6619bccc..8e0395af 100644 --- a/src/callbacks_stage/rain_limiter_dg2d.jl +++ b/src/callbacks_stage/rain_limiter_dg2d.jl @@ -6,8 +6,7 @@ using StaticArrays @muladd begin -function rain_limiter_dg2d!(u, topography, - equations::AbstractCompressibleRainyEulerEquations, dg::DGSEM, cache, mesh) +function rain_limiter_dg2d!(u, equations::AbstractCompressibleRainyEulerEquations, dg::DGSEM, cache, mesh) # iterate over every DGSEM element @batch for element in eachelement(dg, cache) From 2d27987486ed74ac3916367b5a7f4288a9b71976 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Fri, 21 Feb 2025 23:28:48 +0100 Subject: [PATCH 097/115] ec flux and slip wall testing and fixes --- ...iny_euler_explicit_moist_bubble_ec_test.jl | 288 ++++++++++++++++++ ...rainy_euler_explicit_weak_blast_wave_2d.jl | 135 ++++++++ .../energy/elixir_rainy_euler_moist_bubble.jl | 5 +- ...lixir_rainy_euler_explicit_rainy_bubble.jl | 4 +- ...y_euler_explicit_rainy_bubble_diffusion.jl | 10 +- .../elixir_rainy_euler_rainy_bubble.jl | 7 +- src/equations/compressible_rainy_euler_2d.jl | 99 +++--- .../compressible_rainy_euler_explicit_2d.jl | 116 ++++--- 8 files changed, 559 insertions(+), 105 deletions(-) create mode 100644 examples/entropy_conservation_tests/moist_bubble/elixir_rainy_euler_explicit_moist_bubble_ec_test.jl create mode 100644 examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_2d.jl diff --git a/examples/entropy_conservation_tests/moist_bubble/elixir_rainy_euler_explicit_moist_bubble_ec_test.jl b/examples/entropy_conservation_tests/moist_bubble/elixir_rainy_euler_explicit_moist_bubble_ec_test.jl new file mode 100644 index 00000000..94dc2ce9 --- /dev/null +++ b/examples/entropy_conservation_tests/moist_bubble/elixir_rainy_euler_explicit_moist_bubble_ec_test.jl @@ -0,0 +1,288 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: source_terms_moist, saturation_residual, + saturation_residual_jacobian, NonlinearSolveDG, + cons2eq_pot_temp, flux_LMARS, flux_ec_rain +using NLsolve: nlsolve + + + +# Initial condition from elixir_moist_euler_bubble.jl +function moist_state(y, dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) + + @unpack p_0, g, c_pd, c_pv, c_vd, c_vv, R_d, R_v, c_pl, L_00 = equations + g = 0.0 + (p, rho, T, r_t, r_v, rho_qv, theta_e) = y + p0 = y0[1] + + F = zeros(7, 1) + rho_d = rho / (1 + r_t) + p_d = R_d * rho_d * T + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + L = L_00 - (c_pl - c_pv) * T + + F[1] = (p - p0) / dz + g * rho + F[2] = p - (R_d * rho_d + R_v * rho_qv) * T + # H = 1 is assumed + F[3] = (theta_e - + T * (p_d / p_0)^(-R_d / (c_pd + c_pl * r_t)) * + exp(L * r_v / ((c_pd + c_pl * r_t) * T))) + F[4] = r_t - r_t0 + F[5] = rho_qv - rho_d * r_v + F[6] = theta_e - theta_e0 + a = p_vs / (R_v * T) - rho_qv + b = rho - rho_qv - rho_d + # H=1 => phi=0 + F[7] = a + b - sqrt(a * a + b * b) + + return F +end + +function generate_function_of_y(dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) + function function_of_y(y) + return moist_state(y, dz, y0, r_t0, theta_e0, equations) + end +end + +struct AtmosphereLayers{RealT <: Real} + equations::CompressibleMoistEulerEquations2D + # structure: 1--> i-layer (z = total_height/precision *(i-1)), 2--> rho, rho_theta, rho_qv, rho_ql + layer_data::Matrix{RealT} + total_height::RealT + preciseness::Int + layers::Int + ground_state::NTuple{2, RealT} + equivalent_potential_temperature::RealT + mixing_ratios::NTuple{2, RealT} +end + +function AtmosphereLayers(equations; total_height = 10010.0, preciseness = 10, + ground_state = (1.4, 100000.0), + equivalent_potential_temperature = 320, + mixing_ratios = (0.02, 0.02), RealT = Float64) + + @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl = equations + rho0, p0 = ground_state + r_t0, r_v0 = mixing_ratios + theta_e0 = equivalent_potential_temperature + + rho_qv0 = rho0 * r_v0 + T0 = theta_e0 + y0 = [p0, rho0, T0, r_t0, r_v0, rho_qv0, theta_e0] + + n = convert(Int, total_height / preciseness) + dz = 0.01 + layer_data = zeros(RealT, n + 1, 4) + + F = generate_function_of_y(dz, y0, r_t0, theta_e0, equations) + sol = nlsolve(F, y0) + p, rho, T, r_t, r_v, rho_qv, theta_e = sol.zero + + rho_d = rho / (1 + r_t) + rho_ql = rho - rho_d - rho_qv + kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * (p0 / p)^kappa_M * T * (1 + (R_v / R_d) * r_v) / (1 + r_t) + + layer_data[1, :] = [rho, rho_theta, rho_qv, rho_ql] + for i in (1:n) + y0 = deepcopy(sol.zero) + dz = preciseness + F = generate_function_of_y(dz, y0, r_t0, theta_e0, equations) + sol = nlsolve(F, y0) + p, rho, T, r_t, r_v, rho_qv, theta_e = sol.zero + + rho_d = rho / (1 + r_t) + rho_ql = rho - rho_d - rho_qv + kappa_M = (R_d * rho_d + R_v * rho_qv) / + (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * (p0 / p)^kappa_M * T * (1 + (R_v / R_d) * r_v) / (1 + r_t) + + layer_data[i + 1, :] = [rho, rho_theta, rho_qv, rho_ql] + end + + return AtmosphereLayers{RealT}(equations, layer_data, total_height, dz, n, ground_state, + theta_e0, mixing_ratios) +end + +# Moist bubble test case from paper: +# G.H. Bryan, J.M. Fritsch, A Benchmark Simulation for Moist Nonhydrostatic Numerical +# Models, MonthlyWeather Review Vol.130, 2917–2928, 2002, +# https://journals.ametsoc.org/view/journals/mwre/130/12/1520-0493_2002_130_2917_absfmn_2.0.co_2.xml. +function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, atmosphere_layers::AtmosphereLayers) + @unpack layer_data, preciseness, total_height = atmosphere_layers + dz = preciseness + z = x[2] + if (z > total_height && !(isapprox(z, total_height))) + error("The atmosphere does not match the simulation domain") + end + n = convert(Int, floor((z + eps()) / dz)) + 1 + z_l = (n - 1) * dz + (rho_l, rho_theta_l, rho_qv_l, rho_ql_l) = layer_data[n, :] + z_r = n * dz + if (z_l == total_height) + z_r = z_l + dz + n = n - 1 + end + (rho_r, rho_theta_r, rho_qv_r, rho_ql_r) = layer_data[n + 1, :] + rho = (rho_r * (z - z_l) + rho_l * (z_r - z)) / dz + rho_theta = rho * (rho_theta_r / rho_r * (z - z_l) + rho_theta_l / rho_l * (z_r - z)) / + dz + rho_qv = rho * (rho_qv_r / rho_r * (z - z_l) + rho_qv_l / rho_l * (z_r - z)) / dz + rho_ql = rho * (rho_ql_r / rho_r * (z - z_l) + rho_ql_l / rho_l * (z_r - z)) / dz + + rho, rho_e, rho_qv, rho_ql, T_loc = perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, + equations::CompressibleMoistEulerEquations2D) + + v1 = 1.0 + v2 = 1.0 + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_E = rho_e + 1 / 2 * rho * (v1^2 + v2^2) + + return SVector(rho - rho_qv - rho_ql, rho_qv, rho_ql, 0.0, rho_v1, rho_v2, rho_E) +end + +function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, + equations::CompressibleMoistEulerEquations2D) + @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl, L_00 = equations + xc = 10000.0 + zc = 2000.0 + rc = 2000.0 + Δθ = 2.0 + + r = sqrt((x[1] - xc)^2 + (x[2] - zc)^2) + rho_d = rho - rho_qv - rho_ql + kappa_M = (R_d * rho_d + R_v * rho_qv) / (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + p_loc = p_0 * (R_d * rho_theta / p_0)^(1 / (1 - kappa_M)) + T_loc = p_loc / (R_d * rho_d + R_v * rho_qv) + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv + + # Assume pressure stays constant + if (r < rc && Δθ > 0) + # Calculate background density potential temperature + θ_dens = rho_theta / rho * (p_loc / p_0)^(kappa_M - kappa) + # Calculate perturbed density potential temperature + θ_dens_new = θ_dens * (1 + Δθ * cospi(0.5 * r / rc)^2 / 300) + rt = (rho_qv + rho_ql) / rho_d + rv = rho_qv / rho_d + # Calculate moist potential temperature + θ_loc = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rv) + # Adjust varuables until the temperature is met + if rt > 0 + while true + T_loc = θ_loc * (p_loc / p_0)^kappa + T_C = T_loc - 273.15 + # SaturVapor + pvs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + rho_d_new = (p_loc - pvs) / (R_d * T_loc) + rvs = pvs / (R_v * rho_d_new * T_loc) + θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) + if abs(θ_new - θ_loc) <= θ_loc * 1.0e-12 + break + else + θ_loc = θ_new + end + end + else + rvs = 0 + T_loc = θ_loc * (p_loc / p_0)^kappa + rho_d_new = p_loc / (R_d * T_loc) + θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) + end + # test + #T_loc = θ_new * (p_loc / p_0)^kappa + # + rho_qv = rvs * rho_d_new + rho_ql = (rt - rvs) * rho_d_new + rho = rho_d_new * (1 + rt) + rho_d = rho - rho_qv - rho_ql + kappa_M = (R_d * rho_d + R_v * rho_qv) / + (c_pd * rho_d + c_pv * rho_qv + c_pl * rho_ql) + rho_theta = rho * θ_dens_new * (p_loc / p_0)^(kappa - kappa_M) + rho_e = (c_vd * rho_d + c_vv * rho_qv + c_pl * rho_ql) * T_loc + L_00 * rho_qv + end + return SVector(rho, rho_e, rho_qv, rho_ql, T_loc) +end + +# Create background atmosphere data set +atmosphere_data = AtmosphereLayers(CompressibleMoistEulerEquations2D()) + +# Create the initial condition with the initial data set +function initial_condition_moist(x, t, equations::CompressibleRainyEulerEquationsExplicit2D) + return initial_condition_moist_bubble(x, t, CompressibleMoistEulerEquations2D(), atmosphere_data) +end + + + +############################################################################### +# semidiscretization of the compressible rainy Euler equations + +equations = CompressibleRainyEulerEquationsExplicit2D() + +boundary_conditions = (x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_periodic, + y_pos = boundary_condition_periodic) + +polydeg = 3 +basis = LobattoLegendreBasis(polydeg) + + +volume_flux = flux_ec_rain +surface_flux = volume_flux +volume_integral = VolumeIntegralFluxDifferencing(volume_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + +coordinates_min = ( 0.0, 0.0) +coordinates_max = (20_000.0, 10_000.0) + +cells_per_dimension = (64, 32) +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, + periodicity = (true, true)) + +semi = SemidiscretizationHyperbolic(mesh, equations, + initial_condition_moist, solver, + boundary_conditions = boundary_conditions) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 1000.0) + +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 + + +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + extra_analysis_errors = (:entropy_conservation_error,)) + +alive_callback = AliveCallback(analysis_interval = 1000) + +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + output_directory = "out", + solution_variables = cons2eq_pot_temp) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) + +############################################################################### +# run the simulation +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + maxiters = 1.0e7, + dt = 1.0, + save_everystep = false, callback = callbacks); + +summary_callback() \ No newline at end of file diff --git a/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_2d.jl b/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_2d.jl new file mode 100644 index 00000000..6cf2622b --- /dev/null +++ b/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_2d.jl @@ -0,0 +1,135 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: saturation_residual, saturation_residual_jacobian, + flux_ec_rain, saturation_vapour_pressure, flux_chandrashekar, + RainLimiterDG, cons2eq_pot_temp + + +function initial_condition_weak_blast_wave(x, t, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp + + if sqrt(x[1]^2 + x[2]^2) > 0.5 + rho = 1.0 + v1 = 0.0 + v2 = 0.0 + p = 1.0 + else + phi = atan(x[2], x[1]) + rho = 1.1691 + v1 = 0.1882 * cos(phi) + v2 = 0.1882 * sin(phi) + p = 1.245 + end + + rho_dry = 0.4 * rho + rho_vapour = 0.4 * rho + rho_cloud = 0.1 * rho + rho_rain = 0.1 * rho + + T = p / (rho_dry * R_d + rho_vapour * R_v) + + energy_density = (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * T + energy_density += L_ref * rho_vapour + 0.5 * rho * (v1^2 + v2^2) + + return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, rho * v1, rho * v2, energy_density) +end + + +function initial_condition_weak_blast_wave_dry(x, t, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + c_vd = equations.c_dry_air_const_volume + R_d = equations.R_dry_air + + if sqrt(x[1]^2 + x[2]^2) > 0.5 + rho = 1.0 + v1 = 0.0 + v2 = 0.0 + p = 1.0 + else + phi = atan(x[2], x[1]) + rho = 1.1691 + v1 = 0.1882 * cos(phi) + v2 = 0.1882 * sin(phi) + p = 1.245 + end + + rho_dry = rho + T = p / (rho_dry * R_d) + + energy_density = c_vd * rho_dry * T + energy_density += 0.5 * rho * (v1^2 + v2^2) + + return SVector(rho_dry, 0.0, 0.0, 0.0, rho * v1, rho * v2, energy_density) +end + + + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleRainyEulerEquationsExplicit2D() + +initial_condition = initial_condition_weak_blast_wave + +polydeg = 3 +basis = LobattoLegendreBasis(polydeg) + +volume_flux = flux_ec_rain +surface_flux = volume_flux +solver = DGSEM(basis, surface_flux, VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = (-2.0, -2.0) +coordinates_max = ( 2.0, 2.0) + +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 5, + n_cells_max = 1_000_000, + periodicity = true) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_condition_periodic) + + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 1.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + output_directory = "out", + solution_variables = cons2eq_pot_temp) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) + +stage_limiter! = RainLimiterDG() + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limiter!), + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); +summary_callback() # print the timer summary \ No newline at end of file diff --git a/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl b/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl index 25d3574e..ecea985b 100644 --- a/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl +++ b/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl @@ -3,7 +3,8 @@ using Trixi using TrixiAtmo using TrixiAtmo: source_terms_no_phase_change, saturation_residual, saturation_residual_jacobian, NonlinearSolveDG, - cons2eq_pot_temp, flux_LMARS, flux_chandrashekar + cons2eq_pot_temp, flux_LMARS, flux_chandrashekar, + flux_ec_rain using NLsolve: nlsolve @@ -231,7 +232,7 @@ basis = LobattoLegendreBasis(polydeg) #surface_flux = flux_lax_friedrichs surface_flux = flux_LMARS -volume_flux = flux_chandrashekar +volume_flux = flux_ec_rain volume_integral = VolumeIntegralFluxDifferencing(volume_flux) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl index 82398349..8b84ac91 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl @@ -268,9 +268,7 @@ callbacks = CallbackSet(summary_callback, save_solution, stepsize_callback) -topography(x_1) = 0.0 - -stage_limiter! = RainLimiterDG(topography) +stage_limiter! = RainLimiterDG() ############################################################################### # run the simulation diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl index 9db5f46c..181fbe47 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl @@ -7,7 +7,8 @@ using TrixiAtmo: source_terms_rainy, saturation_residual, flux_chandrashekar, flux_LMARS, source_terms_no_phase_change, boundary_condition_laplace, - flux_ec_rain + flux_ec_rain, + boundary_condition_simple_slip_wall using NLsolve: nlsolve #using Plots @@ -227,8 +228,8 @@ equations_parabolic = LaplaceDiffusion2D(diffusivity, equations) boundary_conditions = (x_neg = boundary_condition_periodic, x_pos = boundary_condition_periodic, - y_neg = boundary_condition_slip_wall, - y_pos = boundary_condition_slip_wall) + y_neg = boundary_condition_simple_slip_wall, + y_pos = boundary_condition_simple_slip_wall) boundary_conditions_parabolic = ( x_neg = boundary_condition_periodic, @@ -283,9 +284,8 @@ callbacks = CallbackSet(summary_callback, alive_callback, save_solution, stepsize_callback) -topography(x_1) = 0.0 -stage_limiter! = RainLimiterDG(topography) +stage_limiter! = RainLimiterDG() ############################################################################### # run the simulation diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl index 95179ec0..d37dcfe2 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl @@ -5,7 +5,8 @@ using TrixiAtmo: source_terms_rainy, saturation_residual, saturation_residual_jacobian, NonlinearSolveDG, cons2eq_pot_temp, saturation_vapour_pressure, flux_chandrashekar, flux_LMARS, flux_ec_rain, - source_terms_no_phase_change + source_terms_no_phase_change, + boundary_condition_simple_slip_wall using NLsolve: nlsolve #using Plots @@ -218,8 +219,8 @@ end boundary_conditions = (x_neg = boundary_condition_periodic, x_pos = boundary_condition_periodic, - y_neg = boundary_condition_slip_wall, - y_pos = boundary_condition_slip_wall) + y_neg = boundary_condition_simple_slip_wall, + y_pos = boundary_condition_simple_slip_wall) polydeg = 4 basis = LobattoLegendreBasis(polydeg) diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index 6122badf..abfc7fe5 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -124,8 +124,15 @@ end v1, v2 = velocities(u, rho_inv, equations) v_squared_temp = 0.5 * (v1^2 + v2^2) * inv_temperature - omega_dry = c_vd * ln_temperature - R_d * log(rho_dry) + v_squared_temp - c_vd - R_d - omega_vapour = c_vv * ln_temperature - R_v * log(rho_vapour) + v_squared_temp - c_vv - R_v - L_ref * inv_temperature + # check for zero density + rho_vapour_log = 0.0 + + if (rho_vapour > 0.0) + rho_vapour_log = log(rho_vapour) + end + + omega_dry = c_vd * ln_temperature - R_d * log(rho_dry) + v_squared_temp - c_vd - R_d + omega_vapour = c_vv * ln_temperature - R_v * rho_vapour_log + v_squared_temp - c_vv - R_v - L_ref * inv_temperature omega_liquid = c_l * ln_temperature + v_squared_temp - c_l omega_momentum_1 = -v1 * inv_temperature omega_momentum_2 = -v2 * inv_temperature @@ -925,6 +932,14 @@ end return SVector(f_dry, f_moist, f_rain, f_rhov1, f_rhov2, f_energy, 0.0, 0.0, 0.0) end +@inline function flux_chandrashekar(u_ll, u_rr, orientation::Int, equations::CompressibleRainyEulerEquations2D) + if (orientation == 1) + return flux_chandrashekar(u_ll, u_rr, SVector(1, 0), equations) + else + return flux_chandrashekar(u_ll, u_rr, SVector(0, 1), equations) + end +end + @inline function flux_ec_rain(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) # constants @@ -936,35 +951,27 @@ end L_ref = equations.ref_latent_heat_vap_temp # densities and temperatures - rho_dry_ll, rho_moist_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) - rho_dry_rr, rho_moist_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) - rho_vapour_ll, rho_cloud_ll, temperature_ll = cons2nonlinearsystemsol(u_ll, equations) - rho_vapour_rr, rho_cloud_rr, temperature_rr = cons2nonlinearsystemsol(u_rr, equations) - inv_temperature_ll = inv(temperature_ll) - inv_temperature_rr = inv(temperature_rr) + rho_dry_ll, rho_vapour_ll, rho_cloud_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) + rho_dry_rr, rho_vapour_rr, rho_cloud_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) + temperature_ll = get_temperature(u_ll, equations) + temperature_rr = get_temperature(u_rr, equations) + inv_temperature_ll = inv(temperature_ll) + inv_temperature_rr = inv(temperature_rr) # velocities v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) - vr_ll = terminal_velocity_rain(rho_moist_ll, rho_rain_ll, equations) - vr_rr = terminal_velocity_rain(rho_moist_rr, rho_rain_rr, equations) - - # energy_density - E_ll = energy_density(u_ll, equations) - E_rr = energy_density(u_rr, equations) - - # pressures - p_ll = pressure(u_ll, equations) - p_rr = pressure(u_rr, equations) + vr_ll = terminal_velocity_rain(rho_vapour_ll + rho_cloud_ll, rho_rain_ll, equations) + vr_rr = terminal_velocity_rain(rho_vapour_rr + rho_cloud_rr, rho_rain_rr, equations) # velocity averages - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) - v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) - v_square_avg = v1_square_avg + v2_square_avg - v_dot_n_avg = normal_direction[1] * v1_avg + normal_direction[2] * v2_avg - vr_normal_avg = 0.5 * normal_direction[2] * (vr_ll + vr_rr) + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) + v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) + K_avg = 0.5 * (v1_square_avg + v2_square_avg) + v_dot_n_avg = normal_direction[1] * v1_avg + normal_direction[2] * v2_avg + vr_normal_avg = 0.5 * normal_direction[2] * (vr_ll + vr_rr) # density averages rho_dry_avg = 0.5 * (rho_dry_ll + rho_dry_rr) @@ -995,25 +1002,9 @@ end end # other averages - p_avg = 0.5 * (p_ll + p_rr) - E_avg = 0.5 * (E_ll + E_rr) - temperature_avg = 0.5 * (temperature_ll + temperature_rr) inv_temperature_avg = 0.5 * (inv_temperature_ll + inv_temperature_rr) - temperature_log = ln_mean(temperature_ll, temperature_rr) - inv_temperature_log = ln_mean(inv_temperature_ll, inv_temperature_rr) - - # jumps - rho_dry_jump = rho_dry_rr - rho_dry_ll - rho_vapour_jump = rho_vapour_rr - rho_vapour_ll - rho_cloud_jump = rho_cloud_rr - rho_cloud_ll - rho_rain_jump = rho_rain_rr - rho_rain_ll - temperature_jump = temperature_rr - temperature_ll - inv_temperature_jump = inv_temperature_rr - inv_temperature_ll - v_normal_jump = (v1_rr - v1_ll) * normal_direction[1] + (v2_rr - v2_ll) * normal_direction[2] - v_jump = v1_rr - v1_ll + v2_rr - v2_ll - - # help variables - s_help = inv(inv_temperature_log) + inv_temperature_log = inv_ln_mean(inv_temperature_ll, inv_temperature_rr) + p_int = inv(inv_temperature_avg) * (R_d * rho_dry_avg + R_v * rho_vapour_avg) # density flux f_vapour = rho_vapour_log * v_dot_n_avg @@ -1024,19 +1015,12 @@ end f_rho = f_dry + f_moist + f_rain # momentum flux - f_rhov1 = f_rho * v1_avg + p_avg * normal_direction[1] - f_rhov2 = f_rho * v2_avg + p_avg * normal_direction[2] + f_rhov1 = f_rho * v1_avg + p_int * normal_direction[1] + f_rhov2 = f_rho * v2_avg + p_int * normal_direction[2] # energy flux - if !(isapprox(temperature_jump, 0.0, atol=1e-13)) - v_temp_jump = v_jump / inv_temperature_jump - f_energy = (c_vd * s_help - 0.5 * v_square_avg) * f_dry + (c_vv * s_help - 0.5 * v_square_avg + L_ref) * f_vapour + - (c_l * s_help - 0.5 * v_square_avg) * (f_cloud + f_rain) + - (v_temp_jump * inv_temperature_avg + v_dot_n_avg) * p_avg + - (v1_avg^2 + v2_avg^2) * f_rho - (R_d * rho_dry_avg + R_v * rho_vapour_avg) * v_temp_jump - else - f_energy = 0.0 - end + f_energy = (c_vd * inv_temperature_log - K_avg) * f_dry + (c_vv * inv_temperature_log - K_avg + L_ref) * f_vapour + + (c_l * inv_temperature_log - K_avg) * (f_cloud + f_rain) + (v1_avg * f_rhov1 + v2_avg * f_rhov2) return SVector(f_dry, f_moist, f_rain, f_rhov1, f_rhov2, f_energy, 0.0, 0.0, 0.0) end @@ -1049,7 +1033,6 @@ end end end -end # muladd end # adapted from ShallowWaterEquations2D (Recommended with rain!) @@ -1092,4 +1075,8 @@ end end return flux -end \ No newline at end of file +end + + + +end # muladd end \ No newline at end of file diff --git a/src/equations/compressible_rainy_euler_explicit_2d.jl b/src/equations/compressible_rainy_euler_explicit_2d.jl index f3b0fbb2..9118078d 100644 --- a/src/equations/compressible_rainy_euler_explicit_2d.jl +++ b/src/equations/compressible_rainy_euler_explicit_2d.jl @@ -120,8 +120,15 @@ end v1, v2 = velocities(u, rho_inv, equations) v_squared_temp = 0.5 * (v1^2 + v2^2) * inv_temperature - omega_dry = c_vd * ln_temperature - R_d * log(rho_dry) + v_squared_temp - c_vd - R_d - omega_vapour = c_vv * ln_temperature - R_v * log(rho_vapour) + v_squared_temp - c_vv - R_v - L_ref * inv_temperature + # check for zero density + rho_vapour_log = 0.0 + + if (rho_vapour > 0.0) + rho_vapour_log = log(rho_vapour) + end + + omega_dry = c_vd * ln_temperature - R_d * log(rho_dry) + v_squared_temp - c_vd - R_d + omega_vapour = c_vv * ln_temperature - R_v * rho_vapour_log + v_squared_temp - c_vv - R_v - L_ref * inv_temperature omega_liquid = c_l * ln_temperature + v_squared_temp - c_l omega_momentum_1 = -v1 * inv_temperature omega_momentum_2 = -v2 * inv_temperature @@ -170,7 +177,7 @@ end eq_pot = (temperature * (ref_p / p_d)^(R_d / c_p) * H^(-r_v * R_v / c_p) * exp(L_v * r_v * inv(c_p * temperature))) - return SVector(rho, r_v, r_c, r_r, v1, v2, eq_pot, p) + return SVector(rho, rho_vapour, rho_cloud, rho_rain, v1, v2, eq_pot, rho) end @@ -209,7 +216,7 @@ varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquationsExplicit2D) = ("r varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquationsExplicit2D) = ("rho_dry", "rho_vapour", "rho_cloud", "rho_rain", "v1", "v2", "eq_pot_temp", - "pressure", "entropy") + "rho") @@ -833,6 +840,16 @@ end end +@inline function flux_chandrashekar(u_ll, u_rr, orientation::Int, equations::CompressibleRainyEulerEquationsExplicit2D) + if (orientation == 1) + return flux_chandrashekar(u_ll, u_rr, SVector(1, 0), equations) + else + return flux_chandrashekar(u_ll, u_rr, SVector(0, 1), equations) + end +end + + + @inline function flux_ec_rain(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquationsExplicit2D) # constants c_l = equations.c_liquid_water @@ -856,18 +873,14 @@ end vr_ll = terminal_velocity_rain(rho_vapour_ll + rho_cloud_ll, rho_rain_ll, equations) vr_rr = terminal_velocity_rain(rho_vapour_rr + rho_cloud_rr, rho_rain_rr, equations) - # pressures - p_ll = pressure(u_ll, equations) - p_rr = pressure(u_rr, equations) - # velocity averages - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) - v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) - v_square_avg = v1_square_avg + v2_square_avg - v_dot_n_avg = normal_direction[1] * v1_avg + normal_direction[2] * v2_avg - vr_normal_avg = 0.5 * normal_direction[2] * (vr_ll + vr_rr) + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) + v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) + K_avg = 0.5 * (v1_square_avg + v2_square_avg) + v_dot_n_avg = normal_direction[1] * v1_avg + normal_direction[2] * v2_avg + vr_normal_avg = 0.5 * normal_direction[2] * (vr_ll + vr_rr) # density averages rho_dry_avg = 0.5 * (rho_dry_ll + rho_dry_rr) @@ -898,17 +911,9 @@ end end # other averages - p_avg = 0.5 * (p_ll + p_rr) inv_temperature_avg = 0.5 * (inv_temperature_ll + inv_temperature_rr) - inv_temperature_log = ln_mean(inv_temperature_ll, inv_temperature_rr) - - # jumps - temperature_jump = temperature_rr - temperature_ll - inv_temperature_jump = inv_temperature_rr - inv_temperature_ll - v_jump = v1_rr - v1_ll + v2_rr - v2_ll - - # help variables - s_help = inv(inv_temperature_log) + inv_temperature_log = inv_ln_mean(inv_temperature_ll, inv_temperature_rr) + p_int = inv(inv_temperature_avg) * (R_d * rho_dry_avg + R_v * rho_vapour_avg) # density flux f_vapour = rho_vapour_log * v_dot_n_avg @@ -919,19 +924,12 @@ end f_rho = f_dry + f_moist + f_rain # momentum flux - f_rhov1 = f_rho * v1_avg + p_avg * normal_direction[1] - f_rhov2 = f_rho * v2_avg + p_avg * normal_direction[2] + f_rhov1 = f_rho * v1_avg + p_int * normal_direction[1] + f_rhov2 = f_rho * v2_avg + p_int * normal_direction[2] # energy flux - if !(isapprox(temperature_jump, 0.0, atol=1e-13)) - v_temp_jump = v_jump / inv_temperature_jump - f_energy = (c_vd * s_help - 0.5 * v_square_avg) * f_dry + (c_vv * s_help - 0.5 * v_square_avg + L_ref) * f_vapour + - (c_l * s_help - 0.5 * v_square_avg) * (f_cloud + f_rain) + - (v_temp_jump * inv_temperature_avg + v_dot_n_avg) * p_avg + - (v1_avg^2 + v2_avg^2) * f_rho - (R_d * rho_dry_avg + R_v * rho_vapour_avg) * v_temp_jump - else - f_energy = 0.0 - end + f_energy = (c_vd * inv_temperature_log - K_avg) * f_dry + (c_vv * inv_temperature_log - K_avg + L_ref) * f_vapour + + (c_l * inv_temperature_log - K_avg) * (f_cloud + f_rain) + (v1_avg * f_rhov1 + v2_avg * f_rhov2) return SVector(f_dry, f_vapour, f_cloud, f_rain, f_rhov1, f_rhov2, f_energy) end @@ -944,4 +942,50 @@ end end end + + +# adapted from ShallowWaterEquations2D (Recommended with rain!) +@inline function boundary_condition_simple_slip_wall(u_inner, normal_direction::AbstractVector, x, t, surface_flux_function, + equations::CompressibleRainyEulerEquationsExplicit2D) + # normalize the outward pointing direction + normal = normal_direction / norm(normal_direction) + + # compute the normal velocity + u_normal = normal[1] * u_inner[2] + normal[2] * u_inner[5] + + # create the "external" boundary solution state + u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], u_inner[4], + u_inner[5] - 2 * u_normal * normal[6], + u_inner[6] - 2 * u_normal * normal[5], + u_inner[7]) + + # calculate the boundary flux + flux = surface_flux_function(u_inner, u_boundary, normal_direction, equations) + + return flux +end + + +# adapted from ShallowWaterEquations2D (Recommended with rain!) +@inline function boundary_condition_simple_slip_wall(u_inner, orientation, direction, x, t, surface_flux_function, + equations::CompressibleRainyEulerEquationsExplicit2D) + ## get the appropriate normal vector from the orientation + if orientation == 1 + u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], u_inner[4], -u_inner[5], u_inner[6], u_inner[7]) + else # orientation == 2 + u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], u_inner[4], u_inner[5], -u_inner[6], u_inner[7]) + end + + # Calculate boundary flux + if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary + flux = surface_flux_function(u_inner, u_boundary, orientation, equations) + else # u_boundary is "left" of boundary, u_inner is "right" of boundary + flux = surface_flux_function(u_boundary, u_inner, orientation, equations) + end + + return flux +end + + + end # muladd end \ No newline at end of file From 05e91f0101bc4c29dde8e56d3f3b7e264daa13da Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Fri, 21 Feb 2025 23:39:17 +0100 Subject: [PATCH 098/115] more fixes and updates concerning ec flux and slip wall --- .../elixir_rainy_euler_explicit_rainy_bubble.jl | 4 ++-- .../elixir_rainy_euler_rainy_bubble.jl | 2 +- src/equations/compressible_rainy_euler_2d.jl | 12 ++++-------- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl index 8b84ac91..ae5c5c37 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl @@ -218,8 +218,8 @@ end boundary_conditions = (x_neg = boundary_condition_periodic, x_pos = boundary_condition_periodic, - y_neg = boundary_condition_slip_wall, - y_pos = boundary_condition_slip_wall) + y_neg = boundary_condition_simple_slip_wall, + y_pos = boundary_condition_eimple_slip_wall) polydeg = 1 basis = LobattoLegendreBasis(polydeg) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl index d37dcfe2..5f566e0d 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl @@ -222,7 +222,7 @@ boundary_conditions = (x_neg = boundary_condition_periodic, y_neg = boundary_condition_simple_slip_wall, y_pos = boundary_condition_simple_slip_wall) -polydeg = 4 +polydeg = 1 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_lax_friedrichs diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index abfc7fe5..a33ade8c 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -820,10 +820,6 @@ end v_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] norm_ = norm(normal_direction) - # temperature - rho_vapour_ll, _, temperature_ll = cons2nonlinearsystemsol(u_ll, equations) - rho_vapour_rr, _, temperature_rr = cons2nonlinearsystemsol(u_rr, equations) - # diffusion parameter 0.0 < beta <= 1.0 beta = 1.0 @@ -951,10 +947,10 @@ end L_ref = equations.ref_latent_heat_vap_temp # densities and temperatures - rho_dry_ll, rho_vapour_ll, rho_cloud_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) - rho_dry_rr, rho_vapour_rr, rho_cloud_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) - temperature_ll = get_temperature(u_ll, equations) - temperature_rr = get_temperature(u_rr, equations) + rho_dry_ll, rho_moist_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) + rho_dry_rr, rho_moist_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) + rho_vapour_ll, rho_cloud_ll, temperature_ll = cons2nonlinearsystemsol(u_ll, equations) + rho_vapour_rr, rho_cloud_rr, temperature_rr = cons2nonlinearsystemsol(u_rr, equations) inv_temperature_ll = inv(temperature_ll) inv_temperature_rr = inv(temperature_rr) From 54b8dae75b2a1c2f12870d2880d24c48bf06bf82 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Mon, 24 Feb 2025 17:05:40 +0100 Subject: [PATCH 099/115] split and named different testcases --- ...ainy_euler_explicit_weak_blast_wave_dry.jl | 98 ++++++++++++++++ ...ny_euler_explicit_weak_blast_wave_rainy.jl | 107 ++++++++++++++++++ 2 files changed, 205 insertions(+) create mode 100644 examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl create mode 100644 examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl diff --git a/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl b/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl new file mode 100644 index 00000000..3c02a59d --- /dev/null +++ b/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl @@ -0,0 +1,98 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: flux_ec_rain, flux_chandrashekar, + RainLimiterDG, cons2eq_pot_temp + + +function initial_condition_weak_blast_wave_dry(x, t, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + c_vd = equations.c_dry_air_const_volume + R_d = equations.R_dry_air + + if sqrt(x[1]^2 + x[2]^2) > 0.5 + rho = 1.0 + v1 = 0.0 + v2 = 0.0 + p = 1.0 + else + phi = atan(x[2], x[1]) + rho = 1.1691 + v1 = 0.1882 * cos(phi) + v2 = 0.1882 * sin(phi) + p = 1.245 + end + + rho_dry = rho + T = p / (rho_dry * R_d) + + energy_density = c_vd * rho_dry * T + energy_density += 0.5 * rho * (v1^2 + v2^2) + + return SVector(rho_dry, 0.0, 0.0, 0.0, rho * v1, rho * v2, energy_density) +end + + + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleRainyEulerEquationsExplicit2D() + +initial_condition = initial_condition_weak_blast_wave_dry + +polydeg = 3 +basis = LobattoLegendreBasis(polydeg) + +volume_flux = flux_ec_rain +surface_flux = volume_flux +solver = DGSEM(basis, surface_flux, VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = (-2.0, -2.0) +coordinates_max = ( 2.0, 2.0) + +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 5, + n_cells_max = 1_000_000, + periodicity = true) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_condition_periodic) + + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 8.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + output_directory = "out", + solution_variables = cons2eq_pot_temp) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) + + + +############################################################################### +# run the simulation + +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); +summary_callback() # print the timer summary \ No newline at end of file diff --git a/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl b/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl new file mode 100644 index 00000000..9114ad03 --- /dev/null +++ b/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl @@ -0,0 +1,107 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: saturation_residual, saturation_residual_jacobian, + flux_ec_rain, saturation_vapour_pressure, flux_chandrashekar, + RainLimiterDG, cons2eq_pot_temp + + +function initial_condition_weak_blast_wave_rainy(x, t, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp + + if sqrt(x[1]^2 + x[2]^2) > 0.5 + rho = 1.0 + v1 = 0.0 + v2 = 0.0 + p = 1.0 + else + phi = atan(x[2], x[1]) + rho = 1.1691 + v1 = 0.1882 * cos(phi) + v2 = 0.1882 * sin(phi) + p = 1.245 + end + + rho_dry = 0.25 * rho + rho_vapour = 0.25 * rho + rho_cloud = 0.25 * rho + rho_rain = 0.25 * rho + + T = p / (rho_dry * R_d + rho_vapour * R_v) + + energy_density = (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * T + energy_density += L_ref * rho_vapour + 0.5 * rho * (v1^2 + v2^2) + + return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, rho * v1, rho * v2, energy_density) +end + + + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleRainyEulerEquationsExplicit2D() + +initial_condition = initial_condition_weak_blast_wave_rainy + +polydeg = 3 +basis = LobattoLegendreBasis(polydeg) + +volume_flux = flux_ec_rain +surface_flux = volume_flux +solver = DGSEM(basis, surface_flux, VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = (-2.0, -2.0) +coordinates_max = ( 2.0, 2.0) + +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 5, + n_cells_max = 1_000_000, + periodicity = true) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + boundary_conditions = boundary_condition_periodic) + + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 8.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 1000 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + output_directory = "out", + solution_variables = cons2eq_pot_temp) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, + alive_callback, + save_solution, + stepsize_callback) + + + +############################################################################### +# run the simulation + +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); +summary_callback() # print the timer summary \ No newline at end of file From 6fadf3056d875f28aa567b3892eb5681ea1f800b Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Mon, 24 Feb 2025 17:05:59 +0100 Subject: [PATCH 100/115] split and named different testcases --- ...rainy_euler_explicit_weak_blast_wave_2d.jl | 135 ------------------ 1 file changed, 135 deletions(-) delete mode 100644 examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_2d.jl diff --git a/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_2d.jl b/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_2d.jl deleted file mode 100644 index 6cf2622b..00000000 --- a/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_2d.jl +++ /dev/null @@ -1,135 +0,0 @@ -using OrdinaryDiffEq -using Trixi -using TrixiAtmo -using TrixiAtmo: saturation_residual, saturation_residual_jacobian, - flux_ec_rain, saturation_vapour_pressure, flux_chandrashekar, - RainLimiterDG, cons2eq_pot_temp - - -function initial_condition_weak_blast_wave(x, t, equations::CompressibleRainyEulerEquationsExplicit2D) - # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_d = equations.R_dry_air - R_v = equations.R_vapour - L_ref = equations.ref_latent_heat_vap_temp - - if sqrt(x[1]^2 + x[2]^2) > 0.5 - rho = 1.0 - v1 = 0.0 - v2 = 0.0 - p = 1.0 - else - phi = atan(x[2], x[1]) - rho = 1.1691 - v1 = 0.1882 * cos(phi) - v2 = 0.1882 * sin(phi) - p = 1.245 - end - - rho_dry = 0.4 * rho - rho_vapour = 0.4 * rho - rho_cloud = 0.1 * rho - rho_rain = 0.1 * rho - - T = p / (rho_dry * R_d + rho_vapour * R_v) - - energy_density = (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * T - energy_density += L_ref * rho_vapour + 0.5 * rho * (v1^2 + v2^2) - - return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, rho * v1, rho * v2, energy_density) -end - - -function initial_condition_weak_blast_wave_dry(x, t, equations::CompressibleRainyEulerEquationsExplicit2D) - # constants - c_vd = equations.c_dry_air_const_volume - R_d = equations.R_dry_air - - if sqrt(x[1]^2 + x[2]^2) > 0.5 - rho = 1.0 - v1 = 0.0 - v2 = 0.0 - p = 1.0 - else - phi = atan(x[2], x[1]) - rho = 1.1691 - v1 = 0.1882 * cos(phi) - v2 = 0.1882 * sin(phi) - p = 1.245 - end - - rho_dry = rho - T = p / (rho_dry * R_d) - - energy_density = c_vd * rho_dry * T - energy_density += 0.5 * rho * (v1^2 + v2^2) - - return SVector(rho_dry, 0.0, 0.0, 0.0, rho * v1, rho * v2, energy_density) -end - - - -############################################################################### -# semidiscretization of the compressible Euler equations - -equations = CompressibleRainyEulerEquationsExplicit2D() - -initial_condition = initial_condition_weak_blast_wave - -polydeg = 3 -basis = LobattoLegendreBasis(polydeg) - -volume_flux = flux_ec_rain -surface_flux = volume_flux -solver = DGSEM(basis, surface_flux, VolumeIntegralFluxDifferencing(volume_flux)) - -coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) - -mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level = 5, - n_cells_max = 1_000_000, - periodicity = true) - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - boundary_conditions = boundary_condition_periodic) - - -############################################################################### -# ODE solvers, callbacks etc. - -tspan = (0.0, 1.0) -ode = semidiscretize(semi, tspan) - -summary_callback = SummaryCallback() - -analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval = analysis_interval) - -alive_callback = AliveCallback(analysis_interval = analysis_interval) - -save_solution = SaveSolutionCallback(interval = 1000, - save_initial_solution = true, - save_final_solution = true, - output_directory = "out", - solution_variables = cons2eq_pot_temp) - -stepsize_callback = StepsizeCallback(cfl = 1.0) - -callbacks = CallbackSet(summary_callback, - analysis_callback, - alive_callback, - save_solution, - stepsize_callback) - -stage_limiter! = RainLimiterDG() - -############################################################################### -# run the simulation - -sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limiter!), - dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep = false, callback = callbacks); -summary_callback() # print the timer summary \ No newline at end of file From be292fa7c014e48a563dffc39bc91f1bb34c5835 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Mon, 24 Feb 2025 17:07:22 +0100 Subject: [PATCH 101/115] added convergence test for explicit rainy euler equations --- .../convergence_test_rainy_explicit.jl | 215 ++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 examples/convergence_test_elixirs/convergence_test_rainy_explicit.jl diff --git a/examples/convergence_test_elixirs/convergence_test_rainy_explicit.jl b/examples/convergence_test_elixirs/convergence_test_rainy_explicit.jl new file mode 100644 index 00000000..e09c701e --- /dev/null +++ b/examples/convergence_test_elixirs/convergence_test_rainy_explicit.jl @@ -0,0 +1,215 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: saturation_vapour_pressure, saturation_vapour_pressure_derivative, + terminal_velocity_rain, RainLimiterDG + + + +function initial_condition_convergence_test_rainy(x, t, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour + ref_L = equations.ref_latent_heat_vap_temp + + # define rho like in dry convergence test + c = 2.0 + A = 0.1 + L = 2.0 + f = 1.0 / L + ω = 2 * pi * f + rho = c + A * sin(ω * (x[1] + x[2] - t)) + + # define variables of rho + temperature = rho + 250.0 + rho_vapour = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + rho_cloud = rho / c_l * 3000 + rho_rain = rho / c_l * 1000 + rho_moist = rho_vapour + rho_cloud + rho_dry = rho - rho_moist - rho_rain + + # define matching energydensity with v1 := 1 and v2 := 1 , initially + energy = (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * temperature + energy += rho_vapour * ref_L + rho + + return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho, energy) +end + + +function source_terms_convergence_test_rainy(u, x, t, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + ref_L = equations.ref_latent_heat_vap_temp + N_0 = equations.rain_water_distr + v_0 = equations.v_mean_rain + + # help constant for terminal rain velocity derivative ( \Gamma(4.5) / 6 ~= 1.9386213994279082 ) + c_help = v_0 * 1.9386213994279082 * (pi * N_0)^(-0.125) + + # define rho like initial condition + c = 2.0 + A = 0.1 + L = 2.0 + f = 1.0 / L + ω = 2 * pi * f + si, co = sincos(ω * (x[1] + x[2] - t)) + rho = c + A * si + rho_x = ω * A * co + rho_t = -rho_x + + # define variables of rho + temperature = rho + 250.0 + sat_vap_p = saturation_vapour_pressure(temperature, equations) + rho_vapour = sat_vap_p / (R_v * temperature) + rho_cloud = rho / c_l * 3000 + rho_rain = rho / c_l * 1000 + rho_moist = rho_vapour + rho_cloud + rho_dry = rho - rho_moist - rho_rain + vr = terminal_velocity_rain(rho_moist, rho_rain, equations) + + # define needed derivatives + sat_vap_p_t = rho_t * saturation_vapour_pressure_derivative(temperature, equations) + sat_vap_p_x = rho_x * saturation_vapour_pressure_derivative(temperature, equations) + + rho_vapour_t = (sat_vap_p_t * temperature - rho_t * sat_vap_p) / (R_v * temperature^2) + rho_vapour_x = (sat_vap_p_x * temperature - rho_x * sat_vap_p) / (R_v * temperature^2) + + rho_cloud_t = rho_t / c_l * 3000 + rho_cloud_x = rho_x / c_l * 3000 + + rho_rain_t = rho_t / c_l * 1000 + rho_rain_x = rho_x / c_l * 1000 + + rho_moist_t = rho_vapour_t + rho_cloud_t + rho_moist_x = rho_vapour_x + rho_cloud_x + + rho_dry_t = rho_t - rho_moist_t - rho_rain_t + rho_dry_x = rho_x - rho_moist_x - rho_rain_x + + energy_t = (c_vd * rho_dry_t + c_vv * rho_vapour_t + c_l * (rho_cloud_t + rho_rain_t)) * temperature + energy_t += (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * rho_t + energy_t += rho_vapour_t * ref_L + rho_t + + energy_x = (c_vd * rho_dry_x + c_vv * rho_vapour_x + c_l * (rho_cloud_x + rho_rain_x)) * temperature + energy_x += (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * rho_x + energy_x += rho_vapour_x * ref_L + rho_x + + pressure_x = (rho_dry_x * R_d + rho_vapour_x * R_v) * temperature + pressure_x += (rho_dry * R_d + rho_vapour * R_v) * rho_x # temperature_x = rho_x + + vr_x = c_help * 0.125 * ((rho_rain_x * rho_moist - rho_rain * rho_moist_x) / (rho_moist + rho_rain)^2) + vr_x *= (rho_rain / (rho_moist + rho_rain))^(-0.875) + + rhor_vr__x = rho_rain_x * vr + rho_rain * vr_x + + # calculate source terms for manufactured solution + # density + S_rho_dry = rho_dry_t + 2.0 * rho_dry_x + S_rho_vapour = rho_vapour_t + 2.0 * rho_vapour_x + S_rho_cloud = rho_cloud_t + 2.0 * rho_cloud_x + S_rho_rain = rho_rain_t + 2.0 * rho_rain_x - rhor_vr__x + + # "momentum" + S_rho_v1 = rho_x + pressure_x - rhor_vr__x + S_rho_v2 = rho_x + pressure_x - rhor_vr__x + + # "energy" + S_energy = energy_t + 2.0 * (energy_x + pressure_x) - (c_l * rho_x * rho_rain * vr) + S_energy -= (c_l * temperature + 1) * rhor_vr__x + + return SVector(S_rho_dry, S_rho_vapour, S_rho_cloud, S_rho_rain, S_rho_v1, S_rho_v2, S_energy) +end + + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleRainyEulerEquationsExplicit2D() + +initial_condition = initial_condition_convergence_test_rainy + +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) + +coordinates_min = (0.0, 0.0) +coordinates_max = (2.0, 2.0) + +cells_per_dimension = (6, 6) + +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_convergence_test_rainy) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 2.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 10000 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback) + +stage_limiter! = RainLimiterDG() + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limiter!), + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); +summary_callback() # print the timer summary + +# For copy-paste convenience: +#convergence_test("TrixiAtmo.jl/examples/convergence_test_elixirs/convergence_test_rainy_explicit.jl", 5) + +#= +#################################################################################################### +l2 +rho_dry rho_vapour rho_cloud rho_rain rho_v1 rho_v2 energy_density +error EOC error EOC error EOC error EOC error EOC error EOC error EOC +2.39e-06 - 1.19e-07 - 3.86e-05 - 1.51e-05 - 7.49e-03 - 2.06e-02 - 5.17e+01 - +1.43e-07 4.06 3.43e-09 5.12 2.32e-06 4.06 9.69e-07 3.96 2.89e-04 4.70 1.38e-03 3.90 3.13e+00 4.04 +8.44e-09 4.09 8.83e-11 5.28 1.37e-07 4.08 1.20e-07 3.02 1.13e-05 4.68 3.09e-05 5.48 1.78e-01 4.14 +5.28e-10 4.00 3.28e-12 4.75 8.55e-09 4.00 5.28e-09 4.51 6.34e-07 4.16 9.54e-07 5.02 1.39e-02 3.68 +3.32e-11 3.99 7.50e-14 5.45 5.35e-10 4.00 2.02e-10 4.71 3.85e-08 4.04 3.80e-08 4.65 7.80e-04 4.16 + +mean 4.03 mean 5.15 mean 4.03 mean 4.05 mean 4.39 mean 4.76 mean 4.00 +---------------------------------------------------------------------------------------------------- +linf +rho_dry rho_vapour rho_cloud rho_rain rho_v1 rho_v2 energy_density +error EOC error EOC error EOC error EOC error EOC error EOC error EOC +1.68e-05 - 5.92e-07 - 2.69e-04 - 8.52e-05 - 2.33e-02 - 6.19e-02 - 3.71e+02 - +1.06e-06 3.99 1.25e-08 5.57 1.72e-05 3.97 4.33e-06 4.30 1.12e-03 4.37 3.08e-03 4.33 2.27e+01 4.03 +5.98e-08 4.15 2.97e-10 5.39 9.68e-07 4.15 3.45e-07 3.65 4.43e-05 4.67 6.53e-05 5.56 1.08e+00 4.39 +3.68e-09 4.02 1.28e-11 4.53 5.96e-08 4.02 2.91e-08 3.57 2.47e-06 4.16 2.37e-06 4.79 9.43e-02 3.52 +2.30e-10 4.00 3.03e-13 5.40 3.71e-09 4.00 1.47e-09 4.31 1.50e-07 4.04 1.16e-07 4.36 5.52e-03 4.09 + +mean 4.04 mean 5.22 mean 4.04 mean 3.96 mean 4.31 mean 4.76 mean 4.01 +---------------------------------------------------------------------------------------------------- +Dict{Symbol, Any} with 3 entries: + :variables => ("rho_dry", "rho_vapour", "rho_cloud", "rho_rain", "rho_v1", "rho_v2", "energy_density") + :l2 => [4.03455, 5.14974, 4.0349, 4.04611, 4.39262, 4.76286, 4.0041] + :linf => [4.03983, 5.22416, 4.03676, 3.95607, 4.31093, 4.75739, 4.00916] +=# \ No newline at end of file From e2f22c13f48b111110a55ca6c241f32fb81795db Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Mon, 24 Feb 2025 17:09:43 +0100 Subject: [PATCH 102/115] fixes for convergence test --- .../compressible_rainy_euler_explicit_2d.jl | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/src/equations/compressible_rainy_euler_explicit_2d.jl b/src/equations/compressible_rainy_euler_explicit_2d.jl index 9118078d..398ed110 100644 --- a/src/equations/compressible_rainy_euler_explicit_2d.jl +++ b/src/equations/compressible_rainy_euler_explicit_2d.jl @@ -202,16 +202,14 @@ end ### varnames ### -varnames(::typeof(cons2cons), ::CompressibleRainyEulerEquationsExplicit2D) = ("rho_dry", "rho_moist", "rho_rain", +varnames(::typeof(cons2cons), ::CompressibleRainyEulerEquationsExplicit2D) = ("rho_dry", "rho_vapour", "rho_cloud", "rho_rain", "rho_v1", "rho_v2", - "energy_density", - "rho_vapour", "rho_cloud", "temperature") + "energy_density") -varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquationsExplicit2D) = ("rho_dry", "rho_moist", "rho_rain", +varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquationsExplicit2D) = ("rho_dry", "rho_vapour", "rho_cloud", "rho_rain", "v1", "v2", - "energy_density", - "rho_vapour", "rho_cloud", "temperature") + "energy_density") varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquationsExplicit2D) = ("rho_dry", "rho_vapour", "rho_cloud", "rho_rain", @@ -359,6 +357,32 @@ end end +@inline function saturation_vapour_pressure_derivative(temperature, equations::CompressibleRainyEulerEquationsExplicit2D) + # constants + c_l = equations.c_liquid_water + c_pv = equations.c_vapour_const_pressure + R_v = equations.R_vapour + ref_s_p = equations.ref_saturation_pressure + ref_temp = equations.ref_temperature + ref_L = equations.ref_latent_heat_vap_temp + + # testing + if (temperature < 0.0) + display(temperature) + error("temp less than zero") + end + + const_1 = (c_pv - c_l) / R_v + const_2 = (ref_L - (c_pv - c_l) * ref_temp) / R_v + + p_vapour_saturation_derivative = ref_s_p / (ref_temp^const_1) + p_vapour_saturation_derivative *= (const_1 * temperature^(const_1 - 1) + const_2 * temperature^(const_1 - 2)) + p_vapour_saturation_derivative *= exp(const_2 * (1 / ref_temp - 1 / temperature)) + + return p_vapour_saturation_derivative +end + + # adapted from compressible_moist_euler_2d.jl @inline function moist_air_phase_change(u, equations::CompressibleRainyEulerEquationsExplicit2D) # constants From a4f593d7b51f8773869add6f7f4024a6bcc45700 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Mon, 24 Feb 2025 17:10:07 +0100 Subject: [PATCH 103/115] updated slip wall boundary condition --- .../elixir_rainy_euler_explicit_rainy_bubble.jl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl index ae5c5c37..5f3b4ffe 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl @@ -5,7 +5,8 @@ using TrixiAtmo: source_terms_rainy, saturation_residual, saturation_residual_jacobian, RainLimiterDG, cons2eq_pot_temp, saturation_vapour_pressure, flux_chandrashekar, flux_LMARS, flux_ec_rain, - source_terms_no_phase_change + source_terms_no_phase_change, + boundary_condition_simple_slip_wall using NLsolve: nlsolve #using Plots @@ -219,9 +220,9 @@ end boundary_conditions = (x_neg = boundary_condition_periodic, x_pos = boundary_condition_periodic, y_neg = boundary_condition_simple_slip_wall, - y_pos = boundary_condition_eimple_slip_wall) + y_pos = boundary_condition_simple_slip_wall) -polydeg = 1 +polydeg = 3 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_lax_friedrichs @@ -229,7 +230,7 @@ volume_integral = VolumeIntegralFluxDifferencing(flux_ec_rain) solver = DGSEM(basis, surface_flux, volume_integral) -cells_per_dimension = (100, 100) +cells_per_dimension = (64, 64) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = (true, false)) From 9f5e344eeb2897bcdf98f828f6e71612c3b642a8 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 25 Feb 2025 15:11:31 +0100 Subject: [PATCH 104/115] updated density variables to be more physically and numerically fitting --- .../rainy_euler_explicit_weak_blast_wave_dry.jl | 6 +++--- .../rainy_euler_explicit_weak_blast_wave_rainy.jl | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl b/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl index 3c02a59d..59ee6d28 100644 --- a/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl +++ b/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl @@ -11,13 +11,13 @@ function initial_condition_weak_blast_wave_dry(x, t, equations::CompressibleRain R_d = equations.R_dry_air if sqrt(x[1]^2 + x[2]^2) > 0.5 - rho = 1.0 + rho = 1.0e-4 v1 = 0.0 v2 = 0.0 p = 1.0 else phi = atan(x[2], x[1]) - rho = 1.1691 + rho = 1.1691e-4 v1 = 0.1882 * cos(phi) v2 = 0.1882 * sin(phi) p = 1.245 @@ -63,7 +63,7 @@ semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 8.0) +tspan = (0.0, 0.4) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() diff --git a/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl b/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl index 9114ad03..a781cf81 100644 --- a/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl +++ b/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl @@ -16,13 +16,13 @@ function initial_condition_weak_blast_wave_rainy(x, t, equations::CompressibleRa L_ref = equations.ref_latent_heat_vap_temp if sqrt(x[1]^2 + x[2]^2) > 0.5 - rho = 1.0 + rho = 1.0e-4 v1 = 0.0 v2 = 0.0 p = 1.0 else phi = atan(x[2], x[1]) - rho = 1.1691 + rho = 1.1691e-4 v1 = 0.1882 * cos(phi) v2 = 0.1882 * sin(phi) p = 1.245 @@ -72,7 +72,7 @@ semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 8.0) +tspan = (0.0, 0.4) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() From eecfdb8026e3c5a68bf4e4e678a38520ce869530 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Fri, 28 Feb 2025 00:16:41 +0100 Subject: [PATCH 105/115] added convergence tests for explicit rainy euler equations --- .../convergence_test_rainy_dry_explicit.jl | 139 +++++++++++++ ...convergence_test_rainy_no_rain_explicit.jl | 191 ++++++++++++++++++ 2 files changed, 330 insertions(+) create mode 100644 examples/convergence_test_elixirs/convergence_test_rainy_dry_explicit.jl create mode 100644 examples/convergence_test_elixirs/convergence_test_rainy_no_rain_explicit.jl diff --git a/examples/convergence_test_elixirs/convergence_test_rainy_dry_explicit.jl b/examples/convergence_test_elixirs/convergence_test_rainy_dry_explicit.jl new file mode 100644 index 00000000..79ca94be --- /dev/null +++ b/examples/convergence_test_elixirs/convergence_test_rainy_dry_explicit.jl @@ -0,0 +1,139 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo + + + +# adapted from compressible_euler_2d.jl +function initial_condition_convergence_test(x, t, equations::CompressibleRainyEulerEquationsExplicit2D) + RealT = eltype(x) + c = 2 + A = convert(RealT, 0.1) + L = 2 + f = 1.0f0 / L + ω = 2 * convert(RealT, pi) * f + ini = c + A * sin(ω * (x[1] + x[2] - t)) + + rho = ini + rho_v1 = ini + rho_v2 = ini + rho_e = ini^2 + + return SVector(rho, 0.0, 0.0, 0.0, rho_v1, rho_v2, rho_e) +end + + +# adapted from compressible_euler_2d.jl +function source_terms_convergence_test(u, x, t, equations::CompressibleRainyEulerEquationsExplicit2D) + c_pd = equations.c_dry_air_const_pressure + c_vd = equations.c_dry_air_const_volume + + # Same settings as in `initial_condition` + RealT = eltype(u) + c = 2 + A = convert(RealT, 0.1) + L = 2 + f = 1.0f0 / L + ω = 2 * convert(RealT, pi) * f + γ = c_pd / c_vd + + x1, x2 = x + si, co = sincos(ω * (x1 + x2 - t)) + rho = c + A * si + rho_x = ω * A * co + # Note that d/dt rho = -d/dx rho = -d/dy rho. + + tmp = (2 * rho - 1) * (γ - 1) + du1 = rho_x + du2 = rho_x * (1 + tmp) + du3 = du2 + du4 = 2 * rho_x * (rho + tmp) + + return SVector(du1, 0.0, 0.0, 0.0, du2, du3, du4) +end + + +# from elixir_euler_source_terms.jl +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleRainyEulerEquationsExplicit2D() + +initial_condition = initial_condition_convergence_test + +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) + +coordinates_min = (0.0, 0.0) +coordinates_max = (2.0, 2.0) + +cells_per_dimension = (8, 8) + +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_convergence_test) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 2.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) + +save_solution = SaveSolutionCallback(interval = analysis_interval, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback) + +############################################################################### +# run the simulation + +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); +summary_callback() # print the timer summary + + +#= For copy-paste convenience: +#convergence_test("TrixiAtmo.jl/examples/convergence_test_elixirs/convergence_test_rainy_dry_explicit.jl", 5) + +#################################################################################################### +l2 +rho_dry rho_vapour rho_cloud rho_rain rho_v1 rho_v2 energy_density +error EOC error EOC error EOC error EOC error EOC error EOC error EOC +2.80e-05 - 0.00e+00 - 0.00e+00 - 0.00e+00 - 2.90e-05 - 2.90e-05 - 9.66e-05 - +9.30e-07 4.91 0.00e+00 NaN 0.00e+00 NaN 0.00e+00 NaN 1.42e-06 4.36 1.42e-06 4.36 4.82e-06 4.32 +7.00e-08 3.73 0.00e+00 NaN 0.00e+00 NaN 0.00e+00 NaN 9.51e-08 3.90 9.51e-08 3.90 3.29e-07 3.87 +4.64e-09 3.92 0.00e+00 NaN 0.00e+00 NaN 0.00e+00 NaN 6.08e-09 3.97 6.08e-09 3.97 2.12e-08 3.95 +2.93e-10 3.98 0.00e+00 NaN 0.00e+00 NaN 0.00e+00 NaN 3.82e-10 3.99 3.82e-10 3.99 1.33e-09 3.99 + +mean 4.14 mean NaN mean NaN mean NaN mean 4.05 mean 4.05 mean 4.04 +---------------------------------------------------------------------------------------------------- +linf +rho_dry rho_vapour rho_cloud rho_rain rho_v1 rho_v2 energy_density +error EOC error EOC error EOC error EOC error EOC error EOC error EOC +1.97e-04 - 0.00e+00 - 0.00e+00 - 0.00e+00 - 2.02e-04 - 2.02e-04 - 8.91e-04 - +9.62e-06 4.36 0.00e+00 NaN 0.00e+00 NaN 0.00e+00 NaN 1.17e-05 4.10 1.17e-05 4.10 4.89e-05 4.19 +6.24e-07 3.95 0.00e+00 NaN 0.00e+00 NaN 0.00e+00 NaN 7.49e-07 3.97 7.49e-07 3.97 3.23e-06 3.92 +4.06e-08 3.94 0.00e+00 NaN 0.00e+00 NaN 0.00e+00 NaN 4.97e-08 3.91 4.97e-08 3.91 2.10e-07 3.94 +2.55e-09 3.99 0.00e+00 NaN 0.00e+00 NaN 0.00e+00 NaN 3.19e-09 3.96 3.19e-09 3.96 1.34e-08 3.97 + +mean 4.06 mean NaN mean NaN mean NaN mean 3.99 mean 3.99 mean 4.00 +---------------------------------------------------------------------------------------------------- +Dict{Symbol, Any} with 3 entries: + :variables => ("rho_dry", "rho_vapour", "rho_cloud", "rho_rain", "rho_v1", "rho_v2", "energy_density") + :l2 => [4.13577, NaN, NaN, NaN, 4.05385, 4.05385, 4.03601] + :linf => [4.05911, NaN, NaN, NaN, 3.9867, 3.9867, 4.00476]=# \ No newline at end of file diff --git a/examples/convergence_test_elixirs/convergence_test_rainy_no_rain_explicit.jl b/examples/convergence_test_elixirs/convergence_test_rainy_no_rain_explicit.jl new file mode 100644 index 00000000..7d1a25af --- /dev/null +++ b/examples/convergence_test_elixirs/convergence_test_rainy_no_rain_explicit.jl @@ -0,0 +1,191 @@ +using OrdinaryDiffEq +using Trixi +using TrixiAtmo +using TrixiAtmo: saturation_vapour_pressure, saturation_vapour_pressure_derivative, + saturation_residual, saturation_residual_jacobian + + + +function initial_condition_convergence_test_rainy_no_rain(x, t, equations::CompressibleRainyEulerEquationsExplicit2D) + # needed constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour + ref_L = equations.ref_latent_heat_vap_temp + + # define rho like in dry convergence test + c = 2.0 + A = 0.1 + L = 2.0 + f = 1.0 / L + ω = 2 * pi * f + rho = c + A * sin(ω * (x[1] + x[2] - t)) + + # define variables of rho + temperature = rho + 250.0 + rho_vapour = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + rho_cloud = rho / c_l * 4000 + rho_moist = rho_vapour + rho_cloud + rho_dry = rho - rho_moist + + # define matching energydensity with v1 := 1 and v2 := 1 , initially + energy = (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud) * temperature + energy += rho_vapour * ref_L + rho + + return SVector(rho_dry, rho_vapour, rho_cloud, 0.0, rho, rho, energy) +end + + +function source_terms_convergence_test_rainy_no_rain(u, x, t, equations::CompressibleRainyEulerEquationsExplicit2D) + # needed constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + ref_L = equations.ref_latent_heat_vap_temp + + # define rho like initial condition + c = 2.0 + A = 0.1 + L = 2.0 + f = 1.0 / L + ω = 2 * pi * f + si, co = sincos(ω * (x[1] + x[2] - t)) + rho = c + A * si + rho_x = ω * A * co + rho_t = -rho_x + + # define variables of rho + temperature = rho + 250.0 + sat_vap_p = saturation_vapour_pressure(temperature, equations) + rho_vapour = sat_vap_p / (R_v * temperature) + rho_cloud = rho / c_l * 4000 + rho_moist = rho_vapour + rho_cloud + rho_dry = rho - rho_moist + + # define needed derivatives + sat_vap_p_t = rho_t * saturation_vapour_pressure_derivative(temperature, equations) + sat_vap_p_x = rho_x * saturation_vapour_pressure_derivative(temperature, equations) + + rho_vapour_t = (sat_vap_p_t * temperature - rho_t * sat_vap_p) / (R_v * temperature^2) + rho_vapour_x = (sat_vap_p_x * temperature - rho_x * sat_vap_p) / (R_v * temperature^2) + + rho_cloud_t = rho_t / c_l * 4000 + rho_cloud_x = rho_x / c_l * 4000 + + rho_moist_t = rho_vapour_t + rho_cloud_t + rho_moist_x = rho_vapour_x + rho_cloud_x + + rho_dry_t = rho_t - rho_moist_t + rho_dry_x = rho_x - rho_moist_x + + energy_t = (c_vd * rho_dry_t + c_vv * rho_vapour_t + c_l * rho_cloud_t) * temperature + energy_t += (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud ) * rho_t + energy_t += rho_vapour_t * ref_L + rho_t + + energy_x = (c_vd * rho_dry_x + c_vv * rho_vapour_x + c_l * rho_cloud_x) * temperature + energy_x += (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud ) * rho_x + energy_x += rho_vapour_x * ref_L + rho_x + + pressure_x = (rho_dry_x * R_d + rho_vapour_x * R_v) * temperature + pressure_x += (rho_dry * R_d + rho_vapour * R_v) * rho_x # temperature_x = rho_x + + # calculate source terms for manufactured solution + # density + S_rho_dry = rho_dry_t + 2.0 * rho_dry_x + S_rho_vapour = rho_vapour_t + 2.0 * rho_vapour_x + S_rho_cloud = rho_cloud_t + 2.0 * rho_cloud_x + + # "momentum" + S_rho_v1 = rho_x + pressure_x + S_rho_v2 = rho_x + pressure_x + + # "energy" + S_energy = energy_t + 2.0 * (energy_x + pressure_x) + + return SVector(S_rho_dry, S_rho_vapour, S_rho_cloud, 0.0, S_rho_v1, S_rho_v2, S_energy) +end + + +############################################################################### +# semidiscretization of the compressible Euler equations + +equations = CompressibleRainyEulerEquationsExplicit2D() + +initial_condition = initial_condition_convergence_test_rainy_no_rain + +solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs) + +coordinates_min = (0.0, 0.0) +coordinates_max = (2.0, 2.0) + +cells_per_dimension = (8, 8) + +mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_convergence_test_rainy_no_rain) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 2.0) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 10000 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) + +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(interval = 1000, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 1.0) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback) + +############################################################################### +# run the simulation + +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); +summary_callback() # print the timer summary + +# For copy-paste convenience: +#convergence_test("TrixiAtmo.jl/examples/convergence_test_elixirs/convergence_test_rainy_no_rain_explicit.jl", 4) +#= +#################################################################################################### +l2 +rho_dry rho_vapour rho_cloud rho_rain rho_v1 rho_v2 energy_density +error EOC error EOC error EOC error EOC error EOC error EOC error EOC +8.21e-07 - 1.47e-07 - 1.76e-05 - 0.00e+00 - 7.48e-03 - 7.48e-03 - 1.88e+01 - +4.37e-08 4.23 4.86e-09 4.92 9.38e-07 4.23 0.00e+00 NaN 2.13e-04 5.13 2.13e-04 5.13 1.01e+00 4.23 +2.69e-09 4.02 1.91e-10 4.67 5.78e-08 4.02 0.00e+00 NaN 7.04e-06 4.92 7.04e-06 4.92 6.20e-02 4.02 +1.68e-10 4.00 5.06e-12 5.24 3.61e-09 4.00 0.00e+00 NaN 2.78e-07 4.66 2.78e-07 4.66 3.87e-03 4.00 + +mean 4.09 mean 4.94 mean 4.08 mean NaN mean 4.90 mean 4.90 mean 4.08 +---------------------------------------------------------------------------------------------------- +linf +rho_dry rho_vapour rho_cloud rho_rain rho_v1 rho_v2 energy_density +error EOC error EOC error EOC error EOC error EOC error EOC error EOC +6.66e-06 - 6.69e-07 - 1.42e-04 - 0.00e+00 - 1.55e-02 - 1.55e-02 - 1.54e+02 - +3.44e-07 4.28 1.96e-08 5.09 7.25e-06 4.30 0.00e+00 NaN 4.91e-04 4.98 4.91e-04 4.98 7.81e+00 4.30 +1.93e-08 4.16 7.70e-10 4.67 4.13e-07 4.13 0.00e+00 NaN 1.81e-05 4.76 1.81e-05 4.76 4.43e-01 4.14 +1.18e-09 4.03 2.47e-11 4.96 2.53e-08 4.03 0.00e+00 NaN 8.48e-07 4.42 8.48e-07 4.42 2.72e-02 4.03 + +mean 4.16 mean 4.91 mean 4.15 mean NaN mean 4.72 mean 4.72 mean 4.16 +---------------------------------------------------------------------------------------------------- +Dict{Symbol, Any} with 3 entries: + :variables => ("rho_dry", "rho_vapour", "rho_cloud", "rho_rain", "rho_v1", "rho_v2", "energy_density") + :l2 => [4.08558, 4.94267, 4.08233, NaN, 4.90466, 4.90466, 4.08271] + :linf => [4.1557, 4.90799, 4.15355, NaN, 4.72056, 4.72056, 4.15543]=# \ No newline at end of file From de3b3dc299e18aca1b9f5b76d1528356277abfd1 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Mon, 10 Mar 2025 17:33:50 +0100 Subject: [PATCH 106/115] small comment changes and fixes --- .../elixir_rainy_euler_explicit_rainy_bubble.jl | 3 +-- .../elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl | 8 ++------ .../elixir_rainy_euler_rainy_bubble_diffusion.jl | 3 +-- src/equations/compressible_rainy_euler_explicit_2d.jl | 2 +- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl index 5f3b4ffe..672930ba 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl @@ -8,7 +8,6 @@ using TrixiAtmo: source_terms_rainy, saturation_residual, source_terms_no_phase_change, boundary_condition_simple_slip_wall using NLsolve: nlsolve -#using Plots @@ -249,7 +248,7 @@ summary_callback = SummaryCallback() analysis_interval = 1000 -# entropy? +# entropy analysis_callback = AnalysisCallback(semi, interval = analysis_interval, extra_analysis_errors = (:entropy_conservation_error,)) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl index 181fbe47..e2b87a9e 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl @@ -10,7 +10,6 @@ using TrixiAtmo: source_terms_rainy, saturation_residual, flux_ec_rain, boundary_condition_simple_slip_wall using NLsolve: nlsolve -#using Plots @@ -265,7 +264,7 @@ summary_callback = SummaryCallback() analysis_interval = 1000 -# entropy? +# entropy analysis_callback = AnalysisCallback(semi, interval = analysis_interval, extra_analysis_errors = (:entropy_conservation_error,)) @@ -277,13 +276,10 @@ save_solution = SaveSolutionCallback(interval = 1000, output_directory = "out", solution_variables = cons2eq_pot_temp) -stepsize_callback = StepsizeCallback(cfl = 1.0) - callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, - save_solution, - stepsize_callback) + save_solution) stage_limiter! = RainLimiterDG() diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl index 27e893bf..6825ee05 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl @@ -10,7 +10,6 @@ using TrixiAtmo: source_terms_rainy, saturation_residual, boundary_condition_simple_slip_wall, flux_ec_rain using NLsolve: nlsolve -#using Plots @@ -265,7 +264,7 @@ summary_callback = SummaryCallback() analysis_interval = 1000 -# entropy? +# entropy analysis_callback = AnalysisCallback(semi, interval = analysis_interval, extra_analysis_errors = (:entropy_conservation_error,)) diff --git a/src/equations/compressible_rainy_euler_explicit_2d.jl b/src/equations/compressible_rainy_euler_explicit_2d.jl index 398ed110..eadde41c 100644 --- a/src/equations/compressible_rainy_euler_explicit_2d.jl +++ b/src/equations/compressible_rainy_euler_explicit_2d.jl @@ -554,7 +554,7 @@ end # densities rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) - Q_ph = phase_change_term(u, equations) + Q_ph = moist_air_phase_change(u, equations) return SVector(0.0, Q_ph, -Q_ph, 0.0, 0.0, -rho * g, -rho_v2 * g) From 071cca80e067a9406e807ae677a79f306741736b Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Tue, 15 Apr 2025 20:22:23 +0200 Subject: [PATCH 107/115] Code cleanup, simple slip wall fix, renames for clarification. --- .../elixir_moist_euler_moist_bubble_lucas.jl | 17 +- .../convergence_test_rainy.jl | 26 +- .../convergence_test_rainy_dry.jl | 8 +- .../convergence_test_rainy_explicit.jl | 32 +- ...=> convergence_test_rainy_explicit_dry.jl} | 12 +- ... convergence_test_rainy_explicit_moist.jl} | 28 +- ...ain.jl => convergence_test_rainy_moist.jl} | 22 +- .../energy/elixir_rainy_euler_dry_bubble.jl | 3 +- .../elixir_dry_potential_euler_bubble.jl | 125 --- ...iny_euler_explicit_moist_bubble_ec_test.jl | 7 +- ...ainy_euler_explicit_weak_blast_wave_dry.jl | 4 +- ...ny_euler_explicit_weak_blast_wave_rainy.jl | 12 +- ...elixir_moist_euler_moist_bubble_dgmulti.jl | 10 +- ...lixir_rainy_euler_explicit_moist_bubble.jl | 12 +- .../energy/elixir_rainy_euler_moist_bubble.jl | 9 +- ...elixir_rainy_euler_moist_bubble_dgmulti.jl | 16 +- ...uler_potential_temperature_moist_bubble.jl | 3 +- ...lixir_rainy_euler_explicit_rainy_bubble.jl | 17 +- ...y_euler_explicit_rainy_bubble_diffusion.jl | 12 +- .../elixir_rainy_euler_rainy_bubble.jl | 7 +- .../elixir_rainy_euler_rainy_bubble_amr.jl | 285 ------- ...elixir_rainy_euler_rainy_bubble_dgmulti.jl | 288 ------- ...ixir_rainy_euler_rainy_bubble_diffusion.jl | 5 +- src/TrixiAtmo.jl | 3 +- src/callbacks_stage/nonlinear_solve_dg2d.jl | 4 - .../compressible_moist_euler_2d_lucas.jl | 2 +- src/equations/compressible_rainy_euler_2d.jl | 21 +- .../compressible_rainy_euler_explicit_2d.jl | 109 ++- ...le_rainy_euler_potential_temperature_2d.jl | 800 ------------------ src/equations/equations.jl | 1 - 30 files changed, 182 insertions(+), 1718 deletions(-) rename examples/convergence_test_elixirs/{convergence_test_rainy_dry_explicit.jl => convergence_test_rainy_explicit_dry.jl} (95%) rename examples/convergence_test_elixirs/{convergence_test_rainy_no_rain_explicit.jl => convergence_test_rainy_explicit_moist.jl} (92%) rename examples/convergence_test_elixirs/{convergence_test_rainy_no_rain.jl => convergence_test_rainy_moist.jl} (94%) delete mode 100644 examples/dry_bubble_elixirs/potential_temperature/elixir_dry_potential_euler_bubble.jl delete mode 100644 examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_amr.jl delete mode 100644 examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_dgmulti.jl delete mode 100644 src/equations/compressible_rainy_euler_potential_temperature_2d.jl diff --git a/examples/comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl b/examples/comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl index 70c7f021..5a4ba23e 100644 --- a/examples/comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl +++ b/examples/comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl @@ -229,8 +229,8 @@ end initial_condition = initial_condition_moist -boundary_condition = (x_neg = boundary_condition_slip_wall, - x_pos = boundary_condition_slip_wall, +boundary_condition = (x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, y_neg = boundary_condition_slip_wall, y_pos = boundary_condition_slip_wall) @@ -242,21 +242,16 @@ source_term = source_terms_moist_bubble polydeg = 3 basis = LobattoLegendreBasis(polydeg) -#surface_flux = flux_LMARS -#volume_flux = flux_chandrashekar - -#volume_integral = VolumeIntegralFluxDifferencing(volume_flux) -surface_flux = flux_lax_friedrichs -solver = DGSEM(basis, surface_flux)#, volume_integral) +surface_flux = flux_LMARS +solver = DGSEM(basis, surface_flux) coordinates_min = (0.0, 0.0) coordinates_max = (20000.0, 10000.0) -cells_per_dimension = (64, 32) +cells_per_dimension = (128, 64) -# Create curved mesh with 64 x 32 elements mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, - periodicity = (false, false)) + periodicity = (true, false)) ############################################################################### # create the semi discretization object diff --git a/examples/convergence_test_elixirs/convergence_test_rainy.jl b/examples/convergence_test_elixirs/convergence_test_rainy.jl index 451cef05..d10940b1 100644 --- a/examples/convergence_test_elixirs/convergence_test_rainy.jl +++ b/examples/convergence_test_elixirs/convergence_test_rainy.jl @@ -9,11 +9,11 @@ using TrixiAtmo: saturation_vapour_pressure, saturation_vapour_pressure_derivati function initial_condition_convergence_test_rainy(x, t, equations::CompressibleRainyEulerEquations2D) # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_v = equations.R_vapour - ref_L = equations.ref_latent_heat_vap_temp + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour + ref_L = equations.ref_latent_heat_vap_temp # define rho like in dry convergence test c = 2.0 @@ -41,14 +41,14 @@ end function source_terms_convergence_test_rainy(u, x, t, equations::CompressibleRainyEulerEquations2D) # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_d = equations.R_dry_air - R_v = equations.R_vapour - ref_L = equations.ref_latent_heat_vap_temp - N_0 = equations.rain_water_distr - v_0 = equations.v_mean_rain + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + ref_L = equations.ref_latent_heat_vap_temp + N_0 = equations.rain_water_distr + v_0 = equations.v_mean_rain # help constant for terminal rain velocity derivative ( \Gamma(4.5) / 6 ~= 1.9386213994279082 ) c_help = v_0 * 1.9386213994279082 * (pi * N_0)^(-0.125) diff --git a/examples/convergence_test_elixirs/convergence_test_rainy_dry.jl b/examples/convergence_test_elixirs/convergence_test_rainy_dry.jl index 30dfd846..eb40d639 100644 --- a/examples/convergence_test_elixirs/convergence_test_rainy_dry.jl +++ b/examples/convergence_test_elixirs/convergence_test_rainy_dry.jl @@ -25,10 +25,8 @@ end # adapted from compressible_euler_2d.jl function source_terms_convergence_test(u, x, t, equations::CompressibleRainyEulerEquations2D) - c_pd = equations.c_dry_air_const_pressure - c_vd = equations.c_dry_air_const_volume - #R_d = equations.R_dry_air - #ref_temp = equations.ref_temperature + c_pd = equations.c_dry_air_const_pressure + c_vd = equations.c_dry_air_const_volume # Same settings as in `initial_condition` RealT = eltype(u) @@ -43,7 +41,7 @@ function source_terms_convergence_test(u, x, t, equations::CompressibleRainyEule si, co = sincos(ω * (x1 + x2 - t)) rho = c + A * si rho_x = ω * A * co - # Note that d/dt rho = -d/dx rho = -d/dy rho. + # Notice that d/dt rho = -d/dx rho = -d/dy rho. tmp = (2 * rho - 1) * (γ - 1) #+ R_d * ref_temp diff --git a/examples/convergence_test_elixirs/convergence_test_rainy_explicit.jl b/examples/convergence_test_elixirs/convergence_test_rainy_explicit.jl index e09c701e..bcac380a 100644 --- a/examples/convergence_test_elixirs/convergence_test_rainy_explicit.jl +++ b/examples/convergence_test_elixirs/convergence_test_rainy_explicit.jl @@ -6,13 +6,13 @@ using TrixiAtmo: saturation_vapour_pressure, saturation_vapour_pressure_derivati -function initial_condition_convergence_test_rainy(x, t, equations::CompressibleRainyEulerEquationsExplicit2D) +function initial_condition_convergence_test_rainy(x, t, equations::CompressibleRainyEulerExplicitEquations2D) # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_v = equations.R_vapour - ref_L = equations.ref_latent_heat_vap_temp + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour + ref_L = equations.ref_latent_heat_vap_temp # define rho like in dry convergence test c = 2.0 @@ -38,16 +38,16 @@ function initial_condition_convergence_test_rainy(x, t, equations::CompressibleR end -function source_terms_convergence_test_rainy(u, x, t, equations::CompressibleRainyEulerEquationsExplicit2D) +function source_terms_convergence_test_rainy(u, x, t, equations::CompressibleRainyEulerExplicitEquations2D) # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_d = equations.R_dry_air - R_v = equations.R_vapour - ref_L = equations.ref_latent_heat_vap_temp - N_0 = equations.rain_water_distr - v_0 = equations.v_mean_rain + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + ref_L = equations.ref_latent_heat_vap_temp + N_0 = equations.rain_water_distr + v_0 = equations.v_mean_rain # help constant for terminal rain velocity derivative ( \Gamma(4.5) / 6 ~= 1.9386213994279082 ) c_help = v_0 * 1.9386213994279082 * (pi * N_0)^(-0.125) @@ -130,7 +130,7 @@ end ############################################################################### # semidiscretization of the compressible Euler equations -equations = CompressibleRainyEulerEquationsExplicit2D() +equations = CompressibleRainyEulerExplicitEquations2D() initial_condition = initial_condition_convergence_test_rainy diff --git a/examples/convergence_test_elixirs/convergence_test_rainy_dry_explicit.jl b/examples/convergence_test_elixirs/convergence_test_rainy_explicit_dry.jl similarity index 95% rename from examples/convergence_test_elixirs/convergence_test_rainy_dry_explicit.jl rename to examples/convergence_test_elixirs/convergence_test_rainy_explicit_dry.jl index 79ca94be..1be59acf 100644 --- a/examples/convergence_test_elixirs/convergence_test_rainy_dry_explicit.jl +++ b/examples/convergence_test_elixirs/convergence_test_rainy_explicit_dry.jl @@ -5,7 +5,7 @@ using TrixiAtmo # adapted from compressible_euler_2d.jl -function initial_condition_convergence_test(x, t, equations::CompressibleRainyEulerEquationsExplicit2D) +function initial_condition_convergence_test(x, t, equations::CompressibleRainyEulerExplicitEquations2D) RealT = eltype(x) c = 2 A = convert(RealT, 0.1) @@ -24,9 +24,9 @@ end # adapted from compressible_euler_2d.jl -function source_terms_convergence_test(u, x, t, equations::CompressibleRainyEulerEquationsExplicit2D) - c_pd = equations.c_dry_air_const_pressure - c_vd = equations.c_dry_air_const_volume +function source_terms_convergence_test(u, x, t, equations::CompressibleRainyEulerExplicitEquations2D) + c_pd = equations.c_dry_air_const_pressure + c_vd = equations.c_dry_air_const_volume # Same settings as in `initial_condition` RealT = eltype(u) @@ -41,7 +41,7 @@ function source_terms_convergence_test(u, x, t, equations::CompressibleRainyEule si, co = sincos(ω * (x1 + x2 - t)) rho = c + A * si rho_x = ω * A * co - # Note that d/dt rho = -d/dx rho = -d/dy rho. + # Notice that d/dt rho = -d/dx rho = -d/dy rho. tmp = (2 * rho - 1) * (γ - 1) du1 = rho_x @@ -57,7 +57,7 @@ end ############################################################################### # semidiscretization of the compressible Euler equations -equations = CompressibleRainyEulerEquationsExplicit2D() +equations = CompressibleRainyEulerExplicitEquations2D() initial_condition = initial_condition_convergence_test diff --git a/examples/convergence_test_elixirs/convergence_test_rainy_no_rain_explicit.jl b/examples/convergence_test_elixirs/convergence_test_rainy_explicit_moist.jl similarity index 92% rename from examples/convergence_test_elixirs/convergence_test_rainy_no_rain_explicit.jl rename to examples/convergence_test_elixirs/convergence_test_rainy_explicit_moist.jl index 7d1a25af..29b384e2 100644 --- a/examples/convergence_test_elixirs/convergence_test_rainy_no_rain_explicit.jl +++ b/examples/convergence_test_elixirs/convergence_test_rainy_explicit_moist.jl @@ -6,13 +6,13 @@ using TrixiAtmo: saturation_vapour_pressure, saturation_vapour_pressure_derivati -function initial_condition_convergence_test_rainy_no_rain(x, t, equations::CompressibleRainyEulerEquationsExplicit2D) +function initial_condition_convergence_test_rainy_no_rain(x, t, equations::CompressibleRainyEulerExplicitEquations2D) # needed constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_v = equations.R_vapour - ref_L = equations.ref_latent_heat_vap_temp + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour + ref_L = equations.ref_latent_heat_vap_temp # define rho like in dry convergence test c = 2.0 @@ -37,14 +37,14 @@ function initial_condition_convergence_test_rainy_no_rain(x, t, equations::Compr end -function source_terms_convergence_test_rainy_no_rain(u, x, t, equations::CompressibleRainyEulerEquationsExplicit2D) +function source_terms_convergence_test_rainy_no_rain(u, x, t, equations::CompressibleRainyEulerExplicitEquations2D) # needed constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_d = equations.R_dry_air - R_v = equations.R_vapour - ref_L = equations.ref_latent_heat_vap_temp + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + ref_L = equations.ref_latent_heat_vap_temp # define rho like initial condition c = 2.0 @@ -112,7 +112,7 @@ end ############################################################################### # semidiscretization of the compressible Euler equations -equations = CompressibleRainyEulerEquationsExplicit2D() +equations = CompressibleRainyEulerExplicitEquations2D() initial_condition = initial_condition_convergence_test_rainy_no_rain diff --git a/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl b/examples/convergence_test_elixirs/convergence_test_rainy_moist.jl similarity index 94% rename from examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl rename to examples/convergence_test_elixirs/convergence_test_rainy_moist.jl index f78284ca..565c440a 100644 --- a/examples/convergence_test_elixirs/convergence_test_rainy_no_rain.jl +++ b/examples/convergence_test_elixirs/convergence_test_rainy_moist.jl @@ -8,11 +8,11 @@ using TrixiAtmo: saturation_vapour_pressure, saturation_vapour_pressure_derivati function initial_condition_convergence_test_rainy_no_rain(x, t, equations::CompressibleRainyEulerEquations2D) # needed constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_v = equations.R_vapour - ref_L = equations.ref_latent_heat_vap_temp + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour + ref_L = equations.ref_latent_heat_vap_temp # define rho like in dry convergence test c = 2.0 @@ -39,12 +39,12 @@ end function source_terms_convergence_test_rainy_no_rain(u, x, t, equations::CompressibleRainyEulerEquations2D) # needed constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_d = equations.R_dry_air - R_v = equations.R_vapour - ref_L = equations.ref_latent_heat_vap_temp + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + ref_L = equations.ref_latent_heat_vap_temp # define rho like initial condition c = 2.0 diff --git a/examples/dry_bubble_elixirs/energy/elixir_rainy_euler_dry_bubble.jl b/examples/dry_bubble_elixirs/energy/elixir_rainy_euler_dry_bubble.jl index 4b2166a2..62bc95f9 100644 --- a/examples/dry_bubble_elixirs/energy/elixir_rainy_euler_dry_bubble.jl +++ b/examples/dry_bubble_elixirs/energy/elixir_rainy_euler_dry_bubble.jl @@ -87,7 +87,7 @@ semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 1100.0) +tspan = (0.0, 1000.0) ode = semidiscretize(semi, tspan) @@ -95,7 +95,6 @@ summary_callback = SummaryCallback() analysis_interval = 1000 -# entropy? analysis_callback = AnalysisCallback(semi, interval = analysis_interval, extra_analysis_errors = (:entropy_conservation_error,)) diff --git a/examples/dry_bubble_elixirs/potential_temperature/elixir_dry_potential_euler_bubble.jl b/examples/dry_bubble_elixirs/potential_temperature/elixir_dry_potential_euler_bubble.jl deleted file mode 100644 index 9f6e0b2e..00000000 --- a/examples/dry_bubble_elixirs/potential_temperature/elixir_dry_potential_euler_bubble.jl +++ /dev/null @@ -1,125 +0,0 @@ -using OrdinaryDiffEq -using Trixi -using TrixiAtmo -using TrixiAtmo: source_terms_no_phase_change, flux_LMARS - - - -# copied from elixir_euler_warm_bubble.jl for quick tests -function initial_condition_bubble_dry(x, t, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - g = equations.gravity - c_p = equations.c_dry_air_const_pressure - c_v = equations.c_dry_air_const_volume - - # center of perturbation - center_x = 10000.0 - center_z = 2000.0 - # radius of perturbation - radius = 2000.0 - # 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.0 - potential_temperature_perturbation = 0.0 - if r <= radius - potential_temperature_perturbation = 2 * cospi(0.5 * 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.0 # 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 = 0.0 - v2 = 0.0 - #E = c_v * T + 0.5 * (v1^2 + v2^2) - - return SVector(rho, 0.0, 0.0, rho * v1, rho * v2, rho * potential_temperature, 0.0, 0.0, 0.0) -end - - - -############################################################################### -# semidiscretization of the compressible rainy Euler equations - -equations = CompressibleRainyEulerPotentialTemperatureEquations2D() - -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 = 3 -basis = LobattoLegendreBasis(polydeg) - -surface_flux = flux_LMARS - -solver = DGSEM(basis, surface_flux) - -coordinates_min = ( 0.0, 0.0) -coordinates_max = (20_000.0, 10_000.0) - -cells_per_dimension = (64, 32) - -periodicity = (true, false) - -mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, - periodicity = periodicity) - -initial_condition = initial_condition_bubble_dry -source_terms = source_terms_no_phase_change - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms = source_terms, - boundary_conditions = boundary_conditions) - -############################################################################### -# ODE solvers, callbacks etc. - -tspan = (0.0, 1100.0) - -ode = semidiscretize(semi, tspan) - -summary_callback = SummaryCallback() - -analysis_interval = 1000 - -# entropy? -analysis_callback = AnalysisCallback(semi, interval = analysis_interval, - extra_analysis_errors = (:entropy_conservation_error,)) - -alive_callback = AliveCallback(analysis_interval = analysis_interval) - -save_solution = SaveSolutionCallback(interval = 100, - save_initial_solution = true, - save_final_solution = true, - output_directory = "out", - solution_variables = cons2prim) - -stepsize_callback = StepsizeCallback(cfl = 1.0) - -callbacks = CallbackSet(summary_callback, - analysis_callback, - alive_callback, - save_solution, - stepsize_callback) - -############################################################################### -# run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), - maxiters = 1.0e7, - dt = 1.0, - save_everystep = false, callback = callbacks); - -summary_callback() \ No newline at end of file diff --git a/examples/entropy_conservation_tests/moist_bubble/elixir_rainy_euler_explicit_moist_bubble_ec_test.jl b/examples/entropy_conservation_tests/moist_bubble/elixir_rainy_euler_explicit_moist_bubble_ec_test.jl index 94dc2ce9..d9711907 100644 --- a/examples/entropy_conservation_tests/moist_bubble/elixir_rainy_euler_explicit_moist_bubble_ec_test.jl +++ b/examples/entropy_conservation_tests/moist_bubble/elixir_rainy_euler_explicit_moist_bubble_ec_test.jl @@ -191,9 +191,6 @@ function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, rho_d_new = p_loc / (R_d * T_loc) θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) end - # test - #T_loc = θ_new * (p_loc / p_0)^kappa - # rho_qv = rvs * rho_d_new rho_ql = (rt - rvs) * rho_d_new rho = rho_d_new * (1 + rt) @@ -210,7 +207,7 @@ end atmosphere_data = AtmosphereLayers(CompressibleMoistEulerEquations2D()) # Create the initial condition with the initial data set -function initial_condition_moist(x, t, equations::CompressibleRainyEulerEquationsExplicit2D) +function initial_condition_moist(x, t, equations::CompressibleRainyEulerExplicitEquations2D) return initial_condition_moist_bubble(x, t, CompressibleMoistEulerEquations2D(), atmosphere_data) end @@ -219,7 +216,7 @@ end ############################################################################### # semidiscretization of the compressible rainy Euler equations -equations = CompressibleRainyEulerEquationsExplicit2D() +equations = CompressibleRainyEulerExplicitEquations2D() boundary_conditions = (x_neg = boundary_condition_periodic, x_pos = boundary_condition_periodic, diff --git a/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl b/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl index 59ee6d28..f0281c34 100644 --- a/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl +++ b/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl @@ -5,7 +5,7 @@ using TrixiAtmo: flux_ec_rain, flux_chandrashekar, RainLimiterDG, cons2eq_pot_temp -function initial_condition_weak_blast_wave_dry(x, t, equations::CompressibleRainyEulerEquationsExplicit2D) +function initial_condition_weak_blast_wave_dry(x, t, equations::CompressibleRainyEulerExplicitEquations2D) # constants c_vd = equations.c_dry_air_const_volume R_d = equations.R_dry_air @@ -37,7 +37,7 @@ end ############################################################################### # semidiscretization of the compressible Euler equations -equations = CompressibleRainyEulerEquationsExplicit2D() +equations = CompressibleRainyEulerExplicitEquations2D() initial_condition = initial_condition_weak_blast_wave_dry diff --git a/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl b/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl index a781cf81..5e2b8f2c 100644 --- a/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl +++ b/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl @@ -3,10 +3,10 @@ using Trixi using TrixiAtmo using TrixiAtmo: saturation_residual, saturation_residual_jacobian, flux_ec_rain, saturation_vapour_pressure, flux_chandrashekar, - RainLimiterDG, cons2eq_pot_temp + RainLimiterDG, cons2eq_pot_temp, entropy -function initial_condition_weak_blast_wave_rainy(x, t, equations::CompressibleRainyEulerEquationsExplicit2D) +function initial_condition_weak_blast_wave_rainy(x, t, equations::CompressibleRainyEulerExplicitEquations2D) # constants c_l = equations.c_liquid_water c_vd = equations.c_dry_air_const_volume @@ -46,7 +46,7 @@ end ############################################################################### # semidiscretization of the compressible Euler equations -equations = CompressibleRainyEulerEquationsExplicit2D() +equations = CompressibleRainyEulerExplicitEquations2D() initial_condition = initial_condition_weak_blast_wave_rainy @@ -78,7 +78,9 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval = analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + save_analysis = true, + extra_analysis_integrals = (entropy,)) alive_callback = AliveCallback(analysis_interval = analysis_interval) @@ -88,7 +90,7 @@ save_solution = SaveSolutionCallback(interval = 1000, output_directory = "out", solution_variables = cons2eq_pot_temp) -stepsize_callback = StepsizeCallback(cfl = 1.0) +stepsize_callback = StepsizeCallback(cfl = 0.1) callbacks = CallbackSet(summary_callback, analysis_callback, diff --git a/examples/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl b/examples/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl index c4d121df..afd5ac40 100644 --- a/examples/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl +++ b/examples/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl @@ -251,7 +251,6 @@ boundary_conditions = (; :left => boundary_condition_periodic, solver = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = StartUpDG.Polynomial{MultidimensionalQuadrature}(), surface_integral = SurfaceIntegralWeakForm(flux_LMARS), volume_integral = VolumeIntegralWeakForm(), - #volume_integral = VolumeIntegralFluxDifferencing(flux_chandrashekar); quad_rule_vol = StartUpDG.quad_nodes(Quad(), 6) ) @@ -281,18 +280,11 @@ analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype alive_callback = AliveCallback(analysis_interval = 1000) -#save_solution = SaveSolutionCallback(interval = 1000, - #save_initial_solution = true, - #save_final_solution = true, - #output_directory = "out", - #solution_variables = cons2eq_pot_temp) - stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, - #save_solution, stepsize_callback) ############################################################################### @@ -305,4 +297,4 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), summary_callback() pd = PlotData2D(sol; solution_variables = cons2aeqpot); -plot(pd["aeqpottemp"], c = :vik, dpi = 1000) \ No newline at end of file +plot(pd["aeqpottemp"]) \ No newline at end of file diff --git a/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_explicit_moist_bubble.jl b/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_explicit_moist_bubble.jl index 401d5704..41bfb82c 100644 --- a/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_explicit_moist_bubble.jl +++ b/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_explicit_moist_bubble.jl @@ -191,9 +191,7 @@ function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, rho_d_new = p_loc / (R_d * T_loc) θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) end - # test - #T_loc = θ_new * (p_loc / p_0)^kappa - # + rho_qv = rvs * rho_d_new rho_ql = (rt - rvs) * rho_d_new rho = rho_d_new * (1 + rt) @@ -210,7 +208,7 @@ end atmosphere_data = AtmosphereLayers(CompressibleMoistEulerEquations2D()) # Create the initial condition with the initial data set -function initial_condition_moist(x, t, equations::CompressibleRainyEulerEquationsExplicit2D) +function initial_condition_moist(x, t, equations::CompressibleRainyEulerExplicitEquations2D) return initial_condition_moist_bubble(x, t, CompressibleMoistEulerEquations2D(), atmosphere_data) end @@ -219,7 +217,7 @@ end ############################################################################### # semidiscretization of the compressible rainy Euler equations -equations = CompressibleRainyEulerEquationsExplicit2D() +equations = CompressibleRainyEulerExplicitEquations2D() boundary_conditions = (x_neg = boundary_condition_periodic, x_pos = boundary_condition_periodic, @@ -229,7 +227,6 @@ boundary_conditions = (x_neg = boundary_condition_periodic, polydeg = 3 basis = LobattoLegendreBasis(polydeg) -#surface_flux = flux_lax_friedrichs surface_flux = flux_LMARS volume_flux = flux_ec_rain @@ -240,7 +237,7 @@ solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = ( 0.0, 0.0) coordinates_max = (20_000.0, 10_000.0) -cells_per_dimension = (65, 32) +cells_per_dimension = (128, 64) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = (true, false)) @@ -260,7 +257,6 @@ summary_callback = SummaryCallback() analysis_interval = 1000 - analysis_callback = AnalysisCallback(semi, interval = analysis_interval, extra_analysis_errors = (:entropy_conservation_error,)) diff --git a/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl b/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl index ecea985b..1bf9d01d 100644 --- a/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl +++ b/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl @@ -4,7 +4,7 @@ using TrixiAtmo using TrixiAtmo: source_terms_no_phase_change, saturation_residual, saturation_residual_jacobian, NonlinearSolveDG, cons2eq_pot_temp, flux_LMARS, flux_chandrashekar, - flux_ec_rain + flux_ec_rain, boundary_condition_simple_slip_wall using NLsolve: nlsolve @@ -192,9 +192,6 @@ function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, rho_d_new = p_loc / (R_d * T_loc) θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) end - # test - #T_loc = θ_new * (p_loc / p_0)^kappa - # rho_qv = rvs * rho_d_new rho_ql = (rt - rvs) * rho_d_new rho = rho_d_new * (1 + rt) @@ -230,7 +227,6 @@ boundary_conditions = (x_neg = boundary_condition_periodic, polydeg = 3 basis = LobattoLegendreBasis(polydeg) -#surface_flux = flux_lax_friedrichs surface_flux = flux_LMARS volume_flux = flux_ec_rain @@ -241,7 +237,7 @@ solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = ( 0.0, 0.0) coordinates_max = (20_000.0, 10_000.0) -cells_per_dimension = (65, 32) +cells_per_dimension = (128, 64) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = (true, false)) @@ -261,7 +257,6 @@ summary_callback = SummaryCallback() analysis_interval = 1000 -# entropy? analysis_callback = AnalysisCallback(semi, interval = analysis_interval, extra_analysis_errors = (:entropy_conservation_error,)) diff --git a/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble_dgmulti.jl b/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble_dgmulti.jl index 1dbb560f..7c1d3cea 100644 --- a/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble_dgmulti.jl +++ b/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble_dgmulti.jl @@ -191,9 +191,7 @@ function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, rho_d_new = p_loc / (R_d * T_loc) θ_new = θ_dens_new * (1 + rt) / (1 + (R_v / R_d) * rvs) end - # test - #T_loc = θ_new * (p_loc / p_0)^kappa - # + rho_qv = rvs * rho_d_new rho_ql = (rt - rvs) * rho_d_new rho = rho_d_new * (1 + rt) @@ -234,9 +232,6 @@ boundary_conditions = (; :left => boundary_condition_periodic, :bottom => boundary_condition_slip_wall, :right => boundary_condition_periodic) -#volume_flux = flux_chandrashekar -#volume_integral = VolumeIntegralFluxDifferencing(volume_flux) - solver = DGMulti(polydeg = 1, element_type = Quad(), approximation_type = GaussSBP(), surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), volume_integral = VolumeIntegralWeakForm()) @@ -267,18 +262,11 @@ analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype alive_callback = AliveCallback(analysis_interval = 1000) -#save_solution = SaveSolutionCallback(interval = 1000, - #save_initial_solution = true, - #save_final_solution = true, - #output_directory = "out", - #solution_variables = cons2eq_pot_temp) - stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, - #save_solution, stepsize_callback) stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) @@ -293,4 +281,4 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limite summary_callback() pd = PlotData2D(sol; solution_variables = cons2eq_pot_temp); -plot(pd["eq_pot_temp"], c = :vik, dpi = 1000) \ No newline at end of file +plot(pd["eq_pot_temp"]) \ No newline at end of file diff --git a/examples/moist_bubble_elixirs/potential_temperature/elixir_moist_euler_potential_temperature_moist_bubble.jl b/examples/moist_bubble_elixirs/potential_temperature/elixir_moist_euler_potential_temperature_moist_bubble.jl index 1f85a698..cda5f373 100644 --- a/examples/moist_bubble_elixirs/potential_temperature/elixir_moist_euler_potential_temperature_moist_bubble.jl +++ b/examples/moist_bubble_elixirs/potential_temperature/elixir_moist_euler_potential_temperature_moist_bubble.jl @@ -251,9 +251,8 @@ solver = DGSEM(basis, surface_flux) coordinates_min = (0.0, 0.0) coordinates_max = (20000.0, 10000.0) -cells_per_dimension = (201, 100) +cells_per_dimension = (128, 64) -# Create curved mesh with 64 x 32 elements mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = (true, false)) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl index 672930ba..0a4df76b 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl @@ -17,7 +17,7 @@ coordinates_max = (2400.0, 2400.0) # hydrostatic dry potential temperature -function theta_d(z, equations::CompressibleRainyEulerEquationsExplicit2D) +function theta_d(z, equations::CompressibleRainyEulerExplicitEquations2D) # constants c_pd = equations.c_dry_air_const_pressure R_d = equations.R_dry_air @@ -38,7 +38,7 @@ end # hydrostatic base state residual -function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equations::CompressibleRainyEulerEquationsExplicit2D) +function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equations::CompressibleRainyEulerExplicitEquations2D) # equations constants c_pd = equations.c_dry_air_const_pressure R_d = equations.R_dry_air @@ -72,7 +72,7 @@ function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equ end -function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equations::CompressibleRainyEulerEquationsExplicit2D) +function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equations::CompressibleRainyEulerExplicitEquations2D) # equations constants c_pd = equations.c_dry_air_const_pressure R_d = equations.R_dry_air @@ -111,7 +111,7 @@ struct AtmosphereLayers{RealT <: Real} end -function AtmosphereLayers(equations::CompressibleRainyEulerEquationsExplicit2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) +function AtmosphereLayers(equations::CompressibleRainyEulerExplicitEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) # constants humidity_rel0 = 0.2 # hydrostatic relative humidity surface_pressure = 8.5e4 @@ -145,11 +145,11 @@ end # create layers for initial condition -equations = CompressibleRainyEulerEquationsExplicit2D() +equations = CompressibleRainyEulerExplicitEquations2D() layers = AtmosphereLayers(equations) -function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerEquationsExplicit2D; atmosphere_layers = layers) +function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerExplicitEquations2D; atmosphere_layers = layers) # equations constants c_vd = equations.c_dry_air_const_volume c_vv = equations.c_vapour_const_volume @@ -260,13 +260,10 @@ save_solution = SaveSolutionCallback(interval = 1000, output_directory = "out", solution_variables = cons2eq_pot_temp) -stepsize_callback = StepsizeCallback(cfl = 1.0) - callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, - save_solution, - stepsize_callback) + save_solution) stage_limiter! = RainLimiterDG() diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl index e2b87a9e..749c3ff2 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl @@ -19,7 +19,7 @@ coordinates_max = (2400.0, 2400.0) # hydrostatic dry potential temperature -function theta_d(z, equations::CompressibleRainyEulerEquationsExplicit2D) +function theta_d(z, equations::CompressibleRainyEulerExplicitEquations2D) # constants c_pd = equations.c_dry_air_const_pressure R_d = equations.R_dry_air @@ -40,7 +40,7 @@ end # hydrostatic base state residual -function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equations::CompressibleRainyEulerEquationsExplicit2D) +function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equations::CompressibleRainyEulerExplicitEquations2D) # equations constants c_pd = equations.c_dry_air_const_pressure R_d = equations.R_dry_air @@ -74,7 +74,7 @@ function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equ end -function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equations::CompressibleRainyEulerEquationsExplicit2D) +function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equations::CompressibleRainyEulerExplicitEquations2D) # equations constants c_pd = equations.c_dry_air_const_pressure R_d = equations.R_dry_air @@ -113,7 +113,7 @@ struct AtmosphereLayers{RealT <: Real} end -function AtmosphereLayers(equations::CompressibleRainyEulerEquationsExplicit2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) +function AtmosphereLayers(equations::CompressibleRainyEulerExplicitEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) # constants humidity_rel0 = 0.2 # hydrostatic relative humidity surface_pressure = 8.5e4 @@ -147,11 +147,11 @@ end # create layers for initial condition -equations = CompressibleRainyEulerEquationsExplicit2D() +equations = CompressibleRainyEulerExplicitEquations2D() layers = AtmosphereLayers(equations) -function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerEquationsExplicit2D; atmosphere_layers = layers) +function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerExplicitEquations2D; atmosphere_layers = layers) # equations constants c_vd = equations.c_dry_air_const_volume c_vv = equations.c_vapour_const_volume diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl index 5f566e0d..afd47df7 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl @@ -249,7 +249,7 @@ summary_callback = SummaryCallback() analysis_interval = 1000 -# entropy? +# entropy analysis_callback = AnalysisCallback(semi, interval = analysis_interval, extra_analysis_errors = (:entropy_conservation_error,)) @@ -261,13 +261,10 @@ save_solution = SaveSolutionCallback(interval = 1000, output_directory = "out", solution_variables = cons2eq_pot_temp) -stepsize_callback = StepsizeCallback(cfl = 1.0) - callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, - save_solution, - stepsize_callback) + save_solution) stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_amr.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_amr.jl deleted file mode 100644 index 68257764..00000000 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_amr.jl +++ /dev/null @@ -1,285 +0,0 @@ -using OrdinaryDiffEq -using Trixi -using TrixiAtmo -using TrixiAtmo: source_terms_rainy, saturation_residual, - saturation_residual_jacobian, NonlinearSolveDG, - cons2eq_pot_temp, saturation_vapour_pressure, - flux_chandrashekar, flux_LMARS, - source_terms_no_phase_change, rain_density -using NLsolve: nlsolve - - - -# domain -coordinates_min = ( 0.0, 0.0) -coordinates_max = (3600.0, 3600.0) - - -# hydrostatic dry potential temperature -function theta_d(z, equations::CompressibleRainyEulerEquations2D) - # constants - c_pd = equations.c_dry_air_const_pressure - R_d = equations.R_dry_air - ref_pressure = equations.ref_pressure - - # problem specific constants - surface_temperature = 283.0 - surface_pressure = 8.5e4 - stratification = 1.3e-5 - - # dry potential temperature at surface - Theta0 = surface_temperature * (ref_pressure / surface_pressure)^(R_d / c_pd) - # at height z - theta_d = Theta0 * exp(stratification * z) - - return theta_d -end - - -# hydrostatic base state residual -function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equations::CompressibleRainyEulerEquations2D) - # equations constants - c_pd = equations.c_dry_air_const_pressure - R_d = equations.R_dry_air - R_v = equations.R_vapour - eps = equations.eps - ref_pressure = equations.ref_pressure - g = equations.gravity - - function hydrostatic_residual!(residual, guess) - # variables - pressure, rho_dry, rho_vapour, temperature = guess - - rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) - - # pressure derivative residual approximation - residual[1] = (pressure - pressure_lower) / dz + (rho_dry + rho_vapour) * g - - # pressure residual - residual[2] = pressure - temperature * (rho_dry * R_d + rho_vapour * R_v) - - # hydrostatic dry potential temperature residual - residual[3] = theta_d(z, equations) - temperature * (ref_pressure / pressure)^(R_d / c_pd) - - # humidity residual - residual[4] = rho_vs * (rho_dry + rho_vapour / eps) * humidity_rel0 - residual[4] -= rho_vapour * (rho_dry + rho_vs / eps) - residual[4] *= 1000.0 - end - - return hydrostatic_residual! -end - - -function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equations::CompressibleRainyEulerEquations2D) - # equations constants - c_pd = equations.c_dry_air_const_pressure - R_d = equations.R_dry_air - R_v = equations.R_vapour - eps = equations.eps - ref_pressure = equations.ref_pressure - - function perturbation_residual!(residual, guess) - # variables - rho_dry, rho_vapour, temperature = guess - - rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) - pressure = (rho_dry * R_d + rho_vapour * R_v) * temperature - - # humidity residual - residual[1] = rho_vs * (rho_dry + rho_vapour / eps) * H_init - residual[1] -= rho_vapour * (rho_dry + rho_vs / eps) - residual[1] *= 30.0 - - # hydrostatic dry potential temperature residual - residual[2] = theta_d(z, equations) - temperature * (ref_pressure / pressure_hydrostatic)^(R_d / c_pd) - - # pressure residual - residual[3] = pressure_hydrostatic - pressure - end - - return perturbation_residual! -end - - -# for approximating the dz pressure gradient -struct AtmosphereLayers{RealT <: Real} - layer_data ::Matrix{RealT} - total_height ::RealT - precision ::RealT -end - - -function AtmosphereLayers(equations::CompressibleRainyEulerEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) - # constants - humidity_rel0 = 0.2 # hydrostatic relative humidity - surface_pressure = 8.5e4 - - # surface layer with initial guesses for rho_dry, rho_vapour and temperature - surface_layer = [surface_pressure, 1.4, 0.04, 300.0] - - # allocate layer_data - n = convert(Int, total_height / precision) - layer_data = zeros(RealT, n + 1, 4) - - # solve (slightly above) surface layer - dz = 0.01 - z = 0.01 - residual_function! = generate_hydrostatic_residual(surface_pressure, humidity_rel0, z, dz, equations) - layer_data[1, :] .= nlsolve(residual_function!, surface_layer).zero - - # adjust to chosen precision - dz = precision - - # iterate up the atmosphere - for i in (1:n) - z += dz - residual_function! = generate_hydrostatic_residual(layer_data[i, 1], humidity_rel0, z, dz, equations) - guess = deepcopy(layer_data[i, :]) - layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, iterations = 20).zero - end - - return AtmosphereLayers{RealT}(layer_data, total_height, precision) -end - - -# create layers for initial condition -equations = CompressibleRainyEulerEquations2D() -layers = AtmosphereLayers(equations) - - -function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerEquations2D; atmosphere_layers = layers) - # equations constants - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - ref_L = equations.ref_latent_heat_vap_temp - - # problem specific constants - humidity_rel_bar = 0.2 # background relative humidity field - - # bubble parameters - radius_outer, radius_inner = 300.0, 200.0 # radii of humidity bubble - x_center, z_center = 1800.0, 800.0 # center of humidity bubble - - # radius relative to bubble center - r = sqrt((x[1] - x_center)^2 + (x[2] - z_center)^2) - - # humidity definition - if (r > radius_outer) - # outside the bubble - humidity = humidity_rel_bar - elseif (r > radius_inner) - # outer layers of the bubble - humidity = humidity_rel_bar + (1.0 - humidity_rel_bar) * cos(pi * (r - radius_inner) / (2.0 * (radius_outer - radius_inner)))^2 - else - # inner layer - humidity = 1.0 - end - - # get atmosphere layer and height information - @unpack layer_data, total_height, precision = atmosphere_layers - dz = precision - z = x[2] - n = convert(Int, floor((z + eps()) / dz)) + 1 - z_lower = (n - 1) * dz - z_upper = n * dz - - if (z_lower == total_height) - z_upper = z_lower + dz - n = n - 1 - end - - # check height consistency - if (z > total_height && !(isapprox(z, total_height))) - error("The atmosphere does not match the simulation domain") - end - - # (for IndicatorLöhner) - if (n == 0) - n = 1 - end - - # get hydrostatic pressures and approximate between lower and upper data point - pressure_hydrostatic_lower = layer_data[n, 1] - pressure_hydrostatic_upper = layer_data[n + 1, 1] - pressure_hydrostatic = (pressure_hydrostatic_upper * (z - z_lower) + pressure_hydrostatic_lower * (z_upper - z)) / dz - - # solve perturbation - residual_function! = generate_perturbation_residual(pressure_hydrostatic, humidity, z, equations) - rho_dry, rho_vapour, temperature = nlsolve(residual_function!, layer_data[n, 2:4], ftol = 1e-9, iterations = 20).zero - - energy_density = (c_vd * rho_dry + c_vv * rho_vapour) * temperature + rho_vapour * ref_L - - return SVector(rho_dry, rho_vapour, 0.0, 0.0, 0.0, energy_density, rho_vapour, 0.0, temperature) -end - - -initial_condition = initial_condition_bubble_rainy - -boundary_conditions = (x_neg = boundary_condition_periodic, - x_pos = boundary_condition_periodic, - y_neg = boundary_condition_slip_wall, - y_pos = boundary_condition_slip_wall) - -surface_flux = flux_lax_friedrichs -#volume_integral = VolumeIntegralFluxDifferencing(flux_chandrashekar) -polydeg = 1 -basis = LobattoLegendreBasis(polydeg) - -solver = DGSEM(basis, surface_flux)#, volume_integral) - -mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level = 8, - periodicity = (true, false), - n_cells_max = 1_000_000) - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, - source_terms = source_terms_rainy, solver, - boundary_conditions = boundary_conditions) - -############################################################################### -# ODE solvers, callbacks etc. - -tspan = (0.0, 600.0) -ode = semidiscretize(semi, tspan) - -summary_callback = SummaryCallback() - -analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval = analysis_interval) - -alive_callback = AliveCallback(analysis_interval = analysis_interval) - -save_solution = SaveSolutionCallback(interval = 1000, - save_initial_solution = true, - save_final_solution = true, - output_directory = "out", - solution_variables = cons2eq_pot_temp) - -amr_indicator = IndicatorMax(semi, variable=rain_density) - -amr_controller = ControllerThreeLevel(semi, amr_indicator, - base_level = 8, - med_level = 10, med_threshold = 1e-6, - max_level = 11, max_threshold = 5e-5) - -amr_callback = AMRCallback(semi, amr_controller, - interval = 1, - adapt_initial_condition = false, - adapt_initial_condition_only_refine = true) - -stepsize_callback = StepsizeCallback(cfl = 1.0) - -callbacks = CallbackSet(summary_callback, - analysis_callback, alive_callback, - amr_callback, save_solution, stepsize_callback) - -stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) - -############################################################################### -# run the simulation -# use adaptive time stepping based on error estimates -sol = solve(ode, SSPRK43(stage_limiter!); - ode_default_options()..., callback = callbacks); - -summary_callback() # print the timer summary \ No newline at end of file diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_dgmulti.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_dgmulti.jl deleted file mode 100644 index 7e5b1e98..00000000 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_dgmulti.jl +++ /dev/null @@ -1,288 +0,0 @@ -using OrdinaryDiffEq -using Trixi -using TrixiAtmo -using TrixiAtmo: source_terms_rainy, saturation_residual, - saturation_residual_jacobian, NonlinearSolveDG, - cons2eq_pot_temp, saturation_vapour_pressure, - flux_chandrashekar, flux_LMARS, - source_terms_no_phase_change -using NLsolve: nlsolve -using Plots - - - -# domain -coordinates_min = ( 0.0, 0.0) -coordinates_max = (2400.0, 2400.0) - - -# hydrostatic dry potential temperature -function theta_d(z, equations::CompressibleRainyEulerEquations2D) - # constants - c_pd = equations.c_dry_air_const_pressure - R_d = equations.R_dry_air - ref_pressure = equations.ref_pressure - - # problem specific constants - surface_temperature = 283.0 - surface_pressure = 8.5e4 - stratification = 1.3e-5 - - # dry potential temperature at surface - Theta0 = surface_temperature * (ref_pressure / surface_pressure)^(R_d / c_pd) - # at height z - theta_d = Theta0 * exp(stratification * z) - - return theta_d -end - - -# hydrostatic base state residual -function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equations::CompressibleRainyEulerEquations2D) - # equations constants - c_pd = equations.c_dry_air_const_pressure - R_d = equations.R_dry_air - R_v = equations.R_vapour - eps = equations.eps - ref_pressure = equations.ref_pressure - g = equations.gravity - - function hydrostatic_residual!(residual, guess) - # variables - pressure, rho_dry, rho_vapour, temperature = guess - - rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) - - # pressure derivative residual approximation - residual[1] = (pressure - pressure_lower) / dz + (rho_dry + rho_vapour) * g - - # pressure residual - residual[2] = pressure - temperature * (rho_dry * R_d + rho_vapour * R_v) - - # hydrostatic dry potential temperature residual - residual[3] = theta_d(z, equations) - temperature * (ref_pressure / pressure)^(R_d / c_pd) - - # humidity residual - residual[4] = rho_vs * (rho_dry + rho_vapour / eps) * humidity_rel0 - residual[4] -= rho_vapour * (rho_dry + rho_vs / eps) - residual[4] *= 1000.0 - end - - return hydrostatic_residual! -end - - -function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equations::CompressibleRainyEulerEquations2D) - # equations constants - c_pd = equations.c_dry_air_const_pressure - R_d = equations.R_dry_air - R_v = equations.R_vapour - eps = equations.eps - ref_pressure = equations.ref_pressure - - function perturbation_residual!(residual, guess) - # variables - rho_dry, rho_vapour, temperature = guess - - rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) - pressure = (rho_dry * R_d + rho_vapour * R_v) * temperature - - # humidity residual - residual[1] = rho_vs * (rho_dry + rho_vapour / eps) * H_init - residual[1] -= rho_vapour * (rho_dry + rho_vs / eps) - residual[1] *= 30.0 - - # hydrostatic dry potential temperature residual - residual[2] = theta_d(z, equations) - temperature * (ref_pressure / pressure_hydrostatic)^(R_d / c_pd) - - # pressure residual - residual[3] = pressure_hydrostatic - pressure - end - - return perturbation_residual! -end - - -# for approximating the dz pressure gradient -struct AtmosphereLayers{RealT <: Real} - layer_data ::Matrix{RealT} - total_height ::RealT - precision ::RealT -end - - -function AtmosphereLayers(equations::CompressibleRainyEulerEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) - # constants - humidity_rel0 = 0.2 # hydrostatic relative humidity - surface_pressure = 8.5e4 - - # surface layer with initial guesses for rho_dry, rho_vapour and temperature - surface_layer = [surface_pressure, 1.4, 0.04, 300.0] - - # allocate layer_data - n = convert(Int, total_height / precision) - layer_data = zeros(RealT, n + 1, 4) - - # solve (slightly above) surface layer - dz = 0.01 - z = 0.01 - residual_function! = generate_hydrostatic_residual(surface_pressure, humidity_rel0, z, dz, equations) - layer_data[1, :] .= nlsolve(residual_function!, surface_layer).zero - - # adjust to chosen precision - dz = precision - - # iterate up the atmosphere - for i in (1:n) - z += dz - residual_function! = generate_hydrostatic_residual(layer_data[i, 1], humidity_rel0, z, dz, equations) - guess = deepcopy(layer_data[i, :]) - layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, iterations = 20).zero - end - - return AtmosphereLayers{RealT}(layer_data, total_height, precision) -end - - -# create layers for initial condition -equations = CompressibleRainyEulerEquations2D() -layers = AtmosphereLayers(equations) - - -function initial_condition_rainy_bubble(x, t, equations::CompressibleRainyEulerEquations2D; atmosphere_layers = layers) - # equations constants - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - ref_L = equations.ref_latent_heat_vap_temp - - # problem specific constants - humidity_rel_bar = 0.2 # background relative humidity field - humidity_max = 1.0 - - # bubble parameters - radius_outer, radius_inner = 300.0, 200.0 # radii of humidity bubble - x_center, z_center = 1200.0, 800.0 # center of humidity bubble - - # radius relative to bubble center - r = sqrt((x[1] - x_center)^2 + (x[2] - z_center)^2) - - # humidity definition - if (r > radius_outer) - # outside the bubble - humidity = humidity_rel_bar - elseif (r > radius_inner) - # outer layers of the bubble - humidity = humidity_rel_bar + (humidity_max - humidity_rel_bar) * cos(pi * (r - radius_inner) / (2.0 * (radius_outer - radius_inner)))^2 - else - # inner layer - humidity = humidity_max - end - - # get atmosphere layer and height information - @unpack layer_data, total_height, precision = atmosphere_layers - dz = precision - z = x[2] - n = convert(Int, floor((z + eps()) / dz)) + 1 - z_lower = (n - 1) * dz - z_upper = n * dz - - if (z_lower == total_height) - z_upper = z_lower + dz - n = n - 1 - end - - # check height consistency - if (z > total_height && !(isapprox(z, total_height))) - error("The atmosphere does not match the simulation domain") - end - - # get hydrostatic pressures and approximate between lower and upper data point - pressure_hydrostatic_lower = layer_data[n, 1] - pressure_hydrostatic_upper = layer_data[n + 1, 1] - pressure_hydrostatic = (pressure_hydrostatic_upper * (z - z_lower) + pressure_hydrostatic_lower * (z_upper - z)) / dz - - # solve perturbation - residual_function! = generate_perturbation_residual(pressure_hydrostatic, humidity, z, equations) - rho_dry, rho_vapour, temperature = nlsolve(residual_function!, layer_data[n, 2:4], ftol = 1e-9, iterations = 20).zero - - energy_density = (c_vd * rho_dry + c_vv * rho_vapour) * temperature + rho_vapour * ref_L - - return SVector(rho_dry, rho_vapour, 0.0, 0.0, 0.0, energy_density, rho_vapour, 0.0, temperature) -end - - -############################################################################### -# semidiscretization of the compressible moist Euler equations - -equations = CompressibleRainyEulerEquations2D() - -initial_condition = initial_condition_rainy_bubble - -# tag different boundary segments -left(x, tol = 50 * eps()) = abs(x[1] - coordinates_min[1]) < tol -right(x, tol = 50 * eps()) = abs(x[1] - coordinates_max[1]) < tol -bottom(x, tol = 50 * eps()) = abs(x[2] - coordinates_min[2]) < tol -top(x, tol = 50 * eps()) = abs(x[2] - coordinates_max[2]) < tol - -is_on_boundary = Dict(:left => left, :right => right, :top => top, :bottom => bottom) - -boundary_conditions = (; :left => boundary_condition_periodic, - :top => boundary_condition_slip_wall, - :bottom => boundary_condition_slip_wall, - :right => boundary_condition_periodic) - -#volume_flux = flux_chandrashekar -#volume_integral = VolumeIntegralFluxDifferencing(volume_flux) - -solver = DGMulti(polydeg = 1, element_type = Quad(), approximation_type = GaussSBP(), - surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), - volume_integral = VolumeIntegralWeakForm()) - -cells_per_dimension = (100, 100) -mesh = DGMultiMesh(solver, cells_per_dimension; coordinates_min, coordinates_max, is_on_boundary, periodicity = (true, false)) - -semi = SemidiscretizationHyperbolic(mesh, equations, - initial_condition, solver; - source_terms = source_terms_rainy, - boundary_conditions = boundary_conditions) - -############################################################################### -# ODE solvers, callbacks etc. - -tspan = (0.0, 300.0) - -ode = semidiscretize(semi, tspan) - -summary_callback = SummaryCallback() - -analysis_interval = 1000 - -analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(solver)) - -alive_callback = AliveCallback(analysis_interval = 1000) - -#save_solution = SaveSolutionCallback(interval = 1000, - #save_initial_solution = true, - #save_final_solution = true, - #output_directory = "out", - #solution_variables = cons2eq_pot_temp) - -stepsize_callback = StepsizeCallback(cfl = 1.0) - -callbacks = CallbackSet(summary_callback, - analysis_callback, - alive_callback, - #save_solution, - stepsize_callback) - -stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) - -############################################################################### -# run the simulation -sol = solve(ode, SSPRK43(stage_limiter!); ode_default_options()..., - maxiters = 1.0e7, save_everystep = false, callback = callbacks); - -summary_callback() - -pd = PlotData2D(sol; solution_variables = cons2eq_pot_temp); -plot(pd["eq_pot_temp"], c = :vik, dpi = 1000) \ No newline at end of file diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl index 6825ee05..dbcfbb60 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl @@ -276,13 +276,10 @@ save_solution = SaveSolutionCallback(interval = 1000, output_directory = "out", solution_variables = cons2eq_pot_temp) -stepsize_callback = StepsizeCallback(cfl = 1.0) - callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, - save_solution, - stepsize_callback) + save_solution) stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) diff --git a/src/TrixiAtmo.jl b/src/TrixiAtmo.jl index 9f02ac67..1855db98 100644 --- a/src/TrixiAtmo.jl +++ b/src/TrixiAtmo.jl @@ -22,9 +22,8 @@ baz() = Trixi.examples_dir() include("equations/equations.jl") export CompressibleMoistEulerEquations2D, CompressibleRainyEulerEquations2D, - CompressibleRainyEulerPotentialTemperatureEquations2D, CompressibleMoistEulerPotentialTemperatureEquations2D, - CompressibleRainyEulerEquationsExplicit2D + CompressibleRainyEulerExplicitEquations2D include("callbacks_stage/callbacks_stage.jl") export NonlinearSolveDG diff --git a/src/callbacks_stage/nonlinear_solve_dg2d.jl b/src/callbacks_stage/nonlinear_solve_dg2d.jl index 1317e0d5..3c29dc5d 100644 --- a/src/callbacks_stage/nonlinear_solve_dg2d.jl +++ b/src/callbacks_stage/nonlinear_solve_dg2d.jl @@ -9,10 +9,6 @@ using StaticArrays function nonlinear_solve_dg_2d!(u, residual, jacobian, variables_index_vector, tolerance, equations::AbstractCompressibleRainyEulerEquations, dg::DGSEM, cache, mesh) max_iterations = 20 - rain_threshold = 1e-4 - #=threshold = 0.0 - @unpack weights = dg.basis - @unpack inverse_jacobian = cache.elements=# # iterate over every DGSEM element @batch for element in eachelement(dg, cache) diff --git a/src/equations/compressible_moist_euler_2d_lucas.jl b/src/equations/compressible_moist_euler_2d_lucas.jl index c8cf6f86..d9e5b48d 100644 --- a/src/equations/compressible_moist_euler_2d_lucas.jl +++ b/src/equations/compressible_moist_euler_2d_lucas.jl @@ -584,7 +584,7 @@ end rho_v = exp(s_v - c_pv * log(T) + R_v * log(R_v * T)) end if (s_l != 0.0) - rho_l = 0.0#TODO no information in cons2entropy???? + rho_l = 0.0 end rho = rho_d + rho_v + rho_l diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index a33ade8c..ab75a04a 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -185,10 +185,7 @@ end eq_pot = (temperature * (ref_p / p_d)^(R_d / c_p) * H^(-r_v * R_v / c_p) * exp(L_v * r_v * inv(c_p * temperature))) - #TODO - entropy = 0.0 - - return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, v1, v2, eq_pot, p, entropy) + return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, v1, v2, eq_pot, p) end @@ -271,7 +268,7 @@ varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_vapour", "rho_cloud", "rho_rain", "v1", "v2", "eq_pot_temp", - "pressure", "entropy") + "pressure") @@ -426,13 +423,13 @@ end @inline function flux(u, orientation::Integer, equations::CompressibleRainyEulerEquations2D) # constants - c_l = equations.c_liquid_water + c_l = equations.c_liquid_water #densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) # recover rho_vapour, rho_cloud, temperature from nonlinear system - rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) + _, _, temperature = cons2nonlinearsystemsol(u, equations) # velocity v1, v2 = velocities(u, rho_inv, equations) @@ -479,13 +476,13 @@ end @inline function flux(u, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) # constants - c_l = equations.c_liquid_water + c_l = equations.c_liquid_water # densities rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) # recover rho_vapour, rho_cloud, temperature from nonlinear system - rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) + _, _, temperature = cons2nonlinearsystemsol(u, equations) # velocity v1, v2 = velocities(u, rho_inv, equations) @@ -1038,12 +1035,12 @@ end normal = normal_direction / norm(normal_direction) # compute the normal velocity - u_normal = normal[1] * u_inner[2] + normal[2] * u_inner[5] + u_normal = normal[1] * u_inner[4] + normal[2] * u_inner[5] # create the "external" boundary solution state u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], - u_inner[4] - 2 * u_normal * normal[5], - u_inner[5] - 2 * u_normal * normal[4], + u_inner[4] - 2 * u_normal * normal[1], + u_inner[5] - 2 * u_normal * normal[2], u_inner[6], u_inner[7], u_inner[8], u_inner[9]) # calculate the boundary flux diff --git a/src/equations/compressible_rainy_euler_explicit_2d.jl b/src/equations/compressible_rainy_euler_explicit_2d.jl index eadde41c..d725597e 100644 --- a/src/equations/compressible_rainy_euler_explicit_2d.jl +++ b/src/equations/compressible_rainy_euler_explicit_2d.jl @@ -4,7 +4,7 @@ import Trixi: varnames, cons2prim, cons2entropy, flux, flux_chandrashekar, max_abs_speeds, max_abs_speed_naive, - boundary_condition_slip_wall + boundary_condition_slip_wall, entropy @@ -23,7 +23,7 @@ import Trixi: varnames, ### equation, parameters and constants ### -struct CompressibleRainyEulerEquationsExplicit2D{RealT <: Real} <: AbstractCompressibleRainyEulerEquations{2, 7} +struct CompressibleRainyEulerExplicitEquations2D{RealT <: Real} <: AbstractCompressibleRainyEulerEquations{2, 7} # Specific heat capacities: c_liquid_water ::RealT c_dry_air_const_pressure ::RealT @@ -49,7 +49,7 @@ struct CompressibleRainyEulerEquationsExplicit2D{RealT <: Real} <: AbstractCompr end -function CompressibleRainyEulerEquationsExplicit2D(; RealT = Float64) +function CompressibleRainyEulerExplicitEquations2D(; RealT = Float64) # Specific heat capacities: c_liquid_water = 4186.0 c_dry_air_const_pressure = 1004.0 @@ -73,7 +73,7 @@ function CompressibleRainyEulerEquationsExplicit2D(; RealT = Float64) rain_water_distr = 8e6 v_mean_rain = 130.0 - return CompressibleRainyEulerEquationsExplicit2D{RealT}(c_liquid_water, c_dry_air_const_pressure, c_dry_air_const_volume, + return CompressibleRainyEulerExplicitEquations2D{RealT}(c_liquid_water, c_dry_air_const_pressure, c_dry_air_const_volume, c_vapour_const_pressure, c_vapour_const_volume, R_dry_air, R_vapour, eps, ref_saturation_pressure, ref_temperature, ref_latent_heat_vap_temp, ref_pressure, gravity, @@ -84,7 +84,7 @@ end ### conversion ### -@inline function cons2prim(u, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function cons2prim(u, equations::CompressibleRainyEulerExplicitEquations2D) # densities rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) @@ -99,7 +99,7 @@ end # converts consverved to entropy variables -@inline function cons2entropy(u, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function cons2entropy(u, equations::CompressibleRainyEulerExplicitEquations2D) # constants c_vd = equations.c_dry_air_const_volume c_vv = equations.c_vapour_const_volume @@ -140,7 +140,7 @@ end # adapted from compressible_moist_euler_2d.jl -@inline function cons2eq_pot_temp(u, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function cons2eq_pot_temp(u, equations::CompressibleRainyEulerExplicitEquations2D) # constants c_l = equations.c_liquid_water c_pd = equations.c_dry_air_const_pressure @@ -182,7 +182,7 @@ end # for convenience TODO rename -@inline function cons2speeds(u, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function cons2speeds(u, equations::CompressibleRainyEulerExplicitEquations2D) # densities rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) @@ -202,16 +202,16 @@ end ### varnames ### -varnames(::typeof(cons2cons), ::CompressibleRainyEulerEquationsExplicit2D) = ("rho_dry", "rho_vapour", "rho_cloud", "rho_rain", +varnames(::typeof(cons2cons), ::CompressibleRainyEulerExplicitEquations2D) = ("rho_dry", "rho_vapour", "rho_cloud", "rho_rain", "rho_v1", "rho_v2", "energy_density") -varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquationsExplicit2D) = ("rho_dry", "rho_vapour", "rho_cloud", "rho_rain", +varnames(::typeof(cons2prim), ::CompressibleRainyEulerExplicitEquations2D) = ("rho_dry", "rho_vapour", "rho_cloud", "rho_rain", "v1", "v2", "energy_density") -varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquationsExplicit2D) = ("rho_dry", "rho_vapour", +varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerExplicitEquations2D) = ("rho_dry", "rho_vapour", "rho_cloud", "rho_rain", "v1", "v2", "eq_pot_temp", "rho") @@ -220,7 +220,7 @@ varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquationsExplicit2D ### physics variables ### -@inline function densities(u, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function densities(u, equations::CompressibleRainyEulerExplicitEquations2D) # densities rho_dry = u[1] rho_vapour = u[2] @@ -232,21 +232,21 @@ varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquationsExplicit2D return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv) end -@inline function rain_density(u, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function rain_density(u, equations::CompressibleRainyEulerExplicitEquations2D) return u[4] end -@inline function velocities(u, rho_inv, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function velocities(u, rho_inv, equations::CompressibleRainyEulerExplicitEquations2D) return SVector(u[5] * rho_inv, u[6] * rho_inv) end -@inline function energy_density(u, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function energy_density(u, equations::CompressibleRainyEulerExplicitEquations2D) return u[7] end -@inline function pressure(u, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function pressure(u, equations::CompressibleRainyEulerExplicitEquations2D) # constants R_d = equations.R_dry_air R_v = equations.R_vapour @@ -262,7 +262,7 @@ end end -@inline function speed_of_sound(u, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function speed_of_sound(u, equations::CompressibleRainyEulerExplicitEquations2D) # constants c_l = equations.c_liquid_water c_vd = equations.c_dry_air_const_volume @@ -298,7 +298,7 @@ end end -@inline function get_temperature(u, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function get_temperature(u, equations::CompressibleRainyEulerExplicitEquations2D) # constants c_l = equations.c_liquid_water c_vd = equations.c_dry_air_const_volume @@ -312,13 +312,13 @@ end v1, v2 = velocities(u, rho_inv, equations) # energy density - energy = energy_density(u, equations::CompressibleRainyEulerEquationsExplicit2D) + energy = energy_density(u, equations::CompressibleRainyEulerExplicitEquations2D) return (energy - L_ref * rho_vapour - 0.5 * rho * (v1^2 + v2^2)) / (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) end -@inline function terminal_velocity_rain(rho_moist, rho_rain, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function terminal_velocity_rain(rho_moist, rho_rain, equations::CompressibleRainyEulerExplicitEquations2D) # constants N_0 = equations.rain_water_distr v_0 = equations.v_mean_rain @@ -334,7 +334,7 @@ end end -@inline function saturation_vapour_pressure(temperature, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function saturation_vapour_pressure(temperature, equations::CompressibleRainyEulerExplicitEquations2D) # constants c_l = equations.c_liquid_water c_pv = equations.c_vapour_const_pressure @@ -357,7 +357,7 @@ end end -@inline function saturation_vapour_pressure_derivative(temperature, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function saturation_vapour_pressure_derivative(temperature, equations::CompressibleRainyEulerExplicitEquations2D) # constants c_l = equations.c_liquid_water c_pv = equations.c_vapour_const_pressure @@ -384,7 +384,7 @@ end # adapted from compressible_moist_euler_2d.jl -@inline function moist_air_phase_change(u, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function moist_air_phase_change(u, equations::CompressibleRainyEulerExplicitEquations2D) # constants R_v = equations.R_vapour @@ -416,7 +416,7 @@ end ### pde discretization ### -@inline function flux(u, orientation::Integer, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function flux(u, orientation::Integer, equations::CompressibleRainyEulerExplicitEquations2D) # constants c_l = equations.c_liquid_water @@ -470,7 +470,7 @@ end end -@inline function flux(u, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function flux(u, normal_direction::AbstractVector, equations::CompressibleRainyEulerExplicitEquations2D) # constants c_l = equations.c_liquid_water @@ -513,7 +513,7 @@ end # no Coriolis term -@inline function source_terms_rainy(u, x, t, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function source_terms_rainy(u, x, t, equations::CompressibleRainyEulerExplicitEquations2D) # constants R_v = equations.R_vapour ref_temp = equations.ref_temperature @@ -544,7 +544,7 @@ end # no Coriolis term -@inline function source_terms_moist(u, x, t, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function source_terms_moist(u, x, t, equations::CompressibleRainyEulerExplicitEquations2D) # constants g = equations.gravity @@ -562,7 +562,7 @@ end # no phase changes and no Coriolis term -@inline function source_terms_no_phase_change(u, x, t, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function source_terms_no_phase_change(u, x, t, equations::CompressibleRainyEulerExplicitEquations2D) # constants g = equations.gravity @@ -576,7 +576,7 @@ end end -@inline function max_abs_speeds(u, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function max_abs_speeds(u, equations::CompressibleRainyEulerExplicitEquations2D) # name needed variables v1, v2, v_sound, v_r = cons2speeds(u, equations) @@ -584,7 +584,7 @@ end end -@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerExplicitEquations2D) # name needed variables v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) @@ -600,7 +600,7 @@ end end -@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::CompressibleRainyEulerExplicitEquations2D) # name needed variables v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) @@ -621,7 +621,7 @@ end # adapted from compressible_moist_euler_2d.jl which was probably adapted from compressible_euler_2d.jl @inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, x, t, - surface_flux_function, equations::CompressibleRainyEulerEquationsExplicit2D) + surface_flux_function, equations::CompressibleRainyEulerExplicitEquations2D) norm_ = norm(normal_direction) # Normalize the vector without using `normalize` since we need to multiply by the `norm_` later @@ -670,7 +670,7 @@ end # same as in compressible_euler_2d.jl @inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, direction, x, t, - surface_flux_function, equations::CompressibleRainyEulerEquationsExplicit2D) + surface_flux_function, equations::CompressibleRainyEulerExplicitEquations2D) # flip sign of normal to make it outward pointing, then flip the sign of the normal flux back # to be inward pointing on the -x and -y sides due to the orientation convention used by StructuredMesh if isodd(direction) @@ -688,7 +688,7 @@ end # same as in compressible_euler_2d.jl -@inline function rotate_to_x(u, normal_vector, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function rotate_to_x(u, normal_vector, equations::CompressibleRainyEulerExplicitEquations2D) # cos and sin of the angle between the x-axis and the normalized normal_vector are # the normalized vector's x and y coordinates respectively (see unit circle). c = normal_vector[1] @@ -703,7 +703,7 @@ end # should be used together with TreeMesh (adapted from compressible_euler_2d.jl) @inline function boundary_condition_slip_wall(u_inner, orientation, direction, x, t, surface_flux_function, - equations::CompressibleRainyEulerEquationsExplicit2D) + equations::CompressibleRainyEulerExplicitEquations2D) # get the appropriate normal vector from the orientation RealT = eltype(u_inner) if orientation == 1 @@ -736,7 +736,7 @@ end=# # Coordinate Monthly Weather Review Vol. 141.7, pages 2526–2544, 2013, # https://journals.ametsoc.org/view/journals/mwre/141/7/mwr-d-12-00129.1.xml. # adapted from compressible_moist_euler_2d.jl, does NOT work with rain! -@inline function flux_LMARS(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function flux_LMARS(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerExplicitEquations2D) # constants a = 360.0 @@ -784,7 +784,7 @@ end # multicomponent compressible Euler equations, 4 Feb 2020, doi:10.1016/j.cma.2020.112912, # https://arxiv.org/abs/1904.00972 [math.NA]. # Adapted from compressible_moist_euler_2d.jl, careful, does NOT work for rain! -@inline function flux_chandrashekar(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function flux_chandrashekar(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerExplicitEquations2D) # constants c_l = equations.c_liquid_water c_vd = equations.c_dry_air_const_volume @@ -864,7 +864,7 @@ end end -@inline function flux_chandrashekar(u_ll, u_rr, orientation::Int, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function flux_chandrashekar(u_ll, u_rr, orientation::Int, equations::CompressibleRainyEulerExplicitEquations2D) if (orientation == 1) return flux_chandrashekar(u_ll, u_rr, SVector(1, 0), equations) else @@ -874,7 +874,7 @@ end -@inline function flux_ec_rain(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function flux_ec_rain(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerExplicitEquations2D) # constants c_l = equations.c_liquid_water c_vd = equations.c_dry_air_const_volume @@ -958,7 +958,7 @@ end return SVector(f_dry, f_vapour, f_cloud, f_rain, f_rhov1, f_rhov2, f_energy) end -@inline function flux_ec_rain(u_ll, u_rr, orientation::Int, equations::CompressibleRainyEulerEquationsExplicit2D) +@inline function flux_ec_rain(u_ll, u_rr, orientation::Int, equations::CompressibleRainyEulerExplicitEquations2D) if (orientation == 1) return flux_ec_rain(u_ll, u_rr, SVector(1, 0), equations) else @@ -970,17 +970,17 @@ end # adapted from ShallowWaterEquations2D (Recommended with rain!) @inline function boundary_condition_simple_slip_wall(u_inner, normal_direction::AbstractVector, x, t, surface_flux_function, - equations::CompressibleRainyEulerEquationsExplicit2D) + equations::CompressibleRainyEulerExplicitEquations2D) # normalize the outward pointing direction normal = normal_direction / norm(normal_direction) # compute the normal velocity - u_normal = normal[1] * u_inner[2] + normal[2] * u_inner[5] + u_normal = normal[1] * u_inner[5] + normal[2] * u_inner[6] # create the "external" boundary solution state u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], u_inner[4], - u_inner[5] - 2 * u_normal * normal[6], - u_inner[6] - 2 * u_normal * normal[5], + u_inner[5] - 2 * u_normal * normal[1], + u_inner[6] - 2 * u_normal * normal[2], u_inner[7]) # calculate the boundary flux @@ -992,7 +992,7 @@ end # adapted from ShallowWaterEquations2D (Recommended with rain!) @inline function boundary_condition_simple_slip_wall(u_inner, orientation, direction, x, t, surface_flux_function, - equations::CompressibleRainyEulerEquationsExplicit2D) + equations::CompressibleRainyEulerExplicitEquations2D) ## get the appropriate normal vector from the orientation if orientation == 1 u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], u_inner[4], -u_inner[5], u_inner[6], u_inner[7]) @@ -1011,5 +1011,24 @@ end end +@inline function entropy(u, equations::CompressibleRainyEulerExplicitEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + + # variables + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + temperature = get_temperature(u, equations) + + # s_k + s_d = c_vd * log(temperature) - R_d * log(rho_dry) + s_v = c_vv * log(temperature) - R_v * log(rho_vapour) + s_l = c_l * log(temperature) + + return rho_dry * s_d + rho_vapour * s_v + (rho_cloud + rho_rain) * s_l +end end # muladd end \ No newline at end of file diff --git a/src/equations/compressible_rainy_euler_potential_temperature_2d.jl b/src/equations/compressible_rainy_euler_potential_temperature_2d.jl deleted file mode 100644 index 6e593905..00000000 --- a/src/equations/compressible_rainy_euler_potential_temperature_2d.jl +++ /dev/null @@ -1,800 +0,0 @@ -using Trixi -using NLsolve: nlsolve -import Trixi: varnames, - cons2prim, cons2entropy, - flux, flux_chandrashekar, - max_abs_speeds, max_abs_speed_naive, - boundary_condition_slip_wall - - - -### Implementation similar to: -# Sabine Doppler, Philip L. Lederer, Joachim Schöberl, Henry von Wahl, -# A discontinuous Galerkin approach for atmospheric flows with implicit condensation, -# Journal of Computational Physics, -# Volume 499, -# 2024, -# 112713, -# ISSN 0021-9991 - -### WARNING: Potential temperature implementation does not include rainFALL yet. - -@muladd begin - -### equation, parameters and constants ### - -struct CompressibleRainyEulerPotentialTemperatureEquations2D{RealT <: Real} <: AbstractCompressibleRainyEulerEquations{2, 9} - # Specific heat capacities: - c_liquid_water ::RealT - c_dry_air_const_pressure ::RealT - c_dry_air_const_volume ::RealT - c_vapour_const_pressure ::RealT - c_vapour_const_volume ::RealT - - # Gas constants: - R_dry_air ::RealT - R_vapour ::RealT - eps ::RealT - - # Reference values: - ref_saturation_pressure ::RealT - ref_temperature ::RealT - ref_latent_heat_vap_temp ::RealT - ref_pressure ::RealT - - # Other: - gravity ::RealT - rain_water_distr ::RealT - v_mean_rain ::RealT -end - - -function CompressibleRainyEulerPotentialTemperatureEquations2D(; RealT = Float64) - # Specific heat capacities: - c_liquid_water = 4186.0 - c_dry_air_const_pressure = 1004.0 - c_dry_air_const_volume = 717.0 - c_vapour_const_pressure = 1885.0 - c_vapour_const_volume = 1424.0 - - # Gas constants: - R_dry_air = c_dry_air_const_pressure - c_dry_air_const_volume - R_vapour = c_vapour_const_pressure - c_vapour_const_volume - eps = R_dry_air / R_vapour - - # Reference values: - ref_saturation_pressure = 610.7 # This needs to be adjusted if ref_temperature is changed! - ref_temperature = 273.15 - ref_latent_heat_vap_temp = 2.5e6#3147620.0 - ref_pressure = 1e5 - - # Other: - gravity = 9.81 - rain_water_distr = 8e6 - v_mean_rain = 130.0 - - return CompressibleRainyEulerPotentialTemperatureEquations2D{RealT}(c_liquid_water, c_dry_air_const_pressure, c_dry_air_const_volume, - c_vapour_const_pressure, c_vapour_const_volume, R_dry_air, - R_vapour, eps, ref_saturation_pressure, ref_temperature, - ref_latent_heat_vap_temp, ref_pressure, gravity, - rain_water_distr, v_mean_rain) -end - - - -### conversion ### - -@inline function cons2prim(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - - # velocity - v1, v2 = velocities(u, rho_inv, equations) - - # energy density - energy = energy_density(u, equations) - - # nonlinear system - rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) - - return SVector(rho_dry, rho_moist, rho_rain, v1, v2, energy, rho_vapour, rho_cloud, temperature) -end - - -@inline function cons2entropy(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - #TODO - return SVector(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) -end - - -# adapted from compressible_moist_euler_2d.jl -@inline function cons2eq_pot_temp(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # constants - c_l = equations.c_liquid_water - c_pd = equations.c_dry_air_const_pressure - c_pv = equations.c_vapour_const_pressure - R_d = equations.R_dry_air - R_v = equations.R_vapour - ref_p = equations.ref_pressure - ref_temp = equations.ref_temperature - ref_L = equations.ref_latent_heat_vap_temp - - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - - # velocity - v1, v2 = velocities(u, rho_inv, equations) - - # nonlinear system - rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) - - # pressure - p = pressure(u, equations) - - p_v = rho_vapour * R_v * temperature - p_d = p - p_v - T_C = temperature - ref_temp - p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) - H = p_v / p_vs - r_v = rho_vapour / rho_dry - r_c = rho_cloud / rho_dry - r_r = rho_rain / rho_dry - L_v = ref_L + (c_pv - c_l) * temperature - c_p = c_pd + (r_v + r_c + r_r) * c_l - - # equivalent potential temperature - eq_pot = (temperature * (ref_p / p_d)^(R_d / c_p) * H^(-r_v * R_v / c_p) * - exp(L_v * r_v * inv(c_p * temperature))) - - return SVector(rho, r_v, r_c, r_r, v1, v2, eq_pot, p) -end - - -@inline function cons2nonlinearsystemsol(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # experimental and simple positivity check - rho_vapour = u[7] - rho_cloud = u[8] - temperature = u[9] - - if (rho_vapour < 0.0 && isapprox(rho_vapour, 0.0, atol = 1e-15)) - rho_vapour = 0.0 - end - - if (rho_cloud < 0.0 && isapprox(rho_cloud, 0.0, atol = 1e-15)) - rho_cloud = 0.0 - end - - return SVector(rho_vapour, rho_cloud, temperature) -end - - -# for convenience -@inline function cons2speeds(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - - # velocity - v1, v2 = velocities(u, rho_inv, equations) - - # get speed of sound - v_sound = speed_of_sound(u, equations)[1] - - # get terminal velocity rain - v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) - - return SVector(v1, v2, v_sound, v_r) -end - - - -### varnames ### - -varnames(::typeof(cons2cons), ::CompressibleRainyEulerPotentialTemperatureEquations2D) = ("rho_dry", "rho_moist", "rho_rain", - "rho_v1", "rho_v2", - "potential_temperature_density", - "rho_vapour", "rho_cloud", "temperature") - - -varnames(::typeof(cons2prim), ::CompressibleRainyEulerPotentialTemperatureEquations2D) = ("rho_dry", "rho_moist", "rho_rain", - "v1", "v2", - "energy_density", - "rho_vapour", "rho_cloud", "temperature") - -varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerPotentialTemperatureEquations2D) = ("rho", "r_vapour", - "r_cloud", "r_rain", - "v1", "v2", "eq_pot_temp", - "pressure") - - - -### physics variables ### - -@inline function densities(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # densities - rho_dry = u[1] - rho_moist = u[2] - rho_rain = u[3] - rho = rho_dry + rho_moist + rho_rain - rho_inv = inv(rho) - - return SVector(rho_dry, rho_moist, rho_rain, rho, rho_inv) -end - -@inline function rain_density(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - return u[3] -end - -@inline function velocities(u, rho_inv, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - return SVector(u[4] * rho_inv, u[5] * rho_inv) -end - - -@inline function energy_density(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - c_l = equations.c_liquid_water - ref_L = equations.ref_latent_heat_vap_temp - - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - - rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) - - # velocity - v1, v2 = velocities(u, rho_inv, equations) - - inner_energy_density = (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * temperature - inner_energy_density += rho_vapour * ref_L - kinetic_energy_density = 0.5 * rho * (v1^2 + v2^2) - - return inner_energy_density + kinetic_energy_density -end - - -@inline function pressure(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # constants - c_pd = equations.c_dry_air_const_pressure - c_vd = equations.c_dry_air_const_volume - c_pv = equations.c_vapour_const_pressure - c_vv = equations.c_vapour_const_volume - c_l = equations.c_liquid_water - R_d = equations.R_dry_air - R_v = equations.R_vapour - eps = equations.eps - ref_pressure = equations.ref_pressure - - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - - rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) - - # potential temperature density - rho_pot_temp = potential_temperature_density(u, equations) - - r_v = rho_vapour / rho_dry - r_l = (rho_cloud + rho_rain) / rho_dry - - kappa_m = (R_d + r_v * R_v) / (c_pd + r_v * c_pv + r_l * c_l) - - rho_theta = rho_pot_temp * (rho_dry + rho_vapour / eps) * rho_inv - - p = ((R_d * rho_theta) / (ref_pressure^kappa_m))^(1 / (1 - kappa_m)) - - return p -end - - -@inline function potential_temperature_density(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - return u[6] -end - - -@inline function speed_of_sound(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_d = equations.R_dry_air - R_v = equations.R_vapour - - # densities - rho_dry, _, rho_rain, _, rho_inv = densities(u, equations) - - # recover rho_vapour, rho_cloud, temperature from nonlinear system - rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) - if ( rho_vapour < 0.0 ) - error("rho vapour less than zero") - end - if ( rho_cloud < 0.0 ) - #display(rho_cloud) - error("rho cloud less than zero") - end - - # formula - p = pressure(u, equations) - q_v = rho_vapour / rho_dry - q_l = (rho_cloud + rho_rain) / rho_dry - gamma_m = 1 + (R_d + R_v * q_v) / (c_vd + c_vv * q_v + c_l * q_l) - - if (rho_inv < 0.0) - error("rho less than zero") - elseif (p < 0.0) - error("pressure less than zero") - end - - v_sound = sqrt(gamma_m * p * rho_inv) - - return SVector(v_sound, gamma_m) -end - - -@inline function terminal_velocity_rain(rho_moist, rho_rain, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # constants - N_0 = equations.rain_water_distr - v_0 = equations.v_mean_rain - - # formula ( \Gamma(4.5) / 6 ~= 1.9386213994279082 ) - if ( rho_rain > 0.0) - v_terminal_rain = v_0 * 1.9386213994279082 * (rho_rain / (pi * (rho_moist + rho_rain) * N_0))^(0.125) - else - v_terminal_rain = 0.0 - end - - return v_terminal_rain -end - - -@inline function saturation_vapour_pressure(temperature, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # constants - c_l = equations.c_liquid_water - c_pv = equations.c_vapour_const_pressure - R_v = equations.R_vapour - ref_s_p = equations.ref_saturation_pressure - ref_temp = equations.ref_temperature - ref_L = equations.ref_latent_heat_vap_temp - - # testing - if (temperature < 0.0) - display(temperature) - error("temp less than zero") - end - - # Clausius Clapeyron formula - p_vapour_saturation = ref_s_p * (temperature / ref_temp)^((c_pv - c_l) / R_v) - p_vapour_saturation *= exp(((ref_L - (c_pv - c_l) * ref_temp) / R_v) * (1 / ref_temp - 1 / temperature)) - - return p_vapour_saturation -end - - -@inline function saturation_vapour_pressure_derivative(temperature, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # constants - c_l = equations.c_liquid_water - c_pv = equations.c_vapour_const_pressure - R_v = equations.R_vapour - ref_s_p = equations.ref_saturation_pressure - ref_temp = equations.ref_temperature - ref_L = equations.ref_latent_heat_vap_temp - - # testing - if (temperature < 0.0) - display(temperature) - error("temp less than zero") - end - - const_1 = (c_pv - c_l) / R_v - const_2 = (ref_L - (c_pv - c_l) * ref_temp) / R_v - - p_vapour_saturation_derivative = ref_s_p / (ref_temp^const_1) - p_vapour_saturation_derivative *= (const_1 * temperature^(const_1 - 1) + const_2 * temperature^(const_1 - 2)) - p_vapour_saturation_derivative *= exp(const_2 * (1 / ref_temp - 1 / temperature)) - - return p_vapour_saturation_derivative -end - - - -### pde discretization ### - -@inline function flux(u, orientation::Integer, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # constants - #c_l = equations.c_liquid_water - - #densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - - # recover rho_vapour, rho_cloud, temperature from nonlinear system - #rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) - - # velocity - v1, v2 = velocities(u, rho_inv, equations) - #v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) - - # pressure - p = pressure(u, equations) - - # potential temperature density - rho_pot_temp = potential_temperature_density(u, equations) - - # flux for orientation cases - if (orientation == 1) - # "mass" - f1 = rho_dry * v1 - f2 = rho_moist * v1 - f3 = rho_rain * v1 - - # "momentum" - f4 = rho * v1 * v1 + p - f5 = rho * v1 * v2 - - # "potential temperature" - f6 = rho_pot_temp * v1 - else - # "mass" - f1 = rho_dry * v2 - f2 = rho_moist * v2 - f3 = rho_rain * v2 #- v_r) - - # "momentum" - f4 = rho * v1 * v2 #- rho_rain * v_r * v1 - f5 = rho * v2 * v2 + p #- rho_rain * v_r * v2 - - # "energy" - f6 = rho_pot_temp * v2 #- (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r - end - - return SVector(f1, f2, f3, f4, f5, f6, - 0.0, 0.0, 0.0) -end - - -@inline function flux(u, normal_direction::AbstractVector, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # constants - #c_l = equations.c_liquid_water - - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - - # recover rho_vapour, rho_cloud, temperature from nonlinear system - #rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) - - # velocity - v1, v2 = velocities(u, rho_inv, equations) - #v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) - - # normal velocities - v_normal = v1 * normal_direction[1] + v2 * normal_direction[2] - #v_r_normal = v_r * normal_direction[2] - - # pressure - p = pressure(u, equations) - - # potential temperature density - rho_pot_temp = potential_temperature_density(u, equations) - - # flux - # "mass" - f1 = rho_dry * v_normal - f2 = rho_moist * v_normal - f3 = rho_rain * v_normal #- v_r_normal) - - # "momentum" - f4 = rho * v_normal * v1 + p * normal_direction[1] #- rho_rain * v_r_normal * v1 - f5 = rho * v_normal * v2 + p * normal_direction[2] #- rho_rain * v_r_normal * v2 - - # "energy" - f6 = rho_pot_temp * v_normal #- (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r_normal - - return SVector(f1, f2, f3, f4, f5, f6, - 0.0, 0.0, 0.0) -end - - -# no Coriolis term -@inline function source_terms_rainy(u, x, t, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # constants - R_v = equations.R_vapour - ref_temp = equations.ref_temperature - g = equations.gravity - - # name needed variables - rho_v2 = u[5] - - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - - # recover rho_vapour, rho_cloud, temperature from nonlinear system - rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) - - rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) - - # source terms phase change - S_evaporation = (3.86e-3 - 9.41e-5 * (temperature - ref_temp)) * (1 + 9.1 * rho_rain^(0.1875)) - S_evaporation *= (rho_vs - rho_vapour) * rho_rain^(0.5) - S_auto_conversion = 0.001 * rho_cloud - S_accretion = 1.72 * rho_cloud * rho_rain^(0.875) - S_rain = S_auto_conversion + S_accretion - S_evaporation - S_groundwater = 0.0 - #= - if (x[2] < 100.0) - S_groundwater = rho_rain * (1 - (x[2] * 0.01)^2) - end=# - - return SVector(0.0, -S_rain, S_rain - S_groundwater, 0.0, - -rho * g, -rho_v2 * g, 0.0, 0.0, 0.0) -end - - -# no phase changes and no Coriolis term -@inline function source_terms_no_phase_change(u, x, t, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # constants - g = equations.gravity - - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - - return SVector(0.0, 0.0, 0.0, 0.0, - -g * rho, 0.0, 0.0, 0.0, 0.0) -end - - -@inline function max_abs_speeds(u, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # name needed variables - v1, v2, v_sound, v_r = cons2speeds(u, equations) - - return SVector((abs(v1) + v_sound), (abs(v2) + v_sound + abs(v_r))) -end - - -@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # name needed variables - v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) - v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) - - # calculate upper bounds for left and right speed - v_ll_max = abs(v1_ll * normal_direction[1] + v2_ll * normal_direction[2]) - #v_ll_max += abs( v_r_ll * normal_direction[2]) - - v_rr_max = abs(v1_rr * normal_direction[1] + v2_rr * normal_direction[2]) - #v_rr_max += abs( v_r_rr * normal_direction[2]) - - return max(v_ll_max, v_rr_max) + max(v_sound_ll, v_sound_rr) * norm(normal_direction) -end - - -@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # name needed variables - v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) - v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) - - if (orientation == 1) - v_ll = abs(v1_ll) - v_rr = abs(v1_rr) - else - v_ll = abs(v2_ll) - v_rr = abs(v2_rr) - end - - return max(v_ll, v_rr) + max(v_sound_ll, v_sound_rr) #+ max(abs(v_r_ll), abs(v_r_rr)) -end - - -### boundary conditions ### - -# adapted from compressible_moist_euler_2d.jl which was probably adapted from compressible_euler_2d.jl -@inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, x, t, - surface_flux_function, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - - norm_ = norm(normal_direction) - # Normalize the vector without using `normalize` since we need to multiply by the `norm_` later - normal = normal_direction / norm_ - - # rotate the internal solution state - u_local = rotate_to_x(u_inner, normal, equations) - - # name needed variables - rho_v1 = u_local[4] - - # densities - rho_dry_local, rho_moist_local, rho_rain_local, rho_local, rho_inv_local = densities(u_local, equations) - - # velocities - v_normal = rho_v1 * rho_inv_local - v_sound, gamma = speed_of_sound(u_local, equations) - - # pressure - p_local = pressure(u_local, equations) - - # Get the solution of the pressure Riemann problem - # See Section 6.3.3 of - # Eleuterio F. Toro (2009) - # Riemann Solvers and Numerical Methods for Fluid Dynamics: A Practical Introduction - # [DOI: 10.1007/b79761](https://doi.org/10.1007/b79761) - if v_normal <= 0.0 - p_star = p_local * - (1.0 + 0.5 * (gamma - 1) * v_normal / v_sound)^(2.0 * gamma * - inv(gamma - 1)) - else # v_normal > 0.0 - A = 2.0 / ((gamma + 1) * rho_local) - B = p_local * (gamma - 1) / (gamma + 1) - p_star = p_local + - 0.5 * v_normal / A * - (v_normal + sqrt(v_normal^2 + 4.0 * A * (p_local + B))) - end - - # For the slip wall we directly set the flux as the normal velocity is zero - return SVector(0.0, 0.0, 0.0, - p_star * normal[1] * norm_, - p_star * normal[2] * norm_, - 0.0, 0.0, 0.0, 0.0) -end - - -# same as in compressible_euler_2d.jl -@inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, direction, x, t, - surface_flux_function, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # flip sign of normal to make it outward pointing, then flip the sign of the normal flux back - # to be inward pointing on the -x and -y sides due to the orientation convention used by StructuredMesh - if isodd(direction) - boundary_flux = -boundary_condition_slip_wall(u_inner, -normal_direction, - x, t, surface_flux_function, - equations) - else - boundary_flux = boundary_condition_slip_wall(u_inner, normal_direction, - x, t, surface_flux_function, - equations) - end - - return boundary_flux -end - - -# same as in compressible_euler_2d.jl -@inline function rotate_to_x(u, normal_vector, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # cos and sin of the angle between the x-axis and the normalized normal_vector are - # the normalized vector's x and y coordinates respectively (see unit circle). - c = normal_vector[1] - s = normal_vector[2] - - return SVector(u[1], u[2], u[3], - c * u[4] + s * u[5], - -s * u[4] + c * u[5], - u[6], u[7], u[8], u[9]) -end - - -# should be used together with TreeMesh (adapted from compressible_euler_2d.jl) -@inline function boundary_condition_slip_wall(u_inner, orientation, direction, x, t, surface_flux_function, - equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # get the appropriate normal vector from the orientation - RealT = eltype(u_inner) - if orientation == 1 - normal_direction = SVector(one(RealT), zero(RealT)) - else # orientation == 2 - normal_direction = SVector(zero(RealT), one(RealT)) - end - - # compute and return the flux using `boundary_condition_slip_wall` routine above - return boundary_condition_slip_wall(u_inner, normal_direction, direction, - x, t, surface_flux_function, equations) -end - - -### Nonlinear System Residual ### - -# in preparation for a callback to solve the nonlinear system -@inline function saturation_residual(u, guess, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # constants - R_v = equations.R_vapour - eps = equations.eps - - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - - # potential temperature density - rho_pot_temp = potential_temperature_density(u, equations) - - # define residual - residual1 = guess[3] * (rho_dry + guess[1] / eps) / (rho_dry + guess[1] + guess[2] + rho_rain) - residual1 -= rho_pot_temp * rho_inv - - residual2 = min(saturation_vapour_pressure(guess[3], equations) / (R_v * guess[3]), rho_moist) - residual2 -= guess[1] - residual2 *= 1e4 - - residual3 = rho_moist - residual3 -= guess[1] + guess[2] - residual3 *= 1e4 - - return SVector(residual1, residual2, residual3) -end - - - -@inline function saturation_residual_jacobian(u, guess, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # constants - R_v = equations.R_vapour - eps = equations.eps - - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - - # saturation - svp = saturation_vapour_pressure(guess[3], equations) - svp_t = saturation_vapour_pressure_derivative(guess[3], equations) - - # helper variables - rho_help = rho_dry + guess[1] + guess[2] + rho_rain - inv_eps = inv(eps) - - # define jacobian - J_11 = guess[3] * ((inv_eps - 1) * rho_dry + inv_eps * (guess[2] + rho_rain)) / (rho_help^2) - J_12 = -guess[3] * (rho_dry + guess[1] * inv_eps) / (rho_help^2) - J_13 = (rho_dry + guess[1] * inv_eps) / rho_help - - J_21 = -1e4 - J_22 = 0.0 - - if (svp / (R_v * guess[3]) < rho_moist) - J_23 = (svp_t * guess[3] - svp) / (R_v * guess[3]^2) * 1e4 - else - J_23 = 0.0 - end - - J_31 = -1e4 - J_32 = -1e4 - J_33 = 0.0 - - return SMatrix{3, 3}(J_11, J_21, J_31, J_12, J_22, J_32, J_13, J_23, J_33) -end - - -# TODO Careful with rain != 0.0 does not really work (bad physics) -# fluxes adapted from compressible_moist_euler_2d.jl - -# Low Mach number approximate Riemann solver (LMARS) from -# X. Chen, N. Andronova, B. Van Leer, J. E. Penner, J. P. Boyd, C. Jablonowski, S. -# Lin, A Control-Volume Model of the Compressible Euler Equations with a Vertical Lagrangian -# Coordinate Monthly Weather Review Vol. 141.7, pages 2526–2544, 2013, -# https://journals.ametsoc.org/view/journals/mwre/141/7/mwr-d-12-00129.1.xml. -@inline function flux_LMARS(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerPotentialTemperatureEquations2D) - # constants - a = 340.0 - - # densities - rho_dry_ll, rho_moist_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) - rho_dry_rr, rho_moist_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) - - # pressure - p_ll = pressure(u_ll, equations) - p_rr = pressure(u_rr, equations) - - # velocities - v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) - v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) - - v_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] - v_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] - norm_ = norm(normal_direction) - - # diffusion parameter 0.0 < beta <= 1.0 - beta = 1.0 - - # interface flux components - rho = 0.5 * (rho_ll + rho_rr) - p_interface = 0.5 * (p_ll + p_rr) - beta * 0.5 * a * rho * (v_rr - v_ll) / norm_ - v_interface = 0.5 * (v_ll + v_rr) - beta * 1 / (2 * a * rho) * (p_rr - p_ll) * norm_ - - if (v_interface > 0) - f1, f2, f3, f4, f5, f6, _, _, _ = u_ll * v_interface - else - f1, f2, f3, f4, f5, f6, _, _, _ = u_rr * v_interface - end - - return SVector(f1, f2, f3, - f4 + p_interface * normal_direction[1], - f5 + p_interface * normal_direction[2], - f6, 0.0, 0.0, 0.0) -end - -end #muladd \ No newline at end of file diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 11fdbdcd..dda2dc6b 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -8,6 +8,5 @@ abstract type AbstractCompressibleRainyEulerEquations{NDIMS, NVARS} <: include("compressible_rainy_euler_2d.jl") include("compressible_moist_euler_2d_lucas.jl") -include("compressible_rainy_euler_potential_temperature_2d.jl") include("compressible_moist_euler_potential_temperature_2d.jl") include("compressible_rainy_euler_explicit_2d.jl") \ No newline at end of file From 94a0e8060a094342fdbdad4cb0a1c28c9416e7c2 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Wed, 16 Apr 2025 23:31:43 +0200 Subject: [PATCH 108/115] AtmosphereLayers name change to AtmosphereLayersRainyBubble to have unique struct names --- .../elixir_rainy_euler_explicit_rainy_bubble.jl | 8 ++++---- ...ir_rainy_euler_explicit_rainy_bubble_diffusion.jl | 8 ++++---- .../elixir_rainy_euler_rainy_bubble.jl | 12 ++++++------ .../elixir_rainy_euler_rainy_bubble_diffusion.jl | 10 +++++----- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl index 0a4df76b..0a3b3a4d 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl @@ -104,14 +104,14 @@ end # for approximating the dz pressure gradient -struct AtmosphereLayers{RealT <: Real} +struct AtmosphereLayersRainyBubble{RealT <: Real} layer_data ::Matrix{RealT} total_height ::RealT precision ::RealT end -function AtmosphereLayers(equations::CompressibleRainyEulerExplicitEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) +function AtmosphereLayersRainyBubble(equations::CompressibleRainyEulerExplicitEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) # constants humidity_rel0 = 0.2 # hydrostatic relative humidity surface_pressure = 8.5e4 @@ -140,13 +140,13 @@ function AtmosphereLayers(equations::CompressibleRainyEulerExplicitEquations2D; layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, iterations = 20).zero end - return AtmosphereLayers{RealT}(layer_data, total_height, precision) + return AtmosphereLayersRainyBubble{RealT}(layer_data, total_height, precision) end # create layers for initial condition equations = CompressibleRainyEulerExplicitEquations2D() -layers = AtmosphereLayers(equations) +layers = AtmosphereLayersRainyBubble(equations) function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerExplicitEquations2D; atmosphere_layers = layers) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl index 749c3ff2..ada92e4b 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl @@ -106,14 +106,14 @@ end # for approximating the dz pressure gradient -struct AtmosphereLayers{RealT <: Real} +struct AtmosphereLayersRainyBubble{RealT <: Real} layer_data ::Matrix{RealT} total_height ::RealT precision ::RealT end -function AtmosphereLayers(equations::CompressibleRainyEulerExplicitEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) +function AtmosphereLayersRainyBubble(equations::CompressibleRainyEulerExplicitEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) # constants humidity_rel0 = 0.2 # hydrostatic relative humidity surface_pressure = 8.5e4 @@ -142,13 +142,13 @@ function AtmosphereLayers(equations::CompressibleRainyEulerExplicitEquations2D; layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, iterations = 20).zero end - return AtmosphereLayers{RealT}(layer_data, total_height, precision) + return AtmosphereLayersRainyBubble{RealT}(layer_data, total_height, precision) end # create layers for initial condition equations = CompressibleRainyEulerExplicitEquations2D() -layers = AtmosphereLayers(equations) +layers = AtmosphereLayersRainyBubble(equations) function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerExplicitEquations2D; atmosphere_layers = layers) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl index afd47df7..efb97883 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl @@ -105,14 +105,14 @@ end # for approximating the dz pressure gradient -struct AtmosphereLayers{RealT <: Real} +struct AtmosphereLayersRainyBubble{RealT <: Real} layer_data ::Matrix{RealT} total_height ::RealT precision ::RealT end -function AtmosphereLayers(equations::CompressibleRainyEulerEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) +function AtmosphereLayersRainyBubble(equations::CompressibleRainyEulerEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) # constants humidity_rel0 = 0.2 # hydrostatic relative humidity surface_pressure = 8.5e4 @@ -141,13 +141,13 @@ function AtmosphereLayers(equations::CompressibleRainyEulerEquations2D; total_he layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, iterations = 20).zero end - return AtmosphereLayers{RealT}(layer_data, total_height, precision) + return AtmosphereLayersRainyBubble{RealT}(layer_data, total_height, precision) end # create layers for initial condition equations = CompressibleRainyEulerEquations2D() -layers = AtmosphereLayers(equations) +layers = AtmosphereLayersRainyBubble(equations) function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerEquations2D; atmosphere_layers = layers) @@ -222,7 +222,7 @@ boundary_conditions = (x_neg = boundary_condition_periodic, y_neg = boundary_condition_simple_slip_wall, y_pos = boundary_condition_simple_slip_wall) -polydeg = 1 +polydeg = 3 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_lax_friedrichs @@ -230,7 +230,7 @@ volume_integral = VolumeIntegralFluxDifferencing(flux_ec_rain) solver = DGSEM(basis, surface_flux, volume_integral) -cells_per_dimension = (100, 100) +cells_per_dimension = (64, 64) mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = (true, false)) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl index dbcfbb60..f3ca9896 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl @@ -106,14 +106,14 @@ end # for approximating the dz pressure gradient -struct AtmosphereLayers{RealT <: Real} +struct AtmosphereLayersRainyBubble{RealT <: Real} layer_data ::Matrix{RealT} total_height ::RealT precision ::RealT end -function AtmosphereLayers(equations::CompressibleRainyEulerEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) +function AtmosphereLayersRainyBubble(equations::CompressibleRainyEulerEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) # constants humidity_rel0 = 0.2 # hydrostatic relative humidity surface_pressure = 8.5e4 @@ -142,13 +142,13 @@ function AtmosphereLayers(equations::CompressibleRainyEulerEquations2D; total_he layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, iterations = 20).zero end - return AtmosphereLayers{RealT}(layer_data, total_height, precision) + return AtmosphereLayersRainyBubble{RealT}(layer_data, total_height, precision) end # create layers for initial condition equations = CompressibleRainyEulerEquations2D() -layers = AtmosphereLayers(equations) +layers = AtmosphereLayersRainyBubble(equations) function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerEquations2D; atmosphere_layers = layers) @@ -256,7 +256,7 @@ semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabol ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 600.0) +tspan = (0.0, 1000.0) ode = semidiscretize(semi, tspan) From 0874b27e8da09f1b4bd85b4646ecc2078211fc1e Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Thu, 17 Apr 2025 00:13:05 +0200 Subject: [PATCH 109/115] comment cleanup --- examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl index efb97883..f5b6e793 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl @@ -8,7 +8,6 @@ using TrixiAtmo: source_terms_rainy, saturation_residual, source_terms_no_phase_change, boundary_condition_simple_slip_wall using NLsolve: nlsolve -#using Plots From d2faff4200d2988a40637614a852e5ccbcde00aa Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Fri, 18 Apr 2025 20:57:03 +0200 Subject: [PATCH 110/115] parameter adjustment --- .../elixir_rainy_euler_rainy_bubble_diffusion.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl index f3ca9896..95219914 100644 --- a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl +++ b/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl @@ -256,7 +256,7 @@ semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabol ############################################################################### # ODE solvers, callbacks etc. -tspan = (0.0, 1000.0) +tspan = (0.0, 600.0) ode = semidiscretize(semi, tspan) From f0efa27aa51c53cd154fff298274cd41fd604045 Mon Sep 17 00:00:00 2001 From: FnHck <95546963+FnHck@users.noreply.github.com> Date: Thu, 15 May 2025 16:24:59 +0200 Subject: [PATCH 111/115] adjusted folder structure for pull request convenience --- .../comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl | 0 .../convergence_test_elixirs/convergence_test_rainy.jl | 0 .../convergence_test_elixirs/convergence_test_rainy_dry.jl | 0 .../convergence_test_elixirs/convergence_test_rainy_explicit.jl | 0 .../convergence_test_rainy_explicit_dry.jl | 0 .../convergence_test_rainy_explicit_moist.jl | 0 .../convergence_test_elixirs/convergence_test_rainy_moist.jl | 0 .../dry_bubble_elixirs/energy/elixir_rainy_euler_dry_bubble.jl | 0 .../elixir_rainy_euler_explicit_moist_bubble_ec_test.jl | 0 .../weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl | 0 .../weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl | 0 .../energy/elixir_moist_euler_moist_bubble_dgmulti.jl | 0 .../energy/elixir_rainy_euler_explicit_moist_bubble.jl | 0 .../energy/elixir_rainy_euler_moist_bubble.jl | 0 .../energy/elixir_rainy_euler_moist_bubble_dgmulti.jl | 0 .../elixir_moist_euler_potential_temperature_moist_bubble.jl | 0 .../elixir_rainy_euler_explicit_rainy_bubble.jl | 0 .../elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl | 0 .../rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl | 0 .../elixir_rainy_euler_rainy_bubble_diffusion.jl | 0 20 files changed, 0 insertions(+), 0 deletions(-) rename examples/{ => moist_bubble}/comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl (100%) rename examples/{ => moist_bubble}/convergence_test_elixirs/convergence_test_rainy.jl (100%) rename examples/{ => moist_bubble}/convergence_test_elixirs/convergence_test_rainy_dry.jl (100%) rename examples/{ => moist_bubble}/convergence_test_elixirs/convergence_test_rainy_explicit.jl (100%) rename examples/{ => moist_bubble}/convergence_test_elixirs/convergence_test_rainy_explicit_dry.jl (100%) rename examples/{ => moist_bubble}/convergence_test_elixirs/convergence_test_rainy_explicit_moist.jl (100%) rename examples/{ => moist_bubble}/convergence_test_elixirs/convergence_test_rainy_moist.jl (100%) rename examples/{ => moist_bubble}/dry_bubble_elixirs/energy/elixir_rainy_euler_dry_bubble.jl (100%) rename examples/{ => moist_bubble}/entropy_conservation_tests/moist_bubble/elixir_rainy_euler_explicit_moist_bubble_ec_test.jl (100%) rename examples/{ => moist_bubble}/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl (100%) rename examples/{ => moist_bubble}/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl (100%) rename examples/{ => moist_bubble}/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl (100%) rename examples/{ => moist_bubble}/moist_bubble_elixirs/energy/elixir_rainy_euler_explicit_moist_bubble.jl (100%) rename examples/{ => moist_bubble}/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl (100%) rename examples/{ => moist_bubble}/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble_dgmulti.jl (100%) rename examples/{ => moist_bubble}/moist_bubble_elixirs/potential_temperature/elixir_moist_euler_potential_temperature_moist_bubble.jl (100%) rename examples/{ => moist_bubble}/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl (100%) rename examples/{ => moist_bubble}/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl (100%) rename examples/{ => moist_bubble}/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl (100%) rename examples/{ => moist_bubble}/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl (100%) diff --git a/examples/comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl b/examples/moist_bubble/comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl similarity index 100% rename from examples/comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl rename to examples/moist_bubble/comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl diff --git a/examples/convergence_test_elixirs/convergence_test_rainy.jl b/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy.jl similarity index 100% rename from examples/convergence_test_elixirs/convergence_test_rainy.jl rename to examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy.jl diff --git a/examples/convergence_test_elixirs/convergence_test_rainy_dry.jl b/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_dry.jl similarity index 100% rename from examples/convergence_test_elixirs/convergence_test_rainy_dry.jl rename to examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_dry.jl diff --git a/examples/convergence_test_elixirs/convergence_test_rainy_explicit.jl b/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_explicit.jl similarity index 100% rename from examples/convergence_test_elixirs/convergence_test_rainy_explicit.jl rename to examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_explicit.jl diff --git a/examples/convergence_test_elixirs/convergence_test_rainy_explicit_dry.jl b/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_explicit_dry.jl similarity index 100% rename from examples/convergence_test_elixirs/convergence_test_rainy_explicit_dry.jl rename to examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_explicit_dry.jl diff --git a/examples/convergence_test_elixirs/convergence_test_rainy_explicit_moist.jl b/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_explicit_moist.jl similarity index 100% rename from examples/convergence_test_elixirs/convergence_test_rainy_explicit_moist.jl rename to examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_explicit_moist.jl diff --git a/examples/convergence_test_elixirs/convergence_test_rainy_moist.jl b/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_moist.jl similarity index 100% rename from examples/convergence_test_elixirs/convergence_test_rainy_moist.jl rename to examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_moist.jl diff --git a/examples/dry_bubble_elixirs/energy/elixir_rainy_euler_dry_bubble.jl b/examples/moist_bubble/dry_bubble_elixirs/energy/elixir_rainy_euler_dry_bubble.jl similarity index 100% rename from examples/dry_bubble_elixirs/energy/elixir_rainy_euler_dry_bubble.jl rename to examples/moist_bubble/dry_bubble_elixirs/energy/elixir_rainy_euler_dry_bubble.jl diff --git a/examples/entropy_conservation_tests/moist_bubble/elixir_rainy_euler_explicit_moist_bubble_ec_test.jl b/examples/moist_bubble/entropy_conservation_tests/moist_bubble/elixir_rainy_euler_explicit_moist_bubble_ec_test.jl similarity index 100% rename from examples/entropy_conservation_tests/moist_bubble/elixir_rainy_euler_explicit_moist_bubble_ec_test.jl rename to examples/moist_bubble/entropy_conservation_tests/moist_bubble/elixir_rainy_euler_explicit_moist_bubble_ec_test.jl diff --git a/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl b/examples/moist_bubble/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl similarity index 100% rename from examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl rename to examples/moist_bubble/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl diff --git a/examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl b/examples/moist_bubble/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl similarity index 100% rename from examples/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl rename to examples/moist_bubble/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl diff --git a/examples/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl b/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl similarity index 100% rename from examples/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl rename to examples/moist_bubble/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl diff --git a/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_explicit_moist_bubble.jl b/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_rainy_euler_explicit_moist_bubble.jl similarity index 100% rename from examples/moist_bubble_elixirs/energy/elixir_rainy_euler_explicit_moist_bubble.jl rename to examples/moist_bubble/moist_bubble_elixirs/energy/elixir_rainy_euler_explicit_moist_bubble.jl diff --git a/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl b/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl similarity index 100% rename from examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl rename to examples/moist_bubble/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl diff --git a/examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble_dgmulti.jl b/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble_dgmulti.jl similarity index 100% rename from examples/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble_dgmulti.jl rename to examples/moist_bubble/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble_dgmulti.jl diff --git a/examples/moist_bubble_elixirs/potential_temperature/elixir_moist_euler_potential_temperature_moist_bubble.jl b/examples/moist_bubble/moist_bubble_elixirs/potential_temperature/elixir_moist_euler_potential_temperature_moist_bubble.jl similarity index 100% rename from examples/moist_bubble_elixirs/potential_temperature/elixir_moist_euler_potential_temperature_moist_bubble.jl rename to examples/moist_bubble/moist_bubble_elixirs/potential_temperature/elixir_moist_euler_potential_temperature_moist_bubble.jl diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl b/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl similarity index 100% rename from examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl rename to examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl b/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl similarity index 100% rename from examples/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl rename to examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl b/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl similarity index 100% rename from examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl rename to examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl diff --git a/examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl b/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl similarity index 100% rename from examples/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl rename to examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl From 25fddb2cf7885d5c5f9119deff22d36a12a4f9e1 Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Fri, 16 May 2025 23:57:37 +0200 Subject: [PATCH 112/115] add a test --- ...ixir_rainy_euler_rainy_bubble_diffusion.jl | 5 +- test/runtests.jl | 4 ++ test/test_2d_rainy_euler.jl | 46 +++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 test/test_2d_rainy_euler.jl diff --git a/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl b/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl index 95219914..ef3f665b 100644 --- a/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl +++ b/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl @@ -1,4 +1,4 @@ -using OrdinaryDiffEq +using OrdinaryDiffEqSSPRK using Trixi using TrixiAtmo using TrixiAtmo: source_terms_rainy, saturation_residual, @@ -248,7 +248,8 @@ solver = DGSEM(basis, surface_flux, volume_integral) initial_condition = initial_condition_bubble_rainy source_terms = source_terms_rainy -mesh = TreeMesh(coordinates_min, coordinates_max, initial_refinement_level = 6, periodicity = (true, false), n_cells_max = 1_000_000) +initial_refinement_level = 6 +mesh = TreeMesh(coordinates_min, coordinates_max, initial_refinement_level = initial_refinement_level, periodicity = (true, false), n_cells_max = 1_000_000) semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; source_terms, boundary_conditions = (boundary_conditions, boundary_conditions_parabolic)) diff --git a/test/runtests.jl b/test/runtests.jl index 962e7265..12dc0bfb 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -17,6 +17,10 @@ const TRIXI_NTHREADS = clamp(Sys.CPU_THREADS, 2, 3) include("test_2d_moist_euler.jl") end + @time if TRIXI_TEST == "all" || TRIXI_TEST == "moist_euler" + include("test_2d_rainy_euler.jl") + end + @time if TRIXI_TEST == "all" || TRIXI_TEST == "spherical_advection" include("test_spherical_advection.jl") end diff --git a/test/test_2d_rainy_euler.jl b/test/test_2d_rainy_euler.jl new file mode 100644 index 00000000..92815971 --- /dev/null +++ b/test/test_2d_rainy_euler.jl @@ -0,0 +1,46 @@ +module TestExamples2DRainyEuler + +using Test +using TrixiAtmo + +include("test_trixiatmo.jl") + +EXAMPLES_DIR = TrixiAtmo.examples_dir() * "moist_bubble/" + +@trixiatmo_testset "../examples/elixir_moist_euler_dry_bubble" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl"), + l2=[ + 1.300428671901329e-6, + 2.601090012108739e-5, + 0.0006660124630171347, + 0.008969786054960861, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + linf=[ + 1.0312042909910168e-5, + 0.00020625488871672815, + 0.006392107590872236, + 0.07612038028310053, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + initial_refinement_level=3, + tspan=(0.0, 10.0)) + # Ensure that we do not have excessive memory allocations + # (e.g., from type instabilities) + let + t = sol.t[end] + u_ode = sol.u[end] + du_ode = similar(u_ode) + @test (@allocated TrixiAtmo.Trixi.rhs!(du_ode, u_ode, semi, t)) < 100 + end +end +end # module From 58591a2402bd3cd006fd23a1d062ce7ec15fab5c Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Fri, 16 May 2025 23:57:47 +0200 Subject: [PATCH 113/115] remove StartupDG --- Project.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Project.toml b/Project.toml index 2b05a66b..ec064513 100644 --- a/Project.toml +++ b/Project.toml @@ -9,7 +9,6 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" LoopVectorization = "bdcacae8-1622-11e9-2a5c-532679323890" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" -StartUpDG = "472ebc20-7c99-4d4b-9470-8fde4e9faa0f" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" From 9f678c878fbe846f48e44a56711e99387dcae6d1 Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Fri, 16 May 2025 23:59:46 +0200 Subject: [PATCH 114/115] format --- .../elixir_moist_euler_moist_bubble_lucas.jl | 2 +- .../convergence_test_rainy.jl | 139 +- .../convergence_test_rainy_dry.jl | 13 +- .../convergence_test_rainy_explicit.jl | 135 +- .../convergence_test_rainy_explicit_dry.jl | 13 +- .../convergence_test_rainy_explicit_moist.jl | 102 +- .../convergence_test_rainy_moist.jl | 106 +- .../energy/elixir_rainy_euler_dry_bubble.jl | 16 +- ...iny_euler_explicit_moist_bubble_ec_test.jl | 45 +- ...ainy_euler_explicit_weak_blast_wave_dry.jl | 39 +- ...ny_euler_explicit_weak_blast_wave_rainy.jl | 54 +- ...elixir_moist_euler_moist_bubble_dgmulti.jl | 32 +- ...lixir_rainy_euler_explicit_moist_bubble.jl | 43 +- .../energy/elixir_rainy_euler_moist_bubble.jl | 49 +- ...elixir_rainy_euler_moist_bubble_dgmulti.jl | 64 +- ...uler_potential_temperature_moist_bubble.jl | 7 +- ...lixir_rainy_euler_explicit_rainy_bubble.jl | 140 +- ...y_euler_explicit_rainy_bubble_diffusion.jl | 161 +- .../elixir_rainy_euler_rainy_bubble.jl | 147 +- ...ixir_rainy_euler_rainy_bubble_diffusion.jl | 167 +- src/callbacks_stage/callbacks_stage.jl | 2 +- src/callbacks_stage/nonlinear_solve_dg.jl | 37 +- src/callbacks_stage/nonlinear_solve_dg2d.jl | 128 +- src/callbacks_stage/rain_limiter_dg.jl | 25 +- src/callbacks_stage/rain_limiter_dg2d.jl | 42 +- ...le_moist_euler_potential_temperature_2d.jl | 144 +- src/equations/compressible_rainy_euler_2d.jl | 1852 +++++++++-------- .../compressible_rainy_euler_explicit_2d.jl | 1818 ++++++++-------- src/equations/equations.jl | 1 - test/test_2d_rainy_euler.jl | 2 +- 30 files changed, 2797 insertions(+), 2728 deletions(-) diff --git a/examples/moist_bubble/comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl b/examples/moist_bubble/comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl index 5a4ba23e..8fe7690d 100644 --- a/examples/moist_bubble/comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl +++ b/examples/moist_bubble/comparison_elixirs/elixir_moist_euler_moist_bubble_lucas.jl @@ -1,4 +1,4 @@ -using OrdinaryDiffEq +using OrdinaryDiffEqLowStorageRK using Trixi, TrixiAtmo using TrixiAtmo: cons2aeqpot, saturation_pressure, source_terms_moist_bubble, flux_LMARS diff --git a/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy.jl b/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy.jl index d10940b1..25bdacd9 100644 --- a/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy.jl +++ b/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy.jl @@ -5,14 +5,13 @@ using TrixiAtmo: saturation_vapour_pressure, saturation_vapour_pressure_derivati saturation_residual, saturation_residual_jacobian, terminal_velocity_rain - - -function initial_condition_convergence_test_rainy(x, t, equations::CompressibleRainyEulerEquations2D) +function initial_condition_convergence_test_rainy(x, t, + equations::CompressibleRainyEulerEquations2D) # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_v = equations.R_vapour + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour ref_L = equations.ref_latent_heat_vap_temp # define rho like in dry convergence test @@ -25,33 +24,35 @@ function initial_condition_convergence_test_rainy(x, t, equations::CompressibleR # define variables of rho temperature = rho + 250.0 - rho_vapour = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) - rho_cloud = rho / c_l * 3000 - rho_rain = rho / c_l * 1000 - rho_moist = rho_vapour + rho_cloud - rho_dry = rho - rho_moist - rho_rain + rho_vapour = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + rho_cloud = rho / c_l * 3000 + rho_rain = rho / c_l * 1000 + rho_moist = rho_vapour + rho_cloud + rho_dry = rho - rho_moist - rho_rain # define matching energydensity with v1 := 1 and v2 := 1 , initially - energy = (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * temperature + energy = (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * + temperature energy += rho_vapour * ref_L + rho - return SVector(rho_dry, rho_moist, rho_rain, rho, rho, energy, rho_vapour, rho_cloud, temperature) + return SVector(rho_dry, rho_moist, rho_rain, rho, rho, energy, rho_vapour, rho_cloud, + temperature) end - -function source_terms_convergence_test_rainy(u, x, t, equations::CompressibleRainyEulerEquations2D) +function source_terms_convergence_test_rainy(u, x, t, + equations::CompressibleRainyEulerEquations2D) # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_d = equations.R_dry_air - R_v = equations.R_vapour + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour ref_L = equations.ref_latent_heat_vap_temp - N_0 = equations.rain_water_distr - v_0 = equations.v_mean_rain + N_0 = equations.rain_water_distr + v_0 = equations.v_mean_rain # help constant for terminal rain velocity derivative ( \Gamma(4.5) / 6 ~= 1.9386213994279082 ) - c_help = v_0 * 1.9386213994279082 * (pi * N_0)^(-0.125) + c_help = v_0 * 1.9386213994279082 * (pi * N_0)^(-0.125) # define rho like initial condition c = 2.0 @@ -60,73 +61,76 @@ function source_terms_convergence_test_rainy(u, x, t, equations::CompressibleRai f = 1.0 / L ω = 2 * pi * f si, co = sincos(ω * (x[1] + x[2] - t)) - rho = c + A * si - rho_x = ω * A * co - rho_t = -rho_x + rho = c + A * si + rho_x = ω * A * co + rho_t = -rho_x # define variables of rho temperature = rho + 250.0 - sat_vap_p = saturation_vapour_pressure(temperature, equations) - rho_vapour = sat_vap_p / (R_v * temperature) - rho_cloud = rho / c_l * 3000 - rho_rain = rho / c_l * 1000 - rho_moist = rho_vapour + rho_cloud - rho_dry = rho - rho_moist - rho_rain - vr = terminal_velocity_rain(rho_moist, rho_rain, equations) + sat_vap_p = saturation_vapour_pressure(temperature, equations) + rho_vapour = sat_vap_p / (R_v * temperature) + rho_cloud = rho / c_l * 3000 + rho_rain = rho / c_l * 1000 + rho_moist = rho_vapour + rho_cloud + rho_dry = rho - rho_moist - rho_rain + vr = terminal_velocity_rain(rho_moist, rho_rain, equations) # define needed derivatives - sat_vap_p_t = rho_t * saturation_vapour_pressure_derivative(temperature, equations) - sat_vap_p_x = rho_x * saturation_vapour_pressure_derivative(temperature, equations) + sat_vap_p_t = rho_t * saturation_vapour_pressure_derivative(temperature, equations) + sat_vap_p_x = rho_x * saturation_vapour_pressure_derivative(temperature, equations) rho_vapour_t = (sat_vap_p_t * temperature - rho_t * sat_vap_p) / (R_v * temperature^2) rho_vapour_x = (sat_vap_p_x * temperature - rho_x * sat_vap_p) / (R_v * temperature^2) - rho_cloud_t = rho_t / c_l * 3000 - rho_cloud_x = rho_x / c_l * 3000 + rho_cloud_t = rho_t / c_l * 3000 + rho_cloud_x = rho_x / c_l * 3000 - rho_rain_t = rho_t / c_l * 1000 - rho_rain_x = rho_x / c_l * 1000 + rho_rain_t = rho_t / c_l * 1000 + rho_rain_x = rho_x / c_l * 1000 - rho_moist_t = rho_vapour_t + rho_cloud_t - rho_moist_x = rho_vapour_x + rho_cloud_x - - rho_dry_t = rho_t - rho_moist_t - rho_rain_t - rho_dry_x = rho_x - rho_moist_x - rho_rain_x + rho_moist_t = rho_vapour_t + rho_cloud_t + rho_moist_x = rho_vapour_x + rho_cloud_x - energy_t = (c_vd * rho_dry_t + c_vv * rho_vapour_t + c_l * (rho_cloud_t + rho_rain_t)) * temperature - energy_t += (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * rho_t - energy_t += rho_vapour_t * ref_L + rho_t + rho_dry_t = rho_t - rho_moist_t - rho_rain_t + rho_dry_x = rho_x - rho_moist_x - rho_rain_x - energy_x = (c_vd * rho_dry_x + c_vv * rho_vapour_x + c_l * (rho_cloud_x + rho_rain_x)) * temperature - energy_x += (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * rho_x - energy_x += rho_vapour_x * ref_L + rho_x + energy_t = (c_vd * rho_dry_t + c_vv * rho_vapour_t + c_l * (rho_cloud_t + rho_rain_t)) * + temperature + energy_t += (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * rho_t + energy_t += rho_vapour_t * ref_L + rho_t - pressure_x = (rho_dry_x * R_d + rho_vapour_x * R_v) * temperature - pressure_x += (rho_dry * R_d + rho_vapour * R_v) * rho_x # temperature_x = rho_x + energy_x = (c_vd * rho_dry_x + c_vv * rho_vapour_x + c_l * (rho_cloud_x + rho_rain_x)) * + temperature + energy_x += (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * rho_x + energy_x += rho_vapour_x * ref_L + rho_x - vr_x = c_help * 0.125 * ((rho_rain_x * rho_moist - rho_rain * rho_moist_x) / (rho_moist + rho_rain)^2) - vr_x *= (rho_rain / (rho_moist + rho_rain))^(-0.875) + pressure_x = (rho_dry_x * R_d + rho_vapour_x * R_v) * temperature + pressure_x += (rho_dry * R_d + rho_vapour * R_v) * rho_x # temperature_x = rho_x - rhor_vr__x = rho_rain_x * vr + rho_rain * vr_x + vr_x = c_help * 0.125 * + ((rho_rain_x * rho_moist - rho_rain * rho_moist_x) / (rho_moist + rho_rain)^2) + vr_x *= (rho_rain / (rho_moist + rho_rain))^(-0.875) + + rhor_vr__x = rho_rain_x * vr + rho_rain * vr_x # calculate source terms for manufactured solution # density - S_rho_dry = rho_dry_t + 2.0 * rho_dry_x + S_rho_dry = rho_dry_t + 2.0 * rho_dry_x S_rho_moist = rho_moist_t + 2.0 * rho_moist_x - S_rho_rain = rho_rain_t + 2.0 * rho_rain_x - rhor_vr__x - + S_rho_rain = rho_rain_t + 2.0 * rho_rain_x - rhor_vr__x + # "momentum" - S_rho_v1 = rho_x + pressure_x - rhor_vr__x - S_rho_v2 = rho_x + pressure_x - rhor_vr__x + S_rho_v1 = rho_x + pressure_x - rhor_vr__x + S_rho_v2 = rho_x + pressure_x - rhor_vr__x # "energy" - S_energy = energy_t + 2.0 * (energy_x + pressure_x) - (c_l * rho_x * rho_rain * vr) - S_energy -= (c_l * temperature + 1) * rhor_vr__x + S_energy = energy_t + 2.0 * (energy_x + pressure_x) - (c_l * rho_x * rho_rain * vr) + S_energy -= (c_l * temperature + 1) * rhor_vr__x - return SVector(S_rho_dry, S_rho_moist, S_rho_rain, S_rho_v1, S_rho_v2, S_energy, 0.0, 0.0, 0.0) + return SVector(S_rho_dry, S_rho_moist, S_rho_rain, S_rho_v1, S_rho_v2, S_energy, 0.0, + 0.0, 0.0) end - ############################################################################### # semidiscretization of the compressible Euler equations @@ -171,7 +175,8 @@ callbacks = CallbackSet(summary_callback, save_solution, stepsize_callback) -stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) +stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, + SVector(7, 8, 9), 1e-9) ############################################################################### # run the simulation @@ -216,4 +221,4 @@ Dict{Symbol, Any} with 3 entries: :variables => ("rho_dry", "rho_moist", "rho_rain", "rho_v1", "rho_v2", "energy_density", "rho_vapour", "rho_cloud", "temperature") :l2 => [4.03641, 4.03834, 4.04901, 4.39454, 4.7665, 4.00677, 4.47752, 4.03837, 4.47639] :linf => [4.03824, 4.04306, 3.96283, 4.31327, 4.76078, 4.023, 4.17127, 4.04306, 4.17577] -=# \ No newline at end of file +=# diff --git a/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_dry.jl b/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_dry.jl index eb40d639..06a5f8a0 100644 --- a/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_dry.jl +++ b/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_dry.jl @@ -2,10 +2,9 @@ using OrdinaryDiffEq using Trixi using TrixiAtmo - - # adapted from compressible_euler_2d.jl -function initial_condition_convergence_test(x, t, equations::CompressibleRainyEulerEquations2D) +function initial_condition_convergence_test(x, t, + equations::CompressibleRainyEulerEquations2D) RealT = eltype(x) c = 2 A = convert(RealT, 0.1) @@ -22,9 +21,9 @@ function initial_condition_convergence_test(x, t, equations::CompressibleRainyEu return SVector(rho, 0.0, 0.0, rho_v1, rho_v2, rho_e, 0.0, 0.0, 0.0) end - # adapted from compressible_euler_2d.jl -function source_terms_convergence_test(u, x, t, equations::CompressibleRainyEulerEquations2D) +function source_terms_convergence_test(u, x, t, + equations::CompressibleRainyEulerEquations2D) c_pd = equations.c_dry_air_const_pressure c_vd = equations.c_dry_air_const_volume @@ -53,7 +52,6 @@ function source_terms_convergence_test(u, x, t, equations::CompressibleRainyEule return SVector(du1, 0.0, 0.0, du2, du3, du4, 0.0, 0.0, 0.0) end - # from elixir_euler_source_terms.jl ############################################################################### # semidiscretization of the compressible Euler equations @@ -107,7 +105,6 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), save_everystep = false, callback = callbacks); summary_callback() # print the timer summary - #= For copy-paste convenience: #convergence_test("TrixiAtmo.jl/examples/convergence_test_elixirs/convergence_test_rainy_dry.jl", 5) @@ -151,4 +148,4 @@ NaN Dict{Symbol, Any} with 3 entries: :variables => ("rho_dry", "rho_moist", "rho_rain", "rho_v1", "rho_v2", "energy_density", "rho_vapour", "rho_cloud", "temperature") :l2 => [4.13577, NaN, NaN, 4.05385, 4.05385, 4.03601, NaN, NaN, NaN] - :linf => [4.05911, NaN, NaN, 3.9867, 3.98669, 4.00476, NaN, NaN, NaN]=# \ No newline at end of file + :linf => [4.05911, NaN, NaN, 3.9867, 3.98669, 4.00476, NaN, NaN, NaN]=# diff --git a/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_explicit.jl b/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_explicit.jl index bcac380a..9f1b0155 100644 --- a/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_explicit.jl +++ b/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_explicit.jl @@ -4,14 +4,13 @@ using TrixiAtmo using TrixiAtmo: saturation_vapour_pressure, saturation_vapour_pressure_derivative, terminal_velocity_rain, RainLimiterDG - - -function initial_condition_convergence_test_rainy(x, t, equations::CompressibleRainyEulerExplicitEquations2D) +function initial_condition_convergence_test_rainy(x, t, + equations::CompressibleRainyEulerExplicitEquations2D) # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_v = equations.R_vapour + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour ref_L = equations.ref_latent_heat_vap_temp # define rho like in dry convergence test @@ -24,33 +23,34 @@ function initial_condition_convergence_test_rainy(x, t, equations::CompressibleR # define variables of rho temperature = rho + 250.0 - rho_vapour = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) - rho_cloud = rho / c_l * 3000 - rho_rain = rho / c_l * 1000 - rho_moist = rho_vapour + rho_cloud - rho_dry = rho - rho_moist - rho_rain + rho_vapour = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + rho_cloud = rho / c_l * 3000 + rho_rain = rho / c_l * 1000 + rho_moist = rho_vapour + rho_cloud + rho_dry = rho - rho_moist - rho_rain # define matching energydensity with v1 := 1 and v2 := 1 , initially - energy = (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * temperature + energy = (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * + temperature energy += rho_vapour * ref_L + rho return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho, energy) end - -function source_terms_convergence_test_rainy(u, x, t, equations::CompressibleRainyEulerExplicitEquations2D) +function source_terms_convergence_test_rainy(u, x, t, + equations::CompressibleRainyEulerExplicitEquations2D) # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_d = equations.R_dry_air - R_v = equations.R_vapour + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour ref_L = equations.ref_latent_heat_vap_temp - N_0 = equations.rain_water_distr - v_0 = equations.v_mean_rain + N_0 = equations.rain_water_distr + v_0 = equations.v_mean_rain # help constant for terminal rain velocity derivative ( \Gamma(4.5) / 6 ~= 1.9386213994279082 ) - c_help = v_0 * 1.9386213994279082 * (pi * N_0)^(-0.125) + c_help = v_0 * 1.9386213994279082 * (pi * N_0)^(-0.125) # define rho like initial condition c = 2.0 @@ -59,74 +59,77 @@ function source_terms_convergence_test_rainy(u, x, t, equations::CompressibleRai f = 1.0 / L ω = 2 * pi * f si, co = sincos(ω * (x[1] + x[2] - t)) - rho = c + A * si - rho_x = ω * A * co - rho_t = -rho_x + rho = c + A * si + rho_x = ω * A * co + rho_t = -rho_x # define variables of rho temperature = rho + 250.0 - sat_vap_p = saturation_vapour_pressure(temperature, equations) - rho_vapour = sat_vap_p / (R_v * temperature) - rho_cloud = rho / c_l * 3000 - rho_rain = rho / c_l * 1000 - rho_moist = rho_vapour + rho_cloud - rho_dry = rho - rho_moist - rho_rain - vr = terminal_velocity_rain(rho_moist, rho_rain, equations) + sat_vap_p = saturation_vapour_pressure(temperature, equations) + rho_vapour = sat_vap_p / (R_v * temperature) + rho_cloud = rho / c_l * 3000 + rho_rain = rho / c_l * 1000 + rho_moist = rho_vapour + rho_cloud + rho_dry = rho - rho_moist - rho_rain + vr = terminal_velocity_rain(rho_moist, rho_rain, equations) # define needed derivatives - sat_vap_p_t = rho_t * saturation_vapour_pressure_derivative(temperature, equations) - sat_vap_p_x = rho_x * saturation_vapour_pressure_derivative(temperature, equations) + sat_vap_p_t = rho_t * saturation_vapour_pressure_derivative(temperature, equations) + sat_vap_p_x = rho_x * saturation_vapour_pressure_derivative(temperature, equations) rho_vapour_t = (sat_vap_p_t * temperature - rho_t * sat_vap_p) / (R_v * temperature^2) rho_vapour_x = (sat_vap_p_x * temperature - rho_x * sat_vap_p) / (R_v * temperature^2) - rho_cloud_t = rho_t / c_l * 3000 - rho_cloud_x = rho_x / c_l * 3000 + rho_cloud_t = rho_t / c_l * 3000 + rho_cloud_x = rho_x / c_l * 3000 - rho_rain_t = rho_t / c_l * 1000 - rho_rain_x = rho_x / c_l * 1000 + rho_rain_t = rho_t / c_l * 1000 + rho_rain_x = rho_x / c_l * 1000 - rho_moist_t = rho_vapour_t + rho_cloud_t - rho_moist_x = rho_vapour_x + rho_cloud_x - - rho_dry_t = rho_t - rho_moist_t - rho_rain_t - rho_dry_x = rho_x - rho_moist_x - rho_rain_x + rho_moist_t = rho_vapour_t + rho_cloud_t + rho_moist_x = rho_vapour_x + rho_cloud_x - energy_t = (c_vd * rho_dry_t + c_vv * rho_vapour_t + c_l * (rho_cloud_t + rho_rain_t)) * temperature - energy_t += (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * rho_t - energy_t += rho_vapour_t * ref_L + rho_t + rho_dry_t = rho_t - rho_moist_t - rho_rain_t + rho_dry_x = rho_x - rho_moist_x - rho_rain_x - energy_x = (c_vd * rho_dry_x + c_vv * rho_vapour_x + c_l * (rho_cloud_x + rho_rain_x)) * temperature - energy_x += (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * rho_x - energy_x += rho_vapour_x * ref_L + rho_x + energy_t = (c_vd * rho_dry_t + c_vv * rho_vapour_t + c_l * (rho_cloud_t + rho_rain_t)) * + temperature + energy_t += (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * rho_t + energy_t += rho_vapour_t * ref_L + rho_t - pressure_x = (rho_dry_x * R_d + rho_vapour_x * R_v) * temperature - pressure_x += (rho_dry * R_d + rho_vapour * R_v) * rho_x # temperature_x = rho_x + energy_x = (c_vd * rho_dry_x + c_vv * rho_vapour_x + c_l * (rho_cloud_x + rho_rain_x)) * + temperature + energy_x += (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * rho_x + energy_x += rho_vapour_x * ref_L + rho_x - vr_x = c_help * 0.125 * ((rho_rain_x * rho_moist - rho_rain * rho_moist_x) / (rho_moist + rho_rain)^2) - vr_x *= (rho_rain / (rho_moist + rho_rain))^(-0.875) + pressure_x = (rho_dry_x * R_d + rho_vapour_x * R_v) * temperature + pressure_x += (rho_dry * R_d + rho_vapour * R_v) * rho_x # temperature_x = rho_x - rhor_vr__x = rho_rain_x * vr + rho_rain * vr_x + vr_x = c_help * 0.125 * + ((rho_rain_x * rho_moist - rho_rain * rho_moist_x) / (rho_moist + rho_rain)^2) + vr_x *= (rho_rain / (rho_moist + rho_rain))^(-0.875) + + rhor_vr__x = rho_rain_x * vr + rho_rain * vr_x # calculate source terms for manufactured solution # density - S_rho_dry = rho_dry_t + 2.0 * rho_dry_x + S_rho_dry = rho_dry_t + 2.0 * rho_dry_x S_rho_vapour = rho_vapour_t + 2.0 * rho_vapour_x - S_rho_cloud = rho_cloud_t + 2.0 * rho_cloud_x - S_rho_rain = rho_rain_t + 2.0 * rho_rain_x - rhor_vr__x - + S_rho_cloud = rho_cloud_t + 2.0 * rho_cloud_x + S_rho_rain = rho_rain_t + 2.0 * rho_rain_x - rhor_vr__x + # "momentum" - S_rho_v1 = rho_x + pressure_x - rhor_vr__x - S_rho_v2 = rho_x + pressure_x - rhor_vr__x + S_rho_v1 = rho_x + pressure_x - rhor_vr__x + S_rho_v2 = rho_x + pressure_x - rhor_vr__x # "energy" - S_energy = energy_t + 2.0 * (energy_x + pressure_x) - (c_l * rho_x * rho_rain * vr) - S_energy -= (c_l * temperature + 1) * rhor_vr__x + S_energy = energy_t + 2.0 * (energy_x + pressure_x) - (c_l * rho_x * rho_rain * vr) + S_energy -= (c_l * temperature + 1) * rhor_vr__x - return SVector(S_rho_dry, S_rho_vapour, S_rho_cloud, S_rho_rain, S_rho_v1, S_rho_v2, S_energy) + return SVector(S_rho_dry, S_rho_vapour, S_rho_cloud, S_rho_rain, S_rho_v1, S_rho_v2, + S_energy) end - ############################################################################### # semidiscretization of the compressible Euler equations @@ -212,4 +215,4 @@ Dict{Symbol, Any} with 3 entries: :variables => ("rho_dry", "rho_vapour", "rho_cloud", "rho_rain", "rho_v1", "rho_v2", "energy_density") :l2 => [4.03455, 5.14974, 4.0349, 4.04611, 4.39262, 4.76286, 4.0041] :linf => [4.03983, 5.22416, 4.03676, 3.95607, 4.31093, 4.75739, 4.00916] -=# \ No newline at end of file +=# diff --git a/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_explicit_dry.jl b/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_explicit_dry.jl index 1be59acf..14602092 100644 --- a/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_explicit_dry.jl +++ b/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_explicit_dry.jl @@ -2,10 +2,9 @@ using OrdinaryDiffEq using Trixi using TrixiAtmo - - # adapted from compressible_euler_2d.jl -function initial_condition_convergence_test(x, t, equations::CompressibleRainyEulerExplicitEquations2D) +function initial_condition_convergence_test(x, t, + equations::CompressibleRainyEulerExplicitEquations2D) RealT = eltype(x) c = 2 A = convert(RealT, 0.1) @@ -22,9 +21,9 @@ function initial_condition_convergence_test(x, t, equations::CompressibleRainyEu return SVector(rho, 0.0, 0.0, 0.0, rho_v1, rho_v2, rho_e) end - # adapted from compressible_euler_2d.jl -function source_terms_convergence_test(u, x, t, equations::CompressibleRainyEulerExplicitEquations2D) +function source_terms_convergence_test(u, x, t, + equations::CompressibleRainyEulerExplicitEquations2D) c_pd = equations.c_dry_air_const_pressure c_vd = equations.c_dry_air_const_volume @@ -52,7 +51,6 @@ function source_terms_convergence_test(u, x, t, equations::CompressibleRainyEule return SVector(du1, 0.0, 0.0, 0.0, du2, du3, du4) end - # from elixir_euler_source_terms.jl ############################################################################### # semidiscretization of the compressible Euler equations @@ -106,7 +104,6 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), save_everystep = false, callback = callbacks); summary_callback() # print the timer summary - #= For copy-paste convenience: #convergence_test("TrixiAtmo.jl/examples/convergence_test_elixirs/convergence_test_rainy_dry_explicit.jl", 5) @@ -136,4 +133,4 @@ mean 4.06 mean NaN mean NaN mean NaN Dict{Symbol, Any} with 3 entries: :variables => ("rho_dry", "rho_vapour", "rho_cloud", "rho_rain", "rho_v1", "rho_v2", "energy_density") :l2 => [4.13577, NaN, NaN, NaN, 4.05385, 4.05385, 4.03601] - :linf => [4.05911, NaN, NaN, NaN, 3.9867, 3.9867, 4.00476]=# \ No newline at end of file + :linf => [4.05911, NaN, NaN, NaN, 3.9867, 3.9867, 4.00476]=# diff --git a/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_explicit_moist.jl b/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_explicit_moist.jl index 29b384e2..55791844 100644 --- a/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_explicit_moist.jl +++ b/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_explicit_moist.jl @@ -4,14 +4,13 @@ using TrixiAtmo using TrixiAtmo: saturation_vapour_pressure, saturation_vapour_pressure_derivative, saturation_residual, saturation_residual_jacobian - - -function initial_condition_convergence_test_rainy_no_rain(x, t, equations::CompressibleRainyEulerExplicitEquations2D) +function initial_condition_convergence_test_rainy_no_rain(x, t, + equations::CompressibleRainyEulerExplicitEquations2D) # needed constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_v = equations.R_vapour + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour ref_L = equations.ref_latent_heat_vap_temp # define rho like in dry convergence test @@ -24,26 +23,26 @@ function initial_condition_convergence_test_rainy_no_rain(x, t, equations::Compr # define variables of rho temperature = rho + 250.0 - rho_vapour = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) - rho_cloud = rho / c_l * 4000 - rho_moist = rho_vapour + rho_cloud - rho_dry = rho - rho_moist + rho_vapour = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + rho_cloud = rho / c_l * 4000 + rho_moist = rho_vapour + rho_cloud + rho_dry = rho - rho_moist # define matching energydensity with v1 := 1 and v2 := 1 , initially - energy = (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud) * temperature + energy = (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud) * temperature energy += rho_vapour * ref_L + rho return SVector(rho_dry, rho_vapour, rho_cloud, 0.0, rho, rho, energy) end - -function source_terms_convergence_test_rainy_no_rain(u, x, t, equations::CompressibleRainyEulerExplicitEquations2D) +function source_terms_convergence_test_rainy_no_rain(u, x, t, + equations::CompressibleRainyEulerExplicitEquations2D) # needed constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_d = equations.R_dry_air - R_v = equations.R_vapour + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour ref_L = equations.ref_latent_heat_vap_temp # define rho like initial condition @@ -53,62 +52,61 @@ function source_terms_convergence_test_rainy_no_rain(u, x, t, equations::Compres f = 1.0 / L ω = 2 * pi * f si, co = sincos(ω * (x[1] + x[2] - t)) - rho = c + A * si - rho_x = ω * A * co - rho_t = -rho_x + rho = c + A * si + rho_x = ω * A * co + rho_t = -rho_x # define variables of rho temperature = rho + 250.0 - sat_vap_p = saturation_vapour_pressure(temperature, equations) - rho_vapour = sat_vap_p / (R_v * temperature) - rho_cloud = rho / c_l * 4000 - rho_moist = rho_vapour + rho_cloud - rho_dry = rho - rho_moist + sat_vap_p = saturation_vapour_pressure(temperature, equations) + rho_vapour = sat_vap_p / (R_v * temperature) + rho_cloud = rho / c_l * 4000 + rho_moist = rho_vapour + rho_cloud + rho_dry = rho - rho_moist # define needed derivatives - sat_vap_p_t = rho_t * saturation_vapour_pressure_derivative(temperature, equations) - sat_vap_p_x = rho_x * saturation_vapour_pressure_derivative(temperature, equations) + sat_vap_p_t = rho_t * saturation_vapour_pressure_derivative(temperature, equations) + sat_vap_p_x = rho_x * saturation_vapour_pressure_derivative(temperature, equations) rho_vapour_t = (sat_vap_p_t * temperature - rho_t * sat_vap_p) / (R_v * temperature^2) rho_vapour_x = (sat_vap_p_x * temperature - rho_x * sat_vap_p) / (R_v * temperature^2) - rho_cloud_t = rho_t / c_l * 4000 - rho_cloud_x = rho_x / c_l * 4000 + rho_cloud_t = rho_t / c_l * 4000 + rho_cloud_x = rho_x / c_l * 4000 - rho_moist_t = rho_vapour_t + rho_cloud_t - rho_moist_x = rho_vapour_x + rho_cloud_x - - rho_dry_t = rho_t - rho_moist_t - rho_dry_x = rho_x - rho_moist_x + rho_moist_t = rho_vapour_t + rho_cloud_t + rho_moist_x = rho_vapour_x + rho_cloud_x - energy_t = (c_vd * rho_dry_t + c_vv * rho_vapour_t + c_l * rho_cloud_t) * temperature - energy_t += (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud ) * rho_t - energy_t += rho_vapour_t * ref_L + rho_t + rho_dry_t = rho_t - rho_moist_t + rho_dry_x = rho_x - rho_moist_x - energy_x = (c_vd * rho_dry_x + c_vv * rho_vapour_x + c_l * rho_cloud_x) * temperature - energy_x += (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud ) * rho_x - energy_x += rho_vapour_x * ref_L + rho_x + energy_t = (c_vd * rho_dry_t + c_vv * rho_vapour_t + c_l * rho_cloud_t) * temperature + energy_t += (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud) * rho_t + energy_t += rho_vapour_t * ref_L + rho_t - pressure_x = (rho_dry_x * R_d + rho_vapour_x * R_v) * temperature - pressure_x += (rho_dry * R_d + rho_vapour * R_v) * rho_x # temperature_x = rho_x + energy_x = (c_vd * rho_dry_x + c_vv * rho_vapour_x + c_l * rho_cloud_x) * temperature + energy_x += (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud) * rho_x + energy_x += rho_vapour_x * ref_L + rho_x + + pressure_x = (rho_dry_x * R_d + rho_vapour_x * R_v) * temperature + pressure_x += (rho_dry * R_d + rho_vapour * R_v) * rho_x # temperature_x = rho_x # calculate source terms for manufactured solution # density - S_rho_dry = rho_dry_t + 2.0 * rho_dry_x + S_rho_dry = rho_dry_t + 2.0 * rho_dry_x S_rho_vapour = rho_vapour_t + 2.0 * rho_vapour_x - S_rho_cloud = rho_cloud_t + 2.0 * rho_cloud_x - + S_rho_cloud = rho_cloud_t + 2.0 * rho_cloud_x + # "momentum" - S_rho_v1 = rho_x + pressure_x - S_rho_v2 = rho_x + pressure_x + S_rho_v1 = rho_x + pressure_x + S_rho_v2 = rho_x + pressure_x # "energy" - S_energy = energy_t + 2.0 * (energy_x + pressure_x) + S_energy = energy_t + 2.0 * (energy_x + pressure_x) return SVector(S_rho_dry, S_rho_vapour, S_rho_cloud, 0.0, S_rho_v1, S_rho_v2, S_energy) end - ############################################################################### # semidiscretization of the compressible Euler equations @@ -188,4 +186,4 @@ mean 4.16 mean 4.91 mean 4.15 mean NaN Dict{Symbol, Any} with 3 entries: :variables => ("rho_dry", "rho_vapour", "rho_cloud", "rho_rain", "rho_v1", "rho_v2", "energy_density") :l2 => [4.08558, 4.94267, 4.08233, NaN, 4.90466, 4.90466, 4.08271] - :linf => [4.1557, 4.90799, 4.15355, NaN, 4.72056, 4.72056, 4.15543]=# \ No newline at end of file + :linf => [4.1557, 4.90799, 4.15355, NaN, 4.72056, 4.72056, 4.15543]=# diff --git a/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_moist.jl b/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_moist.jl index 565c440a..b2b38a1b 100644 --- a/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_moist.jl +++ b/examples/moist_bubble/convergence_test_elixirs/convergence_test_rainy_moist.jl @@ -4,14 +4,13 @@ using TrixiAtmo using TrixiAtmo: saturation_vapour_pressure, saturation_vapour_pressure_derivative, saturation_residual, saturation_residual_jacobian - - -function initial_condition_convergence_test_rainy_no_rain(x, t, equations::CompressibleRainyEulerEquations2D) +function initial_condition_convergence_test_rainy_no_rain(x, t, + equations::CompressibleRainyEulerEquations2D) # needed constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_v = equations.R_vapour + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour ref_L = equations.ref_latent_heat_vap_temp # define rho like in dry convergence test @@ -24,26 +23,27 @@ function initial_condition_convergence_test_rainy_no_rain(x, t, equations::Compr # define variables of rho temperature = rho + 250.0 - rho_vapour = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) - rho_cloud = rho / c_l * 4000 - rho_moist = rho_vapour + rho_cloud - rho_dry = rho - rho_moist + rho_vapour = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + rho_cloud = rho / c_l * 4000 + rho_moist = rho_vapour + rho_cloud + rho_dry = rho - rho_moist # define matching energydensity with v1 := 1 and v2 := 1 , initially - energy = (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud) * temperature + energy = (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud) * temperature energy += rho_vapour * ref_L + rho - return SVector(rho_dry, rho_moist, 0.0, rho, rho, energy, rho_vapour, rho_cloud, temperature) + return SVector(rho_dry, rho_moist, 0.0, rho, rho, energy, rho_vapour, rho_cloud, + temperature) end - -function source_terms_convergence_test_rainy_no_rain(u, x, t, equations::CompressibleRainyEulerEquations2D) +function source_terms_convergence_test_rainy_no_rain(u, x, t, + equations::CompressibleRainyEulerEquations2D) # needed constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_d = equations.R_dry_air - R_v = equations.R_vapour + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour ref_L = equations.ref_latent_heat_vap_temp # define rho like initial condition @@ -53,61 +53,60 @@ function source_terms_convergence_test_rainy_no_rain(u, x, t, equations::Compres f = 1.0 / L ω = 2 * pi * f si, co = sincos(ω * (x[1] + x[2] - t)) - rho = c + A * si - rho_x = ω * A * co - rho_t = -rho_x + rho = c + A * si + rho_x = ω * A * co + rho_t = -rho_x # define variables of rho temperature = rho + 250.0 - sat_vap_p = saturation_vapour_pressure(temperature, equations) - rho_vapour = sat_vap_p / (R_v * temperature) - rho_cloud = rho / c_l * 4000 - rho_moist = rho_vapour + rho_cloud - rho_dry = rho - rho_moist + sat_vap_p = saturation_vapour_pressure(temperature, equations) + rho_vapour = sat_vap_p / (R_v * temperature) + rho_cloud = rho / c_l * 4000 + rho_moist = rho_vapour + rho_cloud + rho_dry = rho - rho_moist # define needed derivatives - sat_vap_p_t = rho_t * saturation_vapour_pressure_derivative(temperature, equations) - sat_vap_p_x = rho_x * saturation_vapour_pressure_derivative(temperature, equations) + sat_vap_p_t = rho_t * saturation_vapour_pressure_derivative(temperature, equations) + sat_vap_p_x = rho_x * saturation_vapour_pressure_derivative(temperature, equations) rho_vapour_t = (sat_vap_p_t * temperature - rho_t * sat_vap_p) / (R_v * temperature^2) rho_vapour_x = (sat_vap_p_x * temperature - rho_x * sat_vap_p) / (R_v * temperature^2) - rho_cloud_t = rho_t / c_l * 4000 - rho_cloud_x = rho_x / c_l * 4000 + rho_cloud_t = rho_t / c_l * 4000 + rho_cloud_x = rho_x / c_l * 4000 - rho_moist_t = rho_vapour_t + rho_cloud_t - rho_moist_x = rho_vapour_x + rho_cloud_x - - rho_dry_t = rho_t - rho_moist_t - rho_dry_x = rho_x - rho_moist_x + rho_moist_t = rho_vapour_t + rho_cloud_t + rho_moist_x = rho_vapour_x + rho_cloud_x - energy_t = (c_vd * rho_dry_t + c_vv * rho_vapour_t + c_l * rho_cloud_t) * temperature - energy_t += (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud ) * rho_t - energy_t += rho_vapour_t * ref_L + rho_t + rho_dry_t = rho_t - rho_moist_t + rho_dry_x = rho_x - rho_moist_x - energy_x = (c_vd * rho_dry_x + c_vv * rho_vapour_x + c_l * rho_cloud_x) * temperature - energy_x += (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud ) * rho_x - energy_x += rho_vapour_x * ref_L + rho_x + energy_t = (c_vd * rho_dry_t + c_vv * rho_vapour_t + c_l * rho_cloud_t) * temperature + energy_t += (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud) * rho_t + energy_t += rho_vapour_t * ref_L + rho_t - pressure_x = (rho_dry_x * R_d + rho_vapour_x * R_v) * temperature - pressure_x += (rho_dry * R_d + rho_vapour * R_v) * rho_x # temperature_x = rho_x + energy_x = (c_vd * rho_dry_x + c_vv * rho_vapour_x + c_l * rho_cloud_x) * temperature + energy_x += (c_vd * rho_dry + c_vv * rho_vapour + c_l * rho_cloud) * rho_x + energy_x += rho_vapour_x * ref_L + rho_x + + pressure_x = (rho_dry_x * R_d + rho_vapour_x * R_v) * temperature + pressure_x += (rho_dry * R_d + rho_vapour * R_v) * rho_x # temperature_x = rho_x # calculate source terms for manufactured solution # density - S_rho_dry = rho_dry_t + 2.0 * rho_dry_x + S_rho_dry = rho_dry_t + 2.0 * rho_dry_x S_rho_moist = rho_moist_t + 2.0 * rho_moist_x - + # "momentum" - S_rho_v1 = rho_x + pressure_x - S_rho_v2 = rho_x + pressure_x + S_rho_v1 = rho_x + pressure_x + S_rho_v2 = rho_x + pressure_x # "energy" - S_energy = energy_t + 2.0 * (energy_x + pressure_x) + S_energy = energy_t + 2.0 * (energy_x + pressure_x) return SVector(S_rho_dry, S_rho_moist, 0.0, S_rho_v1, S_rho_v2, S_energy, 0.0, 0.0, 0.0) end - ############################################################################### # semidiscretization of the compressible Euler equations @@ -152,7 +151,8 @@ callbacks = CallbackSet(summary_callback, save_solution, stepsize_callback) -stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) +stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, + SVector(7, 8, 9), 1e-9) ############################################################################### # run the simulation @@ -190,4 +190,4 @@ mean 4.16 mean 4.16 mean NaN mean 4.72 Dict{Symbol, Any} with 3 entries: :variables => ("rho_dry", "rho_moist", "rho_rain", "rho_v1", "rho_v2", "energy_density", "rho_vapour", "rho_cloud", "temperature") :l2 => [4.08874, 4.11293, NaN, 4.90375, 4.90375, 4.09297, 4.86169, 4.11317, 4.85982] - :linf => [4.1567, 4.161, NaN, 4.71912, 4.71912, 4.15581, 4.8092, 4.16105, 4.81099]=# \ No newline at end of file + :linf => [4.1567, 4.161, NaN, 4.71912, 4.71912, 4.15581, 4.8092, 4.16105, 4.81099]=# diff --git a/examples/moist_bubble/dry_bubble_elixirs/energy/elixir_rainy_euler_dry_bubble.jl b/examples/moist_bubble/dry_bubble_elixirs/energy/elixir_rainy_euler_dry_bubble.jl index 62bc95f9..f766f65a 100644 --- a/examples/moist_bubble/dry_bubble_elixirs/energy/elixir_rainy_euler_dry_bubble.jl +++ b/examples/moist_bubble/dry_bubble_elixirs/energy/elixir_rainy_euler_dry_bubble.jl @@ -3,11 +3,9 @@ using Trixi using TrixiAtmo using TrixiAtmo: source_terms_no_phase_change - - # copied from elixir_euler_warm_bubble.jl for quick tests function initial_condition_bubble_dry(x, t, equations::CompressibleRainyEulerEquations2D) - g = equations.gravity + g = equations.gravity c_p = equations.c_dry_air_const_pressure c_v = equations.c_dry_air_const_volume @@ -43,13 +41,11 @@ function initial_condition_bubble_dry(x, t, equations::CompressibleRainyEulerEqu v1 = 0.0 v2 = 0.0 - E = c_v * T + 0.5 * (v1^2 + v2^2) + E = c_v * T + 0.5 * (v1^2 + v2^2) return SVector(rho, 0.0, 0.0, rho * v1, rho * v2, rho * E, 0.0, 0.0, 0.0) end - - ############################################################################### # semidiscretization of the compressible rainy Euler equations @@ -67,7 +63,7 @@ surface_flux = flux_lax_friedrichs solver = DGSEM(basis, surface_flux) -coordinates_min = ( 0.0, 0.0) +coordinates_min = (0.0, 0.0) coordinates_max = (20_000.0, 10_000.0) cells_per_dimension = (64, 32) @@ -78,7 +74,7 @@ mesh = StructuredMesh(cells_per_dimension, coordinates_min, coordinates_max, periodicity = periodicity) initial_condition = initial_condition_bubble_dry -source_terms = source_terms_no_phase_change +source_terms = source_terms_no_phase_change semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, source_terms = source_terms, @@ -118,7 +114,7 @@ callbacks = CallbackSet(summary_callback, # run the simulation sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), maxiters = 1.0e7, - dt = 1.0, + dt = 1.0, save_everystep = false, callback = callbacks); -summary_callback() \ No newline at end of file +summary_callback() diff --git a/examples/moist_bubble/entropy_conservation_tests/moist_bubble/elixir_rainy_euler_explicit_moist_bubble_ec_test.jl b/examples/moist_bubble/entropy_conservation_tests/moist_bubble/elixir_rainy_euler_explicit_moist_bubble_ec_test.jl index d9711907..282775ed 100644 --- a/examples/moist_bubble/entropy_conservation_tests/moist_bubble/elixir_rainy_euler_explicit_moist_bubble_ec_test.jl +++ b/examples/moist_bubble/entropy_conservation_tests/moist_bubble/elixir_rainy_euler_explicit_moist_bubble_ec_test.jl @@ -6,22 +6,20 @@ using TrixiAtmo: source_terms_moist, saturation_residual, cons2eq_pot_temp, flux_LMARS, flux_ec_rain using NLsolve: nlsolve - - # Initial condition from elixir_moist_euler_bubble.jl -function moist_state(y, dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) - +function moist_state(y, dz, y0, r_t0, theta_e0, + equations::CompressibleMoistEulerEquations2D) @unpack p_0, g, c_pd, c_pv, c_vd, c_vv, R_d, R_v, c_pl, L_00 = equations g = 0.0 (p, rho, T, r_t, r_v, rho_qv, theta_e) = y p0 = y0[1] - F = zeros(7, 1) + F = zeros(7, 1) rho_d = rho / (1 + r_t) - p_d = R_d * rho_d * T - T_C = T - 273.15 - p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) - L = L_00 - (c_pl - c_pv) * T + p_d = R_d * rho_d * T + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + L = L_00 - (c_pl - c_pv) * T F[1] = (p - p0) / dz + g * rho F[2] = p - (R_d * rho_d + R_v * rho_qv) * T @@ -32,15 +30,16 @@ function moist_state(y, dz, y0, r_t0, theta_e0, equations::CompressibleMoistEule F[4] = r_t - r_t0 F[5] = rho_qv - rho_d * r_v F[6] = theta_e - theta_e0 - a = p_vs / (R_v * T) - rho_qv - b = rho - rho_qv - rho_d + a = p_vs / (R_v * T) - rho_qv + b = rho - rho_qv - rho_d # H=1 => phi=0 F[7] = a + b - sqrt(a * a + b * b) return F end -function generate_function_of_y(dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) +function generate_function_of_y(dz, y0, r_t0, theta_e0, + equations::CompressibleMoistEulerEquations2D) function function_of_y(y) return moist_state(y, dz, y0, r_t0, theta_e0, equations) end @@ -62,7 +61,6 @@ function AtmosphereLayers(equations; total_height = 10010.0, preciseness = 10, ground_state = (1.4, 100000.0), equivalent_potential_temperature = 320, mixing_ratios = (0.02, 0.02), RealT = Float64) - @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl = equations rho0, p0 = ground_state r_t0, r_v0 = mixing_ratios @@ -110,7 +108,8 @@ end # G.H. Bryan, J.M. Fritsch, A Benchmark Simulation for Moist Nonhydrostatic Numerical # Models, MonthlyWeather Review Vol.130, 2917–2928, 2002, # https://journals.ametsoc.org/view/journals/mwre/130/12/1520-0493_2002_130_2917_absfmn_2.0.co_2.xml. -function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, atmosphere_layers::AtmosphereLayers) +function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, + atmosphere_layers::AtmosphereLayers) @unpack layer_data, preciseness, total_height = atmosphere_layers dz = preciseness z = x[2] @@ -132,8 +131,9 @@ function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerE rho_qv = rho * (rho_qv_r / rho_r * (z - z_l) + rho_qv_l / rho_l * (z_r - z)) / dz rho_ql = rho * (rho_ql_r / rho_r * (z - z_l) + rho_ql_l / rho_l * (z_r - z)) / dz - rho, rho_e, rho_qv, rho_ql, T_loc = perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, - equations::CompressibleMoistEulerEquations2D) + rho, rho_e, rho_qv, rho_ql, T_loc = perturb_moist_profile!(x, rho, rho_theta, rho_qv, + rho_ql, + equations::CompressibleMoistEulerEquations2D) v1 = 1.0 v2 = 1.0 @@ -208,11 +208,10 @@ atmosphere_data = AtmosphereLayers(CompressibleMoistEulerEquations2D()) # Create the initial condition with the initial data set function initial_condition_moist(x, t, equations::CompressibleRainyEulerExplicitEquations2D) - return initial_condition_moist_bubble(x, t, CompressibleMoistEulerEquations2D(), atmosphere_data) + return initial_condition_moist_bubble(x, t, CompressibleMoistEulerEquations2D(), + atmosphere_data) end - - ############################################################################### # semidiscretization of the compressible rainy Euler equations @@ -226,14 +225,13 @@ boundary_conditions = (x_neg = boundary_condition_periodic, polydeg = 3 basis = LobattoLegendreBasis(polydeg) - -volume_flux = flux_ec_rain +volume_flux = flux_ec_rain surface_flux = volume_flux volume_integral = VolumeIntegralFluxDifferencing(volume_flux) solver = DGSEM(basis, surface_flux, volume_integral) -coordinates_min = ( 0.0, 0.0) +coordinates_min = (0.0, 0.0) coordinates_max = (20_000.0, 10_000.0) cells_per_dimension = (64, 32) @@ -255,7 +253,6 @@ summary_callback = SummaryCallback() analysis_interval = 1000 - analysis_callback = AnalysisCallback(semi, interval = analysis_interval, extra_analysis_errors = (:entropy_conservation_error,)) @@ -282,4 +279,4 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, save_everystep = false, callback = callbacks); -summary_callback() \ No newline at end of file +summary_callback() diff --git a/examples/moist_bubble/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl b/examples/moist_bubble/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl index f0281c34..3ab66a02 100644 --- a/examples/moist_bubble/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl +++ b/examples/moist_bubble/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_dry.jl @@ -4,36 +4,34 @@ using TrixiAtmo using TrixiAtmo: flux_ec_rain, flux_chandrashekar, RainLimiterDG, cons2eq_pot_temp - -function initial_condition_weak_blast_wave_dry(x, t, equations::CompressibleRainyEulerExplicitEquations2D) +function initial_condition_weak_blast_wave_dry(x, t, + equations::CompressibleRainyEulerExplicitEquations2D) # constants - c_vd = equations.c_dry_air_const_volume - R_d = equations.R_dry_air + c_vd = equations.c_dry_air_const_volume + R_d = equations.R_dry_air if sqrt(x[1]^2 + x[2]^2) > 0.5 rho = 1.0e-4 - v1 = 0.0 - v2 = 0.0 - p = 1.0 + v1 = 0.0 + v2 = 0.0 + p = 1.0 else phi = atan(x[2], x[1]) rho = 1.1691e-4 - v1 = 0.1882 * cos(phi) - v2 = 0.1882 * sin(phi) - p = 1.245 + v1 = 0.1882 * cos(phi) + v2 = 0.1882 * sin(phi) + p = 1.245 end rho_dry = rho T = p / (rho_dry * R_d) - - energy_density = c_vd * rho_dry * T + + energy_density = c_vd * rho_dry * T energy_density += 0.5 * rho * (v1^2 + v2^2) - + return SVector(rho_dry, 0.0, 0.0, 0.0, rho * v1, rho * v2, energy_density) end - - ############################################################################### # semidiscretization of the compressible Euler equations @@ -44,12 +42,12 @@ initial_condition = initial_condition_weak_blast_wave_dry polydeg = 3 basis = LobattoLegendreBasis(polydeg) -volume_flux = flux_ec_rain +volume_flux = flux_ec_rain surface_flux = volume_flux solver = DGSEM(basis, surface_flux, VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, initial_refinement_level = 5, @@ -59,7 +57,6 @@ mesh = TreeMesh(coordinates_min, coordinates_max, semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions = boundary_condition_periodic) - ############################################################################### # ODE solvers, callbacks etc. @@ -82,17 +79,15 @@ save_solution = SaveSolutionCallback(interval = 1000, stepsize_callback = StepsizeCallback(cfl = 1.0) callbacks = CallbackSet(summary_callback, - analysis_callback, + analysis_callback, alive_callback, save_solution, stepsize_callback) - - ############################################################################### # run the simulation 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); -summary_callback() # print the timer summary \ No newline at end of file +summary_callback() # print the timer summary diff --git a/examples/moist_bubble/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl b/examples/moist_bubble/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl index 5e2b8f2c..35a31c5e 100644 --- a/examples/moist_bubble/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl +++ b/examples/moist_bubble/entropy_conservation_tests/weak_blast_wave/rainy_euler_explicit_weak_blast_wave_rainy.jl @@ -5,43 +5,42 @@ using TrixiAtmo: saturation_residual, saturation_residual_jacobian, flux_ec_rain, saturation_vapour_pressure, flux_chandrashekar, RainLimiterDG, cons2eq_pot_temp, entropy - -function initial_condition_weak_blast_wave_rainy(x, t, equations::CompressibleRainyEulerExplicitEquations2D) +function initial_condition_weak_blast_wave_rainy(x, t, + equations::CompressibleRainyEulerExplicitEquations2D) # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_d = equations.R_dry_air - R_v = equations.R_vapour + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour L_ref = equations.ref_latent_heat_vap_temp if sqrt(x[1]^2 + x[2]^2) > 0.5 rho = 1.0e-4 - v1 = 0.0 - v2 = 0.0 - p = 1.0 + v1 = 0.0 + v2 = 0.0 + p = 1.0 else phi = atan(x[2], x[1]) rho = 1.1691e-4 - v1 = 0.1882 * cos(phi) - v2 = 0.1882 * sin(phi) - p = 1.245 + v1 = 0.1882 * cos(phi) + v2 = 0.1882 * sin(phi) + p = 1.245 end - rho_dry = 0.25 * rho + rho_dry = 0.25 * rho rho_vapour = 0.25 * rho - rho_cloud = 0.25 * rho - rho_rain = 0.25 * rho + rho_cloud = 0.25 * rho + rho_rain = 0.25 * rho T = p / (rho_dry * R_d + rho_vapour * R_v) - - energy_density = (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * T - energy_density += L_ref * rho_vapour + 0.5 * rho * (v1^2 + v2^2) - - return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, rho * v1, rho * v2, energy_density) -end + energy_density = (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) * T + energy_density += L_ref * rho_vapour + 0.5 * rho * (v1^2 + v2^2) + return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, rho * v1, rho * v2, + energy_density) +end ############################################################################### # semidiscretization of the compressible Euler equations @@ -53,12 +52,12 @@ initial_condition = initial_condition_weak_blast_wave_rainy polydeg = 3 basis = LobattoLegendreBasis(polydeg) -volume_flux = flux_ec_rain +volume_flux = flux_ec_rain surface_flux = volume_flux solver = DGSEM(basis, surface_flux, VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, initial_refinement_level = 5, @@ -68,7 +67,6 @@ mesh = TreeMesh(coordinates_min, coordinates_max, semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, boundary_conditions = boundary_condition_periodic) - ############################################################################### # ODE solvers, callbacks etc. @@ -93,17 +91,15 @@ save_solution = SaveSolutionCallback(interval = 1000, stepsize_callback = StepsizeCallback(cfl = 0.1) callbacks = CallbackSet(summary_callback, - analysis_callback, + analysis_callback, alive_callback, save_solution, stepsize_callback) - - ############################################################################### # run the simulation 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); -summary_callback() # print the timer summary \ No newline at end of file +summary_callback() # print the timer summary diff --git a/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl b/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl index afd5ac40..4cd5edaf 100644 --- a/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl +++ b/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_moist_euler_moist_bubble_dgmulti.jl @@ -8,8 +8,6 @@ using NLsolve: nlsolve using Plots using StartUpDG - - equations = CompressibleMoistEulerEquations2D() function moist_state(y, dz, y0, r_t0, theta_e0, @@ -236,29 +234,30 @@ end initial_condition = initial_condition_moist # tag different boundary segments -left(x, tol = 50 * eps()) = abs(x[1] - coordinates_min[1]) < tol -right(x, tol = 50 * eps()) = abs(x[1] - coordinates_max[1]) < tol +left(x, tol = 50 * eps()) = abs(x[1] - coordinates_min[1]) < tol +right(x, tol = 50 * eps()) = abs(x[1] - coordinates_max[1]) < tol bottom(x, tol = 50 * eps()) = abs(x[2] - coordinates_min[2]) < tol -top(x, tol = 50 * eps()) = abs(x[2] - coordinates_max[2]) < tol +top(x, tol = 50 * eps()) = abs(x[2] - coordinates_max[2]) < tol is_on_boundary = Dict(:left => left, :right => right, :top => top, :bottom => bottom) -boundary_conditions = (; :left => boundary_condition_periodic, - :top => boundary_condition_slip_wall, - :bottom => boundary_condition_slip_wall, - :right => boundary_condition_periodic) +boundary_conditions = (; :left => boundary_condition_periodic, + :top => boundary_condition_slip_wall, + :bottom => boundary_condition_slip_wall, + :right => boundary_condition_periodic) -solver = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = StartUpDG.Polynomial{MultidimensionalQuadrature}(), +solver = DGMulti(polydeg = 3, element_type = Quad(), + approximation_type = StartUpDG.Polynomial{MultidimensionalQuadrature}(), surface_integral = SurfaceIntegralWeakForm(flux_LMARS), volume_integral = VolumeIntegralWeakForm(), - quad_rule_vol = StartUpDG.quad_nodes(Quad(), 6) - ) + quad_rule_vol = StartUpDG.quad_nodes(Quad(), 6)) -coordinates_min = ( 0.0, 0.0) +coordinates_min = (0.0, 0.0) coordinates_max = (20_000.0, 10_000.0) cells_per_dimension = (200, 100) -mesh = DGMultiMesh(solver, cells_per_dimension; coordinates_min, coordinates_max, is_on_boundary, periodicity = (true, false)) +mesh = DGMultiMesh(solver, cells_per_dimension; coordinates_min, coordinates_max, + is_on_boundary, periodicity = (true, false)) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver; @@ -276,7 +275,8 @@ summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(solver)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + uEltype = real(solver)) alive_callback = AliveCallback(analysis_interval = 1000) @@ -297,4 +297,4 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), summary_callback() pd = PlotData2D(sol; solution_variables = cons2aeqpot); -plot(pd["aeqpottemp"]) \ No newline at end of file +plot(pd["aeqpottemp"]) diff --git a/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_rainy_euler_explicit_moist_bubble.jl b/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_rainy_euler_explicit_moist_bubble.jl index 41bfb82c..e2a221d0 100644 --- a/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_rainy_euler_explicit_moist_bubble.jl +++ b/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_rainy_euler_explicit_moist_bubble.jl @@ -6,22 +6,20 @@ using TrixiAtmo: source_terms_moist, saturation_residual, cons2eq_pot_temp, flux_LMARS, flux_ec_rain using NLsolve: nlsolve - - # Initial condition from elixir_moist_euler_bubble.jl -function moist_state(y, dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) - +function moist_state(y, dz, y0, r_t0, theta_e0, + equations::CompressibleMoistEulerEquations2D) @unpack p_0, g, c_pd, c_pv, c_vd, c_vv, R_d, R_v, c_pl, L_00 = equations (p, rho, T, r_t, r_v, rho_qv, theta_e) = y p0 = y0[1] - F = zeros(7, 1) + F = zeros(7, 1) rho_d = rho / (1 + r_t) - p_d = R_d * rho_d * T - T_C = T - 273.15 - p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) - L = L_00 - (c_pl - c_pv) * T + p_d = R_d * rho_d * T + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + L = L_00 - (c_pl - c_pv) * T F[1] = (p - p0) / dz + g * rho F[2] = p - (R_d * rho_d + R_v * rho_qv) * T @@ -32,15 +30,16 @@ function moist_state(y, dz, y0, r_t0, theta_e0, equations::CompressibleMoistEule F[4] = r_t - r_t0 F[5] = rho_qv - rho_d * r_v F[6] = theta_e - theta_e0 - a = p_vs / (R_v * T) - rho_qv - b = rho - rho_qv - rho_d + a = p_vs / (R_v * T) - rho_qv + b = rho - rho_qv - rho_d # H=1 => phi=0 F[7] = a + b - sqrt(a * a + b * b) return F end -function generate_function_of_y(dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) +function generate_function_of_y(dz, y0, r_t0, theta_e0, + equations::CompressibleMoistEulerEquations2D) function function_of_y(y) return moist_state(y, dz, y0, r_t0, theta_e0, equations) end @@ -62,7 +61,6 @@ function AtmosphereLayers(equations; total_height = 10010.0, preciseness = 10, ground_state = (1.4, 100000.0), equivalent_potential_temperature = 320, mixing_ratios = (0.02, 0.02), RealT = Float64) - @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl = equations rho0, p0 = ground_state r_t0, r_v0 = mixing_ratios @@ -110,7 +108,8 @@ end # G.H. Bryan, J.M. Fritsch, A Benchmark Simulation for Moist Nonhydrostatic Numerical # Models, MonthlyWeather Review Vol.130, 2917–2928, 2002, # https://journals.ametsoc.org/view/journals/mwre/130/12/1520-0493_2002_130_2917_absfmn_2.0.co_2.xml. -function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, atmosphere_layers::AtmosphereLayers) +function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, + atmosphere_layers::AtmosphereLayers) @unpack layer_data, preciseness, total_height = atmosphere_layers dz = preciseness z = x[2] @@ -132,8 +131,9 @@ function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerE rho_qv = rho * (rho_qv_r / rho_r * (z - z_l) + rho_qv_l / rho_l * (z_r - z)) / dz rho_ql = rho * (rho_ql_r / rho_r * (z - z_l) + rho_ql_l / rho_l * (z_r - z)) / dz - rho, rho_e, rho_qv, rho_ql, T_loc = perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, - equations::CompressibleMoistEulerEquations2D) + rho, rho_e, rho_qv, rho_ql, T_loc = perturb_moist_profile!(x, rho, rho_theta, rho_qv, + rho_ql, + equations::CompressibleMoistEulerEquations2D) v1 = 0.0 v2 = 0.0 @@ -209,11 +209,10 @@ atmosphere_data = AtmosphereLayers(CompressibleMoistEulerEquations2D()) # Create the initial condition with the initial data set function initial_condition_moist(x, t, equations::CompressibleRainyEulerExplicitEquations2D) - return initial_condition_moist_bubble(x, t, CompressibleMoistEulerEquations2D(), atmosphere_data) + return initial_condition_moist_bubble(x, t, CompressibleMoistEulerEquations2D(), + atmosphere_data) end - - ############################################################################### # semidiscretization of the compressible rainy Euler equations @@ -228,13 +227,13 @@ polydeg = 3 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_LMARS -volume_flux = flux_ec_rain +volume_flux = flux_ec_rain volume_integral = VolumeIntegralFluxDifferencing(volume_flux) solver = DGSEM(basis, surface_flux, volume_integral) -coordinates_min = ( 0.0, 0.0) +coordinates_min = (0.0, 0.0) coordinates_max = (20_000.0, 10_000.0) cells_per_dimension = (128, 64) @@ -283,4 +282,4 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, save_everystep = false, callback = callbacks); -summary_callback() \ No newline at end of file +summary_callback() diff --git a/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl b/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl index 1bf9d01d..287b5685 100644 --- a/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl +++ b/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble.jl @@ -7,22 +7,20 @@ using TrixiAtmo: source_terms_no_phase_change, saturation_residual, flux_ec_rain, boundary_condition_simple_slip_wall using NLsolve: nlsolve - - # Initial condition from elixir_moist_euler_bubble.jl -function moist_state(y, dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) - +function moist_state(y, dz, y0, r_t0, theta_e0, + equations::CompressibleMoistEulerEquations2D) @unpack p_0, g, c_pd, c_pv, c_vd, c_vv, R_d, R_v, c_pl, L_00 = equations (p, rho, T, r_t, r_v, rho_qv, theta_e) = y p0 = y0[1] - F = zeros(7, 1) + F = zeros(7, 1) rho_d = rho / (1 + r_t) - p_d = R_d * rho_d * T - T_C = T - 273.15 - p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) - L = L_00 - (c_pl - c_pv) * T + p_d = R_d * rho_d * T + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + L = L_00 - (c_pl - c_pv) * T F[1] = (p - p0) / dz + g * rho F[2] = p - (R_d * rho_d + R_v * rho_qv) * T @@ -33,15 +31,16 @@ function moist_state(y, dz, y0, r_t0, theta_e0, equations::CompressibleMoistEule F[4] = r_t - r_t0 F[5] = rho_qv - rho_d * r_v F[6] = theta_e - theta_e0 - a = p_vs / (R_v * T) - rho_qv - b = rho - rho_qv - rho_d + a = p_vs / (R_v * T) - rho_qv + b = rho - rho_qv - rho_d # H=1 => phi=0 F[7] = a + b - sqrt(a * a + b * b) return F end -function generate_function_of_y(dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) +function generate_function_of_y(dz, y0, r_t0, theta_e0, + equations::CompressibleMoistEulerEquations2D) function function_of_y(y) return moist_state(y, dz, y0, r_t0, theta_e0, equations) end @@ -63,7 +62,6 @@ function AtmosphereLayers(equations; total_height = 10010.0, preciseness = 10, ground_state = (1.4, 100000.0), equivalent_potential_temperature = 320, mixing_ratios = (0.02, 0.02), RealT = Float64) - @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl = equations rho0, p0 = ground_state r_t0, r_v0 = mixing_ratios @@ -111,7 +109,8 @@ end # G.H. Bryan, J.M. Fritsch, A Benchmark Simulation for Moist Nonhydrostatic Numerical # Models, MonthlyWeather Review Vol.130, 2917–2928, 2002, # https://journals.ametsoc.org/view/journals/mwre/130/12/1520-0493_2002_130_2917_absfmn_2.0.co_2.xml. -function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, atmosphere_layers::AtmosphereLayers) +function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, + atmosphere_layers::AtmosphereLayers) @unpack layer_data, preciseness, total_height = atmosphere_layers dz = preciseness z = x[2] @@ -133,8 +132,9 @@ function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerE rho_qv = rho * (rho_qv_r / rho_r * (z - z_l) + rho_qv_l / rho_l * (z_r - z)) / dz rho_ql = rho * (rho_ql_r / rho_r * (z - z_l) + rho_ql_l / rho_l * (z_r - z)) / dz - rho, rho_e, rho_qv, rho_ql, T_loc = perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, - equations::CompressibleMoistEulerEquations2D) + rho, rho_e, rho_qv, rho_ql, T_loc = perturb_moist_profile!(x, rho, rho_theta, rho_qv, + rho_ql, + equations::CompressibleMoistEulerEquations2D) v1 = 0.0 v2 = 0.0 @@ -142,7 +142,8 @@ function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerE rho_v2 = rho * v2 rho_E = rho_e + 1 / 2 * rho * (v1^2 + v2^2) - return SVector(rho - rho_qv - rho_ql, rho_qv + rho_ql, 0.0, rho_v1, rho_v2, rho_E, rho_qv, rho_ql, T_loc) + return SVector(rho - rho_qv - rho_ql, rho_qv + rho_ql, 0.0, rho_v1, rho_v2, rho_E, + rho_qv, rho_ql, T_loc) end function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, @@ -209,11 +210,10 @@ atmosphere_data = AtmosphereLayers(CompressibleMoistEulerEquations2D()) # Create the initial condition with the initial data set function initial_condition_moist(x, t, equations::CompressibleRainyEulerEquations2D) - return initial_condition_moist_bubble(x, t, CompressibleMoistEulerEquations2D(), atmosphere_data) + return initial_condition_moist_bubble(x, t, CompressibleMoistEulerEquations2D(), + atmosphere_data) end - - ############################################################################### # semidiscretization of the compressible rainy Euler equations @@ -228,13 +228,13 @@ polydeg = 3 basis = LobattoLegendreBasis(polydeg) surface_flux = flux_LMARS -volume_flux = flux_ec_rain +volume_flux = flux_ec_rain volume_integral = VolumeIntegralFluxDifferencing(volume_flux) solver = DGSEM(basis, surface_flux, volume_integral) -coordinates_min = ( 0.0, 0.0) +coordinates_min = (0.0, 0.0) coordinates_max = (20_000.0, 10_000.0) cells_per_dimension = (128, 64) @@ -276,7 +276,8 @@ callbacks = CallbackSet(summary_callback, save_solution, stepsize_callback) -stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) +stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, + SVector(7, 8, 9), 1e-9) ############################################################################### # run the simulation @@ -285,4 +286,4 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limite dt = 1.0, save_everystep = false, callback = callbacks); -summary_callback() \ No newline at end of file +summary_callback() diff --git a/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble_dgmulti.jl b/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble_dgmulti.jl index 7c1d3cea..7c1e30a8 100644 --- a/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble_dgmulti.jl +++ b/examples/moist_bubble/moist_bubble_elixirs/energy/elixir_rainy_euler_moist_bubble_dgmulti.jl @@ -7,21 +7,20 @@ using TrixiAtmo: source_terms_no_phase_change, saturation_residual, using NLsolve: nlsolve using Plots - # Initial condition from elixir_moist_euler_bubble.jl -function moist_state(y, dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) - +function moist_state(y, dz, y0, r_t0, theta_e0, + equations::CompressibleMoistEulerEquations2D) @unpack p_0, g, c_pd, c_pv, c_vd, c_vv, R_d, R_v, c_pl, L_00 = equations (p, rho, T, r_t, r_v, rho_qv, theta_e) = y p0 = y0[1] - F = zeros(7, 1) + F = zeros(7, 1) rho_d = rho / (1 + r_t) - p_d = R_d * rho_d * T - T_C = T - 273.15 - p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) - L = L_00 - (c_pl - c_pv) * T + p_d = R_d * rho_d * T + T_C = T - 273.15 + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + L = L_00 - (c_pl - c_pv) * T F[1] = (p - p0) / dz + g * rho F[2] = p - (R_d * rho_d + R_v * rho_qv) * T @@ -32,15 +31,16 @@ function moist_state(y, dz, y0, r_t0, theta_e0, equations::CompressibleMoistEule F[4] = r_t - r_t0 F[5] = rho_qv - rho_d * r_v F[6] = theta_e - theta_e0 - a = p_vs / (R_v * T) - rho_qv - b = rho - rho_qv - rho_d + a = p_vs / (R_v * T) - rho_qv + b = rho - rho_qv - rho_d # H=1 => phi=0 F[7] = a + b - sqrt(a * a + b * b) return F end -function generate_function_of_y(dz, y0, r_t0, theta_e0, equations::CompressibleMoistEulerEquations2D) +function generate_function_of_y(dz, y0, r_t0, theta_e0, + equations::CompressibleMoistEulerEquations2D) function function_of_y(y) return moist_state(y, dz, y0, r_t0, theta_e0, equations) end @@ -62,7 +62,6 @@ function AtmosphereLayers(equations; total_height = 10010.0, preciseness = 10, ground_state = (1.4, 100000.0), equivalent_potential_temperature = 320, mixing_ratios = (0.02, 0.02), RealT = Float64) - @unpack kappa, p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl = equations rho0, p0 = ground_state r_t0, r_v0 = mixing_ratios @@ -110,7 +109,8 @@ end # G.H. Bryan, J.M. Fritsch, A Benchmark Simulation for Moist Nonhydrostatic Numerical # Models, MonthlyWeather Review Vol.130, 2917–2928, 2002, # https://journals.ametsoc.org/view/journals/mwre/130/12/1520-0493_2002_130_2917_absfmn_2.0.co_2.xml. -function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, atmosphere_layers::AtmosphereLayers) +function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerEquations2D, + atmosphere_layers::AtmosphereLayers) @unpack layer_data, preciseness, total_height = atmosphere_layers dz = preciseness z = x[2] @@ -132,8 +132,9 @@ function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerE rho_qv = rho * (rho_qv_r / rho_r * (z - z_l) + rho_qv_l / rho_l * (z_r - z)) / dz rho_ql = rho * (rho_ql_r / rho_r * (z - z_l) + rho_ql_l / rho_l * (z_r - z)) / dz - rho, rho_e, rho_qv, rho_ql, T_loc = perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, - equations::CompressibleMoistEulerEquations2D) + rho, rho_e, rho_qv, rho_ql, T_loc = perturb_moist_profile!(x, rho, rho_theta, rho_qv, + rho_ql, + equations::CompressibleMoistEulerEquations2D) v1 = 0.0 v2 = 0.0 @@ -141,7 +142,8 @@ function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerE rho_v2 = rho * v2 rho_E = rho_e + 1 / 2 * rho * (v1^2 + v2^2) - return SVector(rho - rho_qv - rho_ql, rho_qv + rho_ql, 0.0, rho_v1, rho_v2, rho_E, rho_qv, rho_ql, T_loc) + return SVector(rho - rho_qv - rho_ql, rho_qv + rho_ql, 0.0, rho_v1, rho_v2, rho_E, + rho_qv, rho_ql, T_loc) end function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, @@ -209,7 +211,8 @@ atmosphere_data = AtmosphereLayers(CompressibleMoistEulerEquations2D()) # Create the initial condition with the initial data set function initial_condition_moist(x, t, equations::CompressibleRainyEulerEquations2D) - return initial_condition_moist_bubble(x, t, CompressibleMoistEulerEquations2D(), atmosphere_data) + return initial_condition_moist_bubble(x, t, CompressibleMoistEulerEquations2D(), + atmosphere_data) end ############################################################################### @@ -220,27 +223,28 @@ equations = CompressibleRainyEulerEquations2D() initial_condition = initial_condition_moist # tag different boundary segments -left(x, tol = 50 * eps()) = abs(x[1] - coordinates_min[1]) < tol -right(x, tol = 50 * eps()) = abs(x[1] - coordinates_max[1]) < tol +left(x, tol = 50 * eps()) = abs(x[1] - coordinates_min[1]) < tol +right(x, tol = 50 * eps()) = abs(x[1] - coordinates_max[1]) < tol bottom(x, tol = 50 * eps()) = abs(x[2] - coordinates_min[2]) < tol -top(x, tol = 50 * eps()) = abs(x[2] - coordinates_max[2]) < tol +top(x, tol = 50 * eps()) = abs(x[2] - coordinates_max[2]) < tol is_on_boundary = Dict(:left => left, :right => right, :top => top, :bottom => bottom) -boundary_conditions = (; :left => boundary_condition_periodic, - :top => boundary_condition_slip_wall, - :bottom => boundary_condition_slip_wall, - :right => boundary_condition_periodic) +boundary_conditions = (; :left => boundary_condition_periodic, + :top => boundary_condition_slip_wall, + :bottom => boundary_condition_slip_wall, + :right => boundary_condition_periodic) solver = DGMulti(polydeg = 1, element_type = Quad(), approximation_type = GaussSBP(), surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), volume_integral = VolumeIntegralWeakForm()) -coordinates_min = ( 0.0, 0.0) +coordinates_min = (0.0, 0.0) coordinates_max = (20_000.0, 10_000.0) cells_per_dimension = (200, 100) -mesh = DGMultiMesh(solver, cells_per_dimension; coordinates_min, coordinates_max, is_on_boundary, periodicity = (true, false)) +mesh = DGMultiMesh(solver, cells_per_dimension; coordinates_min, coordinates_max, + is_on_boundary, periodicity = (true, false)) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver; @@ -258,7 +262,8 @@ summary_callback = SummaryCallback() analysis_interval = 1000 -analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(solver)) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, + uEltype = real(solver)) alive_callback = AliveCallback(analysis_interval = 1000) @@ -269,7 +274,8 @@ callbacks = CallbackSet(summary_callback, alive_callback, stepsize_callback) -stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) +stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, + SVector(7, 8, 9), 1e-9) ############################################################################### # run the simulation @@ -281,4 +287,4 @@ sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false, stage_limite summary_callback() pd = PlotData2D(sol; solution_variables = cons2eq_pot_temp); -plot(pd["eq_pot_temp"]) \ No newline at end of file +plot(pd["eq_pot_temp"]) diff --git a/examples/moist_bubble/moist_bubble_elixirs/potential_temperature/elixir_moist_euler_potential_temperature_moist_bubble.jl b/examples/moist_bubble/moist_bubble_elixirs/potential_temperature/elixir_moist_euler_potential_temperature_moist_bubble.jl index cda5f373..a0e2d00a 100644 --- a/examples/moist_bubble/moist_bubble_elixirs/potential_temperature/elixir_moist_euler_potential_temperature_moist_bubble.jl +++ b/examples/moist_bubble/moist_bubble_elixirs/potential_temperature/elixir_moist_euler_potential_temperature_moist_bubble.jl @@ -64,7 +64,7 @@ function AtmosphereLayers(equations; total_height = 10010.0, preciseness = 10, equivalent_potential_temperature = 320, mixing_ratios = (0.02, 0.02), RealT = Float64) @unpack p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl = equations - kappa = 1- inv(equations.gamma) + kappa = 1 - inv(equations.gamma) rho0, p0 = ground_state r_t0, r_v0 = mixing_ratios theta_e0 = equivalent_potential_temperature @@ -111,7 +111,8 @@ end # G.H. Bryan, J.M. Fritsch, A Benchmark Simulation for Moist Nonhydrostatic Numerical # Models, MonthlyWeather Review Vol.130, 2917–2928, 2002, # https://journals.ametsoc.org/view/journals/mwre/130/12/1520-0493_2002_130_2917_absfmn_2.0.co_2.xml. -function initial_condition_moist_bubble(x, t, equations::CompressibleMoistEulerPotentialTemperatureEquations2D, +function initial_condition_moist_bubble(x, t, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D, atmosphere_layers::AtmosphereLayers) @unpack layer_data, preciseness, total_height = atmosphere_layers dz = preciseness @@ -148,7 +149,7 @@ end function perturb_moist_profile!(x, rho, rho_theta, rho_qv, rho_ql, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) - @unpack p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl, L_00 = equations + @unpack p_0, c_pd, c_vd, c_pv, c_vv, R_d, R_v, c_pl, L_00 = equations kappa = 1 - inv(equations.gamma) xc = 10000.0 zc = 2000.0 diff --git a/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl b/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl index 0a3b3a4d..9c513a62 100644 --- a/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl +++ b/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble.jl @@ -9,43 +9,40 @@ using TrixiAtmo: source_terms_rainy, saturation_residual, boundary_condition_simple_slip_wall using NLsolve: nlsolve - - # domain -coordinates_min = ( 0.0, 0.0) +coordinates_min = (0.0, 0.0) coordinates_max = (2400.0, 2400.0) - # hydrostatic dry potential temperature function theta_d(z, equations::CompressibleRainyEulerExplicitEquations2D) # constants - c_pd = equations.c_dry_air_const_pressure - R_d = equations.R_dry_air - ref_pressure = equations.ref_pressure + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + ref_pressure = equations.ref_pressure # problem specific constants surface_temperature = 283.0 - surface_pressure = 8.5e4 - stratification = 1.3e-5 + surface_pressure = 8.5e4 + stratification = 1.3e-5 # dry potential temperature at surface - Theta0 = surface_temperature * (ref_pressure / surface_pressure)^(R_d / c_pd) + Theta0 = surface_temperature * (ref_pressure / surface_pressure)^(R_d / c_pd) # at height z theta_d = Theta0 * exp(stratification * z) return theta_d end - # hydrostatic base state residual -function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equations::CompressibleRainyEulerExplicitEquations2D) +function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, + equations::CompressibleRainyEulerExplicitEquations2D) # equations constants - c_pd = equations.c_dry_air_const_pressure - R_d = equations.R_dry_air - R_v = equations.R_vapour - eps = equations.eps - ref_pressure = equations.ref_pressure - g = equations.gravity + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure + g = equations.gravity function hydrostatic_residual!(residual, guess) # variables @@ -60,10 +57,11 @@ function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equ residual[2] = pressure - temperature * (rho_dry * R_d + rho_vapour * R_v) # hydrostatic dry potential temperature residual - residual[3] = theta_d(z, equations) - temperature * (ref_pressure / pressure)^(R_d / c_pd) + residual[3] = theta_d(z, equations) - + temperature * (ref_pressure / pressure)^(R_d / c_pd) # humidity residual - residual[4] = rho_vs * (rho_dry + rho_vapour / eps) * humidity_rel0 + residual[4] = rho_vs * (rho_dry + rho_vapour / eps) * humidity_rel0 residual[4] -= rho_vapour * (rho_dry + rho_vs / eps) residual[4] *= 1000.0 end @@ -71,29 +69,30 @@ function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equ return hydrostatic_residual! end - -function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equations::CompressibleRainyEulerExplicitEquations2D) +function generate_perturbation_residual(pressure_hydrostatic, H_init, z, + equations::CompressibleRainyEulerExplicitEquations2D) # equations constants - c_pd = equations.c_dry_air_const_pressure - R_d = equations.R_dry_air - R_v = equations.R_vapour - eps = equations.eps - ref_pressure = equations.ref_pressure + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure function perturbation_residual!(residual, guess) # variables rho_dry, rho_vapour, temperature = guess - + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) pressure = (rho_dry * R_d + rho_vapour * R_v) * temperature - + # humidity residual - residual[1] = rho_vs * (rho_dry + rho_vapour / eps) * H_init + residual[1] = rho_vs * (rho_dry + rho_vapour / eps) * H_init residual[1] -= rho_vapour * (rho_dry + rho_vs / eps) residual[1] *= 30.0 # hydrostatic dry potential temperature residual - residual[2] = theta_d(z, equations) - temperature * (ref_pressure / pressure_hydrostatic)^(R_d / c_pd) + residual[2] = theta_d(z, equations) - + temperature * (ref_pressure / pressure_hydrostatic)^(R_d / c_pd) # pressure residual residual[3] = pressure_hydrostatic - pressure @@ -102,32 +101,33 @@ function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equatio return perturbation_residual! end - # for approximating the dz pressure gradient struct AtmosphereLayersRainyBubble{RealT <: Real} - layer_data ::Matrix{RealT} - total_height ::RealT - precision ::RealT + layer_data :: Matrix{RealT} + total_height :: RealT + precision :: RealT end - -function AtmosphereLayersRainyBubble(equations::CompressibleRainyEulerExplicitEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) +function AtmosphereLayersRainyBubble(equations::CompressibleRainyEulerExplicitEquations2D; + total_height = coordinates_max[2] + 1.0, + precision = 1.0, RealT = Float64) # constants - humidity_rel0 = 0.2 # hydrostatic relative humidity + humidity_rel0 = 0.2 # hydrostatic relative humidity surface_pressure = 8.5e4 # surface layer with initial guesses for rho_dry, rho_vapour and temperature surface_layer = [surface_pressure, 1.4, 0.04, 300.0] - + # allocate layer_data n = convert(Int, total_height / precision) layer_data = zeros(RealT, n + 1, 4) # solve (slightly above) surface layer dz = 0.01 - z = 0.01 - residual_function! = generate_hydrostatic_residual(surface_pressure, humidity_rel0, z, dz, equations) - layer_data[1, :] .= nlsolve(residual_function!, surface_layer).zero + z = 0.01 + residual_function! = generate_hydrostatic_residual(surface_pressure, humidity_rel0, z, + dz, equations) + layer_data[1, :] .= nlsolve(residual_function!, surface_layer).zero # adjust to chosen precision dz = precision @@ -135,33 +135,35 @@ function AtmosphereLayersRainyBubble(equations::CompressibleRainyEulerExplicitEq # iterate up the atmosphere for i in (1:n) z += dz - residual_function! = generate_hydrostatic_residual(layer_data[i, 1], humidity_rel0, z, dz, equations) + residual_function! = generate_hydrostatic_residual(layer_data[i, 1], humidity_rel0, + z, dz, equations) guess = deepcopy(layer_data[i, :]) - layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, iterations = 20).zero + layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, + iterations = 20).zero end - + return AtmosphereLayersRainyBubble{RealT}(layer_data, total_height, precision) end - # create layers for initial condition equations = CompressibleRainyEulerExplicitEquations2D() -layers = AtmosphereLayersRainyBubble(equations) +layers = AtmosphereLayersRainyBubble(equations) - -function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerExplicitEquations2D; atmosphere_layers = layers) +function initial_condition_bubble_rainy(x, t, + equations::CompressibleRainyEulerExplicitEquations2D; + atmosphere_layers = layers) # equations constants - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume ref_L = equations.ref_latent_heat_vap_temp # problem specific constants humidity_rel_bar = 0.2 # background relative humidity field - humidity_max = 1.0 + humidity_max = 1.0 # bubble parameters - radius_outer, radius_inner = 300.0, 200.0 # radii of humidity bubble - x_center, z_center = 1200.0, 800.0 # center of humidity bubble + radius_outer, radius_inner = 300.0, 200.0 # radii of humidity bubble + x_center, z_center = 1200.0, 800.0 # center of humidity bubble # radius relative to bubble center r = sqrt((x[1] - x_center)^2 + (x[2] - z_center)^2) @@ -172,20 +174,22 @@ function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerE humidity = humidity_rel_bar elseif (r > radius_inner) # outer layers of the bubble - humidity = humidity_rel_bar + (humidity_max - humidity_rel_bar) * cos(pi * (r - radius_inner) / (2.0 * (radius_outer - radius_inner)))^2 + humidity = humidity_rel_bar + + (humidity_max - humidity_rel_bar) * + cos(pi * (r - radius_inner) / (2.0 * (radius_outer - radius_inner)))^2 else # inner layer humidity = humidity_max end - + # get atmosphere layer and height information @unpack layer_data, total_height, precision = atmosphere_layers dz = precision - z = x[2] - n = convert(Int, floor((z + eps()) / dz)) + 1 + z = x[2] + n = convert(Int, floor((z + eps()) / dz)) + 1 z_lower = (n - 1) * dz - z_upper = n * dz - + z_upper = n * dz + if (z_lower == total_height) z_upper = z_lower + dz n = n - 1 @@ -195,27 +199,27 @@ function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerE if (z > total_height && !(isapprox(z, total_height))) error("The atmosphere does not match the simulation domain") end - + # get hydrostatic pressures and approximate between lower and upper data point pressure_hydrostatic_lower = layer_data[n, 1] pressure_hydrostatic_upper = layer_data[n + 1, 1] - pressure_hydrostatic = (pressure_hydrostatic_upper * (z - z_lower) + pressure_hydrostatic_lower * (z_upper - z)) / dz + pressure_hydrostatic = (pressure_hydrostatic_upper * (z - z_lower) + + pressure_hydrostatic_lower * (z_upper - z)) / dz # solve perturbation - residual_function! = generate_perturbation_residual(pressure_hydrostatic, humidity, z, equations) - rho_dry, rho_vapour, temperature = nlsolve(residual_function!, layer_data[n, 2:4], ftol = 1e-9, iterations = 20).zero + residual_function! = generate_perturbation_residual(pressure_hydrostatic, humidity, z, + equations) + rho_dry, rho_vapour, temperature = nlsolve(residual_function!, layer_data[n, 2:4], + ftol = 1e-9, iterations = 20).zero energy_density = (c_vd * rho_dry + c_vv * rho_vapour) * temperature + rho_vapour * ref_L return SVector(rho_dry, rho_vapour, 0.0, 0.0, 0.0, 0.0, energy_density) end - - ############################################################################### # semidiscretization of the compressible rainy Euler equations - boundary_conditions = (x_neg = boundary_condition_periodic, x_pos = boundary_condition_periodic, y_neg = boundary_condition_simple_slip_wall, @@ -272,4 +276,4 @@ stage_limiter! = RainLimiterDG() sol = solve(ode, SSPRK43(stage_limiter!); ode_default_options()..., maxiters = 1.0e7, save_everystep = false, callback = callbacks); -summary_callback() \ No newline at end of file +summary_callback() diff --git a/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl b/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl index ada92e4b..97a97744 100644 --- a/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl +++ b/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_explicit_rainy_bubble_diffusion.jl @@ -11,43 +11,40 @@ using TrixiAtmo: source_terms_rainy, saturation_residual, boundary_condition_simple_slip_wall using NLsolve: nlsolve - - # domain -coordinates_min = ( 0.0, 0.0) +coordinates_min = (0.0, 0.0) coordinates_max = (2400.0, 2400.0) - # hydrostatic dry potential temperature function theta_d(z, equations::CompressibleRainyEulerExplicitEquations2D) # constants - c_pd = equations.c_dry_air_const_pressure - R_d = equations.R_dry_air - ref_pressure = equations.ref_pressure + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + ref_pressure = equations.ref_pressure # problem specific constants surface_temperature = 283.0 - surface_pressure = 8.5e4 - stratification = 1.3e-5 + surface_pressure = 8.5e4 + stratification = 1.3e-5 # dry potential temperature at surface - Theta0 = surface_temperature * (ref_pressure / surface_pressure)^(R_d / c_pd) + Theta0 = surface_temperature * (ref_pressure / surface_pressure)^(R_d / c_pd) # at height z theta_d = Theta0 * exp(stratification * z) return theta_d end - # hydrostatic base state residual -function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equations::CompressibleRainyEulerExplicitEquations2D) +function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, + equations::CompressibleRainyEulerExplicitEquations2D) # equations constants - c_pd = equations.c_dry_air_const_pressure - R_d = equations.R_dry_air - R_v = equations.R_vapour - eps = equations.eps - ref_pressure = equations.ref_pressure - g = equations.gravity + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure + g = equations.gravity function hydrostatic_residual!(residual, guess) # variables @@ -62,10 +59,11 @@ function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equ residual[2] = pressure - temperature * (rho_dry * R_d + rho_vapour * R_v) # hydrostatic dry potential temperature residual - residual[3] = theta_d(z, equations) - temperature * (ref_pressure / pressure)^(R_d / c_pd) + residual[3] = theta_d(z, equations) - + temperature * (ref_pressure / pressure)^(R_d / c_pd) # humidity residual - residual[4] = rho_vs * (rho_dry + rho_vapour / eps) * humidity_rel0 + residual[4] = rho_vs * (rho_dry + rho_vapour / eps) * humidity_rel0 residual[4] -= rho_vapour * (rho_dry + rho_vs / eps) residual[4] *= 1000.0 end @@ -73,29 +71,30 @@ function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equ return hydrostatic_residual! end - -function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equations::CompressibleRainyEulerExplicitEquations2D) +function generate_perturbation_residual(pressure_hydrostatic, H_init, z, + equations::CompressibleRainyEulerExplicitEquations2D) # equations constants - c_pd = equations.c_dry_air_const_pressure - R_d = equations.R_dry_air - R_v = equations.R_vapour - eps = equations.eps - ref_pressure = equations.ref_pressure + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure function perturbation_residual!(residual, guess) # variables rho_dry, rho_vapour, temperature = guess - + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) pressure = (rho_dry * R_d + rho_vapour * R_v) * temperature - + # humidity residual - residual[1] = rho_vs * (rho_dry + rho_vapour / eps) * H_init + residual[1] = rho_vs * (rho_dry + rho_vapour / eps) * H_init residual[1] -= rho_vapour * (rho_dry + rho_vs / eps) residual[1] *= 30.0 # hydrostatic dry potential temperature residual - residual[2] = theta_d(z, equations) - temperature * (ref_pressure / pressure_hydrostatic)^(R_d / c_pd) + residual[2] = theta_d(z, equations) - + temperature * (ref_pressure / pressure_hydrostatic)^(R_d / c_pd) # pressure residual residual[3] = pressure_hydrostatic - pressure @@ -104,32 +103,33 @@ function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equatio return perturbation_residual! end - # for approximating the dz pressure gradient struct AtmosphereLayersRainyBubble{RealT <: Real} - layer_data ::Matrix{RealT} - total_height ::RealT - precision ::RealT + layer_data :: Matrix{RealT} + total_height :: RealT + precision :: RealT end - -function AtmosphereLayersRainyBubble(equations::CompressibleRainyEulerExplicitEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) +function AtmosphereLayersRainyBubble(equations::CompressibleRainyEulerExplicitEquations2D; + total_height = coordinates_max[2] + 1.0, + precision = 1.0, RealT = Float64) # constants - humidity_rel0 = 0.2 # hydrostatic relative humidity + humidity_rel0 = 0.2 # hydrostatic relative humidity surface_pressure = 8.5e4 # surface layer with initial guesses for rho_dry, rho_vapour and temperature surface_layer = [surface_pressure, 1.4, 0.04, 300.0] - + # allocate layer_data n = convert(Int, total_height / precision) layer_data = zeros(RealT, n + 1, 4) # solve (slightly above) surface layer dz = 0.01 - z = 0.01 - residual_function! = generate_hydrostatic_residual(surface_pressure, humidity_rel0, z, dz, equations) - layer_data[1, :] .= nlsolve(residual_function!, surface_layer).zero + z = 0.01 + residual_function! = generate_hydrostatic_residual(surface_pressure, humidity_rel0, z, + dz, equations) + layer_data[1, :] .= nlsolve(residual_function!, surface_layer).zero # adjust to chosen precision dz = precision @@ -137,33 +137,35 @@ function AtmosphereLayersRainyBubble(equations::CompressibleRainyEulerExplicitEq # iterate up the atmosphere for i in (1:n) z += dz - residual_function! = generate_hydrostatic_residual(layer_data[i, 1], humidity_rel0, z, dz, equations) + residual_function! = generate_hydrostatic_residual(layer_data[i, 1], humidity_rel0, + z, dz, equations) guess = deepcopy(layer_data[i, :]) - layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, iterations = 20).zero + layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, + iterations = 20).zero end - + return AtmosphereLayersRainyBubble{RealT}(layer_data, total_height, precision) end - # create layers for initial condition equations = CompressibleRainyEulerExplicitEquations2D() -layers = AtmosphereLayersRainyBubble(equations) - +layers = AtmosphereLayersRainyBubble(equations) -function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerExplicitEquations2D; atmosphere_layers = layers) +function initial_condition_bubble_rainy(x, t, + equations::CompressibleRainyEulerExplicitEquations2D; + atmosphere_layers = layers) # equations constants - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume ref_L = equations.ref_latent_heat_vap_temp # problem specific constants humidity_rel_bar = 0.2 # background relative humidity field - humidity_max = 1.0 + humidity_max = 1.0 # bubble parameters - radius_outer, radius_inner = 300.0, 200.0 # radii of humidity bubble - x_center, z_center = 1200.0, 800.0 # center of humidity bubble + radius_outer, radius_inner = 300.0, 200.0 # radii of humidity bubble + x_center, z_center = 1200.0, 800.0 # center of humidity bubble # radius relative to bubble center r = sqrt((x[1] - x_center)^2 + (x[2] - z_center)^2) @@ -174,20 +176,22 @@ function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerE humidity = humidity_rel_bar elseif (r > radius_inner) # outer layers of the bubble - humidity = humidity_rel_bar + (humidity_max - humidity_rel_bar) * cos(pi * (r - radius_inner) / (2.0 * (radius_outer - radius_inner)))^2 + humidity = humidity_rel_bar + + (humidity_max - humidity_rel_bar) * + cos(pi * (r - radius_inner) / (2.0 * (radius_outer - radius_inner)))^2 else # inner layer humidity = humidity_max end - + # get atmosphere layer and height information @unpack layer_data, total_height, precision = atmosphere_layers dz = precision - z = x[2] - n = convert(Int, floor((z + eps()) / dz)) + 1 + z = x[2] + n = convert(Int, floor((z + eps()) / dz)) + 1 z_lower = (n - 1) * dz - z_upper = n * dz - + z_upper = n * dz + if (z_lower == total_height) z_upper = z_lower + dz n = n - 1 @@ -201,41 +205,39 @@ function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerE if (z > total_height && !(isapprox(z, total_height))) error("The atmosphere does not match the simulation domain") end - + # get hydrostatic pressures and approximate between lower and upper data point pressure_hydrostatic_lower = layer_data[n, 1] pressure_hydrostatic_upper = layer_data[n + 1, 1] - pressure_hydrostatic = (pressure_hydrostatic_upper * (z - z_lower) + pressure_hydrostatic_lower * (z_upper - z)) / dz + pressure_hydrostatic = (pressure_hydrostatic_upper * (z - z_lower) + + pressure_hydrostatic_lower * (z_upper - z)) / dz # solve perturbation - residual_function! = generate_perturbation_residual(pressure_hydrostatic, humidity, z, equations) - rho_dry, rho_vapour, temperature = nlsolve(residual_function!, layer_data[n, 2:4], ftol = 1e-9, iterations = 20).zero + residual_function! = generate_perturbation_residual(pressure_hydrostatic, humidity, z, + equations) + rho_dry, rho_vapour, temperature = nlsolve(residual_function!, layer_data[n, 2:4], + ftol = 1e-9, iterations = 20).zero energy_density = (c_vd * rho_dry + c_vv * rho_vapour) * temperature + rho_vapour * ref_L return SVector(rho_dry, rho_vapour, 0.0, 0.0, 0.0, 0.0, energy_density) end - - ############################################################################### # semidiscretization of the compressible rainy Euler equations diffusivity = 0.5 equations_parabolic = LaplaceDiffusion2D(diffusivity, equations) - boundary_conditions = (x_neg = boundary_condition_periodic, x_pos = boundary_condition_periodic, y_neg = boundary_condition_simple_slip_wall, y_pos = boundary_condition_simple_slip_wall) -boundary_conditions_parabolic = ( - x_neg = boundary_condition_periodic, - x_pos = boundary_condition_periodic, - y_neg = boundary_condition_laplace, - y_pos = boundary_condition_laplace) - +boundary_conditions_parabolic = (x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_laplace, + y_pos = boundary_condition_laplace) polydeg = 3 basis = LobattoLegendreBasis(polydeg) @@ -246,12 +248,15 @@ volume_integral = VolumeIntegralFluxDifferencing(flux_ec_rain) solver = DGSEM(basis, surface_flux, volume_integral) initial_condition = initial_condition_bubble_rainy -source_terms = source_terms_rainy +source_terms = source_terms_rainy -mesh = TreeMesh(coordinates_min, coordinates_max, initial_refinement_level = 6, periodicity = (true, false), n_cells_max = 1_000_000) +mesh = TreeMesh(coordinates_min, coordinates_max, initial_refinement_level = 6, + periodicity = (true, false), n_cells_max = 1_000_000) -semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; source_terms, - boundary_conditions = (boundary_conditions, boundary_conditions_parabolic)) +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver; source_terms, + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic)) ############################################################################### # ODE solvers, callbacks etc. @@ -288,4 +293,4 @@ stage_limiter! = RainLimiterDG() sol = solve(ode, SSPRK43(stage_limiter!); ode_default_options()..., maxiters = 1.0e7, save_everystep = false, callback = callbacks); -summary_callback() \ No newline at end of file +summary_callback() diff --git a/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl b/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl index f5b6e793..58c58ece 100644 --- a/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl +++ b/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble.jl @@ -5,47 +5,44 @@ using TrixiAtmo: source_terms_rainy, saturation_residual, saturation_residual_jacobian, NonlinearSolveDG, cons2eq_pot_temp, saturation_vapour_pressure, flux_chandrashekar, flux_LMARS, flux_ec_rain, - source_terms_no_phase_change, + source_terms_no_phase_change, boundary_condition_simple_slip_wall using NLsolve: nlsolve - - # domain -coordinates_min = ( 0.0, 0.0) +coordinates_min = (0.0, 0.0) coordinates_max = (2400.0, 2400.0) - # hydrostatic dry potential temperature function theta_d(z, equations::CompressibleRainyEulerEquations2D) # constants - c_pd = equations.c_dry_air_const_pressure - R_d = equations.R_dry_air - ref_pressure = equations.ref_pressure + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + ref_pressure = equations.ref_pressure # problem specific constants surface_temperature = 283.0 - surface_pressure = 8.5e4 - stratification = 1.3e-5 + surface_pressure = 8.5e4 + stratification = 1.3e-5 # dry potential temperature at surface - Theta0 = surface_temperature * (ref_pressure / surface_pressure)^(R_d / c_pd) + Theta0 = surface_temperature * (ref_pressure / surface_pressure)^(R_d / c_pd) # at height z theta_d = Theta0 * exp(stratification * z) return theta_d end - # hydrostatic base state residual -function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equations::CompressibleRainyEulerEquations2D) +function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, + equations::CompressibleRainyEulerEquations2D) # equations constants - c_pd = equations.c_dry_air_const_pressure - R_d = equations.R_dry_air - R_v = equations.R_vapour - eps = equations.eps - ref_pressure = equations.ref_pressure - g = equations.gravity + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure + g = equations.gravity function hydrostatic_residual!(residual, guess) # variables @@ -60,10 +57,11 @@ function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equ residual[2] = pressure - temperature * (rho_dry * R_d + rho_vapour * R_v) # hydrostatic dry potential temperature residual - residual[3] = theta_d(z, equations) - temperature * (ref_pressure / pressure)^(R_d / c_pd) + residual[3] = theta_d(z, equations) - + temperature * (ref_pressure / pressure)^(R_d / c_pd) # humidity residual - residual[4] = rho_vs * (rho_dry + rho_vapour / eps) * humidity_rel0 + residual[4] = rho_vs * (rho_dry + rho_vapour / eps) * humidity_rel0 residual[4] -= rho_vapour * (rho_dry + rho_vs / eps) residual[4] *= 1000.0 end @@ -71,29 +69,30 @@ function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equ return hydrostatic_residual! end - -function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equations::CompressibleRainyEulerEquations2D) +function generate_perturbation_residual(pressure_hydrostatic, H_init, z, + equations::CompressibleRainyEulerEquations2D) # equations constants - c_pd = equations.c_dry_air_const_pressure - R_d = equations.R_dry_air - R_v = equations.R_vapour - eps = equations.eps - ref_pressure = equations.ref_pressure + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure function perturbation_residual!(residual, guess) # variables rho_dry, rho_vapour, temperature = guess - + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) pressure = (rho_dry * R_d + rho_vapour * R_v) * temperature - + # humidity residual - residual[1] = rho_vs * (rho_dry + rho_vapour / eps) * H_init + residual[1] = rho_vs * (rho_dry + rho_vapour / eps) * H_init residual[1] -= rho_vapour * (rho_dry + rho_vs / eps) residual[1] *= 30.0 # hydrostatic dry potential temperature residual - residual[2] = theta_d(z, equations) - temperature * (ref_pressure / pressure_hydrostatic)^(R_d / c_pd) + residual[2] = theta_d(z, equations) - + temperature * (ref_pressure / pressure_hydrostatic)^(R_d / c_pd) # pressure residual residual[3] = pressure_hydrostatic - pressure @@ -102,32 +101,33 @@ function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equatio return perturbation_residual! end - # for approximating the dz pressure gradient struct AtmosphereLayersRainyBubble{RealT <: Real} - layer_data ::Matrix{RealT} - total_height ::RealT - precision ::RealT + layer_data :: Matrix{RealT} + total_height :: RealT + precision :: RealT end - -function AtmosphereLayersRainyBubble(equations::CompressibleRainyEulerEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) +function AtmosphereLayersRainyBubble(equations::CompressibleRainyEulerEquations2D; + total_height = coordinates_max[2] + 1.0, + precision = 1.0, RealT = Float64) # constants - humidity_rel0 = 0.2 # hydrostatic relative humidity + humidity_rel0 = 0.2 # hydrostatic relative humidity surface_pressure = 8.5e4 # surface layer with initial guesses for rho_dry, rho_vapour and temperature surface_layer = [surface_pressure, 1.4, 0.04, 300.0] - + # allocate layer_data n = convert(Int, total_height / precision) layer_data = zeros(RealT, n + 1, 4) # solve (slightly above) surface layer dz = 0.01 - z = 0.01 - residual_function! = generate_hydrostatic_residual(surface_pressure, humidity_rel0, z, dz, equations) - layer_data[1, :] .= nlsolve(residual_function!, surface_layer).zero + z = 0.01 + residual_function! = generate_hydrostatic_residual(surface_pressure, humidity_rel0, z, + dz, equations) + layer_data[1, :] .= nlsolve(residual_function!, surface_layer).zero # adjust to chosen precision dz = precision @@ -135,33 +135,34 @@ function AtmosphereLayersRainyBubble(equations::CompressibleRainyEulerEquations2 # iterate up the atmosphere for i in (1:n) z += dz - residual_function! = generate_hydrostatic_residual(layer_data[i, 1], humidity_rel0, z, dz, equations) + residual_function! = generate_hydrostatic_residual(layer_data[i, 1], humidity_rel0, + z, dz, equations) guess = deepcopy(layer_data[i, :]) - layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, iterations = 20).zero + layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, + iterations = 20).zero end - + return AtmosphereLayersRainyBubble{RealT}(layer_data, total_height, precision) end - # create layers for initial condition equations = CompressibleRainyEulerEquations2D() -layers = AtmosphereLayersRainyBubble(equations) +layers = AtmosphereLayersRainyBubble(equations) - -function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerEquations2D; atmosphere_layers = layers) +function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerEquations2D; + atmosphere_layers = layers) # equations constants - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume ref_L = equations.ref_latent_heat_vap_temp # problem specific constants humidity_rel_bar = 0.2 # background relative humidity field - humidity_max = 1.0 + humidity_max = 1.0 # bubble parameters - radius_outer, radius_inner = 300.0, 200.0 # radii of humidity bubble - x_center, z_center = 1200.0, 800.0 # center of humidity bubble + radius_outer, radius_inner = 300.0, 200.0 # radii of humidity bubble + x_center, z_center = 1200.0, 800.0 # center of humidity bubble # radius relative to bubble center r = sqrt((x[1] - x_center)^2 + (x[2] - z_center)^2) @@ -172,20 +173,22 @@ function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerE humidity = humidity_rel_bar elseif (r > radius_inner) # outer layers of the bubble - humidity = humidity_rel_bar + (humidity_max - humidity_rel_bar) * cos(pi * (r - radius_inner) / (2.0 * (radius_outer - radius_inner)))^2 + humidity = humidity_rel_bar + + (humidity_max - humidity_rel_bar) * + cos(pi * (r - radius_inner) / (2.0 * (radius_outer - radius_inner)))^2 else # inner layer humidity = humidity_max end - + # get atmosphere layer and height information @unpack layer_data, total_height, precision = atmosphere_layers dz = precision - z = x[2] - n = convert(Int, floor((z + eps()) / dz)) + 1 + z = x[2] + n = convert(Int, floor((z + eps()) / dz)) + 1 z_lower = (n - 1) * dz - z_upper = n * dz - + z_upper = n * dz + if (z_lower == total_height) z_upper = z_lower + dz n = n - 1 @@ -195,27 +198,28 @@ function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerE if (z > total_height && !(isapprox(z, total_height))) error("The atmosphere does not match the simulation domain") end - + # get hydrostatic pressures and approximate between lower and upper data point pressure_hydrostatic_lower = layer_data[n, 1] pressure_hydrostatic_upper = layer_data[n + 1, 1] - pressure_hydrostatic = (pressure_hydrostatic_upper * (z - z_lower) + pressure_hydrostatic_lower * (z_upper - z)) / dz + pressure_hydrostatic = (pressure_hydrostatic_upper * (z - z_lower) + + pressure_hydrostatic_lower * (z_upper - z)) / dz # solve perturbation - residual_function! = generate_perturbation_residual(pressure_hydrostatic, humidity, z, equations) - rho_dry, rho_vapour, temperature = nlsolve(residual_function!, layer_data[n, 2:4], ftol = 1e-9, iterations = 20).zero + residual_function! = generate_perturbation_residual(pressure_hydrostatic, humidity, z, + equations) + rho_dry, rho_vapour, temperature = nlsolve(residual_function!, layer_data[n, 2:4], + ftol = 1e-9, iterations = 20).zero energy_density = (c_vd * rho_dry + c_vv * rho_vapour) * temperature + rho_vapour * ref_L - return SVector(rho_dry, rho_vapour, 0.0, 0.0, 0.0, energy_density, rho_vapour, 0.0, temperature) + return SVector(rho_dry, rho_vapour, 0.0, 0.0, 0.0, energy_density, rho_vapour, 0.0, + temperature) end - - ############################################################################### # semidiscretization of the compressible rainy Euler equations - boundary_conditions = (x_neg = boundary_condition_periodic, x_pos = boundary_condition_periodic, y_neg = boundary_condition_simple_slip_wall, @@ -265,11 +269,12 @@ callbacks = CallbackSet(summary_callback, alive_callback, save_solution) -stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) +stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, + SVector(7, 8, 9), 1e-9) ############################################################################### # run the simulation sol = solve(ode, SSPRK43(stage_limiter!); ode_default_options()..., maxiters = 1.0e7, save_everystep = false, callback = callbacks); -summary_callback() \ No newline at end of file +summary_callback() diff --git a/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl b/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl index ef3f665b..aefe38c6 100644 --- a/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl +++ b/examples/moist_bubble/rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl @@ -11,43 +11,40 @@ using TrixiAtmo: source_terms_rainy, saturation_residual, flux_ec_rain using NLsolve: nlsolve - - # domain -coordinates_min = ( 0.0, 0.0) +coordinates_min = (0.0, 0.0) coordinates_max = (2400.0, 2400.0) - # hydrostatic dry potential temperature function theta_d(z, equations::CompressibleRainyEulerEquations2D) # constants - c_pd = equations.c_dry_air_const_pressure - R_d = equations.R_dry_air - ref_pressure = equations.ref_pressure + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + ref_pressure = equations.ref_pressure # problem specific constants surface_temperature = 283.0 - surface_pressure = 8.5e4 - stratification = 1.3e-5 + surface_pressure = 8.5e4 + stratification = 1.3e-5 # dry potential temperature at surface - Theta0 = surface_temperature * (ref_pressure / surface_pressure)^(R_d / c_pd) + Theta0 = surface_temperature * (ref_pressure / surface_pressure)^(R_d / c_pd) # at height z theta_d = Theta0 * exp(stratification * z) return theta_d end - # hydrostatic base state residual -function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equations::CompressibleRainyEulerEquations2D) +function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, + equations::CompressibleRainyEulerEquations2D) # equations constants - c_pd = equations.c_dry_air_const_pressure - R_d = equations.R_dry_air - R_v = equations.R_vapour - eps = equations.eps - ref_pressure = equations.ref_pressure - g = equations.gravity + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure + g = equations.gravity function hydrostatic_residual!(residual, guess) # variables @@ -62,10 +59,11 @@ function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equ residual[2] = pressure - temperature * (rho_dry * R_d + rho_vapour * R_v) # hydrostatic dry potential temperature residual - residual[3] = theta_d(z, equations) - temperature * (ref_pressure / pressure)^(R_d / c_pd) + residual[3] = theta_d(z, equations) - + temperature * (ref_pressure / pressure)^(R_d / c_pd) # humidity residual - residual[4] = rho_vs * (rho_dry + rho_vapour / eps) * humidity_rel0 + residual[4] = rho_vs * (rho_dry + rho_vapour / eps) * humidity_rel0 residual[4] -= rho_vapour * (rho_dry + rho_vs / eps) residual[4] *= 1000.0 end @@ -73,29 +71,30 @@ function generate_hydrostatic_residual(pressure_lower, humidity_rel0, z, dz, equ return hydrostatic_residual! end - -function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equations::CompressibleRainyEulerEquations2D) +function generate_perturbation_residual(pressure_hydrostatic, H_init, z, + equations::CompressibleRainyEulerEquations2D) # equations constants - c_pd = equations.c_dry_air_const_pressure - R_d = equations.R_dry_air - R_v = equations.R_vapour - eps = equations.eps - ref_pressure = equations.ref_pressure + c_pd = equations.c_dry_air_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + eps = equations.eps + ref_pressure = equations.ref_pressure function perturbation_residual!(residual, guess) # variables rho_dry, rho_vapour, temperature = guess - + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) pressure = (rho_dry * R_d + rho_vapour * R_v) * temperature - + # humidity residual - residual[1] = rho_vs * (rho_dry + rho_vapour / eps) * H_init + residual[1] = rho_vs * (rho_dry + rho_vapour / eps) * H_init residual[1] -= rho_vapour * (rho_dry + rho_vs / eps) residual[1] *= 30.0 # hydrostatic dry potential temperature residual - residual[2] = theta_d(z, equations) - temperature * (ref_pressure / pressure_hydrostatic)^(R_d / c_pd) + residual[2] = theta_d(z, equations) - + temperature * (ref_pressure / pressure_hydrostatic)^(R_d / c_pd) # pressure residual residual[3] = pressure_hydrostatic - pressure @@ -104,32 +103,33 @@ function generate_perturbation_residual(pressure_hydrostatic, H_init, z, equatio return perturbation_residual! end - # for approximating the dz pressure gradient struct AtmosphereLayersRainyBubble{RealT <: Real} - layer_data ::Matrix{RealT} - total_height ::RealT - precision ::RealT + layer_data :: Matrix{RealT} + total_height :: RealT + precision :: RealT end - -function AtmosphereLayersRainyBubble(equations::CompressibleRainyEulerEquations2D; total_height = coordinates_max[2] + 1.0, precision = 1.0, RealT = Float64) +function AtmosphereLayersRainyBubble(equations::CompressibleRainyEulerEquations2D; + total_height = coordinates_max[2] + 1.0, + precision = 1.0, RealT = Float64) # constants - humidity_rel0 = 0.2 # hydrostatic relative humidity + humidity_rel0 = 0.2 # hydrostatic relative humidity surface_pressure = 8.5e4 # surface layer with initial guesses for rho_dry, rho_vapour and temperature surface_layer = [surface_pressure, 1.4, 0.04, 300.0] - + # allocate layer_data n = convert(Int, total_height / precision) layer_data = zeros(RealT, n + 1, 4) # solve (slightly above) surface layer dz = 0.01 - z = 0.01 - residual_function! = generate_hydrostatic_residual(surface_pressure, humidity_rel0, z, dz, equations) - layer_data[1, :] .= nlsolve(residual_function!, surface_layer).zero + z = 0.01 + residual_function! = generate_hydrostatic_residual(surface_pressure, humidity_rel0, z, + dz, equations) + layer_data[1, :] .= nlsolve(residual_function!, surface_layer).zero # adjust to chosen precision dz = precision @@ -137,33 +137,34 @@ function AtmosphereLayersRainyBubble(equations::CompressibleRainyEulerEquations2 # iterate up the atmosphere for i in (1:n) z += dz - residual_function! = generate_hydrostatic_residual(layer_data[i, 1], humidity_rel0, z, dz, equations) + residual_function! = generate_hydrostatic_residual(layer_data[i, 1], humidity_rel0, + z, dz, equations) guess = deepcopy(layer_data[i, :]) - layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, iterations = 20).zero + layer_data[i + 1, :] .= nlsolve(residual_function!, guess, ftol = 1e-10, + iterations = 20).zero end - + return AtmosphereLayersRainyBubble{RealT}(layer_data, total_height, precision) end - # create layers for initial condition equations = CompressibleRainyEulerEquations2D() -layers = AtmosphereLayersRainyBubble(equations) - +layers = AtmosphereLayersRainyBubble(equations) -function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerEquations2D; atmosphere_layers = layers) +function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerEquations2D; + atmosphere_layers = layers) # equations constants - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume ref_L = equations.ref_latent_heat_vap_temp # problem specific constants humidity_rel_bar = 0.2 # background relative humidity field - humidity_max = 1.0 + humidity_max = 1.0 # bubble parameters - radius_outer, radius_inner = 300.0, 200.0 # radii of humidity bubble - x_center, z_center = 1200.0, 800.0 # center of humidity bubble + radius_outer, radius_inner = 300.0, 200.0 # radii of humidity bubble + x_center, z_center = 1200.0, 800.0 # center of humidity bubble # radius relative to bubble center r = sqrt((x[1] - x_center)^2 + (x[2] - z_center)^2) @@ -174,20 +175,22 @@ function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerE humidity = humidity_rel_bar elseif (r > radius_inner) # outer layers of the bubble - humidity = humidity_rel_bar + (humidity_max - humidity_rel_bar) * cos(pi * (r - radius_inner) / (2.0 * (radius_outer - radius_inner)))^2 + humidity = humidity_rel_bar + + (humidity_max - humidity_rel_bar) * + cos(pi * (r - radius_inner) / (2.0 * (radius_outer - radius_inner)))^2 else # inner layer humidity = humidity_max end - + # get atmosphere layer and height information @unpack layer_data, total_height, precision = atmosphere_layers dz = precision - z = x[2] - n = convert(Int, floor((z + eps()) / dz)) + 1 + z = x[2] + n = convert(Int, floor((z + eps()) / dz)) + 1 z_lower = (n - 1) * dz - z_upper = n * dz - + z_upper = n * dz + if (z_lower == total_height) z_upper = z_lower + dz n = n - 1 @@ -201,41 +204,40 @@ function initial_condition_bubble_rainy(x, t, equations::CompressibleRainyEulerE if (z > total_height && !(isapprox(z, total_height))) error("The atmosphere does not match the simulation domain") end - + # get hydrostatic pressures and approximate between lower and upper data point pressure_hydrostatic_lower = layer_data[n, 1] pressure_hydrostatic_upper = layer_data[n + 1, 1] - pressure_hydrostatic = (pressure_hydrostatic_upper * (z - z_lower) + pressure_hydrostatic_lower * (z_upper - z)) / dz + pressure_hydrostatic = (pressure_hydrostatic_upper * (z - z_lower) + + pressure_hydrostatic_lower * (z_upper - z)) / dz # solve perturbation - residual_function! = generate_perturbation_residual(pressure_hydrostatic, humidity, z, equations) - rho_dry, rho_vapour, temperature = nlsolve(residual_function!, layer_data[n, 2:4], ftol = 1e-9, iterations = 20).zero + residual_function! = generate_perturbation_residual(pressure_hydrostatic, humidity, z, + equations) + rho_dry, rho_vapour, temperature = nlsolve(residual_function!, layer_data[n, 2:4], + ftol = 1e-9, iterations = 20).zero energy_density = (c_vd * rho_dry + c_vv * rho_vapour) * temperature + rho_vapour * ref_L - return SVector(rho_dry, rho_vapour, 0.0, 0.0, 0.0, energy_density, rho_vapour, 0.0, temperature) + return SVector(rho_dry, rho_vapour, 0.0, 0.0, 0.0, energy_density, rho_vapour, 0.0, + temperature) end - - ############################################################################### # semidiscretization of the compressible rainy Euler equations diffusivity = 0.5 equations_parabolic = LaplaceDiffusion2D(diffusivity, equations) - boundary_conditions = (x_neg = boundary_condition_periodic, x_pos = boundary_condition_periodic, y_neg = boundary_condition_simple_slip_wall, y_pos = boundary_condition_simple_slip_wall) -boundary_conditions_parabolic = ( - x_neg = boundary_condition_periodic, - x_pos = boundary_condition_periodic, - y_neg = boundary_condition_laplace, - y_pos = boundary_condition_laplace) - +boundary_conditions_parabolic = (x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_laplace, + y_pos = boundary_condition_laplace) polydeg = 3 basis = LobattoLegendreBasis(polydeg) @@ -246,13 +248,17 @@ volume_integral = VolumeIntegralFluxDifferencing(flux_ec_rain) solver = DGSEM(basis, surface_flux, volume_integral) initial_condition = initial_condition_bubble_rainy -source_terms = source_terms_rainy +source_terms = source_terms_rainy initial_refinement_level = 6 -mesh = TreeMesh(coordinates_min, coordinates_max, initial_refinement_level = initial_refinement_level, periodicity = (true, false), n_cells_max = 1_000_000) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = initial_refinement_level, + periodicity = (true, false), n_cells_max = 1_000_000) -semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; source_terms, - boundary_conditions = (boundary_conditions, boundary_conditions_parabolic)) +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver; source_terms, + boundary_conditions = (boundary_conditions, + boundary_conditions_parabolic)) ############################################################################### # ODE solvers, callbacks etc. @@ -282,11 +288,12 @@ callbacks = CallbackSet(summary_callback, alive_callback, save_solution) -stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, SVector(7, 8, 9), 1e-9) +stage_limiter! = NonlinearSolveDG(saturation_residual, saturation_residual_jacobian, + SVector(7, 8, 9), 1e-9) ############################################################################### # run the simulation sol = solve(ode, SSPRK43(stage_limiter!); ode_default_options()..., maxiters = 1.0e7, save_everystep = false, callback = callbacks); -summary_callback() \ No newline at end of file +summary_callback() diff --git a/src/callbacks_stage/callbacks_stage.jl b/src/callbacks_stage/callbacks_stage.jl index 3e756c20..b7cfd68f 100644 --- a/src/callbacks_stage/callbacks_stage.jl +++ b/src/callbacks_stage/callbacks_stage.jl @@ -1,4 +1,4 @@ @muladd begin include("nonlinear_solve_dg.jl") include("rain_limiter_dg.jl") -end \ No newline at end of file +end diff --git a/src/callbacks_stage/nonlinear_solve_dg.jl b/src/callbacks_stage/nonlinear_solve_dg.jl index 264b720e..2fe7b01e 100644 --- a/src/callbacks_stage/nonlinear_solve_dg.jl +++ b/src/callbacks_stage/nonlinear_solve_dg.jl @@ -1,27 +1,24 @@ using Trixi: wrap_array, AbstractSemidiscretization, TimerOutputs, @trixi_timeit, timer - - @muladd begin - -struct NonlinearSolveDG - residual ::Function - jacobian ::Function - variables_index_vector::Vector{Int} - tolerance ::Real -end - - -function (limiter!::NonlinearSolveDG)(u_ode, integrator, semi::AbstractSemidiscretization, t) - u = wrap_array(u_ode, semi) - - @trixi_timeit timer() "nonlinear system solver" begin - nonlinear_solve_dg_2d!(u, limiter!.residual, limiter!.jacobian, limiter!.variables_index_vector, - limiter!.tolerance, semi.equations, semi.solver, semi.cache, semi.mesh) + struct NonlinearSolveDG + residual :: Function + jacobian :: Function + variables_index_vector :: Vector{Int} + tolerance :: Real end -end + function (limiter!::NonlinearSolveDG)(u_ode, integrator, + semi::AbstractSemidiscretization, t) + u = wrap_array(u_ode, semi) -include("nonlinear_solve_dg2d.jl") + @trixi_timeit timer() "nonlinear system solver" begin + nonlinear_solve_dg_2d!(u, limiter!.residual, limiter!.jacobian, + limiter!.variables_index_vector, + limiter!.tolerance, semi.equations, semi.solver, + semi.cache, semi.mesh) + end + end -end \ No newline at end of file + include("nonlinear_solve_dg2d.jl") +end diff --git a/src/callbacks_stage/nonlinear_solve_dg2d.jl b/src/callbacks_stage/nonlinear_solve_dg2d.jl index 3c29dc5d..7140454c 100644 --- a/src/callbacks_stage/nonlinear_solve_dg2d.jl +++ b/src/callbacks_stage/nonlinear_solve_dg2d.jl @@ -1,89 +1,89 @@ -using Trixi: get_node_vars, @batch, get_inverse_jacobian, set_node_vars!, get_node_coords, each_quad_node +using Trixi: get_node_vars, @batch, get_inverse_jacobian, set_node_vars!, get_node_coords, + each_quad_node using LinearAlgebra using StaticArrays - - @muladd begin + function nonlinear_solve_dg_2d!(u, residual, jacobian, variables_index_vector, + tolerance, + equations::AbstractCompressibleRainyEulerEquations, + dg::DGSEM, cache, mesh) + max_iterations = 20 + + # iterate over every DGSEM element + @batch for element in eachelement(dg, cache) + # iterate over every node + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, j, element) + guess = SVector(u_node[7], u_node[8], u_node[9]) + + # keep rain positive + if (u_node[3] < 0.0) + u[3, i, j, element] = 0.0 + end -function nonlinear_solve_dg_2d!(u, residual, jacobian, variables_index_vector, tolerance, - equations::AbstractCompressibleRainyEulerEquations, dg::DGSEM, cache, mesh) - max_iterations = 20 - - # iterate over every DGSEM element - @batch for element in eachelement(dg, cache) - # iterate over every node - for j in eachnode(dg), i in eachnode(dg) - - u_node = get_node_vars(u, equations, dg, i, j, element) - guess = SVector(u_node[7], u_node[8], u_node[9]) + # newton method + for iteration in range(1, max_iterations) + res_vector = residual(u_node, guess, equations) - # keep rain positive - if (u_node[3] < 0.0) - u[3, i, j, element] = 0.0 - end + if (maximum(abs.(res_vector)) < tolerance) + break + end - # newton method - for iteration in range(1, max_iterations) - res_vector = residual(u_node, guess, equations) + jac_matrix = jacobian(u_node, guess, equations) + guess += -jac_matrix \ res_vector - if (maximum(abs.(res_vector)) < tolerance) - break + #= warnings seem to have allocations... + if iteration == max_iterations + @warn "newton method: tolerance not met" + end + =# end - jac_matrix = jacobian(u_node, guess, equations) - guess += - jac_matrix \ res_vector - - #= warnings seem to have allocations... - if iteration == max_iterations - @warn "newton method: tolerance not met" + # similar to set_node_vars! + for index in eachindex(variables_index_vector) + u[variables_index_vector[index], i, j, element] = guess[index] end - =# - end - - # similar to set_node_vars! - for index in eachindex(variables_index_vector) - u[variables_index_vector[index], i, j, element] = guess[index] end end end -end + function nonlinear_solve_dg_2d!(u, residual, jacobian, variables_index_vector, + tolerance, + equations::AbstractCompressibleRainyEulerEquations, + dg::DGMulti, cache, mesh::DGMultiMesh) + max_iterations = 20 -function nonlinear_solve_dg_2d!(u, residual, jacobian, variables_index_vector, tolerance, - equations::AbstractCompressibleRainyEulerEquations, dg::DGMulti, cache, mesh::DGMultiMesh) - max_iterations = 20 + # iterate over every node + @batch for element in eachelement(mesh, dg) + for j in each_quad_node(mesh, dg) + u_node = u[j, element] + + # keep rain positive + if (u_node[3] < 0.0) + u_node = SVector(u_node[1], u_node[2], 0.0, u_node[4], u_node[5], + u_node[6], + u_node[7], u_node[8], u_node[9]) + end - # iterate over every node - @batch for element in eachelement(mesh, dg) - for j in each_quad_node(mesh, dg) + guess = SVector(u_node[7], u_node[8], u_node[9]) - u_node = u[j, element] - - # keep rain positive - if (u_node[3] < 0.0) - u_node = SVector(u_node[1], u_node[2], 0.0, u_node[4], u_node[5], u_node[6], - u_node[7], u_node[8], u_node[9]) - end + # newton method + for iteration in range(1, max_iterations) + res_vector = residual(u_node, guess, equations) - guess = SVector(u_node[7], u_node[8], u_node[9]) + if (maximum(abs.(res_vector)) < tolerance) + break + end - # newton method - for iteration in range(1, max_iterations) - res_vector = residual(u_node, guess, equations) - - if (maximum(abs.(res_vector)) < tolerance) - break + jac_matrix = jacobian(u_node, guess, equations) + guess += -jac_matrix \ res_vector end - jac_matrix = jacobian(u_node, guess, equations) - guess += - jac_matrix \ res_vector + u[j, element] = SVector(u_node[1], u_node[2], u_node[3], u_node[4], + u_node[5], u_node[6], + guess[1], guess[2], guess[3]) end - - u[j, element] = SVector(u_node[1], u_node[2], u_node[3], u_node[4], u_node[5], u_node[6], - guess[1], guess[2], guess[3]) end end -end - -end # muladd end \ No newline at end of file +end # muladd end diff --git a/src/callbacks_stage/rain_limiter_dg.jl b/src/callbacks_stage/rain_limiter_dg.jl index 13b54d6e..409b0d46 100644 --- a/src/callbacks_stage/rain_limiter_dg.jl +++ b/src/callbacks_stage/rain_limiter_dg.jl @@ -1,22 +1,17 @@ using Trixi: wrap_array, TimerOutputs, @trixi_timeit, timer - - @muladd begin - -struct RainLimiterDG -end - - -function (limiter!::RainLimiterDG)(u_ode, integrator, semi::AbstractSemidiscretization, t) - u = wrap_array(u_ode, semi) - - @trixi_timeit timer() "rain limiter" begin - rain_limiter_dg2d!(u, semi.equations, semi.solver, semi.cache, semi.mesh) + struct RainLimiterDG end -end + function (limiter!::RainLimiterDG)(u_ode, integrator, semi::AbstractSemidiscretization, + t) + u = wrap_array(u_ode, semi) -include("rain_limiter_dg2d.jl") + @trixi_timeit timer() "rain limiter" begin + rain_limiter_dg2d!(u, semi.equations, semi.solver, semi.cache, semi.mesh) + end + end -end \ No newline at end of file + include("rain_limiter_dg2d.jl") +end diff --git a/src/callbacks_stage/rain_limiter_dg2d.jl b/src/callbacks_stage/rain_limiter_dg2d.jl index 8e0395af..097ab1e1 100644 --- a/src/callbacks_stage/rain_limiter_dg2d.jl +++ b/src/callbacks_stage/rain_limiter_dg2d.jl @@ -2,30 +2,26 @@ using Trixi: get_node_vars, @batch, set_node_vars!, get_node_coords, each_quad_n using LinearAlgebra using StaticArrays - - @muladd begin - -function rain_limiter_dg2d!(u, equations::AbstractCompressibleRainyEulerEquations, dg::DGSEM, cache, mesh) - - # iterate over every DGSEM element - @batch for element in eachelement(dg, cache) - # iterate over every node - for j in eachnode(dg), i in eachnode(dg) - - u_node = get_node_vars(u, equations, dg, i, j, element) - - # keep rho_rain positive - if (u_node[4] < 0.0) - u[4, i, j, element] = 0.0 - end - - # keep rho_cloud positive - if (u_node[3] < 0.0) - u[3, i, j, element] = 0.0 + function rain_limiter_dg2d!(u, equations::AbstractCompressibleRainyEulerEquations, + dg::DGSEM, cache, mesh) + + # iterate over every DGSEM element + @batch for element in eachelement(dg, cache) + # iterate over every node + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations, dg, i, j, element) + + # keep rho_rain positive + if (u_node[4] < 0.0) + u[4, i, j, element] = 0.0 + end + + # keep rho_cloud positive + if (u_node[3] < 0.0) + u[3, i, j, element] = 0.0 + end end end end -end - -end #muladd end \ No newline at end of file +end #muladd end diff --git a/src/equations/compressible_moist_euler_potential_temperature_2d.jl b/src/equations/compressible_moist_euler_potential_temperature_2d.jl index 02eae587..09d8ea34 100644 --- a/src/equations/compressible_moist_euler_potential_temperature_2d.jl +++ b/src/equations/compressible_moist_euler_potential_temperature_2d.jl @@ -26,7 +26,8 @@ struct CompressibleMoistEulerPotentialTemperatureEquations2D{RealT <: Real} <: K::RealT end -function CompressibleMoistEulerPotentialTemperatureEquations2D(; g = 9.81, RealT = Float64) +function CompressibleMoistEulerPotentialTemperatureEquations2D(; g = 9.81, + RealT = Float64) p_0 = 100000.0 c_pd = 1004.0 c_vd = 717.0 @@ -37,14 +38,17 @@ function CompressibleMoistEulerPotentialTemperatureEquations2D(; g = 9.81, RealT c_pl = 4186.0 gamma = c_pd / c_vd # = 1/(1 - kappa) inv_gamma_minus_one = inv(1 - gamma) - K = - L_00 = 2.5e6 #+ (c_pl - c_pv)*273.15 + K = L_00 = 2.5e6 #+ (c_pl - c_pv)*273.15 K = p_0 * (R_d / p_0)^gamma - return CompressibleMoistEulerPotentialTemperatureEquations2D{RealT}(p_0, c_pd, c_vd, R_d, c_pv, c_vv, - R_v, c_pl, g, inv_gamma_minus_one, gamma, L_00, K) + return CompressibleMoistEulerPotentialTemperatureEquations2D{RealT}(p_0, c_pd, c_vd, + R_d, c_pv, c_vv, + R_v, c_pl, g, + inv_gamma_minus_one, + gamma, L_00, K) end -@inline function pressure(u, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) +@inline function pressure(u, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) @unpack p_0, R_d, R_v, c_pd, c_pv, c_pl, c_vd, c_vv = equations rho, rho_v1, rho_v2, rho_theta, rho_v, rho_l = u @@ -195,7 +199,7 @@ end # Recreates the convergence test initial condition from compressible euler 2D. function initial_condition_warm_bubble(x, t, - equations::CompressibleMoistEulerPotentialTemperatureEquations2D) + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) @unpack R_d, R_v, c_vd, c_vv, c_pl, L_00 = equations xc = 0 zc = 2000 @@ -207,16 +211,17 @@ function initial_condition_warm_bubble(x, t, Δtheta = 0 Δqv = 0 Δqc = 0 - + if r <= rc - Δtheta = 2 * cospi(0.5*r/rc)^2 + Δtheta = 2 * cospi(0.5 * r / rc)^2 end - + #Perturbed state: theta = theta_ref + Δtheta # potential temperature π_exner = 1 - equation._grav / (equation.c_pd * theta) * x[2] # exner pressure - rho = equation.p_0 / (equation.R_d * theta) * (π_exner)^(equation.c_vd / equation.R_d) # density - + rho = equation.p_0 / (equation.R_d * theta) * + (π_exner)^(equation.c_vd / equation.R_d) # density + v1 = 20 v2 = 0 qv = 0 @@ -230,11 +235,9 @@ function initial_condition_warm_bubble(x, t, return SVector(rho, rho_v1, rho_v2, rho_e, rho_qv, rho_qc) end - - # Gravity source term @inline function source_terms_gravity(u, x, t, - equations::CompressibleMoistEulerEquations2D) + equations::CompressibleMoistEulerEquations2D) @unpack g = equations rho, _, _, _, _, _ = u @@ -276,14 +279,14 @@ end zero(eltype(u)), zero(eltype(u)), zero(eltype(u))) end -function source_terms_moist_bubble(u, x, t, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) - +function source_terms_moist_bubble(u, x, t, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) rho, rho_v1, rho_v2, rho_theta, rho_qv, rho_qc = u RelCloud = 1 rho_d = rho - rho_qv - rho_qc c_pml = equations.c_pd * rho_d + equations.c_pv * rho_qv + equations.c_pl * rho_qc c_vml = equations.c_vd * rho_d + equations.c_vv * rho_qv + equations.c_pl * rho_qc - R_m = equations.R_d * rho_d + equations.R_v * rho_qv + R_m = equations.R_d * rho_d + equations.R_v * rho_qv kappa_M = R_m / c_pml p = pressure(u, equations) T = p / R_m @@ -293,16 +296,19 @@ function source_terms_moist_bubble(u, x, t, equations::CompressibleMoistEulerPot b = rho_qc rho_q_cond = RelCloud * (a + b - sqrt(a * a + b * b)) L = equations.L_00 - (equations.c_pl - equations.c_pv) * T - du4 = rho_theta * ((-L / (c_pml * T) - log(p / equations.p_0) * kappa_M * (equations.R_v / R_m - equations.c_pv / c_pml) + - equations.R_v / R_m) * rho_q_cond + (log(p / equations.p_0) * kappa_M * (equations.c_pl / c_pml)) * (-rho_q_cond)) - - du5 = rho_q_cond + du4 = rho_theta * ((-L / (c_pml * T) - + log(p / equations.p_0) * kappa_M * + (equations.R_v / R_m - equations.c_pv / c_pml) + + equations.R_v / R_m) * rho_q_cond + + (log(p / equations.p_0) * kappa_M * (equations.c_pl / c_pml)) * + (-rho_q_cond)) + + du5 = rho_q_cond du6 = -rho_q_cond - return SVector(zero(eltype(u)), zero(eltype(u)), -equations.g*rho, du4, du5, du6) + return SVector(zero(eltype(u)), zero(eltype(u)), -equations.g * rho, du4, du5, du6) end - # Low Mach number approximate Riemann solver (LMARS) from # X. Chen, N. Andronova, B. Van Leer, J. E. Penner, J. P. Boyd, C. Jablonowski, S. # Lin, A Control-Volume Model of the Compressible Euler Equations with a Vertical Lagrangian @@ -347,11 +353,12 @@ end end # Convert conservative variables to primitive. -@inline function cons2prim(u, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) +@inline function cons2prim(u, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) rho, rho_v1, rho_v2, rho_theta, rho_qv, rho_ql = u v1 = rho_v1 / rho v2 = rho_v2 / rho - p = pressure(u, equations) + p = pressure(u, equations) qv = rho_qv / rho ql = rho_ql / rho @@ -359,29 +366,31 @@ end end # Convert conservative variables to entropy -@inline function cons2entropy(u, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) +@inline function cons2entropy(u, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) @unpack R_d, R_v, c_pd, c_pv, c_pl, L_00 = equations rho, rho_v1, rho_v2, rho_theta, rho_qv, rho_qc = u - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v_square = v1^2 + v2^2 - p = pressure(u, equations) - s = log(p) - equations.gamma*log(rho) - rho_p = rho / p + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v_square = v1^2 + v2^2 + p = pressure(u, equations) + s = log(p) - equations.gamma * log(rho) + rho_p = rho / p - w1 = (equations.gamma - s) / (equations.gamma-1) - 0.5 * rho_p * v_square - w2 = rho_p * v1 - w3 = rho_p * v2 - w4 = -rho_p - w5 = rho_p * rho_qv / rho - w6 = rho_p * rho_qc / rho + w1 = (equations.gamma - s) / (equations.gamma - 1) - 0.5 * rho_p * v_square + w2 = rho_p * v1 + w3 = rho_p * v2 + w4 = -rho_p + w5 = rho_p * rho_qv / rho + w6 = rho_p * rho_qc / rho return SVector(w1, w2, w3, w4, w5, w6) end # Convert primitive to conservative variables. -@inline function prim2cons(prim, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) +@inline function prim2cons(prim, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) rho, v1, v2, p, qv, ql = prim rho_v1 = rho * v1 rho_v2 = rho * v2 @@ -391,33 +400,31 @@ end return SVector(rho, rho_v1, rho_v2, rho_theta, rho_qv, rho_ql) end - -@inline function density(u, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) +@inline function density(u, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) rho = u[1] return rho end -@inline function density_dry(u, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) +@inline function density_dry(u, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) rho_qd = u[1] - (u[5] + u[6]) return rho_qd end -@inline function density_vapor(u, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) +@inline function density_vapor(u, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) rho_qv = u[5] return rho_qv end - - - - # Calculate kinetic energy for a conservative state `cons`. -@inline function energy_kinetic(u, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) +@inline function energy_kinetic(u, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) rho, rho_v1, rho_v2, rho_theta, rho_qv, rho_ql = u return (rho_v1^2 + rho_v2^2) / (2 * rho) end - @inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) @unpack c_pd, c_pv, c_pl, c_vd, c_vv = equations @@ -469,7 +476,8 @@ end end # Adjusted version of lambda_max from compressible euler. -@inline function max_abs_speeds(u, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) +@inline function max_abs_speeds(u, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) @unpack c_pd, c_pv, c_pl, c_vd, c_vv = equations rho, v1, v2, p, qv, ql = cons2prim(u, equations) qd = 1 - qv - ql @@ -480,7 +488,8 @@ end return (abs(v1) + c, abs(v2) + c) end -@inline function cons2aeqpot(u, equations::CompressibleMoistEulerPotentialTemperatureEquations2D) +@inline function cons2aeqpot(u, + equations::CompressibleMoistEulerPotentialTemperatureEquations2D) @unpack c_pd, c_pv, c_pl, R_d, R_v, p_0, L_00 = equations rho, rho_v1, rho_v2, rho_theta, rho_qv, rho_ql = u rho_d = rho - rho_qv - rho_ql @@ -513,16 +522,23 @@ end return SVector(pot1, pot2, pot3, pot4, pot5, pot6) end -varnames(::typeof(cons2aeqpot), ::CompressibleMoistEulerPotentialTemperatureEquations2D) = ("rho", "v1", - "v2", - "aeqpottemp", - "rv", "rt") - - -varnames(::typeof(cons2cons), ::CompressibleMoistEulerPotentialTemperatureEquations2D) = ("rho", "rho_v1", - "rho_v2", "rho_theta", - "rho_qv", - "rho_ql") -varnames(::typeof(cons2prim), ::CompressibleMoistEulerPotentialTemperatureEquations2D) = ("rho", "v1", "v2", - "p", "qv", "ql") +varnames(::typeof(cons2aeqpot), ::CompressibleMoistEulerPotentialTemperatureEquations2D) = ("rho", + "v1", + "v2", + "aeqpottemp", + "rv", + "rt") + +varnames(::typeof(cons2cons), ::CompressibleMoistEulerPotentialTemperatureEquations2D) = ("rho", + "rho_v1", + "rho_v2", + "rho_theta", + "rho_qv", + "rho_ql") +varnames(::typeof(cons2prim), ::CompressibleMoistEulerPotentialTemperatureEquations2D) = ("rho", + "v1", + "v2", + "p", + "qv", + "ql") end # @muladd diff --git a/src/equations/compressible_rainy_euler_2d.jl b/src/equations/compressible_rainy_euler_2d.jl index ab75a04a..e085a58d 100644 --- a/src/equations/compressible_rainy_euler_2d.jl +++ b/src/equations/compressible_rainy_euler_2d.jl @@ -1,13 +1,11 @@ using Trixi using NLsolve: nlsolve -import Trixi: varnames, - cons2prim, cons2entropy, - flux, flux_chandrashekar, - max_abs_speeds, max_abs_speed_naive, - boundary_condition_slip_wall, - LaplaceDiffusion2D - - +import Trixi: varnames, + cons2prim, cons2entropy, + flux, flux_chandrashekar, + max_abs_speeds, max_abs_speed_naive, + boundary_condition_slip_wall, + LaplaceDiffusion2D ### Implementation similar to: # Sabine Doppler, Philip L. Lederer, Joachim Schöberl, Henry von Wahl, @@ -18,1058 +16,1088 @@ import Trixi: varnames, # 112713, # ISSN 0021-9991 - - @muladd begin -### equation, parameters and constants ### - -struct CompressibleRainyEulerEquations2D{RealT <: Real} <: AbstractCompressibleRainyEulerEquations{2, 9} - # Specific heat capacities: - c_liquid_water ::RealT - c_dry_air_const_pressure ::RealT - c_dry_air_const_volume ::RealT - c_vapour_const_pressure ::RealT - c_vapour_const_volume ::RealT - - # Gas constants: - R_dry_air ::RealT - R_vapour ::RealT - eps ::RealT - - # Reference values: - ref_saturation_pressure ::RealT - ref_temperature ::RealT - ref_latent_heat_vap_temp ::RealT - ref_pressure ::RealT - - # Other: - gravity ::RealT - rain_water_distr ::RealT - v_mean_rain ::RealT -end - - -function CompressibleRainyEulerEquations2D(; RealT = Float64) - # Specific heat capacities: - c_liquid_water = 4186.0 - c_dry_air_const_pressure = 1004.0 - c_dry_air_const_volume = 717.0 - c_vapour_const_pressure = 1885.0 - c_vapour_const_volume = 1424.0 - - # Gas constants: - R_dry_air = c_dry_air_const_pressure - c_dry_air_const_volume - R_vapour = c_vapour_const_pressure - c_vapour_const_volume - eps = R_dry_air / R_vapour - - # Reference values: - ref_saturation_pressure = 610.7 # This needs to be adjusted if ref_temperature is changed! - ref_temperature = 273.15 - ref_latent_heat_vap_temp = 2.5e6#3147620.0 - ref_pressure = 1e5 - - # Other: - gravity = 9.81 - rain_water_distr = 8e6 - v_mean_rain = 130.0 - - return CompressibleRainyEulerEquations2D{RealT}(c_liquid_water, c_dry_air_const_pressure, c_dry_air_const_volume, - c_vapour_const_pressure, c_vapour_const_volume, R_dry_air, - R_vapour, eps, ref_saturation_pressure, ref_temperature, - ref_latent_heat_vap_temp, ref_pressure, gravity, - rain_water_distr, v_mean_rain) -end - - - -### conversion ### - -@inline function cons2prim(u, equations::CompressibleRainyEulerEquations2D) - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - - # velocity - v1, v2 = velocities(u, rho_inv, equations) - - # energy density - energy = energy_density(u, equations) - - # nonlinear system - rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) - - return SVector(rho_dry, rho_moist, rho_rain, v1, v2, energy, rho_vapour, rho_cloud, temperature) -end - - -# converts consverved to entropy variables -@inline function cons2entropy(u, equations::CompressibleRainyEulerEquations2D) - # constants - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - c_l = equations.c_liquid_water - R_d = equations.R_dry_air - R_v = equations.R_vapour - L_ref = equations.ref_latent_heat_vap_temp - - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - - # nonlinear system - rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) - ln_temperature = log(temperature) - inv_temperature = inv(temperature) - - # velocity - v1, v2 = velocities(u, rho_inv, equations) - v_squared_temp = 0.5 * (v1^2 + v2^2) * inv_temperature - - # check for zero density - rho_vapour_log = 0.0 - - if (rho_vapour > 0.0) - rho_vapour_log = log(rho_vapour) + ### equation, parameters and constants ### + + struct CompressibleRainyEulerEquations2D{RealT <: Real} <: + AbstractCompressibleRainyEulerEquations{2, 9} + # Specific heat capacities: + c_liquid_water :: RealT + c_dry_air_const_pressure :: RealT + c_dry_air_const_volume :: RealT + c_vapour_const_pressure :: RealT + c_vapour_const_volume :: RealT + + # Gas constants: + R_dry_air :: RealT + R_vapour :: RealT + eps :: RealT + + # Reference values: + ref_saturation_pressure :: RealT + ref_temperature :: RealT + ref_latent_heat_vap_temp :: RealT + ref_pressure :: RealT + + # Other: + gravity :: RealT + rain_water_distr :: RealT + v_mean_rain :: RealT end - omega_dry = c_vd * ln_temperature - R_d * log(rho_dry) + v_squared_temp - c_vd - R_d - omega_vapour = c_vv * ln_temperature - R_v * rho_vapour_log + v_squared_temp - c_vv - R_v - L_ref * inv_temperature - omega_liquid = c_l * ln_temperature + v_squared_temp - c_l - omega_momentum_1 = -v1 * inv_temperature - omega_momentum_2 = -v2 * inv_temperature - omega_energy = inv_temperature - - return SVector(omega_dry, omega_vapour + omega_liquid, omega_liquid, - omega_momentum_1, omega_momentum_2, omega_energy, 0.0, 0.0, 0.0) -end - - -# adapted from compressible_moist_euler_2d.jl -@inline function cons2eq_pot_temp(u, equations::CompressibleRainyEulerEquations2D) - # constants - c_l = equations.c_liquid_water - c_pd = equations.c_dry_air_const_pressure - c_pv = equations.c_vapour_const_pressure - R_d = equations.R_dry_air - R_v = equations.R_vapour - ref_p = equations.ref_pressure - ref_temp = equations.ref_temperature - ref_L = equations.ref_latent_heat_vap_temp - - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - - # velocity - v1, v2 = velocities(u, rho_inv, equations) - - # energy density - energy = energy_density(u, equations) - - # nonlinear system - rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) - - # pressure - p = pressure(u, equations) - - p_v = rho_vapour * R_v * temperature - p_d = p - p_v - T_C = temperature - ref_temp - p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) - H = p_v / p_vs - r_v = rho_vapour / rho_dry - r_c = rho_cloud / rho_dry - r_r = rho_rain / rho_dry - L_v = ref_L + (c_pv - c_l) * temperature - c_p = c_pd + (r_v + r_c + r_r) * c_l - - # equivalent potential temperature - eq_pot = (temperature * (ref_p / p_d)^(R_d / c_p) * H^(-r_v * R_v / c_p) * - exp(L_v * r_v * inv(c_p * temperature))) - - return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, v1, v2, eq_pot, p) -end - - -@inline function cons2nonlinearsystemsol(u, equations::CompressibleRainyEulerEquations2D) - # constants - c_vd = equations.c_dry_air_const_volume - #ref_temp = equations.ref_temperature - - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - - # velocity - v1, v2 = velocities(u, rho_inv, equations) - - # energy density - energy = energy_density(u, equations) - - # recover temperature explicitly from energy when other variables are zero - if (rho_moist == 0.0 && rho_rain == 0.0) - # energy density definition without ref_temp for dry case - energy_kinetic = 0.5 * (v1^2 + v2^2) * rho - temperature = (energy - energy_kinetic) / (c_vd * rho) #+ ref_temp - - if (temperature < 0.0) - error("temp negative") - end - - return SVector(0.0, 0.0, temperature) - else - # experimental and overly simple positivity check - rho_vapour = u[7] - rho_cloud = u[8] - temperature = u[9] - - if (rho_vapour < 0.0 && isapprox(rho_vapour, 0.0, atol = 1e-15)) - rho_vapour = 0.0 - end - - if (rho_cloud < 0.0 && isapprox(rho_cloud, 0.0, atol = 1e-15)) - rho_cloud = 0.0 - end - - return SVector(rho_vapour, rho_cloud, temperature) + function CompressibleRainyEulerEquations2D(; RealT = Float64) + # Specific heat capacities: + c_liquid_water = 4186.0 + c_dry_air_const_pressure = 1004.0 + c_dry_air_const_volume = 717.0 + c_vapour_const_pressure = 1885.0 + c_vapour_const_volume = 1424.0 + + # Gas constants: + R_dry_air = c_dry_air_const_pressure - c_dry_air_const_volume + R_vapour = c_vapour_const_pressure - c_vapour_const_volume + eps = R_dry_air / R_vapour + + # Reference values: + ref_saturation_pressure = 610.7 # This needs to be adjusted if ref_temperature is changed! + ref_temperature = 273.15 + ref_latent_heat_vap_temp = 2.5e6#3147620.0 + ref_pressure = 1e5 + + # Other: + gravity = 9.81 + rain_water_distr = 8e6 + v_mean_rain = 130.0 + + return CompressibleRainyEulerEquations2D{RealT}(c_liquid_water, + c_dry_air_const_pressure, + c_dry_air_const_volume, + c_vapour_const_pressure, + c_vapour_const_volume, R_dry_air, + R_vapour, eps, + ref_saturation_pressure, + ref_temperature, + ref_latent_heat_vap_temp, + ref_pressure, gravity, + rain_water_distr, v_mean_rain) end -end + ### conversion ### -# for convenience TODO rename -@inline function cons2speeds(u, equations::CompressibleRainyEulerEquations2D) - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + @inline function cons2prim(u, equations::CompressibleRainyEulerEquations2D) + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - # velocity - v1, v2 = velocities(u, rho_inv, equations) + # velocity + v1, v2 = velocities(u, rho_inv, equations) - # get speed of sound - v_sound = speed_of_sound(u, equations)[1] + # energy density + energy = energy_density(u, equations) - # get terminal velocity rain - v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) - - return SVector(v1, v2, v_sound, v_r) -end - - - -### varnames ### - -varnames(::typeof(cons2cons), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_moist", "rho_rain", - "rho_v1", "rho_v2", - "energy_density", - "rho_vapour", "rho_cloud", "temperature") + # nonlinear system + rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) + return SVector(rho_dry, rho_moist, rho_rain, v1, v2, energy, rho_vapour, rho_cloud, + temperature) + end -varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_moist", "rho_rain", - "v1", "v2", - "energy_density", - "rho_vapour", "rho_cloud", "temperature") + # converts consverved to entropy variables + @inline function cons2entropy(u, equations::CompressibleRainyEulerEquations2D) + # constants + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + c_l = equations.c_liquid_water + R_d = equations.R_dry_air + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + # nonlinear system + rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) + ln_temperature = log(temperature) + inv_temperature = inv(temperature) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + v_squared_temp = 0.5 * (v1^2 + v2^2) * inv_temperature + + # check for zero density + rho_vapour_log = 0.0 + + if (rho_vapour > 0.0) + rho_vapour_log = log(rho_vapour) + end -varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquations2D) = ("rho_dry", "rho_vapour", - "rho_cloud", "rho_rain", - "v1", "v2", "eq_pot_temp", - "pressure") + omega_dry = c_vd * ln_temperature - R_d * log(rho_dry) + v_squared_temp - c_vd - R_d + omega_vapour = c_vv * ln_temperature - R_v * rho_vapour_log + v_squared_temp - + c_vv - R_v - L_ref * inv_temperature + omega_liquid = c_l * ln_temperature + v_squared_temp - c_l + omega_momentum_1 = -v1 * inv_temperature + omega_momentum_2 = -v2 * inv_temperature + omega_energy = inv_temperature + return SVector(omega_dry, omega_vapour + omega_liquid, omega_liquid, + omega_momentum_1, omega_momentum_2, omega_energy, 0.0, 0.0, 0.0) + end + # adapted from compressible_moist_euler_2d.jl + @inline function cons2eq_pot_temp(u, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_pd = equations.c_dry_air_const_pressure + c_pv = equations.c_vapour_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + ref_p = equations.ref_pressure + ref_temp = equations.ref_temperature + ref_L = equations.ref_latent_heat_vap_temp + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + + # energy density + energy = energy_density(u, equations) + + # nonlinear system + rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) + + # pressure + p = pressure(u, equations) + + p_v = rho_vapour * R_v * temperature + p_d = p - p_v + T_C = temperature - ref_temp + p_vs = 611.2 * exp(17.62 * T_C / (243.12 + T_C)) + H = p_v / p_vs + r_v = rho_vapour / rho_dry + r_c = rho_cloud / rho_dry + r_r = rho_rain / rho_dry + L_v = ref_L + (c_pv - c_l) * temperature + c_p = c_pd + (r_v + r_c + r_r) * c_l + + # equivalent potential temperature + eq_pot = (temperature * (ref_p / p_d)^(R_d / c_p) * H^(-r_v * R_v / c_p) * + exp(L_v * r_v * inv(c_p * temperature))) + + return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, v1, v2, eq_pot, p) + end -### physics variables ### + @inline function cons2nonlinearsystemsol(u, + equations::CompressibleRainyEulerEquations2D) + # constants + c_vd = equations.c_dry_air_const_volume + #ref_temp = equations.ref_temperature -@inline function densities(u, equations::CompressibleRainyEulerEquations2D) - # densities - rho_dry = u[1] - rho_moist = u[2] - rho_rain = u[3] - rho = rho_dry + rho_moist + rho_rain - rho_inv = inv(rho) + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - return SVector(rho_dry, rho_moist, rho_rain, rho, rho_inv) -end + # velocity + v1, v2 = velocities(u, rho_inv, equations) -@inline function rain_density(u, equations::CompressibleRainyEulerEquations2D) - return u[3] -end + # energy density + energy = energy_density(u, equations) -@inline function velocities(u, rho_inv, equations::CompressibleRainyEulerEquations2D) - return SVector(u[4] * rho_inv, u[5] * rho_inv) -end + # recover temperature explicitly from energy when other variables are zero + if (rho_moist == 0.0 && rho_rain == 0.0) + # energy density definition without ref_temp for dry case + energy_kinetic = 0.5 * (v1^2 + v2^2) * rho + temperature = (energy - energy_kinetic) / (c_vd * rho) #+ ref_temp + if (temperature < 0.0) + error("temp negative") + end -@inline function energy_density(u, equations::CompressibleRainyEulerEquations2D) - return u[6] -end + return SVector(0.0, 0.0, temperature) + else + # experimental and overly simple positivity check + rho_vapour = u[7] + rho_cloud = u[8] + temperature = u[9] + if (rho_vapour < 0.0 && isapprox(rho_vapour, 0.0, atol = 1e-15)) + rho_vapour = 0.0 + end -@inline function pressure(u, equations::CompressibleRainyEulerEquations2D) - # constants - R_d = equations.R_dry_air - R_v = equations.R_vapour + if (rho_cloud < 0.0 && isapprox(rho_cloud, 0.0, atol = 1e-15)) + rho_cloud = 0.0 + end - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + return SVector(rho_vapour, rho_cloud, temperature) + end + end - rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) - - p = (R_d * rho_dry + R_v * rho_vapour) * temperature + # for convenience TODO rename + @inline function cons2speeds(u, equations::CompressibleRainyEulerEquations2D) + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - return p -end + # velocity + v1, v2 = velocities(u, rho_inv, equations) + # get speed of sound + v_sound = speed_of_sound(u, equations)[1] -@inline function speed_of_sound(u, equations::CompressibleRainyEulerEquations2D) - # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_d = equations.R_dry_air - R_v = equations.R_vapour + # get terminal velocity rain + v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) - # densities - rho_dry, _, rho_rain, _, rho_inv = densities(u, equations) + return SVector(v1, v2, v_sound, v_r) + end - # recover rho_vapour, rho_cloud, temperature from nonlinear system - rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) - if ( rho_vapour < 0.0 ) - error("rho vapour less than zero") + ### varnames ### + + varnames(::typeof(cons2cons), ::CompressibleRainyEulerEquations2D) = ("rho_dry", + "rho_moist", + "rho_rain", + "rho_v1", + "rho_v2", + "energy_density", + "rho_vapour", + "rho_cloud", + "temperature") + + varnames(::typeof(cons2prim), ::CompressibleRainyEulerEquations2D) = ("rho_dry", + "rho_moist", + "rho_rain", + "v1", "v2", + "energy_density", + "rho_vapour", + "rho_cloud", + "temperature") + + varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerEquations2D) = ("rho_dry", + "rho_vapour", + "rho_cloud", + "rho_rain", + "v1", "v2", + "eq_pot_temp", + "pressure") + + ### physics variables ### + + @inline function densities(u, equations::CompressibleRainyEulerEquations2D) + # densities + rho_dry = u[1] + rho_moist = u[2] + rho_rain = u[3] + rho = rho_dry + rho_moist + rho_rain + rho_inv = inv(rho) + + return SVector(rho_dry, rho_moist, rho_rain, rho, rho_inv) end - if ( rho_cloud < 0.0 ) - error("rho cloud less than zero") + + @inline function rain_density(u, equations::CompressibleRainyEulerEquations2D) + return u[3] end - # formula - p = pressure(u, equations) - q_v = rho_vapour / rho_dry - q_l = (rho_cloud + rho_rain) / rho_dry - gamma_m = 1 + (R_d + R_v * q_v) / (c_vd + c_vv * q_v + c_l * q_l) + @inline function velocities(u, rho_inv, equations::CompressibleRainyEulerEquations2D) + return SVector(u[4] * rho_inv, u[5] * rho_inv) + end - if (rho_inv < 0.0) - error("rho less than zero") - elseif (p < 0.0) - error("pressure less than zero") + @inline function energy_density(u, equations::CompressibleRainyEulerEquations2D) + return u[6] end - v_sound = sqrt(gamma_m * p * rho_inv) - - return SVector(v_sound, gamma_m) -end + @inline function pressure(u, equations::CompressibleRainyEulerEquations2D) + # constants + R_d = equations.R_dry_air + R_v = equations.R_vapour + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + rho_vapour, _, temperature = cons2nonlinearsystemsol(u, equations) -@inline function terminal_velocity_rain(rho_moist, rho_rain, equations::CompressibleRainyEulerEquations2D) - # constants - N_0 = equations.rain_water_distr - v_0 = equations.v_mean_rain + p = (R_d * rho_dry + R_v * rho_vapour) * temperature - # formula ( \Gamma(4.5) / 6 ~= 1.9386213994279082 ) - if ( rho_rain > 0.0) - v_terminal_rain = v_0 * 1.9386213994279082 * (rho_rain / (pi * (rho_moist + rho_rain) * N_0))^(0.125) - else - v_terminal_rain = 0.0 + return p end - return v_terminal_rain -end + @inline function speed_of_sound(u, equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + + # densities + rho_dry, _, rho_rain, _, rho_inv = densities(u, equations) + + # recover rho_vapour, rho_cloud, temperature from nonlinear system + rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) + if (rho_vapour < 0.0) + error("rho vapour less than zero") + end + if (rho_cloud < 0.0) + error("rho cloud less than zero") + end + # formula + p = pressure(u, equations) + q_v = rho_vapour / rho_dry + q_l = (rho_cloud + rho_rain) / rho_dry + gamma_m = 1 + (R_d + R_v * q_v) / (c_vd + c_vv * q_v + c_l * q_l) -@inline function saturation_vapour_pressure(temperature, equations::CompressibleRainyEulerEquations2D) - # constants - c_l = equations.c_liquid_water - c_pv = equations.c_vapour_const_pressure - R_v = equations.R_vapour - ref_s_p = equations.ref_saturation_pressure - ref_temp = equations.ref_temperature - ref_L = equations.ref_latent_heat_vap_temp + if (rho_inv < 0.0) + error("rho less than zero") + elseif (p < 0.0) + error("pressure less than zero") + end + + v_sound = sqrt(gamma_m * p * rho_inv) - # testing - if (temperature < 0.0) - display(temperature) - error("temp less than zero") + return SVector(v_sound, gamma_m) end - # Clausius Clapeyron formula - p_vapour_saturation = ref_s_p * (temperature / ref_temp)^((c_pv - c_l) / R_v) - p_vapour_saturation *= exp(((ref_L - (c_pv - c_l) * ref_temp) / R_v) * (1 / ref_temp - 1 / temperature)) + @inline function terminal_velocity_rain(rho_moist, rho_rain, + equations::CompressibleRainyEulerEquations2D) + # constants + N_0 = equations.rain_water_distr + v_0 = equations.v_mean_rain + + # formula ( \Gamma(4.5) / 6 ~= 1.9386213994279082 ) + if (rho_rain > 0.0) + v_terminal_rain = v_0 * 1.9386213994279082 * + (rho_rain / (pi * (rho_moist + rho_rain) * N_0))^(0.125) + else + v_terminal_rain = 0.0 + end - return p_vapour_saturation -end + return v_terminal_rain + end + @inline function saturation_vapour_pressure(temperature, + equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_pv = equations.c_vapour_const_pressure + R_v = equations.R_vapour + ref_s_p = equations.ref_saturation_pressure + ref_temp = equations.ref_temperature + ref_L = equations.ref_latent_heat_vap_temp + + # testing + if (temperature < 0.0) + display(temperature) + error("temp less than zero") + end -@inline function saturation_vapour_pressure_derivative(temperature, equations::CompressibleRainyEulerEquations2D) - # constants - c_l = equations.c_liquid_water - c_pv = equations.c_vapour_const_pressure - R_v = equations.R_vapour - ref_s_p = equations.ref_saturation_pressure - ref_temp = equations.ref_temperature - ref_L = equations.ref_latent_heat_vap_temp + # Clausius Clapeyron formula + p_vapour_saturation = ref_s_p * (temperature / ref_temp)^((c_pv - c_l) / R_v) + p_vapour_saturation *= exp(((ref_L - (c_pv - c_l) * ref_temp) / R_v) * + (1 / ref_temp - 1 / temperature)) - # testing - if (temperature < 0.0) - display(temperature) - error("temp less than zero") + return p_vapour_saturation end - const_1 = (c_pv - c_l) / R_v - const_2 = (ref_L - (c_pv - c_l) * ref_temp) / R_v + @inline function saturation_vapour_pressure_derivative(temperature, + equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_pv = equations.c_vapour_const_pressure + R_v = equations.R_vapour + ref_s_p = equations.ref_saturation_pressure + ref_temp = equations.ref_temperature + ref_L = equations.ref_latent_heat_vap_temp + + # testing + if (temperature < 0.0) + display(temperature) + error("temp less than zero") + end - p_vapour_saturation_derivative = ref_s_p / (ref_temp^const_1) - p_vapour_saturation_derivative *= (const_1 * temperature^(const_1 - 1) + const_2 * temperature^(const_1 - 2)) - p_vapour_saturation_derivative *= exp(const_2 * (1 / ref_temp - 1 / temperature)) + const_1 = (c_pv - c_l) / R_v + const_2 = (ref_L - (c_pv - c_l) * ref_temp) / R_v - return p_vapour_saturation_derivative -end + p_vapour_saturation_derivative = ref_s_p / (ref_temp^const_1) + p_vapour_saturation_derivative *= (const_1 * temperature^(const_1 - 1) + + const_2 * temperature^(const_1 - 2)) + p_vapour_saturation_derivative *= exp(const_2 * (1 / ref_temp - 1 / temperature)) + return p_vapour_saturation_derivative + end + ### pde discretization ### -### pde discretization ### + @inline function flux(u, orientation::Integer, + equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water -@inline function flux(u, orientation::Integer, equations::CompressibleRainyEulerEquations2D) - # constants - c_l = equations.c_liquid_water + #densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - #densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + # recover rho_vapour, rho_cloud, temperature from nonlinear system + _, _, temperature = cons2nonlinearsystemsol(u, equations) - # recover rho_vapour, rho_cloud, temperature from nonlinear system - _, _, temperature = cons2nonlinearsystemsol(u, equations) + # velocity + v1, v2 = velocities(u, rho_inv, equations) + v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) - # velocity - v1, v2 = velocities(u, rho_inv, equations) - v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) + # pressure + p = pressure(u, equations) - # pressure - p = pressure(u, equations) + # energy density + energy = energy_density(u, equations) - # energy density - energy = energy_density(u, equations) + # flux for orientation cases + if (orientation == 1) + # "mass" + f1 = rho_dry * v1 + f2 = rho_moist * v1 + f3 = rho_rain * v1 - # flux for orientation cases - if (orientation == 1) - # "mass" - f1 = rho_dry * v1 - f2 = rho_moist * v1 - f3 = rho_rain * v1 + # "momentum" + f4 = rho * v1 * v1 + p + f5 = rho * v1 * v2 - # "momentum" - f4 = rho * v1 * v1 + p - f5 = rho * v1 * v2 + # "energy" + f6 = (energy + p) * v1 - # "energy" - f6 = (energy + p) * v1 + else + # "mass" + f1 = rho_dry * v2 + f2 = rho_moist * v2 + f3 = rho_rain * (v2 - v_r) - else - # "mass" - f1 = rho_dry * v2 - f2 = rho_moist * v2 - f3 = rho_rain * (v2 - v_r) + # "momentum" + f4 = rho * v1 * v2 - rho_rain * v_r * v1 + f5 = rho * v2 * v2 + p - rho_rain * v_r * v2 - # "momentum" - f4 = rho * v1 * v2 - rho_rain * v_r * v1 - f5 = rho * v2 * v2 + p - rho_rain * v_r * v2 + # "energy" + f6 = (energy + p) * v2 - + (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r + end - # "energy" - f6 = (energy + p) * v2 - (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r + return SVector(f1, f2, f3, f4, f5, f6, + 0.0, 0.0, 0.0) end - return SVector(f1, f2, f3, f4, f5, f6, - 0.0, 0.0, 0.0) -end + @inline function flux(u, normal_direction::AbstractVector, + equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) -@inline function flux(u, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) - # constants - c_l = equations.c_liquid_water + # recover rho_vapour, rho_cloud, temperature from nonlinear system + _, _, temperature = cons2nonlinearsystemsol(u, equations) - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + # velocity + v1, v2 = velocities(u, rho_inv, equations) + v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) - # recover rho_vapour, rho_cloud, temperature from nonlinear system - _, _, temperature = cons2nonlinearsystemsol(u, equations) + # normal velocities + v_normal = v1 * normal_direction[1] + v2 * normal_direction[2] + v_r_normal = v_r * normal_direction[2] - # velocity - v1, v2 = velocities(u, rho_inv, equations) - v_r = terminal_velocity_rain(rho_moist, rho_rain, equations) + # pressure + p = pressure(u, equations) - # normal velocities - v_normal = v1 * normal_direction[1] + v2 * normal_direction[2] - v_r_normal = v_r * normal_direction[2] + # energy density + energy = energy_density(u, equations) - # pressure - p = pressure(u, equations) - - # energy density - energy = energy_density(u, equations) - - # flux - # "mass" - f1 = rho_dry * v_normal - f2 = rho_moist * v_normal - f3 = rho_rain * (v_normal - v_r_normal) + # flux + # "mass" + f1 = rho_dry * v_normal + f2 = rho_moist * v_normal + f3 = rho_rain * (v_normal - v_r_normal) - # "momentum" - f4 = rho * v_normal * v1 + p * normal_direction[1] - rho_rain * v_r_normal * v1 - f5 = rho * v_normal * v2 + p * normal_direction[2] - rho_rain * v_r_normal * v2 + # "momentum" + f4 = rho * v_normal * v1 + p * normal_direction[1] - rho_rain * v_r_normal * v1 + f5 = rho * v_normal * v2 + p * normal_direction[2] - rho_rain * v_r_normal * v2 - # "energy" - f6 = (energy + p) * v_normal - (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r_normal + # "energy" + f6 = (energy + p) * v_normal - + (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r_normal - return SVector(f1, f2, f3, f4, f5, f6, - 0.0, 0.0, 0.0) -end + return SVector(f1, f2, f3, f4, f5, f6, + 0.0, 0.0, 0.0) + end + # no Coriolis term + @inline function source_terms_rainy(u, x, t, + equations::CompressibleRainyEulerEquations2D) + # constants + R_v = equations.R_vapour + ref_temp = equations.ref_temperature + g = equations.gravity -# no Coriolis term -@inline function source_terms_rainy(u, x, t, equations::CompressibleRainyEulerEquations2D) - # constants - R_v = equations.R_vapour - ref_temp = equations.ref_temperature - g = equations.gravity - - # name needed variables - rho_v2 = u[5] + # name needed variables + rho_v2 = u[5] - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - # recover rho_vapour, rho_cloud, temperature from nonlinear system - rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) + # recover rho_vapour, rho_cloud, temperature from nonlinear system + rho_vapour, rho_cloud, temperature = cons2nonlinearsystemsol(u, equations) - rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) - # source terms phase change - S_evaporation = (3.86e-3 - 9.41e-5 * (temperature - ref_temp)) * (1 + 9.1 * rho_rain^(0.1875)) - S_evaporation *= (rho_vs - rho_vapour) * rho_rain^(0.5) - S_auto_conversion = 0.001 * rho_cloud - S_accretion = 1.72 * rho_cloud * rho_rain^(0.875) - S_rain = S_auto_conversion + S_accretion - S_evaporation + # source terms phase change + S_evaporation = (3.86e-3 - 9.41e-5 * (temperature - ref_temp)) * + (1 + 9.1 * rho_rain^(0.1875)) + S_evaporation *= (rho_vs - rho_vapour) * rho_rain^(0.5) + S_auto_conversion = 0.001 * rho_cloud + S_accretion = 1.72 * rho_cloud * rho_rain^(0.875) + S_rain = S_auto_conversion + S_accretion - S_evaporation - return SVector(0.0, -S_rain, S_rain, 0.0, - -rho * g, -rho_v2 * g, 0.0, 0.0, 0.0) -end + return SVector(0.0, -S_rain, S_rain, 0.0, + -rho * g, -rho_v2 * g, 0.0, 0.0, 0.0) + end + # no phase changes and no Coriolis term + @inline function source_terms_no_phase_change(u, x, t, + equations::CompressibleRainyEulerEquations2D) + # constants + g = equations.gravity -# no phase changes and no Coriolis term -@inline function source_terms_no_phase_change(u, x, t, equations::CompressibleRainyEulerEquations2D) - # constants - g = equations.gravity - - # name needed variables - rho_v2 = u[5] + # name needed variables + rho_v2 = u[5] - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) - return SVector(0.0, 0.0, 0.0, 0.0, - -g * rho, -g * rho_v2, 0.0, 0.0, 0.0) -end + return SVector(0.0, 0.0, 0.0, 0.0, + -g * rho, -g * rho_v2, 0.0, 0.0, 0.0) + end + @inline function max_abs_speeds(u, equations::CompressibleRainyEulerEquations2D) + # name needed variables + v1, v2, v_sound, v_r = cons2speeds(u, equations) -@inline function max_abs_speeds(u, equations::CompressibleRainyEulerEquations2D) - # name needed variables - v1, v2, v_sound, v_r = cons2speeds(u, equations) + return SVector((abs(v1) + v_sound), (abs(v2) + v_sound + abs(v_r))) + end - return SVector((abs(v1) + v_sound), (abs(v2) + v_sound + abs(v_r))) -end + @inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleRainyEulerEquations2D) + # name needed variables + v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) + v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) + # calculate upper bounds for left and right speed + v_ll_max = abs(v1_ll * normal_direction[1] + v2_ll * normal_direction[2]) + v_ll_max += abs(v_r_ll * normal_direction[2]) -@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) - # name needed variables - v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) - v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) + v_rr_max = abs(v1_rr * normal_direction[1] + v2_rr * normal_direction[2]) + v_rr_max += abs(v_r_rr * normal_direction[2]) - # calculate upper bounds for left and right speed - v_ll_max = abs(v1_ll * normal_direction[1] + v2_ll * normal_direction[2]) - v_ll_max += abs( v_r_ll * normal_direction[2]) + return max(v_ll_max, v_rr_max) + + max(v_sound_ll, v_sound_rr) * norm(normal_direction) + end - v_rr_max = abs(v1_rr * normal_direction[1] + v2_rr * normal_direction[2]) - v_rr_max += abs( v_r_rr * normal_direction[2]) + @inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, + equations::CompressibleRainyEulerEquations2D) + # name needed variables + v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) + v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) + + if (orientation == 1) + v_ll = abs(v1_ll) + v_rr = abs(v1_rr) + else + v_ll = abs(v2_ll) + v_rr = abs(v2_rr) + end + # experimental + return max(v_ll, v_rr) + max(v_sound_ll, v_sound_rr) + max(abs(v_r_ll), abs(v_r_rr)) + end - return max(v_ll_max, v_rr_max) + max(v_sound_ll, v_sound_rr) * norm(normal_direction) -end + ### boundary conditions ### + + # adapted from compressible_moist_euler_2d.jl which was probably adapted from compressible_euler_2d.jl + @inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, + x, t, + surface_flux_function, + equations::CompressibleRainyEulerEquations2D) + norm_ = norm(normal_direction) + # Normalize the vector without using `normalize` since we need to multiply by the `norm_` later + normal = normal_direction / norm_ + + # rotate the internal solution state + u_local = rotate_to_x(u_inner, normal, equations) + + # name needed variables + rho_v1 = u_local[4] + + # densities + rho_dry_local, rho_moist_local, rho_rain_local, rho_local, rho_inv_local = densities(u_local, + equations) + + # velocities + v_normal = rho_v1 * rho_inv_local + v_sound, gamma = speed_of_sound(u_local, equations) + + # pressure + p_local = pressure(u_local, equations) + + # Get the solution of the pressure Riemann problem + # See Section 6.3.3 of + # Eleuterio F. Toro (2009) + # Riemann Solvers and Numerical Methods for Fluid Dynamics: A Practical Introduction + # [DOI: 10.1007/b79761](https://doi.org/10.1007/b79761) + if v_normal <= 0.0 + p_star = p_local * + (1.0 + 0.5 * (gamma - 1) * v_normal / v_sound)^(2.0 * gamma * + inv(gamma - 1)) + else # v_normal > 0.0 + A = 2.0 / ((gamma + 1) * rho_local) + B = p_local * (gamma - 1) / (gamma + 1) + p_star = p_local + + 0.5 * v_normal / A * + (v_normal + sqrt(v_normal^2 + 4.0 * A * (p_local + B))) + end + # For the slip wall we directly set the flux as the normal velocity is zero + return SVector(0.0, 0.0, 0.0, + p_star * normal[1] * norm_, + p_star * normal[2] * norm_, + 0.0, 0.0, 0.0, 0.0) + end -@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::CompressibleRainyEulerEquations2D) - # name needed variables - v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) - v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) + # same as in compressible_euler_2d.jl + @inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, + direction, x, t, + surface_flux_function, + equations::CompressibleRainyEulerEquations2D) + # flip sign of normal to make it outward pointing, then flip the sign of the normal flux back + # to be inward pointing on the -x and -y sides due to the orientation convention used by StructuredMesh + if isodd(direction) + boundary_flux = -boundary_condition_slip_wall(u_inner, -normal_direction, + x, t, surface_flux_function, + equations) + else + boundary_flux = boundary_condition_slip_wall(u_inner, normal_direction, + x, t, surface_flux_function, + equations) + end - if (orientation == 1) - v_ll = abs(v1_ll) - v_rr = abs(v1_rr) - else - v_ll = abs(v2_ll) - v_rr = abs(v2_rr) - end - # experimental - return max(v_ll, v_rr) + max(v_sound_ll, v_sound_rr) + max(abs(v_r_ll), abs(v_r_rr)) -end - - -### boundary conditions ### - -# adapted from compressible_moist_euler_2d.jl which was probably adapted from compressible_euler_2d.jl -@inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, x, t, - surface_flux_function, equations::CompressibleRainyEulerEquations2D) - - norm_ = norm(normal_direction) - # Normalize the vector without using `normalize` since we need to multiply by the `norm_` later - normal = normal_direction / norm_ - - # rotate the internal solution state - u_local = rotate_to_x(u_inner, normal, equations) - - # name needed variables - rho_v1 = u_local[4] - - # densities - rho_dry_local, rho_moist_local, rho_rain_local, rho_local, rho_inv_local = densities(u_local, equations) - - # velocities - v_normal = rho_v1 * rho_inv_local - v_sound, gamma = speed_of_sound(u_local, equations) - - # pressure - p_local = pressure(u_local, equations) - - # Get the solution of the pressure Riemann problem - # See Section 6.3.3 of - # Eleuterio F. Toro (2009) - # Riemann Solvers and Numerical Methods for Fluid Dynamics: A Practical Introduction - # [DOI: 10.1007/b79761](https://doi.org/10.1007/b79761) - if v_normal <= 0.0 - p_star = p_local * - (1.0 + 0.5 * (gamma - 1) * v_normal / v_sound)^(2.0 * gamma * - inv(gamma - 1)) - else # v_normal > 0.0 - A = 2.0 / ((gamma + 1) * rho_local) - B = p_local * (gamma - 1) / (gamma + 1) - p_star = p_local + - 0.5 * v_normal / A * - (v_normal + sqrt(v_normal^2 + 4.0 * A * (p_local + B))) + return boundary_flux end - # For the slip wall we directly set the flux as the normal velocity is zero - return SVector(0.0, 0.0, 0.0, - p_star * normal[1] * norm_, - p_star * normal[2] * norm_, - 0.0, 0.0, 0.0, 0.0) -end - - -# same as in compressible_euler_2d.jl -@inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, direction, x, t, - surface_flux_function, equations::CompressibleRainyEulerEquations2D) - # flip sign of normal to make it outward pointing, then flip the sign of the normal flux back - # to be inward pointing on the -x and -y sides due to the orientation convention used by StructuredMesh - if isodd(direction) - boundary_flux = -boundary_condition_slip_wall(u_inner, -normal_direction, - x, t, surface_flux_function, - equations) - else - boundary_flux = boundary_condition_slip_wall(u_inner, normal_direction, - x, t, surface_flux_function, - equations) + # same as in compressible_euler_2d.jl + @inline function rotate_to_x(u, normal_vector, + equations::CompressibleRainyEulerEquations2D) + # cos and sin of the angle between the x-axis and the normalized normal_vector are + # the normalized vector's x and y coordinates respectively (see unit circle). + c = normal_vector[1] + s = normal_vector[2] + + return SVector(u[1], u[2], u[3], + c * u[4] + s * u[5], + -s * u[4] + c * u[5], + u[6], u[7], u[8], u[9]) end - return boundary_flux -end - - -# same as in compressible_euler_2d.jl -@inline function rotate_to_x(u, normal_vector, equations::CompressibleRainyEulerEquations2D) - # cos and sin of the angle between the x-axis and the normalized normal_vector are - # the normalized vector's x and y coordinates respectively (see unit circle). - c = normal_vector[1] - s = normal_vector[2] - - return SVector(u[1], u[2], u[3], - c * u[4] + s * u[5], - -s * u[4] + c * u[5], - u[6], u[7], u[8], u[9]) -end - - -# should be used together with TreeMesh (adapted from compressible_euler_2d.jl) -@inline function boundary_condition_slip_wall(u_inner, orientation, direction, x, t, surface_flux_function, - equations::CompressibleRainyEulerEquations2D) - # get the appropriate normal vector from the orientation - RealT = eltype(u_inner) - if orientation == 1 - normal_direction = SVector(one(RealT), zero(RealT)) - else # orientation == 2 - normal_direction = SVector(zero(RealT), one(RealT)) - end + # should be used together with TreeMesh (adapted from compressible_euler_2d.jl) + @inline function boundary_condition_slip_wall(u_inner, orientation, direction, x, t, + surface_flux_function, + equations::CompressibleRainyEulerEquations2D) + # get the appropriate normal vector from the orientation + RealT = eltype(u_inner) + if orientation == 1 + normal_direction = SVector(one(RealT), zero(RealT)) + else # orientation == 2 + normal_direction = SVector(zero(RealT), one(RealT)) + end - # compute and return the flux using `boundary_condition_slip_wall` routine above - return boundary_condition_slip_wall(u_inner, normal_direction, direction, - x, t, surface_flux_function, equations) -end + # compute and return the flux using `boundary_condition_slip_wall` routine above + return boundary_condition_slip_wall(u_inner, normal_direction, direction, + x, t, surface_flux_function, equations) + end + # for parabolic terms (LaplaceDiffusion2D) + @inline function boundary_condition_laplace(flux_inner, u_inner, normal::AbstractVector, + x, t, operator_type::Trixi.Gradient, + equations_parabolic::LaplaceDiffusion2D) + return u_inner + end -# for parabolic terms (LaplaceDiffusion2D) -@inline function boundary_condition_laplace(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Trixi.Gradient, - equations_parabolic::LaplaceDiffusion2D) - return u_inner -end + @inline function boundary_condition_laplace(flux_inner, u_inner, normal::AbstractVector, + x, t, operator_type::Trixi.Divergence, + equations_parabolic::LaplaceDiffusion2D) + return flux_inner + end -@inline function boundary_condition_laplace(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Trixi.Divergence, - equations_parabolic::LaplaceDiffusion2D) - return flux_inner -end + ### Nonlinear System Residual ### + # in preparation for a callback to solve the nonlinear system + @inline function saturation_residual(u, guess, + equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp -### Nonlinear System Residual ### + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) -# in preparation for a callback to solve the nonlinear system -@inline function saturation_residual(u, guess, equations::CompressibleRainyEulerEquations2D) - # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_v = equations.R_vapour - L_ref = equations.ref_latent_heat_vap_temp + # velocity + v1, v2 = velocities(u, rho_inv, equations) - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + # energy density + energy = energy_density(u, equations) - # velocity - v1, v2 = velocities(u, rho_inv, equations) + # define residual + residual1 = (c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain)) * + guess[3] + residual1 += guess[1] * L_ref + residual1 -= (energy - rho * 0.5 * (v1^2 + v2^2)) - # energy density - energy = energy_density(u, equations) + residual2 = min(saturation_vapour_pressure(guess[3], equations) / (R_v * guess[3]), + rho_moist) + residual2 -= guess[1] + residual2 *= 1e7 - # define residual - residual1 = (c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain)) * guess[3] - residual1 += guess[1] * L_ref - residual1 -= (energy - rho * 0.5 * (v1^2 + v2^2)) + residual3 = rho_moist + residual3 -= guess[1] + guess[2] + residual3 *= 1e7 - residual2 = min(saturation_vapour_pressure(guess[3], equations) / (R_v * guess[3]), rho_moist) - residual2 -= guess[1] - residual2 *= 1e7 + return SVector(residual1, residual2, residual3) + end - residual3 = rho_moist - residual3 -= guess[1] + guess[2] - residual3 *= 1e7 + @inline function saturation_residual_jacobian(u, guess, + equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp + + # densities + rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + + # saturation + svp = saturation_vapour_pressure(guess[3], equations) + svp_t = saturation_vapour_pressure_derivative(guess[3], equations) + + # define jacobian + J_11 = c_vv * guess[3] + L_ref + J_12 = c_l * guess[3] + J_13 = c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain) + + J_21 = -1e7 + J_22 = 0.0 + + if (svp / (R_v * guess[3]) < rho_moist) + J_23 = (svp_t * guess[3] - svp) / (R_v * guess[3]^2) * 1e7 + else + J_23 = 0.0 + end - return SVector(residual1, residual2, residual3) -end + J_31 = -1e7 + J_32 = -1e7 + J_33 = 0.0 + return SMatrix{3, 3}(J_11, J_21, J_31, J_12, J_22, J_32, J_13, J_23, J_33) + end + # Low Mach number approximate Riemann solver (LMARS) from + # X. Chen, N. Andronova, B. Van Leer, J. E. Penner, J. P. Boyd, C. Jablonowski, S. + # Lin, A Control-Volume Model of the Compressible Euler Equations with a Vertical Lagrangian + # Coordinate Monthly Weather Review Vol. 141.7, pages 2526–2544, 2013, + # https://journals.ametsoc.org/view/journals/mwre/141/7/mwr-d-12-00129.1.xml. + # adapted from compressible_moist_euler_2d.jl, does NOT work with rain! + @inline function flux_LMARS(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleRainyEulerEquations2D) + # constants + a = 360.0 + + # densities + rho_dry_ll, rho_moist_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, + equations) + rho_dry_rr, rho_moist_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, + equations) + + # pressure + p_ll = pressure(u_ll, equations) + p_rr = pressure(u_rr, equations) + + # velocities + v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) + v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) + + v_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] + v_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] + norm_ = norm(normal_direction) + + # diffusion parameter 0.0 < beta <= 1.0 + beta = 1.0 + + # interface flux components + rho = 0.5 * (rho_ll + rho_rr) + p_interface = 0.5 * (p_ll + p_rr) - beta * 0.5 * a * rho * (v_rr - v_ll) / norm_ + v_interface = 0.5 * (v_ll + v_rr) - beta * 1 / (2 * a * rho) * (p_rr - p_ll) * norm_ + + if (v_interface > 0) + f1, f2, _, f4, f5, f6, _, _, _ = u_ll * v_interface + f6 += p_ll * v_interface + else + f1, f2, _, f4, f5, f6, _, _, _ = u_rr * v_interface + f6 += p_rr * v_interface + end -@inline function saturation_residual_jacobian(u, guess, equations::CompressibleRainyEulerEquations2D) - # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_v = equations.R_vapour - L_ref = equations.ref_latent_heat_vap_temp + return SVector(f1, f2, 0.0, + f4 + p_interface * normal_direction[1], + f5 + p_interface * normal_direction[2], + f6, 0.0, 0.0, 0.0) + end - # densities - rho_dry, rho_moist, rho_rain, rho, rho_inv = densities(u, equations) + # Adjusted EC flux in a normal direction with R_q=0. This is based on + # A. Gouasmi, K. Duraisamy, S. M. Murman, Formulation of Entropy-Stable schemes for the + # multicomponent compressible Euler equations, 4 Feb 2020, doi:10.1016/j.cma.2020.112912, + # https://arxiv.org/abs/1904.00972 [math.NA]. + # Adapted from compressible_moist_euler_2d.jl, careful, does NOT work for rain! + @inline function flux_chandrashekar(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + ref_L = equations.ref_latent_heat_vap_temp + R_q = 0.0 + + # densities and temperatures + rho_dry_ll, rho_moist_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, + equations) + rho_dry_rr, rho_moist_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, + equations) + rho_vapour_ll, rho_cloud_ll, temperature_ll = cons2nonlinearsystemsol(u_ll, + equations) + rho_vapour_rr, rho_cloud_rr, temperature_rr = cons2nonlinearsystemsol(u_rr, + equations) + + # velocities + v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) + v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) + vr_ll = terminal_velocity_rain(rho_moist_ll, rho_rain_ll, equations) + vr_rr = terminal_velocity_rain(rho_moist_rr, rho_rain_rr, equations) + + # mean values + rho_dry_mean = 0.0 + rho_vapour_mean = 0.0 + rho_cloud_mean = 0.0 + rho_rain_mean = 0.0 + inv_temperature_mean = 0.0 + + if (!(rho_dry_ll == 0.0) && !(rho_dry_rr == 0.0)) + rho_dry_mean = ln_mean(rho_dry_ll, rho_dry_rr) + end - # saturation - svp = saturation_vapour_pressure(guess[3], equations) - svp_t = saturation_vapour_pressure_derivative(guess[3], equations) + if (!(rho_vapour_ll == 0.0) && !(rho_vapour_rr == 0.0)) + rho_vapour_mean = ln_mean(rho_vapour_ll, rho_vapour_rr) + end - # define jacobian - J_11 = c_vv * guess[3] + L_ref - J_12 = c_l * guess[3] - J_13 = c_vd * rho_dry + c_vv * guess[1] + c_l * (guess[2] + rho_rain) + if (!(rho_cloud_ll == 0.0) && !(rho_cloud_rr == 0.0)) + rho_cloud_mean = ln_mean(rho_cloud_ll, rho_cloud_rr) + end - J_21 = -1e7 - J_22 = 0.0 - - if (svp / (R_v * guess[3]) < rho_moist) - J_23 = (svp_t * guess[3] - svp) / (R_v * guess[3]^2) * 1e7 - else - J_23 = 0.0 - end + if (!(rho_rain_ll == 0.0) && !(rho_rain_rr == 0.0)) + rho_rain_mean = ln_mean(rho_rain_ll, rho_rain_rr) + end - J_31 = -1e7 - J_32 = -1e7 - J_33 = 0.0 - - return SMatrix{3, 3}(J_11, J_21, J_31, J_12, J_22, J_32, J_13, J_23, J_33) -end - - -# Low Mach number approximate Riemann solver (LMARS) from -# X. Chen, N. Andronova, B. Van Leer, J. E. Penner, J. P. Boyd, C. Jablonowski, S. -# Lin, A Control-Volume Model of the Compressible Euler Equations with a Vertical Lagrangian -# Coordinate Monthly Weather Review Vol. 141.7, pages 2526–2544, 2013, -# https://journals.ametsoc.org/view/journals/mwre/141/7/mwr-d-12-00129.1.xml. -# adapted from compressible_moist_euler_2d.jl, does NOT work with rain! -@inline function flux_LMARS(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) - # constants - a = 360.0 - - # densities - rho_dry_ll, rho_moist_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) - rho_dry_rr, rho_moist_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) - - # pressure - p_ll = pressure(u_ll, equations) - p_rr = pressure(u_rr, equations) - - # velocities - v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) - v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) - - v_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] - v_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] - norm_ = norm(normal_direction) - - # diffusion parameter 0.0 < beta <= 1.0 - beta = 1.0 - - # interface flux components - rho = 0.5 * (rho_ll + rho_rr) - p_interface = 0.5 * (p_ll + p_rr) - beta * 0.5 * a * rho * (v_rr - v_ll) / norm_ - v_interface = 0.5 * (v_ll + v_rr) - beta * 1 / (2 * a * rho) * (p_rr - p_ll) * norm_ - - if (v_interface > 0) - f1, f2, _, f4, f5, f6, _, _, _ = u_ll * v_interface - f6 += p_ll * v_interface - else - f1, f2, _, f4, f5, f6, _, _, _ = u_rr * v_interface - f6 += p_rr * v_interface - end - - return SVector(f1, f2, 0.0, - f4 + p_interface * normal_direction[1], - f5 + p_interface * normal_direction[2], - f6, 0.0, 0.0, 0.0) -end - - -# Adjusted EC flux in a normal direction with R_q=0. This is based on -# A. Gouasmi, K. Duraisamy, S. M. Murman, Formulation of Entropy-Stable schemes for the -# multicomponent compressible Euler equations, 4 Feb 2020, doi:10.1016/j.cma.2020.112912, -# https://arxiv.org/abs/1904.00972 [math.NA]. -# Adapted from compressible_moist_euler_2d.jl, careful, does NOT work for rain! -@inline function flux_chandrashekar(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) - # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_d = equations.R_dry_air - R_v = equations.R_vapour - ref_L = equations.ref_latent_heat_vap_temp - R_q = 0.0 - - # densities and temperatures - rho_dry_ll, rho_moist_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) - rho_dry_rr, rho_moist_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) - rho_vapour_ll, rho_cloud_ll, temperature_ll = cons2nonlinearsystemsol(u_ll, equations) - rho_vapour_rr, rho_cloud_rr, temperature_rr = cons2nonlinearsystemsol(u_rr, equations) - - # velocities - v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) - v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) - vr_ll = terminal_velocity_rain(rho_moist_ll, rho_rain_ll, equations) - vr_rr = terminal_velocity_rain(rho_moist_rr, rho_rain_rr, equations) - - # mean values - rho_dry_mean = 0.0 - rho_vapour_mean = 0.0 - rho_cloud_mean = 0.0 - rho_rain_mean = 0.0 - inv_temperature_mean = 0.0 - - if (!(rho_dry_ll == 0.0) && !(rho_dry_rr == 0.0)) - rho_dry_mean = ln_mean(rho_dry_ll, rho_dry_rr) - end + if (!(inv(temperature_ll) == 0.0) && !(inv(temperature_rr) == 0.0)) + inv_temperature_mean = inv_ln_mean(inv(temperature_ll), inv(temperature_rr)) + end - if (!(rho_vapour_ll == 0.0) && !(rho_vapour_rr == 0.0)) - rho_vapour_mean = ln_mean(rho_vapour_ll, rho_vapour_rr) + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) + v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) + rho_dry_avg = 0.5 * (rho_dry_ll + rho_dry_rr) + rho_vapour_avg = 0.5 * (rho_vapour_ll + rho_vapour_rr) + rho_cloud_avg = 0.5 * (rho_cloud_ll + rho_cloud_rr) + rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) + inv_temperature_avg = 0.5 * (inv(temperature_ll) + inv(temperature_rr)) + v_dot_n_avg = normal_direction[1] * v1_avg + normal_direction[2] * v2_avg + + p_int = inv(inv_temperature_avg) * (R_d * rho_dry_avg + R_v * rho_vapour_avg + + R_q * (rho_cloud_avg + rho_rain_avg)) + K_avg = 0.5 * (v1_square_avg + v2_square_avg) + vr_normal_avg = 0.5 * normal_direction[2] * (vr_ll + vr_rr) + rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) + + # assemble the flux + f_dry = rho_dry_mean * v_dot_n_avg + f_rain = rho_rain_avg * (v_dot_n_avg - vr_normal_avg) + f_vapour = rho_vapour_mean * v_dot_n_avg + f_cloud = rho_cloud_mean * v_dot_n_avg + f_moist = (rho_vapour_mean + rho_cloud_mean) * v_dot_n_avg + f_rhov1 = (f_dry + f_moist + f_rain) * v1_avg + normal_direction[1] * p_int + f_rhov2 = (f_dry + f_moist + f_rain) * v2_avg + normal_direction[2] * p_int + f_energy = ((c_vd * inv_temperature_mean - K_avg) * f_dry + + (ref_L + c_vv * inv_temperature_mean - K_avg) * f_vapour + + (c_l * inv_temperature_mean - K_avg) * (f_cloud + f_rain) + + v1_avg * f_rhov1 + v2_avg * f_rhov2) + + return SVector(f_dry, f_moist, f_rain, f_rhov1, f_rhov2, f_energy, 0.0, 0.0, 0.0) end - if (!(rho_cloud_ll == 0.0) && !(rho_cloud_rr == 0.0)) - rho_cloud_mean = ln_mean(rho_cloud_ll, rho_cloud_rr) + @inline function flux_chandrashekar(u_ll, u_rr, orientation::Int, + equations::CompressibleRainyEulerEquations2D) + if (orientation == 1) + return flux_chandrashekar(u_ll, u_rr, SVector(1, 0), equations) + else + return flux_chandrashekar(u_ll, u_rr, SVector(0, 1), equations) + end end - if (!(rho_rain_ll == 0.0) && !(rho_rain_rr == 0.0)) - rho_rain_mean = ln_mean(rho_rain_ll, rho_rain_rr) - end + @inline function flux_ec_rain(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleRainyEulerEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp + + # densities and temperatures + rho_dry_ll, rho_moist_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, + equations) + rho_dry_rr, rho_moist_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, + equations) + rho_vapour_ll, rho_cloud_ll, temperature_ll = cons2nonlinearsystemsol(u_ll, + equations) + rho_vapour_rr, rho_cloud_rr, temperature_rr = cons2nonlinearsystemsol(u_rr, + equations) + inv_temperature_ll = inv(temperature_ll) + inv_temperature_rr = inv(temperature_rr) + + # velocities + v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) + v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) + vr_ll = terminal_velocity_rain(rho_vapour_ll + rho_cloud_ll, rho_rain_ll, equations) + vr_rr = terminal_velocity_rain(rho_vapour_rr + rho_cloud_rr, rho_rain_rr, equations) + + # velocity averages + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) + v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) + K_avg = 0.5 * (v1_square_avg + v2_square_avg) + v_dot_n_avg = normal_direction[1] * v1_avg + normal_direction[2] * v2_avg + vr_normal_avg = 0.5 * normal_direction[2] * (vr_ll + vr_rr) + + # density averages + rho_dry_avg = 0.5 * (rho_dry_ll + rho_dry_rr) + rho_vapour_avg = 0.5 * (rho_vapour_ll + rho_vapour_rr) + rho_cloud_avg = 0.5 * (rho_cloud_ll + rho_cloud_rr) + rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) + + # density log means + rho_dry_log = 0.0 + rho_vapour_log = 0.0 + rho_cloud_log = 0.0 + rho_rain_log = 0.0 + + if (!(rho_dry_ll == 0.0) && !(rho_dry_rr == 0.0)) + rho_dry_log = ln_mean(rho_dry_ll, rho_dry_rr) + end - if (!(inv(temperature_ll) == 0.0) && !(inv(temperature_rr) == 0.0)) - inv_temperature_mean = inv_ln_mean(inv(temperature_ll), inv(temperature_rr)) - end - - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) - v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) - rho_dry_avg = 0.5 * (rho_dry_ll + rho_dry_rr) - rho_vapour_avg = 0.5 * (rho_vapour_ll + rho_vapour_rr) - rho_cloud_avg = 0.5 * (rho_cloud_ll + rho_cloud_rr) - rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) - inv_temperature_avg = 0.5 * (inv(temperature_ll) + inv(temperature_rr)) - v_dot_n_avg = normal_direction[1] * v1_avg + normal_direction[2] * v2_avg - - p_int = inv(inv_temperature_avg) * (R_d * rho_dry_avg + R_v * rho_vapour_avg + R_q * (rho_cloud_avg + rho_rain_avg)) - K_avg = 0.5 * (v1_square_avg + v2_square_avg) - vr_normal_avg = 0.5 * normal_direction[2] * (vr_ll + vr_rr) - rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) - - # assemble the flux - f_dry = rho_dry_mean * v_dot_n_avg - f_rain = rho_rain_avg * (v_dot_n_avg - vr_normal_avg) - f_vapour = rho_vapour_mean * v_dot_n_avg - f_cloud = rho_cloud_mean * v_dot_n_avg - f_moist = (rho_vapour_mean + rho_cloud_mean) * v_dot_n_avg - f_rhov1 = (f_dry + f_moist + f_rain) * v1_avg + normal_direction[1] * p_int - f_rhov2 = (f_dry + f_moist + f_rain) * v2_avg + normal_direction[2] * p_int - f_energy = (( c_vd * inv_temperature_mean - K_avg) * f_dry + - (ref_L + c_vv * inv_temperature_mean - K_avg) * f_vapour + - ( c_l * inv_temperature_mean - K_avg) * (f_cloud + f_rain) + v1_avg * f_rhov1 + v2_avg * f_rhov2) - - return SVector(f_dry, f_moist, f_rain, f_rhov1, f_rhov2, f_energy, 0.0, 0.0, 0.0) -end - -@inline function flux_chandrashekar(u_ll, u_rr, orientation::Int, equations::CompressibleRainyEulerEquations2D) - if (orientation == 1) - return flux_chandrashekar(u_ll, u_rr, SVector(1, 0), equations) - else - return flux_chandrashekar(u_ll, u_rr, SVector(0, 1), equations) - end -end - - -@inline function flux_ec_rain(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerEquations2D) - # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_d = equations.R_dry_air - R_v = equations.R_vapour - L_ref = equations.ref_latent_heat_vap_temp - - # densities and temperatures - rho_dry_ll, rho_moist_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) - rho_dry_rr, rho_moist_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) - rho_vapour_ll, rho_cloud_ll, temperature_ll = cons2nonlinearsystemsol(u_ll, equations) - rho_vapour_rr, rho_cloud_rr, temperature_rr = cons2nonlinearsystemsol(u_rr, equations) - inv_temperature_ll = inv(temperature_ll) - inv_temperature_rr = inv(temperature_rr) - - # velocities - v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) - v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) - vr_ll = terminal_velocity_rain(rho_vapour_ll + rho_cloud_ll, rho_rain_ll, equations) - vr_rr = terminal_velocity_rain(rho_vapour_rr + rho_cloud_rr, rho_rain_rr, equations) - - # velocity averages - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) - v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) - K_avg = 0.5 * (v1_square_avg + v2_square_avg) - v_dot_n_avg = normal_direction[1] * v1_avg + normal_direction[2] * v2_avg - vr_normal_avg = 0.5 * normal_direction[2] * (vr_ll + vr_rr) - - # density averages - rho_dry_avg = 0.5 * (rho_dry_ll + rho_dry_rr) - rho_vapour_avg = 0.5 * (rho_vapour_ll + rho_vapour_rr) - rho_cloud_avg = 0.5 * (rho_cloud_ll + rho_cloud_rr) - rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) - - # density log means - rho_dry_log = 0.0 - rho_vapour_log = 0.0 - rho_cloud_log = 0.0 - rho_rain_log = 0.0 - - if (!(rho_dry_ll == 0.0) && !(rho_dry_rr == 0.0)) - rho_dry_log = ln_mean(rho_dry_ll, rho_dry_rr) - end + if (!(rho_vapour_ll == 0.0) && !(rho_vapour_rr == 0.0)) + rho_vapour_log = ln_mean(rho_vapour_ll, rho_vapour_rr) + end - if (!(rho_vapour_ll == 0.0) && !(rho_vapour_rr == 0.0)) - rho_vapour_log = ln_mean(rho_vapour_ll, rho_vapour_rr) - end + if (!(rho_cloud_ll == 0.0) && !(rho_cloud_rr == 0.0)) + rho_cloud_log = ln_mean(rho_cloud_ll, rho_cloud_rr) + end - if (!(rho_cloud_ll == 0.0) && !(rho_cloud_rr == 0.0)) - rho_cloud_log = ln_mean(rho_cloud_ll, rho_cloud_rr) - end + if (!(rho_rain_ll == 0.0) && !(rho_rain_rr == 0.0)) + rho_rain_log = ln_mean(rho_rain_ll, rho_rain_rr) + end - if (!(rho_rain_ll == 0.0) && !(rho_rain_rr == 0.0)) - rho_rain_log = ln_mean(rho_rain_ll, rho_rain_rr) + # other averages + inv_temperature_avg = 0.5 * (inv_temperature_ll + inv_temperature_rr) + inv_temperature_log = inv_ln_mean(inv_temperature_ll, inv_temperature_rr) + p_int = inv(inv_temperature_avg) * (R_d * rho_dry_avg + R_v * rho_vapour_avg) + + # density flux + f_vapour = rho_vapour_log * v_dot_n_avg + f_cloud = rho_cloud_avg * v_dot_n_avg + f_dry = rho_dry_log * v_dot_n_avg + f_rain = rho_rain_avg * (v_dot_n_avg - vr_normal_avg) + f_moist = f_vapour + f_cloud + f_rho = f_dry + f_moist + f_rain + + # momentum flux + f_rhov1 = f_rho * v1_avg + p_int * normal_direction[1] + f_rhov2 = f_rho * v2_avg + p_int * normal_direction[2] + + # energy flux + f_energy = (c_vd * inv_temperature_log - K_avg) * f_dry + + (c_vv * inv_temperature_log - K_avg + L_ref) * f_vapour + + (c_l * inv_temperature_log - K_avg) * (f_cloud + f_rain) + + (v1_avg * f_rhov1 + v2_avg * f_rhov2) + + return SVector(f_dry, f_moist, f_rain, f_rhov1, f_rhov2, f_energy, 0.0, 0.0, 0.0) end - # other averages - inv_temperature_avg = 0.5 * (inv_temperature_ll + inv_temperature_rr) - inv_temperature_log = inv_ln_mean(inv_temperature_ll, inv_temperature_rr) - p_int = inv(inv_temperature_avg) * (R_d * rho_dry_avg + R_v * rho_vapour_avg) - - # density flux - f_vapour = rho_vapour_log * v_dot_n_avg - f_cloud = rho_cloud_avg * v_dot_n_avg - f_dry = rho_dry_log * v_dot_n_avg - f_rain = rho_rain_avg * (v_dot_n_avg - vr_normal_avg) - f_moist = f_vapour + f_cloud - f_rho = f_dry + f_moist + f_rain - - # momentum flux - f_rhov1 = f_rho * v1_avg + p_int * normal_direction[1] - f_rhov2 = f_rho * v2_avg + p_int * normal_direction[2] - - # energy flux - f_energy = (c_vd * inv_temperature_log - K_avg) * f_dry + (c_vv * inv_temperature_log - K_avg + L_ref) * f_vapour + - (c_l * inv_temperature_log - K_avg) * (f_cloud + f_rain) + (v1_avg * f_rhov1 + v2_avg * f_rhov2) - - return SVector(f_dry, f_moist, f_rain, f_rhov1, f_rhov2, f_energy, 0.0, 0.0, 0.0) -end - -@inline function flux_ec_rain(u_ll, u_rr, orientation::Int, equations::CompressibleRainyEulerEquations2D) - if (orientation == 1) - return flux_ec_rain(u_ll, u_rr, SVector(1, 0), equations) - else - return flux_ec_rain(u_ll, u_rr, SVector(0, 1), equations) + @inline function flux_ec_rain(u_ll, u_rr, orientation::Int, + equations::CompressibleRainyEulerEquations2D) + if (orientation == 1) + return flux_ec_rain(u_ll, u_rr, SVector(1, 0), equations) + else + return flux_ec_rain(u_ll, u_rr, SVector(0, 1), equations) + end end -end - - - -# adapted from ShallowWaterEquations2D (Recommended with rain!) -@inline function boundary_condition_simple_slip_wall(u_inner, normal_direction::AbstractVector, x, t, surface_flux_function, - equations::CompressibleRainyEulerEquations2D) - # normalize the outward pointing direction - normal = normal_direction / norm(normal_direction) - - # compute the normal velocity - u_normal = normal[1] * u_inner[4] + normal[2] * u_inner[5] - # create the "external" boundary solution state - u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], - u_inner[4] - 2 * u_normal * normal[1], - u_inner[5] - 2 * u_normal * normal[2], - u_inner[6], u_inner[7], u_inner[8], u_inner[9]) + # adapted from ShallowWaterEquations2D (Recommended with rain!) + @inline function boundary_condition_simple_slip_wall(u_inner, + normal_direction::AbstractVector, + x, t, surface_flux_function, + equations::CompressibleRainyEulerEquations2D) + # normalize the outward pointing direction + normal = normal_direction / norm(normal_direction) - # calculate the boundary flux - flux = surface_flux_function(u_inner, u_boundary, normal_direction, equations) + # compute the normal velocity + u_normal = normal[1] * u_inner[4] + normal[2] * u_inner[5] - return flux -end + # create the "external" boundary solution state + u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], + u_inner[4] - 2 * u_normal * normal[1], + u_inner[5] - 2 * u_normal * normal[2], + u_inner[6], u_inner[7], u_inner[8], u_inner[9]) + # calculate the boundary flux + flux = surface_flux_function(u_inner, u_boundary, normal_direction, equations) -# adapted from ShallowWaterEquations2D (Recommended with rain!) -@inline function boundary_condition_simple_slip_wall(u_inner, orientation, direction, x, t, surface_flux_function, - equations::CompressibleRainyEulerEquations2D) - ## get the appropriate normal vector from the orientation - if orientation == 1 - u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], -u_inner[4], u_inner[5], u_inner[6], u_inner[7], u_inner[8], u_inner[9]) - else # orientation == 2 - u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], u_inner[4], -u_inner[5], u_inner[6], u_inner[7], u_inner[8], u_inner[9]) + return flux end - # Calculate boundary flux - if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary - flux = surface_flux_function(u_inner, u_boundary, orientation, equations) - else # u_boundary is "left" of boundary, u_inner is "right" of boundary - flux = surface_flux_function(u_boundary, u_inner, orientation, equations) - end - - return flux -end - + # adapted from ShallowWaterEquations2D (Recommended with rain!) + @inline function boundary_condition_simple_slip_wall(u_inner, orientation, direction, x, + t, surface_flux_function, + equations::CompressibleRainyEulerEquations2D) + ## get the appropriate normal vector from the orientation + if orientation == 1 + u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], -u_inner[4], + u_inner[5], u_inner[6], u_inner[7], u_inner[8], u_inner[9]) + else # orientation == 2 + u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], u_inner[4], + -u_inner[5], u_inner[6], u_inner[7], u_inner[8], + u_inner[9]) + end + # Calculate boundary flux + if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary + flux = surface_flux_function(u_inner, u_boundary, orientation, equations) + else # u_boundary is "left" of boundary, u_inner is "right" of boundary + flux = surface_flux_function(u_boundary, u_inner, orientation, equations) + end -end # muladd end \ No newline at end of file + return flux + end +end # muladd end diff --git a/src/equations/compressible_rainy_euler_explicit_2d.jl b/src/equations/compressible_rainy_euler_explicit_2d.jl index d725597e..8a3214f2 100644 --- a/src/equations/compressible_rainy_euler_explicit_2d.jl +++ b/src/equations/compressible_rainy_euler_explicit_2d.jl @@ -1,12 +1,10 @@ using Trixi using NLsolve: nlsolve -import Trixi: varnames, - cons2prim, cons2entropy, - flux, flux_chandrashekar, - max_abs_speeds, max_abs_speed_naive, - boundary_condition_slip_wall, entropy - - +import Trixi: varnames, + cons2prim, cons2entropy, + flux, flux_chandrashekar, + max_abs_speeds, max_abs_speed_naive, + boundary_condition_slip_wall, entropy ### Implementation similar to: # Sabine Doppler, Philip L. Lederer, Joachim Schöberl, Henry von Wahl, @@ -17,1018 +15,1046 @@ import Trixi: varnames, # 112713, # ISSN 0021-9991 - - @muladd begin -### equation, parameters and constants ### - -struct CompressibleRainyEulerExplicitEquations2D{RealT <: Real} <: AbstractCompressibleRainyEulerEquations{2, 7} - # Specific heat capacities: - c_liquid_water ::RealT - c_dry_air_const_pressure ::RealT - c_dry_air_const_volume ::RealT - c_vapour_const_pressure ::RealT - c_vapour_const_volume ::RealT - - # Gas constants: - R_dry_air ::RealT - R_vapour ::RealT - eps ::RealT - - # Reference values: - ref_saturation_pressure ::RealT - ref_temperature ::RealT - ref_latent_heat_vap_temp ::RealT - ref_pressure ::RealT - - # Other: - gravity ::RealT - rain_water_distr ::RealT - v_mean_rain ::RealT -end - - -function CompressibleRainyEulerExplicitEquations2D(; RealT = Float64) - # Specific heat capacities: - c_liquid_water = 4186.0 - c_dry_air_const_pressure = 1004.0 - c_dry_air_const_volume = 717.0 - c_vapour_const_pressure = 1885.0 - c_vapour_const_volume = 1424.0 - - # Gas constants: - R_dry_air = c_dry_air_const_pressure - c_dry_air_const_volume - R_vapour = c_vapour_const_pressure - c_vapour_const_volume - eps = R_dry_air / R_vapour - - # Reference values: - ref_saturation_pressure = 610.7 # This needs to be adjusted if ref_temperature is changed! - ref_temperature = 273.15 - ref_latent_heat_vap_temp = 2.5e6#3147620.0 - ref_pressure = 1e5 - - # Other: - gravity = 9.81 - rain_water_distr = 8e6 - v_mean_rain = 130.0 - - return CompressibleRainyEulerExplicitEquations2D{RealT}(c_liquid_water, c_dry_air_const_pressure, c_dry_air_const_volume, - c_vapour_const_pressure, c_vapour_const_volume, R_dry_air, - R_vapour, eps, ref_saturation_pressure, ref_temperature, - ref_latent_heat_vap_temp, ref_pressure, gravity, - rain_water_distr, v_mean_rain) -end - - - -### conversion ### - -@inline function cons2prim(u, equations::CompressibleRainyEulerExplicitEquations2D) - # densities - rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) - - # velocity - v1, v2 = velocities(u, rho_inv, equations) - - # energy density - energy = energy_density(u, equations) - - return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, v1, v2, energy) -end - - -# converts consverved to entropy variables -@inline function cons2entropy(u, equations::CompressibleRainyEulerExplicitEquations2D) - # constants - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - c_l = equations.c_liquid_water - R_d = equations.R_dry_air - R_v = equations.R_vapour - L_ref = equations.ref_latent_heat_vap_temp - - # densities - rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) - - # nonlinear system - temperature = get_temperature(u, equations) - ln_temperature = log(temperature) - inv_temperature = inv(temperature) - - # velocity - v1, v2 = velocities(u, rho_inv, equations) - v_squared_temp = 0.5 * (v1^2 + v2^2) * inv_temperature - - # check for zero density - rho_vapour_log = 0.0 - - if (rho_vapour > 0.0) - rho_vapour_log = log(rho_vapour) + ### equation, parameters and constants ### + + struct CompressibleRainyEulerExplicitEquations2D{RealT <: Real} <: + AbstractCompressibleRainyEulerEquations{2, 7} + # Specific heat capacities: + c_liquid_water :: RealT + c_dry_air_const_pressure :: RealT + c_dry_air_const_volume :: RealT + c_vapour_const_pressure :: RealT + c_vapour_const_volume :: RealT + + # Gas constants: + R_dry_air :: RealT + R_vapour :: RealT + eps :: RealT + + # Reference values: + ref_saturation_pressure :: RealT + ref_temperature :: RealT + ref_latent_heat_vap_temp :: RealT + ref_pressure :: RealT + + # Other: + gravity :: RealT + rain_water_distr :: RealT + v_mean_rain :: RealT end - omega_dry = c_vd * ln_temperature - R_d * log(rho_dry) + v_squared_temp - c_vd - R_d - omega_vapour = c_vv * ln_temperature - R_v * rho_vapour_log + v_squared_temp - c_vv - R_v - L_ref * inv_temperature - omega_liquid = c_l * ln_temperature + v_squared_temp - c_l - omega_momentum_1 = -v1 * inv_temperature - omega_momentum_2 = -v2 * inv_temperature - omega_energy = inv_temperature - - return SVector(omega_dry, omega_vapour, omega_liquid, omega_liquid, - omega_momentum_1, omega_momentum_2, omega_energy) -end - - -# adapted from compressible_moist_euler_2d.jl -@inline function cons2eq_pot_temp(u, equations::CompressibleRainyEulerExplicitEquations2D) - # constants - c_l = equations.c_liquid_water - c_pd = equations.c_dry_air_const_pressure - c_pv = equations.c_vapour_const_pressure - R_d = equations.R_dry_air - R_v = equations.R_vapour - ref_p = equations.ref_pressure - ref_temp = equations.ref_temperature - ref_L = equations.ref_latent_heat_vap_temp - - # densities - rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) - - # velocity - v1, v2 = velocities(u, rho_inv, equations) - - # nonlinear system - temperature = get_temperature(u, equations) - - # pressure - p = pressure(u, equations) - - p_v = rho_vapour * R_v * temperature - p_d = p - p_v - p_vs = saturation_vapour_pressure(temperature, equations) - H = p_v / p_vs - r_v = rho_vapour / rho_dry - r_c = rho_cloud / rho_dry - r_r = rho_rain / rho_dry - L_v = ref_L + (c_pv - c_l) * temperature - c_p = c_pd + (r_v + r_c + r_r) * c_l - - # equivalent potential temperature - eq_pot = (temperature * (ref_p / p_d)^(R_d / c_p) * H^(-r_v * R_v / c_p) * - exp(L_v * r_v * inv(c_p * temperature))) - - return SVector(rho, rho_vapour, rho_cloud, rho_rain, v1, v2, eq_pot, rho) -end - - -# for convenience TODO rename -@inline function cons2speeds(u, equations::CompressibleRainyEulerExplicitEquations2D) - # densities - rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) - - # velocity - v1, v2 = velocities(u, rho_inv, equations) - - # get speed of sound - v_sound = speed_of_sound(u, equations)[1] - - # get terminal velocity rain - v_r = terminal_velocity_rain(rho_vapour + rho_cloud, rho_rain, equations) - - return SVector(v1, v2, v_sound, v_r) -end - - - -### varnames ### - -varnames(::typeof(cons2cons), ::CompressibleRainyEulerExplicitEquations2D) = ("rho_dry", "rho_vapour", "rho_cloud", "rho_rain", - "rho_v1", "rho_v2", - "energy_density") + function CompressibleRainyEulerExplicitEquations2D(; RealT = Float64) + # Specific heat capacities: + c_liquid_water = 4186.0 + c_dry_air_const_pressure = 1004.0 + c_dry_air_const_volume = 717.0 + c_vapour_const_pressure = 1885.0 + c_vapour_const_volume = 1424.0 + + # Gas constants: + R_dry_air = c_dry_air_const_pressure - c_dry_air_const_volume + R_vapour = c_vapour_const_pressure - c_vapour_const_volume + eps = R_dry_air / R_vapour + + # Reference values: + ref_saturation_pressure = 610.7 # This needs to be adjusted if ref_temperature is changed! + ref_temperature = 273.15 + ref_latent_heat_vap_temp = 2.5e6#3147620.0 + ref_pressure = 1e5 + + # Other: + gravity = 9.81 + rain_water_distr = 8e6 + v_mean_rain = 130.0 + + return CompressibleRainyEulerExplicitEquations2D{RealT}(c_liquid_water, + c_dry_air_const_pressure, + c_dry_air_const_volume, + c_vapour_const_pressure, + c_vapour_const_volume, + R_dry_air, + R_vapour, eps, + ref_saturation_pressure, + ref_temperature, + ref_latent_heat_vap_temp, + ref_pressure, gravity, + rain_water_distr, + v_mean_rain) + end + ### conversion ### -varnames(::typeof(cons2prim), ::CompressibleRainyEulerExplicitEquations2D) = ("rho_dry", "rho_vapour", "rho_cloud", "rho_rain", - "v1", "v2", - "energy_density") + @inline function cons2prim(u, equations::CompressibleRainyEulerExplicitEquations2D) + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) -varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerExplicitEquations2D) = ("rho_dry", "rho_vapour", - "rho_cloud", "rho_rain", - "v1", "v2", "eq_pot_temp", - "rho") + # velocity + v1, v2 = velocities(u, rho_inv, equations) + # energy density + energy = energy_density(u, equations) + return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, v1, v2, energy) + end -### physics variables ### + # converts consverved to entropy variables + @inline function cons2entropy(u, equations::CompressibleRainyEulerExplicitEquations2D) + # constants + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + c_l = equations.c_liquid_water + R_d = equations.R_dry_air + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp + + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + + # nonlinear system + temperature = get_temperature(u, equations) + ln_temperature = log(temperature) + inv_temperature = inv(temperature) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + v_squared_temp = 0.5 * (v1^2 + v2^2) * inv_temperature + + # check for zero density + rho_vapour_log = 0.0 + + if (rho_vapour > 0.0) + rho_vapour_log = log(rho_vapour) + end + + omega_dry = c_vd * ln_temperature - R_d * log(rho_dry) + v_squared_temp - c_vd - R_d + omega_vapour = c_vv * ln_temperature - R_v * rho_vapour_log + v_squared_temp - + c_vv - R_v - L_ref * inv_temperature + omega_liquid = c_l * ln_temperature + v_squared_temp - c_l + omega_momentum_1 = -v1 * inv_temperature + omega_momentum_2 = -v2 * inv_temperature + omega_energy = inv_temperature + + return SVector(omega_dry, omega_vapour, omega_liquid, omega_liquid, + omega_momentum_1, omega_momentum_2, omega_energy) + end -@inline function densities(u, equations::CompressibleRainyEulerExplicitEquations2D) - # densities - rho_dry = u[1] - rho_vapour = u[2] - rho_cloud = u[3] - rho_rain = u[4] - rho = rho_dry + rho_vapour + rho_cloud + rho_rain - rho_inv = inv(rho) + # adapted from compressible_moist_euler_2d.jl + @inline function cons2eq_pot_temp(u, + equations::CompressibleRainyEulerExplicitEquations2D) + # constants + c_l = equations.c_liquid_water + c_pd = equations.c_dry_air_const_pressure + c_pv = equations.c_vapour_const_pressure + R_d = equations.R_dry_air + R_v = equations.R_vapour + ref_p = equations.ref_pressure + ref_temp = equations.ref_temperature + ref_L = equations.ref_latent_heat_vap_temp + + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + + # velocity + v1, v2 = velocities(u, rho_inv, equations) + + # nonlinear system + temperature = get_temperature(u, equations) + + # pressure + p = pressure(u, equations) + + p_v = rho_vapour * R_v * temperature + p_d = p - p_v + p_vs = saturation_vapour_pressure(temperature, equations) + H = p_v / p_vs + r_v = rho_vapour / rho_dry + r_c = rho_cloud / rho_dry + r_r = rho_rain / rho_dry + L_v = ref_L + (c_pv - c_l) * temperature + c_p = c_pd + (r_v + r_c + r_r) * c_l + + # equivalent potential temperature + eq_pot = (temperature * (ref_p / p_d)^(R_d / c_p) * H^(-r_v * R_v / c_p) * + exp(L_v * r_v * inv(c_p * temperature))) + + return SVector(rho, rho_vapour, rho_cloud, rho_rain, v1, v2, eq_pot, rho) + end - return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv) -end + # for convenience TODO rename + @inline function cons2speeds(u, equations::CompressibleRainyEulerExplicitEquations2D) + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) -@inline function rain_density(u, equations::CompressibleRainyEulerExplicitEquations2D) - return u[4] -end + # velocity + v1, v2 = velocities(u, rho_inv, equations) -@inline function velocities(u, rho_inv, equations::CompressibleRainyEulerExplicitEquations2D) - return SVector(u[5] * rho_inv, u[6] * rho_inv) -end + # get speed of sound + v_sound = speed_of_sound(u, equations)[1] + # get terminal velocity rain + v_r = terminal_velocity_rain(rho_vapour + rho_cloud, rho_rain, equations) -@inline function energy_density(u, equations::CompressibleRainyEulerExplicitEquations2D) - return u[7] -end + return SVector(v1, v2, v_sound, v_r) + end + ### varnames ### + + varnames(::typeof(cons2cons), ::CompressibleRainyEulerExplicitEquations2D) = ("rho_dry", + "rho_vapour", + "rho_cloud", + "rho_rain", + "rho_v1", + "rho_v2", + "energy_density") + + varnames(::typeof(cons2prim), ::CompressibleRainyEulerExplicitEquations2D) = ("rho_dry", + "rho_vapour", + "rho_cloud", + "rho_rain", + "v1", + "v2", + "energy_density") + + varnames(::typeof(cons2eq_pot_temp), ::CompressibleRainyEulerExplicitEquations2D) = ("rho_dry", + "rho_vapour", + "rho_cloud", + "rho_rain", + "v1", + "v2", + "eq_pot_temp", + "rho") + + ### physics variables ### + + @inline function densities(u, equations::CompressibleRainyEulerExplicitEquations2D) + # densities + rho_dry = u[1] + rho_vapour = u[2] + rho_cloud = u[3] + rho_rain = u[4] + rho = rho_dry + rho_vapour + rho_cloud + rho_rain + rho_inv = inv(rho) + + return SVector(rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv) + end -@inline function pressure(u, equations::CompressibleRainyEulerExplicitEquations2D) - # constants - R_d = equations.R_dry_air - R_v = equations.R_vapour + @inline function rain_density(u, equations::CompressibleRainyEulerExplicitEquations2D) + return u[4] + end - # densities - rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + @inline function velocities(u, rho_inv, + equations::CompressibleRainyEulerExplicitEquations2D) + return SVector(u[5] * rho_inv, u[6] * rho_inv) + end - temperature = get_temperature(u, equations) - - p = (R_d * rho_dry + R_v * rho_vapour) * temperature + @inline function energy_density(u, equations::CompressibleRainyEulerExplicitEquations2D) + return u[7] + end - return p -end + @inline function pressure(u, equations::CompressibleRainyEulerExplicitEquations2D) + # constants + R_d = equations.R_dry_air + R_v = equations.R_vapour + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) -@inline function speed_of_sound(u, equations::CompressibleRainyEulerExplicitEquations2D) - # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_d = equations.R_dry_air - R_v = equations.R_vapour + temperature = get_temperature(u, equations) - # densities - rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + p = (R_d * rho_dry + R_v * rho_vapour) * temperature - if ( rho_vapour < 0.0 ) - error("rho vapour less than zero") - end - if ( rho_cloud < 0.0 ) - error("rho cloud less than zero") + return p end - # formula - p = pressure(u, equations) - q_v = rho_vapour / rho_dry - q_l = (rho_cloud + rho_rain) / rho_dry - gamma_m = 1 + (R_d + R_v * q_v) / (c_vd + c_vv * q_v + c_l * q_l) - - if (rho_inv < 0.0) - error("rho less than zero") - elseif (p < 0.0) - error("pressure less than zero") + @inline function speed_of_sound(u, equations::CompressibleRainyEulerExplicitEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + + if (rho_vapour < 0.0) + error("rho vapour less than zero") + end + if (rho_cloud < 0.0) + error("rho cloud less than zero") + end + + # formula + p = pressure(u, equations) + q_v = rho_vapour / rho_dry + q_l = (rho_cloud + rho_rain) / rho_dry + gamma_m = 1 + (R_d + R_v * q_v) / (c_vd + c_vv * q_v + c_l * q_l) + + if (rho_inv < 0.0) + error("rho less than zero") + elseif (p < 0.0) + error("pressure less than zero") + end + + v_sound = sqrt(gamma_m * p * rho_inv) + + return SVector(v_sound, gamma_m) end - v_sound = sqrt(gamma_m * p * rho_inv) - - return SVector(v_sound, gamma_m) -end - - -@inline function get_temperature(u, equations::CompressibleRainyEulerExplicitEquations2D) - # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - L_ref = equations.ref_latent_heat_vap_temp + @inline function get_temperature(u, + equations::CompressibleRainyEulerExplicitEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + L_ref = equations.ref_latent_heat_vap_temp - # densities - rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) - # velocity - v1, v2 = velocities(u, rho_inv, equations) + # velocity + v1, v2 = velocities(u, rho_inv, equations) - # energy density - energy = energy_density(u, equations::CompressibleRainyEulerExplicitEquations2D) - - return (energy - L_ref * rho_vapour - 0.5 * rho * (v1^2 + v2^2)) / (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) -end + # energy density + energy = energy_density(u, equations::CompressibleRainyEulerExplicitEquations2D) + return (energy - L_ref * rho_vapour - 0.5 * rho * (v1^2 + v2^2)) / + (c_vd * rho_dry + c_vv * rho_vapour + c_l * (rho_cloud + rho_rain)) + end -@inline function terminal_velocity_rain(rho_moist, rho_rain, equations::CompressibleRainyEulerExplicitEquations2D) - # constants - N_0 = equations.rain_water_distr - v_0 = equations.v_mean_rain + @inline function terminal_velocity_rain(rho_moist, rho_rain, + equations::CompressibleRainyEulerExplicitEquations2D) + # constants + N_0 = equations.rain_water_distr + v_0 = equations.v_mean_rain + + # formula ( \Gamma(4.5) / 6 ~= 1.9386213994279082 ) + if (rho_rain > 0.0) + v_terminal_rain = v_0 * 1.9386213994279082 * + (rho_rain / (pi * (rho_moist + rho_rain) * N_0))^(0.125) + else + v_terminal_rain = 0.0 + end + + return v_terminal_rain + end - # formula ( \Gamma(4.5) / 6 ~= 1.9386213994279082 ) - if ( rho_rain > 0.0) - v_terminal_rain = v_0 * 1.9386213994279082 * (rho_rain / (pi * (rho_moist + rho_rain) * N_0))^(0.125) - else - v_terminal_rain = 0.0 + @inline function saturation_vapour_pressure(temperature, + equations::CompressibleRainyEulerExplicitEquations2D) + # constants + c_l = equations.c_liquid_water + c_pv = equations.c_vapour_const_pressure + R_v = equations.R_vapour + ref_s_p = equations.ref_saturation_pressure + ref_temp = equations.ref_temperature + ref_L = equations.ref_latent_heat_vap_temp + + # testing + if (temperature < 0.0) + display(temperature) + error("temp less than zero") + end + + # Clausius Clapeyron formula + p_vapour_saturation = ref_s_p * (temperature / ref_temp)^((c_pv - c_l) / R_v) + p_vapour_saturation *= exp(((ref_L - (c_pv - c_l) * ref_temp) / R_v) * + (1 / ref_temp - 1 / temperature)) + + return p_vapour_saturation end - return v_terminal_rain -end + @inline function saturation_vapour_pressure_derivative(temperature, + equations::CompressibleRainyEulerExplicitEquations2D) + # constants + c_l = equations.c_liquid_water + c_pv = equations.c_vapour_const_pressure + R_v = equations.R_vapour + ref_s_p = equations.ref_saturation_pressure + ref_temp = equations.ref_temperature + ref_L = equations.ref_latent_heat_vap_temp + + # testing + if (temperature < 0.0) + display(temperature) + error("temp less than zero") + end + + const_1 = (c_pv - c_l) / R_v + const_2 = (ref_L - (c_pv - c_l) * ref_temp) / R_v + + p_vapour_saturation_derivative = ref_s_p / (ref_temp^const_1) + p_vapour_saturation_derivative *= (const_1 * temperature^(const_1 - 1) + + const_2 * temperature^(const_1 - 2)) + p_vapour_saturation_derivative *= exp(const_2 * (1 / ref_temp - 1 / temperature)) + + return p_vapour_saturation_derivative + end + # adapted from compressible_moist_euler_2d.jl + @inline function moist_air_phase_change(u, + equations::CompressibleRainyEulerExplicitEquations2D) + # constants + R_v = equations.R_vapour -@inline function saturation_vapour_pressure(temperature, equations::CompressibleRainyEulerExplicitEquations2D) - # constants - c_l = equations.c_liquid_water - c_pv = equations.c_vapour_const_pressure - R_v = equations.R_vapour - ref_s_p = equations.ref_saturation_pressure - ref_temp = equations.ref_temperature - ref_L = equations.ref_latent_heat_vap_temp + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) - # testing - if (temperature < 0.0) - display(temperature) - error("temp less than zero") - end + # temperature + temperature = get_temperature(u, equations) - # Clausius Clapeyron formula - p_vapour_saturation = ref_s_p * (temperature / ref_temp)^((c_pv - c_l) / R_v) - p_vapour_saturation *= exp(((ref_L - (c_pv - c_l) * ref_temp) / R_v) * (1 / ref_temp - 1 / temperature)) + # saturation vapor pressure + p_vs = saturation_vapour_pressure(temperature, equations) - return p_vapour_saturation -end + # saturation density of vapor + rho_star_qv = p_vs / (R_v * temperature) + # Fisher-Burgmeister-Function + a = rho_star_qv - rho_vapour + b = rho_cloud -@inline function saturation_vapour_pressure_derivative(temperature, equations::CompressibleRainyEulerExplicitEquations2D) - # constants - c_l = equations.c_liquid_water - c_pv = equations.c_vapour_const_pressure - R_v = equations.R_vapour - ref_s_p = equations.ref_saturation_pressure - ref_temp = equations.ref_temperature - ref_L = equations.ref_latent_heat_vap_temp + # saturation control factor + # < 1: stronger saturation effect + # > 1: weaker saturation effect + C = 1.0 - # testing - if (temperature < 0.0) - display(temperature) - error("temp less than zero") + return (a + b - sqrt(a^2 + b^2)) * C end - const_1 = (c_pv - c_l) / R_v - const_2 = (ref_L - (c_pv - c_l) * ref_temp) / R_v + ### pde discretization ### - p_vapour_saturation_derivative = ref_s_p / (ref_temp^const_1) - p_vapour_saturation_derivative *= (const_1 * temperature^(const_1 - 1) + const_2 * temperature^(const_1 - 2)) - p_vapour_saturation_derivative *= exp(const_2 * (1 / ref_temp - 1 / temperature)) + @inline function flux(u, orientation::Integer, + equations::CompressibleRainyEulerExplicitEquations2D) + # constants + c_l = equations.c_liquid_water - return p_vapour_saturation_derivative -end + #densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + # recover rho_vapour, rho_cloud, temperature from nonlinear system + temperature = get_temperature(u, equations) -# adapted from compressible_moist_euler_2d.jl -@inline function moist_air_phase_change(u, equations::CompressibleRainyEulerExplicitEquations2D) - # constants - R_v = equations.R_vapour + # velocity + v1, v2 = velocities(u, rho_inv, equations) + v_r = terminal_velocity_rain(rho_vapour + rho_cloud, rho_rain, equations) - # densities - rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + # pressure + p = pressure(u, equations) - # temperature - temperature = get_temperature(u, equations) + # energy density + energy = energy_density(u, equations) - # saturation vapor pressure - p_vs = saturation_vapour_pressure(temperature, equations) + # flux for orientation cases + if (orientation == 1) + # "mass" + f1 = rho_dry * v1 + f2 = rho_vapour * v1 + f3 = rho_cloud * v1 + f4 = rho_rain * v1 - # saturation density of vapor - rho_star_qv = p_vs / (R_v * temperature) + # "momentum" + f5 = rho * v1 * v1 + p + f6 = rho * v1 * v2 - # Fisher-Burgmeister-Function - a = rho_star_qv - rho_vapour - b = rho_cloud + # "energy" + f7 = (energy + p) * v1 - # saturation control factor - # < 1: stronger saturation effect - # > 1: weaker saturation effect - C = 1.0 + else + # "mass" + f1 = rho_dry * v2 + f2 = rho_vapour * v2 + f3 = rho_cloud * v2 + f4 = rho_rain * (v2 - v_r) - return (a + b - sqrt(a^2 + b^2)) * C -end + # "momentum" + f5 = rho * v1 * v2 - rho_rain * v_r * v1 + f6 = rho * v2 * v2 + p - rho_rain * v_r * v2 + # "energy" + f7 = (energy + p) * v2 - + (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r + end + return SVector(f1, f2, f3, f4, f5, f6, f7) + end -### pde discretization ### + @inline function flux(u, normal_direction::AbstractVector, + equations::CompressibleRainyEulerExplicitEquations2D) + # constants + c_l = equations.c_liquid_water -@inline function flux(u, orientation::Integer, equations::CompressibleRainyEulerExplicitEquations2D) - # constants - c_l = equations.c_liquid_water + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) - #densities - rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + # recover rho_vapour, rho_cloud, temperature from nonlinear system + temperature = get_temperature(u, equations) - # recover rho_vapour, rho_cloud, temperature from nonlinear system - temperature = get_temperature(u, equations) + # velocity + v1, v2 = velocities(u, rho_inv, equations) + v_r = terminal_velocity_rain(rho_vapour + rho_cloud, rho_rain, equations) - # velocity - v1, v2 = velocities(u, rho_inv, equations) - v_r = terminal_velocity_rain(rho_vapour + rho_cloud, rho_rain, equations) + # normal velocities + v_normal = v1 * normal_direction[1] + v2 * normal_direction[2] + v_r_normal = v_r * normal_direction[2] - # pressure - p = pressure(u, equations) + # pressure + p = pressure(u, equations) - # energy density - energy = energy_density(u, equations) + # energy density + energy = energy_density(u, equations) - # flux for orientation cases - if (orientation == 1) + # flux # "mass" - f1 = rho_dry * v1 - f2 = rho_vapour * v1 - f3 = rho_cloud * v1 - f4 = rho_rain * v1 + f1 = rho_dry * v_normal + f2 = rho_vapour * v_normal + f3 = rho_cloud * v_normal + f4 = rho_rain * (v_normal - v_r_normal) # "momentum" - f5 = rho * v1 * v1 + p - f6 = rho * v1 * v2 + f5 = rho * v_normal * v1 + p * normal_direction[1] - rho_rain * v_r_normal * v1 + f6 = rho * v_normal * v2 + p * normal_direction[2] - rho_rain * v_r_normal * v2 # "energy" - f7 = (energy + p) * v1 - - else - # "mass" - f1 = rho_dry * v2 - f2 = rho_vapour * v2 - f3 = rho_cloud * v2 - f4 = rho_rain * (v2 - v_r) + f7 = (energy + p) * v_normal - + (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r_normal - # "momentum" - f5 = rho * v1 * v2 - rho_rain * v_r * v1 - f6 = rho * v2 * v2 + p - rho_rain * v_r * v2 - - # "energy" - f7 = (energy + p) * v2 - (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r + return SVector(f1, f2, f3, f4, f5, f6, f7) end - return SVector(f1, f2, f3, f4, f5, f6, f7) -end - - -@inline function flux(u, normal_direction::AbstractVector, equations::CompressibleRainyEulerExplicitEquations2D) - # constants - c_l = equations.c_liquid_water - - # densities - rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) - - # recover rho_vapour, rho_cloud, temperature from nonlinear system - temperature = get_temperature(u, equations) - - # velocity - v1, v2 = velocities(u, rho_inv, equations) - v_r = terminal_velocity_rain(rho_vapour + rho_cloud, rho_rain, equations) - - # normal velocities - v_normal = v1 * normal_direction[1] + v2 * normal_direction[2] - v_r_normal = v_r * normal_direction[2] - - # pressure - p = pressure(u, equations) - - # energy density - energy = energy_density(u, equations) - - # flux - # "mass" - f1 = rho_dry * v_normal - f2 = rho_vapour * v_normal - f3 = rho_cloud * v_normal - f4 = rho_rain * (v_normal - v_r_normal) - - # "momentum" - f5 = rho * v_normal * v1 + p * normal_direction[1] - rho_rain * v_r_normal * v1 - f6 = rho * v_normal * v2 + p * normal_direction[2] - rho_rain * v_r_normal * v2 - - # "energy" - f7 = (energy + p) * v_normal - (c_l * temperature + 0.5 * (v1^2 + v2^2)) * rho_rain * v_r_normal - - return SVector(f1, f2, f3, f4, f5, f6, f7) -end - - -# no Coriolis term -@inline function source_terms_rainy(u, x, t, equations::CompressibleRainyEulerExplicitEquations2D) - # constants - R_v = equations.R_vapour - ref_temp = equations.ref_temperature - g = equations.gravity - - # name needed variables - rho_v2 = u[6] - - # densities - rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) - - # temperature - temperature = get_temperature(u, equations) - - rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) - Q_ph = moist_air_phase_change(u, equations) - - # source terms phase change - S_evaporation = (3.86e-3 - 9.41e-5 * (temperature - ref_temp)) * (1 + 9.1 * rho_rain^(0.1875)) - S_evaporation *= (rho_vs - rho_vapour) * rho_rain^(0.5) - S_auto_conversion = 0.001 * rho_cloud - S_accretion = 1.72 * rho_cloud * rho_rain^(0.875) - S_rain = S_auto_conversion + S_accretion - S_evaporation - - return SVector(0.0, Q_ph + S_evaporation, -Q_ph - S_auto_conversion - S_accretion, S_rain, 0.0, - -rho * g, -rho_v2 * g) -end - - -# no Coriolis term -@inline function source_terms_moist(u, x, t, equations::CompressibleRainyEulerExplicitEquations2D) - # constants - g = equations.gravity - - # name needed variables - rho_v2 = u[6] - - # densities - rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) - - Q_ph = moist_air_phase_change(u, equations) - - return SVector(0.0, Q_ph, -Q_ph, 0.0, 0.0, - -rho * g, -rho_v2 * g) -end + # no Coriolis term + @inline function source_terms_rainy(u, x, t, + equations::CompressibleRainyEulerExplicitEquations2D) + # constants + R_v = equations.R_vapour + ref_temp = equations.ref_temperature + g = equations.gravity + + # name needed variables + rho_v2 = u[6] + + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + + # temperature + temperature = get_temperature(u, equations) + + rho_vs = saturation_vapour_pressure(temperature, equations) / (R_v * temperature) + Q_ph = moist_air_phase_change(u, equations) + + # source terms phase change + S_evaporation = (3.86e-3 - 9.41e-5 * (temperature - ref_temp)) * + (1 + 9.1 * rho_rain^(0.1875)) + S_evaporation *= (rho_vs - rho_vapour) * rho_rain^(0.5) + S_auto_conversion = 0.001 * rho_cloud + S_accretion = 1.72 * rho_cloud * rho_rain^(0.875) + S_rain = S_auto_conversion + S_accretion - S_evaporation + + return SVector(0.0, Q_ph + S_evaporation, -Q_ph - S_auto_conversion - S_accretion, + S_rain, 0.0, + -rho * g, -rho_v2 * g) + end + # no Coriolis term + @inline function source_terms_moist(u, x, t, + equations::CompressibleRainyEulerExplicitEquations2D) + # constants + g = equations.gravity -# no phase changes and no Coriolis term -@inline function source_terms_no_phase_change(u, x, t, equations::CompressibleRainyEulerExplicitEquations2D) - # constants - g = equations.gravity - - # name needed variables - rho_v2 = u[6] + # name needed variables + rho_v2 = u[6] - # densities - rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) - return SVector(0.0, 0.0, 0.0, 0.0, 0.0, -g * rho, -g * rho_v2) -end + Q_ph = moist_air_phase_change(u, equations) + return SVector(0.0, Q_ph, -Q_ph, 0.0, 0.0, + -rho * g, -rho_v2 * g) + end -@inline function max_abs_speeds(u, equations::CompressibleRainyEulerExplicitEquations2D) - # name needed variables - v1, v2, v_sound, v_r = cons2speeds(u, equations) + # no phase changes and no Coriolis term + @inline function source_terms_no_phase_change(u, x, t, + equations::CompressibleRainyEulerExplicitEquations2D) + # constants + g = equations.gravity - return SVector((abs(v1) + v_sound), (abs(v2) + v_sound + abs(v_r))) -end + # name needed variables + rho_v2 = u[6] + # densities + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) -@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerExplicitEquations2D) - # name needed variables - v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) - v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) + return SVector(0.0, 0.0, 0.0, 0.0, 0.0, -g * rho, -g * rho_v2) + end - # calculate upper bounds for left and right speed - v_ll_max = abs(v1_ll * normal_direction[1] + v2_ll * normal_direction[2]) - v_ll_max += abs( v_r_ll * normal_direction[2]) + @inline function max_abs_speeds(u, equations::CompressibleRainyEulerExplicitEquations2D) + # name needed variables + v1, v2, v_sound, v_r = cons2speeds(u, equations) - v_rr_max = abs(v1_rr * normal_direction[1] + v2_rr * normal_direction[2]) - v_rr_max += abs( v_r_rr * normal_direction[2]) + return SVector((abs(v1) + v_sound), (abs(v2) + v_sound + abs(v_r))) + end - return max(v_ll_max, v_rr_max) + max(v_sound_ll, v_sound_rr) * norm(normal_direction) -end + @inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleRainyEulerExplicitEquations2D) + # name needed variables + v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) + v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) + # calculate upper bounds for left and right speed + v_ll_max = abs(v1_ll * normal_direction[1] + v2_ll * normal_direction[2]) + v_ll_max += abs(v_r_ll * normal_direction[2]) -@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::CompressibleRainyEulerExplicitEquations2D) - # name needed variables - v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) - v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) + v_rr_max = abs(v1_rr * normal_direction[1] + v2_rr * normal_direction[2]) + v_rr_max += abs(v_r_rr * normal_direction[2]) - if (orientation == 1) - v_ll = abs(v1_ll) - v_rr = abs(v1_rr) - else - v_ll = abs(v2_ll) - v_rr = abs(v2_rr) - end - # experimental - return max(v_ll, v_rr) + max(v_sound_ll, v_sound_rr) + max(abs(v_r_ll), abs(v_r_rr)) -end - - -### boundary conditions ### - -# adapted from compressible_moist_euler_2d.jl which was probably adapted from compressible_euler_2d.jl -@inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, x, t, - surface_flux_function, equations::CompressibleRainyEulerExplicitEquations2D) - - norm_ = norm(normal_direction) - # Normalize the vector without using `normalize` since we need to multiply by the `norm_` later - normal = normal_direction / norm_ - - # rotate the internal solution state - u_local = rotate_to_x(u_inner, normal, equations) - - # name needed variables - rho_v1 = u_local[5] - - # densities - rho_dry_local, rho_vapour_local, rho_cloud_local, rho_rain_local, rho_local, rho_inv_local = densities(u_local, equations) - - # velocities - v_normal = rho_v1 * rho_inv_local - v_sound, gamma = speed_of_sound(u_local, equations) - - # pressure - p_local = pressure(u_local, equations) - - # Get the solution of the pressure Riemann problem - # See Section 6.3.3 of - # Eleuterio F. Toro (2009) - # Riemann Solvers and Numerical Methods for Fluid Dynamics: A Practical Introduction - # [DOI: 10.1007/b79761](https://doi.org/10.1007/b79761) - if v_normal <= 0.0 - p_star = p_local * - (1.0 + 0.5 * (gamma - 1) * v_normal / v_sound)^(2.0 * gamma * - inv(gamma - 1)) - else # v_normal > 0.0 - A = 2.0 / ((gamma + 1) * rho_local) - B = p_local * (gamma - 1) / (gamma + 1) - p_star = p_local + - 0.5 * v_normal / A * - (v_normal + sqrt(v_normal^2 + 4.0 * A * (p_local + B))) + return max(v_ll_max, v_rr_max) + + max(v_sound_ll, v_sound_rr) * norm(normal_direction) end - # For the slip wall we directly set the flux as the normal velocity is zero - return SVector(0.0, 0.0, 0.0, 0.0, - p_star * normal[1] * norm_, - p_star * normal[2] * norm_, - 0.0) -end - - -# same as in compressible_euler_2d.jl -@inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, direction, x, t, - surface_flux_function, equations::CompressibleRainyEulerExplicitEquations2D) - # flip sign of normal to make it outward pointing, then flip the sign of the normal flux back - # to be inward pointing on the -x and -y sides due to the orientation convention used by StructuredMesh - if isodd(direction) - boundary_flux = -boundary_condition_slip_wall(u_inner, -normal_direction, - x, t, surface_flux_function, - equations) - else - boundary_flux = boundary_condition_slip_wall(u_inner, normal_direction, - x, t, surface_flux_function, - equations) + @inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, + equations::CompressibleRainyEulerExplicitEquations2D) + # name needed variables + v1_ll, v2_ll, v_sound_ll, v_r_ll = cons2speeds(u_ll, equations) + v1_rr, v2_rr, v_sound_rr, v_r_rr = cons2speeds(u_rr, equations) + + if (orientation == 1) + v_ll = abs(v1_ll) + v_rr = abs(v1_rr) + else + v_ll = abs(v2_ll) + v_rr = abs(v2_rr) + end + # experimental + return max(v_ll, v_rr) + max(v_sound_ll, v_sound_rr) + max(abs(v_r_ll), abs(v_r_rr)) end - return boundary_flux -end - - -# same as in compressible_euler_2d.jl -@inline function rotate_to_x(u, normal_vector, equations::CompressibleRainyEulerExplicitEquations2D) - # cos and sin of the angle between the x-axis and the normalized normal_vector are - # the normalized vector's x and y coordinates respectively (see unit circle). - c = normal_vector[1] - s = normal_vector[2] - - return SVector(u[1], u[2], u[3], u[4], - c * u[5] + s * u[6], - -s * u[5] + c * u[6], - u[7]) -end - - -# should be used together with TreeMesh (adapted from compressible_euler_2d.jl) -@inline function boundary_condition_slip_wall(u_inner, orientation, direction, x, t, surface_flux_function, - equations::CompressibleRainyEulerExplicitEquations2D) - # get the appropriate normal vector from the orientation - RealT = eltype(u_inner) - if orientation == 1 - normal_direction = SVector(one(RealT), zero(RealT)) - else # orientation == 2 - normal_direction = SVector(zero(RealT), one(RealT)) + ### boundary conditions ### + + # adapted from compressible_moist_euler_2d.jl which was probably adapted from compressible_euler_2d.jl + @inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, + x, t, + surface_flux_function, + equations::CompressibleRainyEulerExplicitEquations2D) + norm_ = norm(normal_direction) + # Normalize the vector without using `normalize` since we need to multiply by the `norm_` later + normal = normal_direction / norm_ + + # rotate the internal solution state + u_local = rotate_to_x(u_inner, normal, equations) + + # name needed variables + rho_v1 = u_local[5] + + # densities + rho_dry_local, rho_vapour_local, rho_cloud_local, rho_rain_local, rho_local, rho_inv_local = densities(u_local, + equations) + + # velocities + v_normal = rho_v1 * rho_inv_local + v_sound, gamma = speed_of_sound(u_local, equations) + + # pressure + p_local = pressure(u_local, equations) + + # Get the solution of the pressure Riemann problem + # See Section 6.3.3 of + # Eleuterio F. Toro (2009) + # Riemann Solvers and Numerical Methods for Fluid Dynamics: A Practical Introduction + # [DOI: 10.1007/b79761](https://doi.org/10.1007/b79761) + if v_normal <= 0.0 + p_star = p_local * + (1.0 + 0.5 * (gamma - 1) * v_normal / v_sound)^(2.0 * gamma * + inv(gamma - 1)) + else # v_normal > 0.0 + A = 2.0 / ((gamma + 1) * rho_local) + B = p_local * (gamma - 1) / (gamma + 1) + p_star = p_local + + 0.5 * v_normal / A * + (v_normal + sqrt(v_normal^2 + 4.0 * A * (p_local + B))) + end + + # For the slip wall we directly set the flux as the normal velocity is zero + return SVector(0.0, 0.0, 0.0, 0.0, + p_star * normal[1] * norm_, + p_star * normal[2] * norm_, + 0.0) end - # compute and return the flux using `boundary_condition_slip_wall` routine above - return boundary_condition_slip_wall(u_inner, normal_direction, direction, - x, t, surface_flux_function, equations) -end - - -#= for parabolic terms (LaplaceDiffusion2D) -@inline function boundary_condition_laplace(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Trixi.Gradient, - equations_parabolic::LaplaceDiffusion2D) - return u_inner -end - -@inline function boundary_condition_laplace(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Trixi.Divergence, - equations_parabolic::LaplaceDiffusion2D) - return flux_inner -end=# - - -# Low Mach number approximate Riemann solver (LMARS) from -# X. Chen, N. Andronova, B. Van Leer, J. E. Penner, J. P. Boyd, C. Jablonowski, S. -# Lin, A Control-Volume Model of the Compressible Euler Equations with a Vertical Lagrangian -# Coordinate Monthly Weather Review Vol. 141.7, pages 2526–2544, 2013, -# https://journals.ametsoc.org/view/journals/mwre/141/7/mwr-d-12-00129.1.xml. -# adapted from compressible_moist_euler_2d.jl, does NOT work with rain! -@inline function flux_LMARS(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerExplicitEquations2D) - # constants - a = 360.0 - - # densities - rho_dry_ll, rho_vapour_ll, rho_cloud_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) - rho_dry_rr, rho_vapour_rr, rho_cloud_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) - - # pressure - p_ll = pressure(u_ll, equations) - p_rr = pressure(u_rr, equations) - - # velocities - v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) - v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) - - v_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] - v_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] - norm_ = norm(normal_direction) - - # diffusion parameter 0.0 < beta <= 1.0 - beta = 1.0 - - # interface flux components - rho = 0.5 * (rho_ll + rho_rr) - p_interface = 0.5 * (p_ll + p_rr) - beta * 0.5 * a * rho * (v_rr - v_ll) / norm_ - v_interface = 0.5 * (v_ll + v_rr) - beta * 1 / (2 * a * rho) * (p_rr - p_ll) * norm_ - - if (v_interface > 0) - f1, f2, f3, _, f5, f6, f7 = u_ll * v_interface - f7 += p_ll * v_interface - else - f1, f2, f3, _, f5, f6, f7 = u_rr * v_interface - f7 += p_rr * v_interface - end - - return SVector(f1, f2, f3, 0.0, - f5 + p_interface * normal_direction[1], - f6 + p_interface * normal_direction[2], - f7) -end - - -# Adjusted EC flux in a normal direction with R_q=0. This is based on -# A. Gouasmi, K. Duraisamy, S. M. Murman, Formulation of Entropy-Stable schemes for the -# multicomponent compressible Euler equations, 4 Feb 2020, doi:10.1016/j.cma.2020.112912, -# https://arxiv.org/abs/1904.00972 [math.NA]. -# Adapted from compressible_moist_euler_2d.jl, careful, does NOT work for rain! -@inline function flux_chandrashekar(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerExplicitEquations2D) - # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_d = equations.R_dry_air - R_v = equations.R_vapour - ref_L = equations.ref_latent_heat_vap_temp - R_q = 0.0 - - # densities and temperatures - rho_dry_ll, rho_vapour_ll, rho_cloud_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) - rho_dry_rr, rho_vapour_rr, rho_cloud_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) - temperature_ll = get_temperature(u_ll, equations) - temperature_rr = get_temperature(u_rr, equations) - - # velocities - v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) - v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) - vr_ll = terminal_velocity_rain(rho_vapour_ll + rho_cloud_ll, rho_rain_ll, equations) - vr_rr = terminal_velocity_rain(rho_vapour_rr + rho_cloud_rr, rho_rain_rr, equations) - - # mean values - rho_dry_mean = 0.0 - rho_vapour_mean = 0.0 - rho_cloud_mean = 0.0 - rho_rain_mean = 0.0 - inv_temperature_mean = 0.0 - - if (!(rho_dry_ll == 0.0) && !(rho_dry_rr == 0.0)) - rho_dry_mean = ln_mean(rho_dry_ll, rho_dry_rr) + # same as in compressible_euler_2d.jl + @inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, + direction, x, t, + surface_flux_function, + equations::CompressibleRainyEulerExplicitEquations2D) + # flip sign of normal to make it outward pointing, then flip the sign of the normal flux back + # to be inward pointing on the -x and -y sides due to the orientation convention used by StructuredMesh + if isodd(direction) + boundary_flux = -boundary_condition_slip_wall(u_inner, -normal_direction, + x, t, surface_flux_function, + equations) + else + boundary_flux = boundary_condition_slip_wall(u_inner, normal_direction, + x, t, surface_flux_function, + equations) + end + + return boundary_flux end - if (!(rho_vapour_ll == 0.0) && !(rho_vapour_rr == 0.0)) - rho_vapour_mean = ln_mean(rho_vapour_ll, rho_vapour_rr) + # same as in compressible_euler_2d.jl + @inline function rotate_to_x(u, normal_vector, + equations::CompressibleRainyEulerExplicitEquations2D) + # cos and sin of the angle between the x-axis and the normalized normal_vector are + # the normalized vector's x and y coordinates respectively (see unit circle). + c = normal_vector[1] + s = normal_vector[2] + + return SVector(u[1], u[2], u[3], u[4], + c * u[5] + s * u[6], + -s * u[5] + c * u[6], + u[7]) end - if (!(rho_cloud_ll == 0.0) && !(rho_cloud_rr == 0.0)) - rho_cloud_mean = ln_mean(rho_cloud_ll, rho_cloud_rr) + # should be used together with TreeMesh (adapted from compressible_euler_2d.jl) + @inline function boundary_condition_slip_wall(u_inner, orientation, direction, x, t, + surface_flux_function, + equations::CompressibleRainyEulerExplicitEquations2D) + # get the appropriate normal vector from the orientation + RealT = eltype(u_inner) + if orientation == 1 + normal_direction = SVector(one(RealT), zero(RealT)) + else # orientation == 2 + normal_direction = SVector(zero(RealT), one(RealT)) + end + + # compute and return the flux using `boundary_condition_slip_wall` routine above + return boundary_condition_slip_wall(u_inner, normal_direction, direction, + x, t, surface_flux_function, equations) end - if (!(rho_rain_ll == 0.0) && !(rho_rain_rr == 0.0)) - rho_rain_mean = ln_mean(rho_rain_ll, rho_rain_rr) + #= for parabolic terms (LaplaceDiffusion2D) + @inline function boundary_condition_laplace(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Trixi.Gradient, + equations_parabolic::LaplaceDiffusion2D) + return u_inner end - if (!(inv(temperature_ll) == 0.0) && !(inv(temperature_rr) == 0.0)) - inv_temperature_mean = inv_ln_mean(inv(temperature_ll), inv(temperature_rr)) - end - - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) - v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) - rho_dry_avg = 0.5 * (rho_dry_ll + rho_dry_rr) - rho_vapour_avg = 0.5 * (rho_vapour_ll + rho_vapour_rr) - rho_cloud_avg = 0.5 * (rho_cloud_ll + rho_cloud_rr) - rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) - inv_temperature_avg = 0.5 * (inv(temperature_ll) + inv(temperature_rr)) - v_dot_n_avg = normal_direction[1] * v1_avg + normal_direction[2] * v2_avg - - p_int = inv(inv_temperature_avg) * (R_d * rho_dry_avg + R_v * rho_vapour_avg + R_q * (rho_cloud_avg + rho_rain_avg)) - K_avg = 0.5 * (v1_square_avg + v2_square_avg) - vr_normal_avg = 0.5 * normal_direction[2] * (vr_ll + vr_rr) - rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) - - # assemble the flux - f_dry = rho_dry_mean * v_dot_n_avg - f_vapour = rho_vapour_mean * v_dot_n_avg - f_cloud = rho_cloud_mean * v_dot_n_avg - f_rain = rho_rain_avg * (v_dot_n_avg - vr_normal_avg) - f_rhov1 = (f_dry + f_vapour + f_cloud + f_rain) * v1_avg + normal_direction[1] * p_int - f_rhov2 = (f_dry + f_vapour + f_cloud + f_rain) * v2_avg + normal_direction[2] * p_int - f_energy = (( c_vd * inv_temperature_mean - K_avg) * f_dry + - (ref_L + c_vv * inv_temperature_mean - K_avg) * f_vapour + - ( c_l * inv_temperature_mean - K_avg) * (f_cloud + f_rain) + v1_avg * f_rhov1 + v2_avg * f_rhov2) - - return SVector(f_dry, f_vapour, f_cloud, f_rain, f_rhov1, f_rhov2, f_energy) -end - - -@inline function flux_chandrashekar(u_ll, u_rr, orientation::Int, equations::CompressibleRainyEulerExplicitEquations2D) - if (orientation == 1) - return flux_chandrashekar(u_ll, u_rr, SVector(1, 0), equations) - else - return flux_chandrashekar(u_ll, u_rr, SVector(0, 1), equations) - end -end - - - -@inline function flux_ec_rain(u_ll, u_rr, normal_direction::AbstractVector, equations::CompressibleRainyEulerExplicitEquations2D) - # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_d = equations.R_dry_air - R_v = equations.R_vapour - L_ref = equations.ref_latent_heat_vap_temp - - # densities and temperatures - rho_dry_ll, rho_vapour_ll, rho_cloud_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, equations) - rho_dry_rr, rho_vapour_rr, rho_cloud_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, equations) - temperature_ll = get_temperature(u_ll, equations) - temperature_rr = get_temperature(u_rr, equations) - inv_temperature_ll = inv(temperature_ll) - inv_temperature_rr = inv(temperature_rr) - - # velocities - v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) - v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) - vr_ll = terminal_velocity_rain(rho_vapour_ll + rho_cloud_ll, rho_rain_ll, equations) - vr_rr = terminal_velocity_rain(rho_vapour_rr + rho_cloud_rr, rho_rain_rr, equations) - - # velocity averages - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) - v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) - K_avg = 0.5 * (v1_square_avg + v2_square_avg) - v_dot_n_avg = normal_direction[1] * v1_avg + normal_direction[2] * v2_avg - vr_normal_avg = 0.5 * normal_direction[2] * (vr_ll + vr_rr) - - # density averages - rho_dry_avg = 0.5 * (rho_dry_ll + rho_dry_rr) - rho_vapour_avg = 0.5 * (rho_vapour_ll + rho_vapour_rr) - rho_cloud_avg = 0.5 * (rho_cloud_ll + rho_cloud_rr) - rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) - - # density log means - rho_dry_log = 0.0 - rho_vapour_log = 0.0 - rho_cloud_log = 0.0 - rho_rain_log = 0.0 - - if (!(rho_dry_ll == 0.0) && !(rho_dry_rr == 0.0)) - rho_dry_log = ln_mean(rho_dry_ll, rho_dry_rr) + @inline function boundary_condition_laplace(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Trixi.Divergence, + equations_parabolic::LaplaceDiffusion2D) + return flux_inner + end=# + + # Low Mach number approximate Riemann solver (LMARS) from + # X. Chen, N. Andronova, B. Van Leer, J. E. Penner, J. P. Boyd, C. Jablonowski, S. + # Lin, A Control-Volume Model of the Compressible Euler Equations with a Vertical Lagrangian + # Coordinate Monthly Weather Review Vol. 141.7, pages 2526–2544, 2013, + # https://journals.ametsoc.org/view/journals/mwre/141/7/mwr-d-12-00129.1.xml. + # adapted from compressible_moist_euler_2d.jl, does NOT work with rain! + @inline function flux_LMARS(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleRainyEulerExplicitEquations2D) + # constants + a = 360.0 + + # densities + rho_dry_ll, rho_vapour_ll, rho_cloud_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, + equations) + rho_dry_rr, rho_vapour_rr, rho_cloud_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, + equations) + + # pressure + p_ll = pressure(u_ll, equations) + p_rr = pressure(u_rr, equations) + + # velocities + v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) + v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) + + v_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] + v_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] + norm_ = norm(normal_direction) + + # diffusion parameter 0.0 < beta <= 1.0 + beta = 1.0 + + # interface flux components + rho = 0.5 * (rho_ll + rho_rr) + p_interface = 0.5 * (p_ll + p_rr) - beta * 0.5 * a * rho * (v_rr - v_ll) / norm_ + v_interface = 0.5 * (v_ll + v_rr) - beta * 1 / (2 * a * rho) * (p_rr - p_ll) * norm_ + + if (v_interface > 0) + f1, f2, f3, _, f5, f6, f7 = u_ll * v_interface + f7 += p_ll * v_interface + else + f1, f2, f3, _, f5, f6, f7 = u_rr * v_interface + f7 += p_rr * v_interface + end + + return SVector(f1, f2, f3, 0.0, + f5 + p_interface * normal_direction[1], + f6 + p_interface * normal_direction[2], + f7) end - if (!(rho_vapour_ll == 0.0) && !(rho_vapour_rr == 0.0)) - rho_vapour_log = ln_mean(rho_vapour_ll, rho_vapour_rr) + # Adjusted EC flux in a normal direction with R_q=0. This is based on + # A. Gouasmi, K. Duraisamy, S. M. Murman, Formulation of Entropy-Stable schemes for the + # multicomponent compressible Euler equations, 4 Feb 2020, doi:10.1016/j.cma.2020.112912, + # https://arxiv.org/abs/1904.00972 [math.NA]. + # Adapted from compressible_moist_euler_2d.jl, careful, does NOT work for rain! + @inline function flux_chandrashekar(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleRainyEulerExplicitEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + ref_L = equations.ref_latent_heat_vap_temp + R_q = 0.0 + + # densities and temperatures + rho_dry_ll, rho_vapour_ll, rho_cloud_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, + equations) + rho_dry_rr, rho_vapour_rr, rho_cloud_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, + equations) + temperature_ll = get_temperature(u_ll, equations) + temperature_rr = get_temperature(u_rr, equations) + + # velocities + v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) + v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) + vr_ll = terminal_velocity_rain(rho_vapour_ll + rho_cloud_ll, rho_rain_ll, equations) + vr_rr = terminal_velocity_rain(rho_vapour_rr + rho_cloud_rr, rho_rain_rr, equations) + + # mean values + rho_dry_mean = 0.0 + rho_vapour_mean = 0.0 + rho_cloud_mean = 0.0 + rho_rain_mean = 0.0 + inv_temperature_mean = 0.0 + + if (!(rho_dry_ll == 0.0) && !(rho_dry_rr == 0.0)) + rho_dry_mean = ln_mean(rho_dry_ll, rho_dry_rr) + end + + if (!(rho_vapour_ll == 0.0) && !(rho_vapour_rr == 0.0)) + rho_vapour_mean = ln_mean(rho_vapour_ll, rho_vapour_rr) + end + + if (!(rho_cloud_ll == 0.0) && !(rho_cloud_rr == 0.0)) + rho_cloud_mean = ln_mean(rho_cloud_ll, rho_cloud_rr) + end + + if (!(rho_rain_ll == 0.0) && !(rho_rain_rr == 0.0)) + rho_rain_mean = ln_mean(rho_rain_ll, rho_rain_rr) + end + + if (!(inv(temperature_ll) == 0.0) && !(inv(temperature_rr) == 0.0)) + inv_temperature_mean = inv_ln_mean(inv(temperature_ll), inv(temperature_rr)) + end + + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) + v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) + rho_dry_avg = 0.5 * (rho_dry_ll + rho_dry_rr) + rho_vapour_avg = 0.5 * (rho_vapour_ll + rho_vapour_rr) + rho_cloud_avg = 0.5 * (rho_cloud_ll + rho_cloud_rr) + rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) + inv_temperature_avg = 0.5 * (inv(temperature_ll) + inv(temperature_rr)) + v_dot_n_avg = normal_direction[1] * v1_avg + normal_direction[2] * v2_avg + + p_int = inv(inv_temperature_avg) * (R_d * rho_dry_avg + R_v * rho_vapour_avg + + R_q * (rho_cloud_avg + rho_rain_avg)) + K_avg = 0.5 * (v1_square_avg + v2_square_avg) + vr_normal_avg = 0.5 * normal_direction[2] * (vr_ll + vr_rr) + rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) + + # assemble the flux + f_dry = rho_dry_mean * v_dot_n_avg + f_vapour = rho_vapour_mean * v_dot_n_avg + f_cloud = rho_cloud_mean * v_dot_n_avg + f_rain = rho_rain_avg * (v_dot_n_avg - vr_normal_avg) + f_rhov1 = (f_dry + f_vapour + f_cloud + f_rain) * v1_avg + + normal_direction[1] * p_int + f_rhov2 = (f_dry + f_vapour + f_cloud + f_rain) * v2_avg + + normal_direction[2] * p_int + f_energy = ((c_vd * inv_temperature_mean - K_avg) * f_dry + + (ref_L + c_vv * inv_temperature_mean - K_avg) * f_vapour + + (c_l * inv_temperature_mean - K_avg) * (f_cloud + f_rain) + + v1_avg * f_rhov1 + v2_avg * f_rhov2) + + return SVector(f_dry, f_vapour, f_cloud, f_rain, f_rhov1, f_rhov2, f_energy) end - if (!(rho_cloud_ll == 0.0) && !(rho_cloud_rr == 0.0)) - rho_cloud_log = ln_mean(rho_cloud_ll, rho_cloud_rr) + @inline function flux_chandrashekar(u_ll, u_rr, orientation::Int, + equations::CompressibleRainyEulerExplicitEquations2D) + if (orientation == 1) + return flux_chandrashekar(u_ll, u_rr, SVector(1, 0), equations) + else + return flux_chandrashekar(u_ll, u_rr, SVector(0, 1), equations) + end end - if (!(rho_rain_ll == 0.0) && !(rho_rain_rr == 0.0)) - rho_rain_log = ln_mean(rho_rain_ll, rho_rain_rr) + @inline function flux_ec_rain(u_ll, u_rr, normal_direction::AbstractVector, + equations::CompressibleRainyEulerExplicitEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour + L_ref = equations.ref_latent_heat_vap_temp + + # densities and temperatures + rho_dry_ll, rho_vapour_ll, rho_cloud_ll, rho_rain_ll, rho_ll, rho_inv_ll = densities(u_ll, + equations) + rho_dry_rr, rho_vapour_rr, rho_cloud_rr, rho_rain_rr, rho_rr, rho_inv_rr = densities(u_rr, + equations) + temperature_ll = get_temperature(u_ll, equations) + temperature_rr = get_temperature(u_rr, equations) + inv_temperature_ll = inv(temperature_ll) + inv_temperature_rr = inv(temperature_rr) + + # velocities + v1_ll, v2_ll = velocities(u_ll, rho_inv_ll, equations) + v1_rr, v2_rr = velocities(u_rr, rho_inv_rr, equations) + vr_ll = terminal_velocity_rain(rho_vapour_ll + rho_cloud_ll, rho_rain_ll, equations) + vr_rr = terminal_velocity_rain(rho_vapour_rr + rho_cloud_rr, rho_rain_rr, equations) + + # velocity averages + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v1_square_avg = 0.5 * (v1_ll^2 + v1_rr^2) + v2_square_avg = 0.5 * (v2_ll^2 + v2_rr^2) + K_avg = 0.5 * (v1_square_avg + v2_square_avg) + v_dot_n_avg = normal_direction[1] * v1_avg + normal_direction[2] * v2_avg + vr_normal_avg = 0.5 * normal_direction[2] * (vr_ll + vr_rr) + + # density averages + rho_dry_avg = 0.5 * (rho_dry_ll + rho_dry_rr) + rho_vapour_avg = 0.5 * (rho_vapour_ll + rho_vapour_rr) + rho_cloud_avg = 0.5 * (rho_cloud_ll + rho_cloud_rr) + rho_rain_avg = 0.5 * (rho_rain_ll + rho_rain_rr) + + # density log means + rho_dry_log = 0.0 + rho_vapour_log = 0.0 + rho_cloud_log = 0.0 + rho_rain_log = 0.0 + + if (!(rho_dry_ll == 0.0) && !(rho_dry_rr == 0.0)) + rho_dry_log = ln_mean(rho_dry_ll, rho_dry_rr) + end + + if (!(rho_vapour_ll == 0.0) && !(rho_vapour_rr == 0.0)) + rho_vapour_log = ln_mean(rho_vapour_ll, rho_vapour_rr) + end + + if (!(rho_cloud_ll == 0.0) && !(rho_cloud_rr == 0.0)) + rho_cloud_log = ln_mean(rho_cloud_ll, rho_cloud_rr) + end + + if (!(rho_rain_ll == 0.0) && !(rho_rain_rr == 0.0)) + rho_rain_log = ln_mean(rho_rain_ll, rho_rain_rr) + end + + # other averages + inv_temperature_avg = 0.5 * (inv_temperature_ll + inv_temperature_rr) + inv_temperature_log = inv_ln_mean(inv_temperature_ll, inv_temperature_rr) + p_int = inv(inv_temperature_avg) * (R_d * rho_dry_avg + R_v * rho_vapour_avg) + + # density flux + f_vapour = rho_vapour_log * v_dot_n_avg + f_cloud = rho_cloud_avg * v_dot_n_avg + f_dry = rho_dry_log * v_dot_n_avg + f_rain = rho_rain_avg * (v_dot_n_avg - vr_normal_avg) + f_moist = f_vapour + f_cloud + f_rho = f_dry + f_moist + f_rain + + # momentum flux + f_rhov1 = f_rho * v1_avg + p_int * normal_direction[1] + f_rhov2 = f_rho * v2_avg + p_int * normal_direction[2] + + # energy flux + f_energy = (c_vd * inv_temperature_log - K_avg) * f_dry + + (c_vv * inv_temperature_log - K_avg + L_ref) * f_vapour + + (c_l * inv_temperature_log - K_avg) * (f_cloud + f_rain) + + (v1_avg * f_rhov1 + v2_avg * f_rhov2) + + return SVector(f_dry, f_vapour, f_cloud, f_rain, f_rhov1, f_rhov2, f_energy) end - # other averages - inv_temperature_avg = 0.5 * (inv_temperature_ll + inv_temperature_rr) - inv_temperature_log = inv_ln_mean(inv_temperature_ll, inv_temperature_rr) - p_int = inv(inv_temperature_avg) * (R_d * rho_dry_avg + R_v * rho_vapour_avg) - - # density flux - f_vapour = rho_vapour_log * v_dot_n_avg - f_cloud = rho_cloud_avg * v_dot_n_avg - f_dry = rho_dry_log * v_dot_n_avg - f_rain = rho_rain_avg * (v_dot_n_avg - vr_normal_avg) - f_moist = f_vapour + f_cloud - f_rho = f_dry + f_moist + f_rain - - # momentum flux - f_rhov1 = f_rho * v1_avg + p_int * normal_direction[1] - f_rhov2 = f_rho * v2_avg + p_int * normal_direction[2] - - # energy flux - f_energy = (c_vd * inv_temperature_log - K_avg) * f_dry + (c_vv * inv_temperature_log - K_avg + L_ref) * f_vapour + - (c_l * inv_temperature_log - K_avg) * (f_cloud + f_rain) + (v1_avg * f_rhov1 + v2_avg * f_rhov2) - - return SVector(f_dry, f_vapour, f_cloud, f_rain, f_rhov1, f_rhov2, f_energy) -end - -@inline function flux_ec_rain(u_ll, u_rr, orientation::Int, equations::CompressibleRainyEulerExplicitEquations2D) - if (orientation == 1) - return flux_ec_rain(u_ll, u_rr, SVector(1, 0), equations) - else - return flux_ec_rain(u_ll, u_rr, SVector(0, 1), equations) + @inline function flux_ec_rain(u_ll, u_rr, orientation::Int, + equations::CompressibleRainyEulerExplicitEquations2D) + if (orientation == 1) + return flux_ec_rain(u_ll, u_rr, SVector(1, 0), equations) + else + return flux_ec_rain(u_ll, u_rr, SVector(0, 1), equations) + end end -end - - -# adapted from ShallowWaterEquations2D (Recommended with rain!) -@inline function boundary_condition_simple_slip_wall(u_inner, normal_direction::AbstractVector, x, t, surface_flux_function, - equations::CompressibleRainyEulerExplicitEquations2D) - # normalize the outward pointing direction - normal = normal_direction / norm(normal_direction) + # adapted from ShallowWaterEquations2D (Recommended with rain!) + @inline function boundary_condition_simple_slip_wall(u_inner, + normal_direction::AbstractVector, + x, t, surface_flux_function, + equations::CompressibleRainyEulerExplicitEquations2D) + # normalize the outward pointing direction + normal = normal_direction / norm(normal_direction) - # compute the normal velocity - u_normal = normal[1] * u_inner[5] + normal[2] * u_inner[6] + # compute the normal velocity + u_normal = normal[1] * u_inner[5] + normal[2] * u_inner[6] - # create the "external" boundary solution state - u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], u_inner[4], - u_inner[5] - 2 * u_normal * normal[1], - u_inner[6] - 2 * u_normal * normal[2], - u_inner[7]) + # create the "external" boundary solution state + u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], u_inner[4], + u_inner[5] - 2 * u_normal * normal[1], + u_inner[6] - 2 * u_normal * normal[2], + u_inner[7]) - # calculate the boundary flux - flux = surface_flux_function(u_inner, u_boundary, normal_direction, equations) + # calculate the boundary flux + flux = surface_flux_function(u_inner, u_boundary, normal_direction, equations) - return flux -end - - -# adapted from ShallowWaterEquations2D (Recommended with rain!) -@inline function boundary_condition_simple_slip_wall(u_inner, orientation, direction, x, t, surface_flux_function, - equations::CompressibleRainyEulerExplicitEquations2D) - ## get the appropriate normal vector from the orientation - if orientation == 1 - u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], u_inner[4], -u_inner[5], u_inner[6], u_inner[7]) - else # orientation == 2 - u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], u_inner[4], u_inner[5], -u_inner[6], u_inner[7]) + return flux end - # Calculate boundary flux - if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary - flux = surface_flux_function(u_inner, u_boundary, orientation, equations) - else # u_boundary is "left" of boundary, u_inner is "right" of boundary - flux = surface_flux_function(u_boundary, u_inner, orientation, equations) + # adapted from ShallowWaterEquations2D (Recommended with rain!) + @inline function boundary_condition_simple_slip_wall(u_inner, orientation, direction, x, + t, surface_flux_function, + equations::CompressibleRainyEulerExplicitEquations2D) + ## get the appropriate normal vector from the orientation + if orientation == 1 + u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], u_inner[4], + -u_inner[5], u_inner[6], u_inner[7]) + else # orientation == 2 + u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], u_inner[4], u_inner[5], + -u_inner[6], u_inner[7]) + end + + # Calculate boundary flux + if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary + flux = surface_flux_function(u_inner, u_boundary, orientation, equations) + else # u_boundary is "left" of boundary, u_inner is "right" of boundary + flux = surface_flux_function(u_boundary, u_inner, orientation, equations) + end + + return flux end - return flux -end - + @inline function entropy(u, equations::CompressibleRainyEulerExplicitEquations2D) + # constants + c_l = equations.c_liquid_water + c_vd = equations.c_dry_air_const_volume + c_vv = equations.c_vapour_const_volume + R_d = equations.R_dry_air + R_v = equations.R_vapour -@inline function entropy(u, equations::CompressibleRainyEulerExplicitEquations2D) - # constants - c_l = equations.c_liquid_water - c_vd = equations.c_dry_air_const_volume - c_vv = equations.c_vapour_const_volume - R_d = equations.R_dry_air - R_v = equations.R_vapour + # variables + rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) + temperature = get_temperature(u, equations) - # variables - rho_dry, rho_vapour, rho_cloud, rho_rain, rho, rho_inv = densities(u, equations) - temperature = get_temperature(u, equations) + # s_k + s_d = c_vd * log(temperature) - R_d * log(rho_dry) + s_v = c_vv * log(temperature) - R_v * log(rho_vapour) + s_l = c_l * log(temperature) - # s_k - s_d = c_vd * log(temperature) - R_d * log(rho_dry) - s_v = c_vv * log(temperature) - R_v * log(rho_vapour) - s_l = c_l * log(temperature) - - return rho_dry * s_d + rho_vapour * s_v + (rho_cloud + rho_rain) * s_l -end - -end # muladd end \ No newline at end of file + return rho_dry * s_d + rho_vapour * s_v + (rho_cloud + rho_rain) * s_l + end +end # muladd end diff --git a/src/equations/equations.jl b/src/equations/equations.jl index d0e96350..da83cb34 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -343,5 +343,4 @@ include("reference_data.jl") include("compressible_rainy_euler_2d.jl") include("compressible_moist_euler_potential_temperature_2d.jl") include("compressible_rainy_euler_explicit_2d.jl") - end # @muladd diff --git a/test/test_2d_rainy_euler.jl b/test/test_2d_rainy_euler.jl index 92815971..9a1f4fb2 100644 --- a/test/test_2d_rainy_euler.jl +++ b/test/test_2d_rainy_euler.jl @@ -9,7 +9,7 @@ EXAMPLES_DIR = TrixiAtmo.examples_dir() * "moist_bubble/" @trixiatmo_testset "../examples/elixir_moist_euler_dry_bubble" begin @test_trixi_include(joinpath(EXAMPLES_DIR, - "rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl"), + "rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl"), l2=[ 1.300428671901329e-6, 2.601090012108739e-5, From 337ca0c49c6d6c140cd170b5caba8f4938c7050e Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Mon, 19 May 2025 09:18:50 +0200 Subject: [PATCH 115/115] correct path --- test/test_2d_rainy_euler.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/test_2d_rainy_euler.jl b/test/test_2d_rainy_euler.jl index 9a1f4fb2..9aa55fb4 100644 --- a/test/test_2d_rainy_euler.jl +++ b/test/test_2d_rainy_euler.jl @@ -5,11 +5,12 @@ using TrixiAtmo include("test_trixiatmo.jl") -EXAMPLES_DIR = TrixiAtmo.examples_dir() * "moist_bubble/" +EXAMPLES_DIR = joinpath(TrixiAtmo.examples_dir(), "moist_bubble") -@trixiatmo_testset "../examples/elixir_moist_euler_dry_bubble" begin +@trixiatmo_testset "elixir_rainy_euler_rainy_bubble_diffusion" begin @test_trixi_include(joinpath(EXAMPLES_DIR, - "rainy_bubble_elixirs/elixir_rainy_euler_rainy_bubble_diffusion.jl"), + "rainy_bubble_elixirs", + "elixir_rainy_euler_rainy_bubble_diffusion.jl"), l2=[ 1.300428671901329e-6, 2.601090012108739e-5,