From ddb2af6f92b110ef30f1f6e247e1ddfc9468c61e Mon Sep 17 00:00:00 2001 From: Dennis Yatunin Date: Mon, 27 Jan 2025 17:25:59 -0800 Subject: [PATCH] Modify velocity, kinetic energy, and curl terms to match dycore paper --- .../diagnostic_edmf_precomputed_quantities.jl | 27 ++---- src/cache/precomputed_quantities.jl | 83 ++++++++++--------- .../prognostic_edmf_precomputed_quantities.jl | 21 +++-- src/prognostic_equations/advection.jl | 26 +++--- src/utils/utilities.jl | 37 +++++---- 5 files changed, 92 insertions(+), 102 deletions(-) diff --git a/src/cache/diagnostic_edmf_precomputed_quantities.jl b/src/cache/diagnostic_edmf_precomputed_quantities.jl index 59d88ba0c3a..81a852def90 100644 --- a/src/cache/diagnostic_edmf_precomputed_quantities.jl +++ b/src/cache/diagnostic_edmf_precomputed_quantities.jl @@ -9,21 +9,16 @@ import ClimaCore: Spaces, Fields, RecursiveApply uₕ_level, u³_halflevel, local_geometry_level, - local_geometry_halflevel, ) + g³³_level = g³³(local_geometry_level.gⁱʲ) + uₕʰ_level = CT12(uₕ_level, local_geometry_level) + uₕ³_level = CT3(uₕ_level, local_geometry_level) + u₃³_level = u³_halflevel - uₕ³_level # assume that u³_level = u³_halflevel + u₃_level = inv(g³³_level) * u₃³_level return ( - dot( - C123(uₕ_level, local_geometry_level), - CT123(uₕ_level, local_geometry_level), - ) + - dot( - C123(u³_halflevel, local_geometry_halflevel), - CT123(u³_halflevel, local_geometry_halflevel), - ) + - 2 * dot( - CT123(uₕ_level, local_geometry_level), - C123(u³_halflevel, local_geometry_halflevel), - ) + dot(uₕʰ_level, uₕ_level) + + 2 * dot(uₕ³_level, u₃_level) + + dot(u₃³_level, u₃_level) ) / 2 end @@ -58,7 +53,6 @@ NVTX.@annotate function set_diagnostic_edmfx_env_quantities_level!( uₕ_level, K⁰_level, local_geometry_level, - local_geometry_halflevel, turbconv_model, ) @. u³⁰_halflevel = divide_by_ρa( @@ -73,7 +67,6 @@ NVTX.@annotate function set_diagnostic_edmfx_env_quantities_level!( uₕ_level, u³⁰_halflevel, local_geometry_level, - local_geometry_halflevel, ) return nothing end @@ -178,7 +171,6 @@ NVTX.@annotate function set_diagnostic_edmf_precomputed_quantities_bottom_bc!( uₕ_int_level, u³ʲ_int_halflevel, local_geometry_int_level, - local_geometry_int_halflevel, ) set_diagnostic_edmfx_draft_quantities_level!( thermo_params, @@ -205,7 +197,6 @@ NVTX.@annotate function set_diagnostic_edmf_precomputed_quantities_bottom_bc!( uₕ_int_level, K⁰_int_level, local_geometry_int_level, - local_geometry_int_halflevel, turbconv_model, ) @@ -798,7 +789,6 @@ NVTX.@annotate function set_diagnostic_edmf_precomputed_quantities_do_integral!( uₕ_level, u³ʲ_halflevel, local_geometry_level, - local_geometry_halflevel, ) set_diagnostic_edmfx_draft_quantities_level!( thermo_params, @@ -823,7 +813,6 @@ NVTX.@annotate function set_diagnostic_edmf_precomputed_quantities_do_integral!( uₕ_level, K⁰_level, local_geometry_level, - local_geometry_halflevel, turbconv_model, ) end diff --git a/src/cache/precomputed_quantities.jl b/src/cache/precomputed_quantities.jl index 4859fe03886..ffe7d7d39ff 100644 --- a/src/cache/precomputed_quantities.jl +++ b/src/cache/precomputed_quantities.jl @@ -48,6 +48,7 @@ function precomputed_quantities(Y, atmos) ᶜspecific = specific_gs.(Y.c), ᶜu = similar(Y.c, C123{FT}), ᶠu³ = similar(Y.f, CT3{FT}), + ᶠu = similar(Y.f, CT123{FT}), ᶜwₜqₜ = similar(Y.c, Geometry.WVector{FT}), ᶜwₕhₜ = similar(Y.c, Geometry.WVector{FT}), ᶜK = similar(Y.c, FT), @@ -86,6 +87,7 @@ function precomputed_quantities(Y, atmos) ᶠu₃⁰ = similar(Y.f, C3{FT}), ᶜu⁰ = similar(Y.c, C123{FT}), ᶠu³⁰ = similar(Y.f, CT3{FT}), + ᶠu⁰ = similar(Y.f, CT123{FT}), ᶜK⁰ = similar(Y.c, FT), ᶜmse⁰ = similar(Y.c, FT), ᶜq_tot⁰ = similar(Y.c, FT), @@ -97,6 +99,7 @@ function precomputed_quantities(Y, atmos) ρatke_flux = similar(Fields.level(Y.f, half), C3{FT}), ᶜuʲs = similar(Y.c, NTuple{n, C123{FT}}), ᶠu³ʲs = similar(Y.f, NTuple{n, CT3{FT}}), + ᶠuʲs = similar(Y.f, NTuple{n, CT123{FT}}), ᶜKʲs = similar(Y.c, NTuple{n, FT}), ᶠKᵥʲs = similar(Y.f, NTuple{n, FT}), ᶜtsʲs = similar(Y.c, NTuple{n, TST}), @@ -186,29 +189,24 @@ function precomputed_quantities(Y, atmos) ) end -# Interpolates the third contravariant component of Y.c.uₕ to cell faces. -function set_ᶠuₕ³!(ᶠuₕ³, Y) - ᶜJ = Fields.local_geometry_field(Y.c).J - @. ᶠuₕ³ = ᶠwinterp(Y.c.ρ * ᶜJ, CT3(Y.c.uₕ)) - return nothing -end - """ - set_velocity_at_surface!(Y, ᶠuₕ³, turbconv_model) + set_velocity_at_surface!(Y, turbconv_model) Modifies `Y.f.u₃` so that `ᶠu³` is 0 at the surface. Specifically, since -`u³ = uₕ³ + u³ = uₕ³ + u₃ * g³³`, setting `u³` to 0 gives `u₃ = -uₕ³ / g³³`. If -the `turbconv_model` is EDMFX, the `Y.f.sgsʲs` are also modified so that each -`u₃ʲ` is equal to `u₃` at the surface. +`u³ = g³ʰ uₕ + g³³ u₃`, setting `u³` to 0 gives `u₃ = -(g³³)⁻¹ g³ʰ uₕ`. If the +`turbconv_model` is EDMFX, the `Y.f.sgsʲs` are also modified so that each `u₃ʲ` +is equal to `u₃` at the surface. """ -function set_velocity_at_surface!(Y, ᶠuₕ³, turbconv_model) - sfc_u₃ = Fields.level(Y.f.u₃.components.data.:1, half) - sfc_uₕ³ = Fields.level(ᶠuₕ³.components.data.:1, half) - sfc_g³³ = g³³_field(sfc_u₃) - @. sfc_u₃ = -sfc_uₕ³ / sfc_g³³ # u³ = uₕ³ + w³ = uₕ³ + w₃ * g³³ +function set_velocity_at_surface!(Y, turbconv_model) + bot_uₕ = Fields.level(Y.c.uₕ, 1) + sfc_u₃ = Fields.level(Y.f.u₃, half) + sfc_gⁱʲ = Fields.local_geometry_field(sfc_u₃).gⁱʲ + shifted_sfc_u₃ = Fields.Field(Fields.field_values(sfc_u₃), axes(bot_uₕ)) + shifted_sfc_gⁱʲ = Fields.Field(Fields.field_values(sfc_gⁱʲ), axes(bot_uₕ)) + @. shifted_sfc_u₃ = -inv(g³³(shifted_sfc_gⁱʲ)) * CT3(bot_uₕ) if turbconv_model isa PrognosticEDMFX for j in 1:n_mass_flux_subdomains(turbconv_model) - sfc_u₃ʲ = Fields.level(Y.f.sgsʲs.:($j).u₃.components.data.:1, half) + sfc_u₃ʲ = Fields.level(Y.f.sgsʲs.:($j).u₃, half) @. sfc_u₃ʲ = sfc_u₃ end end @@ -221,15 +219,12 @@ end Modifies `Y.f.u₃` so that `u₃` is 0 at the model top. """ function set_velocity_at_top!(Y, turbconv_model) - top_u₃ = Fields.level( - Y.f.u₃.components.data.:1, - Spaces.nlevels(axes(Y.c)) + half, - ) - @. top_u₃ = 0 + top_u₃ = Fields.level(Y.f.u₃, Spaces.nlevels(axes(Y.c)) + half) + @. top_u₃ = C3(0) if turbconv_model isa PrognosticEDMFX for j in 1:n_mass_flux_subdomains(turbconv_model) top_u₃ʲ = Fields.level( - Y.f.sgsʲs.:($j).u₃.components.data.:1, + Y.f.sgsʲs.:($j).u₃, Spaces.nlevels(axes(Y.c)) + half, ) @. top_u₃ʲ = top_u₃ @@ -238,15 +233,21 @@ function set_velocity_at_top!(Y, turbconv_model) return nothing end -# This is used to set the grid-scale velocity quantities ᶜu, ᶠu³, ᶜK based on -# ᶠu₃, and it is also used to set the SGS quantities based on ᶠu₃⁰ and ᶠu₃ʲ. -function set_velocity_quantities!(ᶜu, ᶠu³, ᶜK, ᶠu₃, ᶜuₕ, ᶠuₕ³) - @. ᶜu = C123(ᶜuₕ) + ᶜinterp(C123(ᶠu₃)) - @. ᶠu³ = ᶠuₕ³ + CT3(ᶠu₃) +function set_ᶜu_and_ᶜK!(ᶜu, ᶜK, ᶜuₕ, ᶠu₃) + @. ᶜu = C123(ᶜuₕ) + C123(ᶜinterp(ᶠu₃)) compute_kinetic!(ᶜK, ᶜuₕ, ᶠu₃) return nothing end +function set_ᶠu³_and_ᶠu!(ᶠu³, ᶠu, ᶜu, ᶠu₃, ᶜρ) + ᶜJ = Fields.local_geometry_field(ᶜu).J + ᶜgⁱʲ = Fields.local_geometry_field(ᶜu).gⁱʲ + @. ᶠu³ = + ᶠwinterp(ᶜρ * ᶜJ, CT3(C12(ᶜu))) + ᶠwinterp(ᶜρ * ᶜJ, g³³(ᶜgⁱʲ)) * ᶠu₃ + @. ᶠu = CT123(ᶠwinterp(ᶜρ * ᶜJ, CT12(ᶜu))) + CT123(ᶠu³) + return nothing +end + function set_sgs_ᶠu₃!(w_function, ᶠu₃, Y, turbconv_model) ρaʲs(sgsʲs) = map(sgsʲ -> sgsʲ.ρa, sgsʲs) u₃ʲs(sgsʲs) = map(sgsʲ -> sgsʲ.u₃, sgsʲs) @@ -472,18 +473,17 @@ NVTX.@annotate function set_precomputed_quantities!(Y, p, t) n = n_mass_flux_subdomains(turbconv_model) thermo_args = (thermo_params, moisture_model) (; ᶜΦ) = p.core - (; ᶜspecific, ᶜu, ᶠu³, ᶜK, ᶜts, ᶜp) = p.precomputed - ᶠuₕ³ = p.scratch.ᶠtemp_CT3 + (; ᶜspecific, ᶜu, ᶠu³, ᶠu, ᶜK, ᶜts, ᶜp) = p.precomputed @. ᶜspecific = specific_gs(Y.c) - set_ᶠuₕ³!(ᶠuₕ³, Y) # TODO: We might want to move this to dss! (and rename dss! to something # like enforce_constraints!). - set_velocity_at_surface!(Y, ᶠuₕ³, turbconv_model) + set_velocity_at_surface!(Y, turbconv_model) set_velocity_at_top!(Y, turbconv_model) - set_velocity_quantities!(ᶜu, ᶠu³, ᶜK, Y.f.u₃, Y.c.uₕ, ᶠuₕ³) + set_ᶜu_and_ᶜK!(ᶜu, ᶜK, Y.c.uₕ, Y.f.u₃) + set_ᶠu³_and_ᶠu!(ᶠu³, ᶠu, ᶜu, Y.f.u₃, Y.c.ρ) if n > 0 # TODO: In the following increments to ᶜK, we actually need to add # quantities of the form ᶜρaχ⁰ / ᶜρ⁰ and ᶜρaχʲ / ᶜρʲ to ᶜK, rather than @@ -550,8 +550,8 @@ NVTX.@annotate function set_precomputed_quantities!(Y, p, t) end if turbconv_model isa PrognosticEDMFX - set_prognostic_edmf_precomputed_quantities_draft_and_bc!(Y, p, ᶠuₕ³, t) - set_prognostic_edmf_precomputed_quantities_environment!(Y, p, ᶠuₕ³, t) + set_prognostic_edmf_precomputed_quantities_draft_and_bc!(Y, p, t) + set_prognostic_edmf_precomputed_quantities_environment!(Y, p, t) set_prognostic_edmf_precomputed_quantities_closures!(Y, p, t) set_prognostic_edmf_precomputed_quantities_precipitation!( Y, @@ -703,21 +703,22 @@ function output_prognostic_sgs_quantities(Y, p, t) (; turbconv_model) = p.atmos thermo_params = CAP.thermodynamics_params(p.params) (; ᶜρa⁰, ᶜρ⁰, ᶜtsʲs) = p.precomputed - ᶠuₕ³ = p.scratch.ᶠtemp_CT3 - set_ᶠuₕ³!(ᶠuₕ³, Y) - (ᶠu₃⁺, ᶜu⁺, ᶠu³⁺, ᶜK⁺) = + (ᶠu₃⁺, ᶜu⁺, ᶠu³⁺, ᶠu⁺, ᶜK⁺) = similar.(( p.precomputed.ᶠu₃⁰, p.precomputed.ᶜu⁰, p.precomputed.ᶠu³⁰, + p.precomputed.ᶠu⁰, p.precomputed.ᶜK⁰, )) set_sgs_ᶠu₃!(u₃⁺, ᶠu₃⁺, Y, turbconv_model) - set_velocity_quantities!(ᶜu⁺, ᶠu³⁺, ᶜK⁺, ᶠu₃⁺, Y.c.uₕ, ᶠuₕ³) + set_ᶜu_and_ᶜK!(ᶜu⁺, ᶜK⁺, Y.c.uₕ, ᶠu₃⁺) ᶜts⁺ = ᶜtsʲs.:1 - ᶜa⁺ = @. draft_area(ρa⁺(Y.c), TD.air_density(thermo_params, ᶜts⁺)) + ᶜρ⁺ = TD.air_density.(thermo_params, ᶜts⁺) + set_ᶠu³_and_ᶠu!(ᶠu³⁺, ᶠu⁺, ᶜu⁺, ᶠu₃⁺, ᶜρ⁺) + ᶜa⁺ = @. draft_area(ρa⁺(Y.c), ᶜρ⁺) ᶜa⁰ = @. draft_area(ᶜρa⁰, ᶜρ⁰) - return (; ᶠu₃⁺, ᶜu⁺, ᶠu³⁺, ᶜK⁺, ᶜts⁺, ᶜa⁺, ᶜa⁰) + return (; ᶠu₃⁺, ᶜu⁺, ᶠu³⁺, ᶠu⁺, ᶜK⁺, ᶜts⁺, ᶜa⁺, ᶜa⁰) end """ diff --git a/src/cache/prognostic_edmf_precomputed_quantities.jl b/src/cache/prognostic_edmf_precomputed_quantities.jl index cf6b889f414..a233b4b4ffc 100644 --- a/src/cache/prognostic_edmf_precomputed_quantities.jl +++ b/src/cache/prognostic_edmf_precomputed_quantities.jl @@ -6,14 +6,13 @@ import Thermodynamics as TD import ClimaCore: Spaces, Fields """ - set_prognostic_edmf_precomputed_quantities!(Y, p, ᶠuₕ³, t) + set_prognostic_edmf_precomputed_quantities!(Y, p, t) Updates the edmf environment precomputed quantities stored in `p` for edmfx. """ NVTX.@annotate function set_prognostic_edmf_precomputed_quantities_environment!( Y, p, - ᶠuₕ³, t, ) @assert !(p.atmos.moisture_model isa DryModel) @@ -22,7 +21,7 @@ NVTX.@annotate function set_prognostic_edmf_precomputed_quantities_environment!( (; turbconv_model) = p.atmos (; ᶜΦ,) = p.core (; ᶜp, ᶜh_tot, ᶜK) = p.precomputed - (; ᶜtke⁰, ᶜρa⁰, ᶠu₃⁰, ᶜu⁰, ᶠu³⁰, ᶜK⁰, ᶜts⁰, ᶜρ⁰, ᶜmse⁰, ᶜq_tot⁰) = + (; ᶜtke⁰, ᶜρa⁰, ᶠu₃⁰, ᶜu⁰, ᶠu³⁰, ᶠu⁰, ᶜK⁰, ᶜts⁰, ᶜρ⁰, ᶜmse⁰, ᶜq_tot⁰) = p.precomputed @. ᶜρa⁰ = ρa⁰(Y.c) @@ -42,15 +41,16 @@ NVTX.@annotate function set_prognostic_edmf_precomputed_quantities_environment!( turbconv_model, ) set_sgs_ᶠu₃!(u₃⁰, ᶠu₃⁰, Y, turbconv_model) - set_velocity_quantities!(ᶜu⁰, ᶠu³⁰, ᶜK⁰, ᶠu₃⁰, Y.c.uₕ, ᶠuₕ³) + set_ᶜu_and_ᶜK!(ᶜu⁰, ᶜK⁰, Y.c.uₕ, ᶠu₃⁰) # @. ᶜK⁰ += ᶜtke⁰ @. ᶜts⁰ = TD.PhaseEquil_phq(thermo_params, ᶜp, ᶜmse⁰ - ᶜΦ, ᶜq_tot⁰) @. ᶜρ⁰ = TD.air_density(thermo_params, ᶜts⁰) + set_ᶠu³_and_ᶠu!(ᶠu³⁰, ᶠu⁰, ᶜu⁰, ᶠu₃⁰, ᶜρ⁰) return nothing end """ - set_prognostic_edmf_precomputed_quantities_draft_and_bc!(Y, p, ᶠuₕ³, t) + set_prognostic_edmf_precomputed_quantities_draft_and_bc!(Y, p, t) Updates the draft thermo state and boundary conditions precomputed quantities stored in `p` for edmfx. @@ -58,7 +58,6 @@ precomputed quantities stored in `p` for edmfx. NVTX.@annotate function set_prognostic_edmf_precomputed_quantities_draft_and_bc!( Y, p, - ᶠuₕ³, t, ) (; moisture_model, turbconv_model) = p.atmos @@ -74,12 +73,13 @@ NVTX.@annotate function set_prognostic_edmf_precomputed_quantities_draft_and_bc! (; ᶜΦ,) = p.core (; ᶜspecific, ᶜp, ᶜh_tot, ᶜK) = p.precomputed - (; ᶜuʲs, ᶠu³ʲs, ᶜKʲs, ᶠKᵥʲs, ᶜtsʲs, ᶜρʲs) = p.precomputed + (; ᶜuʲs, ᶠu³ʲs, ᶠuʲs, ᶜKʲs, ᶠKᵥʲs, ᶜtsʲs, ᶜρʲs) = p.precomputed (; ustar, obukhov_length, buoyancy_flux) = p.precomputed.sfc_conditions for j in 1:n ᶜuʲ = ᶜuʲs.:($j) ᶠu³ʲ = ᶠu³ʲs.:($j) + ᶠuʲ = ᶠuʲs.:($j) ᶜKʲ = ᶜKʲs.:($j) ᶠKᵥʲ = ᶠKᵥʲs.:($j) ᶠu₃ʲ = Y.f.sgsʲs.:($j).u₃ @@ -88,10 +88,11 @@ NVTX.@annotate function set_prognostic_edmf_precomputed_quantities_draft_and_bc! ᶜmseʲ = Y.c.sgsʲs.:($j).mse ᶜq_totʲ = Y.c.sgsʲs.:($j).q_tot - set_velocity_quantities!(ᶜuʲ, ᶠu³ʲ, ᶜKʲ, ᶠu₃ʲ, Y.c.uₕ, ᶠuₕ³) + set_ᶜu_and_ᶜK!(ᶜuʲ, ᶜKʲ, Y.c.uₕ, ᶠu₃ʲ) @. ᶠKᵥʲ = (adjoint(CT3(ᶠu₃ʲ)) * ᶠu₃ʲ) / 2 @. ᶜtsʲ = TD.PhaseEquil_phq(thermo_params, ᶜp, ᶜmseʲ - ᶜΦ, ᶜq_totʲ) @. ᶜρʲ = TD.air_density(thermo_params, ᶜtsʲ) + set_ᶠu³_and_ᶠu!(ᶠu³ʲ, ᶠuʲ, ᶜuʲ, ᶠu₃ʲ, ᶜρʲ) # EDMFX boundary condition: @@ -195,7 +196,7 @@ NVTX.@annotate function set_prognostic_edmf_precomputed_quantities_closures!( FT = eltype(params) n = n_mass_flux_subdomains(turbconv_model) - (; ᶜtke⁰, ᶜu, ᶜp, ᶜρa⁰, ᶠu³⁰, ᶜts⁰, ᶜq_tot⁰) = p.precomputed + (; ᶜtke⁰, ᶜu, ᶜp, ᶜρa⁰, ᶠu³⁰, ᶠu⁰, ᶜts⁰, ᶜq_tot⁰) = p.precomputed (; ᶜmixing_length_tuple, ᶜmixing_length, @@ -303,8 +304,6 @@ NVTX.@annotate function set_prognostic_edmf_precomputed_quantities_closures!( ) # TODO: Currently the shear production only includes vertical gradients - ᶠu⁰ = p.scratch.ᶠtemp_C123 - @. ᶠu⁰ = C123(ᶠinterp(Y.c.uₕ)) + C123(ᶠu³⁰) ᶜstrain_rate = p.scratch.ᶜtemp_UVWxUVW compute_strain_rate_center!(ᶜstrain_rate, ᶠu⁰) @. ᶜstrain_rate_norm = norm_sqr(ᶜstrain_rate) diff --git a/src/prognostic_equations/advection.jl b/src/prognostic_equations/advection.jl index 44dcbf6ba57..aa4acef88d3 100644 --- a/src/prognostic_equations/advection.jl +++ b/src/prognostic_equations/advection.jl @@ -74,9 +74,9 @@ NVTX.@annotate function explicit_vertical_advection_tendency!(Yₜ, Y, p, t) (; dt) = p ᶜJ = Fields.local_geometry_field(Y.c).J (; ᶜf³, ᶠf¹², ᶜΦ) = p.core - (; ᶜu, ᶠu³, ᶜK) = p.precomputed + (; ᶜu, ᶠu³, ᶠu, ᶜK) = p.precomputed (; edmfx_upwinding) = n > 0 || advect_tke ? p.atmos.numerics : all_nothing - (; ᶜuʲs, ᶜKʲs, ᶠKᵥʲs) = n > 0 ? p.precomputed : all_nothing + (; ᶜuʲs, ᶠuʲs, ᶜKʲs, ᶠKᵥʲs) = n > 0 ? p.precomputed : all_nothing (; ᶠu³⁰) = advect_tke ? p.precomputed : all_nothing (; energy_upwinding, tracer_upwinding) = p.atmos.numerics (; ᶜspecific) = p.precomputed @@ -90,7 +90,7 @@ NVTX.@annotate function explicit_vertical_advection_tendency!(Yₜ, Y, p, t) ᶠω¹²ʲs = p.scratch.ᶠtemp_CT12ʲs if point_type <: Geometry.Abstract3DPoint - @. ᶜω³ = curlₕ(Y.c.uₕ) + @. ᶜω³ = wcurlₕ(Y.c.uₕ) elseif point_type <: Geometry.Abstract2DPoint @. ᶜω³ = zero(ᶜω³) end @@ -99,9 +99,9 @@ NVTX.@annotate function explicit_vertical_advection_tendency!(Yₜ, Y, p, t) for j in 1:n @. ᶠω¹²ʲs.:($$j) = ᶠω¹² end - @. ᶠω¹² += CT12(curlₕ(Y.f.u₃)) + @. ᶠω¹² += CT12(wcurlₕ(Y.f.u₃)) for j in 1:n - @. ᶠω¹²ʲs.:($$j) += CT12(curlₕ(Y.f.sgsʲs.:($$j).u₃)) + @. ᶠω¹²ʲs.:($$j) += CT12(wcurlₕ(Y.f.sgsʲs.:($$j).u₃)) end # Without the CT12(), the right-hand side would be a CT1 or CT2 in 2D space. @@ -131,24 +131,20 @@ NVTX.@annotate function explicit_vertical_advection_tendency!(Yₜ, Y, p, t) if isnothing(ᶠf¹²) # shallow atmosphere - @. Yₜ.c.uₕ -= - ᶜinterp(ᶠω¹² × (ᶠinterp(Y.c.ρ * ᶜJ) * ᶠu³)) / (Y.c.ρ * ᶜJ) + - (ᶜf³ + ᶜω³) × CT12(ᶜu) - @. Yₜ.f.u₃ -= ᶠω¹² × ᶠinterp(CT12(ᶜu)) + ᶠgradᵥ(ᶜK) + @. Yₜ.c.uₕ -= ᶜinterp(ᶠω¹² × ᶠu³) + (ᶜf³ + ᶜω³) × CT12(ᶜu) + @. Yₜ.f.u₃ -= ᶠω¹² × CT12(ᶠu) + ᶠgradᵥ(ᶜK) for j in 1:n @. Yₜ.f.sgsʲs.:($$j).u₃ -= - ᶠω¹²ʲs.:($$j) × ᶠinterp(CT12(ᶜuʲs.:($$j))) + + ᶠω¹²ʲs.:($$j) × CT12(ᶠuʲs.:($$j)) + ᶠgradᵥ(ᶜKʲs.:($$j) - ᶜinterp(ᶠKᵥʲs.:($$j))) end else # deep atmosphere - @. Yₜ.c.uₕ -= - ᶜinterp((ᶠf¹² + ᶠω¹²) × (ᶠinterp(Y.c.ρ * ᶜJ) * ᶠu³)) / - (Y.c.ρ * ᶜJ) + (ᶜf³ + ᶜω³) × CT12(ᶜu) - @. Yₜ.f.u₃ -= (ᶠf¹² + ᶠω¹²) × ᶠinterp(CT12(ᶜu)) + ᶠgradᵥ(ᶜK) + @. Yₜ.c.uₕ -= ᶜinterp((ᶠf¹² + ᶠω¹²) × ᶠu³) + (ᶜf³ + ᶜω³) × CT12(ᶜu) + @. Yₜ.f.u₃ -= (ᶠf¹² + ᶠω¹²) × CT12(ᶠu) + ᶠgradᵥ(ᶜK) for j in 1:n @. Yₜ.f.sgsʲs.:($$j).u₃ -= - (ᶠf¹² + ᶠω¹²ʲs.:($$j)) × ᶠinterp(CT12(ᶜuʲs.:($$j))) + + (ᶠf¹² + ᶠω¹²ʲs.:($$j)) × CT12(ᶠuʲs.:($$j)) + ᶠgradᵥ(ᶜKʲs.:($$j) - ᶜinterp(ᶠKᵥʲs.:($$j))) end end diff --git a/src/utils/utilities.jl b/src/utils/utilities.jl index 2d5715bdf54..0f8d4ee3207 100644 --- a/src/utils/utilities.jl +++ b/src/utils/utilities.jl @@ -48,24 +48,30 @@ sort_files_by_time(files) = permute!(files, sortperm(time_from_filename.(files))) """ - compute_kinetic!(κ::Field, uₕ::Field, uᵥ::Field) + compute_kinetic!(ᶜκ::Field, ᶜuₕ::Field, ᶠu₃::Field) -Compute the specific kinetic energy at cell centers, storing in `κ` from +Compute the specific kinetic energy at cell centers, storing in `ᶜκ` from individual velocity components: -κ = 1/2 (uₕ⋅uʰ + 2uʰ⋅ᶜI(uᵥ) + ᶜI(uᵥ⋅uᵛ)) -- `uₕ` should be a `Covariant1Vector` or `Covariant12Vector`-valued field at +ᶜκ = ((ᶜgʰʰ ᶜuₕ) ⋅ ᶜuₕ + 2 (ᶜg³ʰ ᶜuₕ) ⋅ ᶜI(ᶠu₃) + ᶜg³³ ᶜI(ᶠu₃^2))/2 +- `ᶜuₕ` should be a `Covariant1Vector` or `Covariant12Vector`-valued field at cell centers, and -- `uᵥ` should be a `Covariant3Vector`-valued field at cell faces. -""" -function compute_kinetic!(κ::Fields.Field, uₕ::Fields.Field, uᵥ::Fields.Field) - @assert eltype(uₕ) <: Union{C1, C2, C12} - @assert eltype(uᵥ) <: C3 - @. κ = - 1 / 2 * ( - dot(C123(uₕ), CT123(uₕ)) + - ᶜinterp(dot(C123(uᵥ), CT123(uᵥ))) + - 2 * dot(CT123(uₕ), ᶜinterp(C123(uᵥ))) - ) +- `ᶠu₃` should be a `Covariant3Vector`-valued field at cell faces. +""" +function compute_kinetic!( + ᶜκ::Fields.Field, + ᶜuₕ::Fields.Field, + ᶠu₃::Fields.Field, +) + @assert eltype(ᶜuₕ) <: Union{C1, C2, C12} + @assert eltype(ᶠu₃) <: C3 + ᶜg³³_component = g³³_field(ᶜκ) + ᶠu₃_component = ᶠu₃.components.data.:1 + @. ᶜκ = + ( + dot(CT12(ᶜuₕ), C12(ᶜuₕ)) + + 2 * dot(CT3(ᶜuₕ), ᶜinterp(ᶠu₃)) + + ᶜg³³_component * ᶜinterp(ᶠu₃_component^2) + ) / 2 end """ @@ -84,7 +90,6 @@ Compute the strain_rate at cell centers, storing in `ϵ` from velocity at cell faces. """ function compute_strain_rate_center!(ϵ::Fields.Field, u::Fields.Field) - @assert eltype(u) <: C123 axis_uvw = Geometry.UVWAxis() @. ϵ = (