From df5d7b62139c61e2967720f7652743abcbbcc893 Mon Sep 17 00:00:00 2001 From: imreddyTeja Date: Mon, 24 Feb 2025 15:21:45 -0800 Subject: [PATCH] Add more get_fields to ClimaAtmosSimulation Add diffuse_fraction, SW_d, LW_d, and cos of the zenith_angle to get_field on AtmosModelSimulation in Interfacer.jl. Add get_field methods for the above values in ClimaAtmosSimulation Remove safe_div and use anonymous func Only calculate on first level for diffuse_frac Add update_field for emissivity in AtmosModelSim Add emissivity to update_field in the Interfacer, and add a method definition for it in climaatmos.jl All 16 bands are set to the same values. Clamp diffuse_fraction to [0,1] Remove :co2 from atmos update_field :co2 is removed from the default AtmosModelSimulation update_field. The method definition is also removed for ClimaAtmosSimulation. Add atmos get_field for :co2 Add a default get_field for :co2 with AtmosModelSimulation, and a method definition for ClimaAtmosSimulation. Note that this returns a scalar. Add new fields to interfacer_tests Revert to returning zero when dividing by zero In get_field(::ClimaAtmosSimulation, ::Val{:diffuse_fraction} --- .../components/atmosphere/climaatmos.jl | 46 +++++++++++++++---- src/Interfacer.jl | 7 ++- test/field_exchanger_tests.jl | 1 - test/interfacer_tests.jl | 7 ++- 4 files changed, 50 insertions(+), 11 deletions(-) diff --git a/experiments/ClimaEarth/components/atmosphere/climaatmos.jl b/experiments/ClimaEarth/components/atmosphere/climaatmos.jl index 5d81414c93..ed61f78ed7 100644 --- a/experiments/ClimaEarth/components/atmosphere/climaatmos.jl +++ b/experiments/ClimaEarth/components/atmosphere/climaatmos.jl @@ -171,12 +171,45 @@ moisture_flux(::Union{CA.EquilMoistModel, CA.NonEquilMoistModel}, integrator) = ρq_tot(::Union{CA.EquilMoistModel, CA.NonEquilMoistModel}, integrator) = integrator.u.c.ρq_tot # extensions required by the Interfacer +Interfacer.get_field(sim::ClimaAtmosSimulation, ::Val{:cos_zenith_angle}) = CC.Fields.array2field( + sim.integrator.p.radiation.rrtmgp_model.cos_zenith, + CC.Fields.level(axes(sim.integrator.u.c), 1), +) +Interfacer.get_field(sim::ClimaAtmosSimulation, ::Val{:co2}) = + sim.integrator.p.radiation.rrtmgp_model.volume_mixing_ratio_co2[] +function Interfacer.get_field(sim::ClimaAtmosSimulation, ::Val{:diffuse_fraction}) + radiation_model = sim.integrator.p.radiation.rrtmgp_model + # only take the first level + total_flux_dn = radiation_model.face_sw_flux_dn[1, :] + lowest_face_space = CC.Spaces.level(axes(sim.integrator.u.f), CC.Utilities.half) + if radiation_model.radiation_mode isa CA.RRTMGPInterface.GrayRadiation + diffuse_fraction = zero(total_flux_dn) + else + direct_flux_dn = radiation_model.face_sw_direct_flux_dn[1, :] + FT = eltype(total_flux_dn) + diffuse_fraction = + clamp.( + ((x, y) -> y > zero(y) ? x / y : zero(y)).(total_flux_dn .- direct_flux_dn, total_flux_dn), + zero(FT), + one(FT), + ) + end + return CC.Fields.array2field(diffuse_fraction, lowest_face_space) +end Interfacer.get_field(sim::ClimaAtmosSimulation, ::Val{:liquid_precipitation}) = surface_rain_flux(sim.integrator.p.atmos.moisture_model, sim.integrator) +Interfacer.get_field(sim::ClimaAtmosSimulation, ::Val{:LW_d}) = CC.Fields.level( + CC.Fields.array2field(sim.integrator.p.radiation.rrtmgp_model.face_lw_flux_dn, axes(sim.integrator.u.f)), + CC.Utilities.half, +) Interfacer.get_field(sim::ClimaAtmosSimulation, ::Val{:radiative_energy_flux_sfc}) = surface_radiation_flux(sim.integrator.p.atmos.radiation_mode, sim.integrator) Interfacer.get_field(sim::ClimaAtmosSimulation, ::Val{:snow_precipitation}) = surface_snow_flux(sim.integrator.p.atmos.moisture_model, sim.integrator) +Interfacer.get_field(sim::ClimaAtmosSimulation, ::Val{:SW_d}) = CC.Fields.level( + CC.Fields.array2field(sim.integrator.p.radiation.rrtmgp_model.face_sw_flux_dn, axes(sim.integrator.u.f)), + CC.Utilities.half, +) Interfacer.get_field(sim::ClimaAtmosSimulation, ::Val{:turbulent_energy_flux}) = CC.Geometry.WVector.(sim.integrator.p.precomputed.sfc_conditions.ρ_flux_h_tot) Interfacer.get_field(sim::ClimaAtmosSimulation, ::Val{:turbulent_moisture_flux}) = @@ -201,15 +234,12 @@ function Interfacer.get_field(sim::ClimaAtmosSimulation, ::Val{:uv_int}) return @. StaticArrays.SVector(uₕ_int.components.data.:1, uₕ_int.components.data.:2) end -function Interfacer.update_field!(atmos_sim::ClimaAtmosSimulation, ::Val{:co2}, field) - if atmos_sim.integrator.p.atmos.radiation_mode isa CA.RRTMGPI.GrayRadiation - @warn("Gray radiation model initialized, skipping CO2 update", maxlog = 1) - return - else - atmos_sim.integrator.p.radiation.rrtmgp_model.volume_mixing_ratio_co2 .= Statistics.mean(parent(field)) - end -end # extensions required by the Interfacer +function Interfacer.update_field!(sim::ClimaAtmosSimulation, ::Val{:emissivity}, field) + # sets all 16 bands (rows) to the same values + sim.integrator.p.radiation.rrtmgp_model.surface_emissivity .= + reshape(CC.Fields.field2array(field), 1, length(parent(field))) +end function Interfacer.update_field!(sim::ClimaAtmosSimulation, ::Val{:surface_direct_albedo}, field) sim.integrator.p.radiation.rrtmgp_model.direct_sw_surface_albedo .= reshape(CC.Fields.field2array(field), 1, length(parent(field))) diff --git a/src/Interfacer.jl b/src/Interfacer.jl index 3c37c23bcd..5582a159f8 100644 --- a/src/Interfacer.jl +++ b/src/Interfacer.jl @@ -155,12 +155,17 @@ an atmosphere component model. get_field( sim::AtmosModelSimulation, val::Union{ + Val{:cos_zenith_angle}, + Val{:co2}, + Val{:diffuse_fraction}, Val{:height_int}, Val{:height_sfc}, Val{:liquid_precipitation}, + Val{:LW_d}, Val{:radiative_energy_flux_sfc}, Val{:radiative_energy_flux_toa}, Val{:snow_precipitation}, + Val{:SW_d}, Val{:turblent_energy_flux}, Val{:turbulent_moisture_flux}, Val{:thermo_state_int}, @@ -214,7 +219,7 @@ If it isn't extended, the field won't be updated and a warning will be raised. update_field!( sim::AtmosModelSimulation, val::Union{ - Val{:co2}, + Val{:emissivity}, Val{:surface_direct_albedo}, Val{:surface_diffuse_albedo}, Val{:surface_temperature}, diff --git a/test/field_exchanger_tests.jl b/test/field_exchanger_tests.jl index abae5fe5e7..5557bf8b1b 100644 --- a/test/field_exchanger_tests.jl +++ b/test/field_exchanger_tests.jl @@ -93,7 +93,6 @@ end function Interfacer.update_field!(sim::TestAtmosSimulation, ::Val{:roughness_momentum}, field) parent(sim.cache.roughness_momentum) .= parent(field) end -Interfacer.update_field!(sim::TestAtmosSimulation, ::Val{:co2}, field) = nothing Interfacer.update_field!(sim::TestAtmosSimulation, ::Val{:surface_temperature}, field) = nothing Interfacer.update_field!(sim::TestAtmosSimulation, ::Val{:roughness_buoyancy}, field) = nothing Interfacer.update_field!(sim::TestAtmosSimulation, ::Val{:beta}, field) = nothing diff --git a/test/interfacer_tests.jl b/test/interfacer_tests.jl index 977c5e7b37..c1516f9fc8 100644 --- a/test/interfacer_tests.jl +++ b/test/interfacer_tests.jl @@ -155,12 +155,17 @@ end # Test that get_field gives correct warnings for unextended fields for value in ( + :cos_zenith_angle, + :co2, + :diffuse_fraction, :height_int, :height_sfc, :liquid_precipitation, + :LW_d, :radiative_energy_flux_sfc, :radiative_energy_flux_toa, :snow_precipitation, + :SW_d, :turbulent_energy_flux, :turbulent_moisture_flux, :thermo_state_int, @@ -209,7 +214,7 @@ end sim = DummySimulation4(space) # Test that update_field! gives correct warnings for unextended fields - for value in (:co2, :surface_direct_albedo, :surface_diffuse_albedo, :surface_temperature, :turbulent_fluxes) + for value in (:emissivity, :surface_direct_albedo, :surface_diffuse_albedo, :surface_temperature, :turbulent_fluxes) val = Val(value) @test_logs ( :warn,