diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..846e6dbf --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.pf linguist-language=Fortran-Free-Form diff --git a/.github/workflows/unit-tests.yaml b/.github/workflows/unit-tests.yaml index 45ef3a57..bb54666f 100644 --- a/.github/workflows/unit-tests.yaml +++ b/.github/workflows/unit-tests.yaml @@ -35,7 +35,7 @@ jobs: - name: Build atmospheric_physics run: | cmake \ - -DCMAKE_PREFIX_PATH=/home/runner/work/atmospheric_physics/atmospheric_physics/pFUnit/build/installed \ + -DCMAKE_PREFIX_PATH=$GITHUB_WORKSPACE/pFUnit/build/installed \ -DATMOSPHERIC_PHYSICS_ENABLE_CODE_COVERAGE=ON \ -B./build \ -S./test/unit-test diff --git a/.gitmodules b/.gitmodules index 6606b271..10431cb9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,7 @@ [submodule "mmm-physics"] path = schemes/mmm/mmm_physics url = https://github.com/NCAR/MMM-physics.git - fxtag = 20250616-MPASv8.3 + fxtag = 20251208-CAM-SIMA fxrequired = AlwaysRequired fxDONOTUSEurl = https://github.com/NCAR/MMM-physics.git [submodule "pumas"] diff --git a/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml b/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml index 18c511bd..f91074fe 100644 --- a/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml +++ b/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml @@ -133,6 +133,7 @@ 0.900D0 0.8975D0 0.8975D0 + 0.910D0 diff --git a/schemes/gravity_wave_drag/gw_common_namelist.xml b/schemes/gravity_wave_drag/gw_common_namelist.xml index 167d9543..1cc191ab 100644 --- a/schemes/gravity_wave_drag/gw_common_namelist.xml +++ b/schemes/gravity_wave_drag/gw_common_namelist.xml @@ -32,6 +32,7 @@ 2.5D0 + 0.D0 @@ -47,6 +48,7 @@ 10 + 0 @@ -63,6 +65,7 @@ 2.0D0 + 0.D0 @@ -94,6 +97,7 @@ .true. + .false. diff --git a/schemes/mmm/CMakeLists.txt b/schemes/mmm/CMakeLists.txt index e52c1192..82f278de 100644 --- a/schemes/mmm/CMakeLists.txt +++ b/schemes/mmm/CMakeLists.txt @@ -1,8 +1,8 @@ -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) # `mmm_physics_compat` has not been integrated into the CMake build of any top level projects yet, # and this CMakeLists.txt file is currently for unit testing purposes only. -# Making a change to this CMakeLists.txt file will not impact the build of a parent project at this time. +# Therefore, making a change to this CMakeLists.txt file will not impact the build of a parent project at this time. project(mmm_physics_compat VERSION 0.1.0 @@ -19,11 +19,13 @@ target_sources(mmm_physics_compat ccpp_kind_types.F90 mmm_physics_compat.F90 ) -target_compile_options(mmm_physics_compat - PRIVATE - $<$,$>:-fbacktrace -fcheck=all -std=f2018 -Wall -Wextra -Wpedantic> -) target_include_directories(mmm_physics_compat INTERFACE ${CMAKE_CURRENT_BINARY_DIR} ) +target_compile_options(mmm_physics_compat + PRIVATE + $<$,$>:-fbacktrace -fcheck=all -ffpe-trap=invalid,overflow,zero -fno-unsafe-math-optimizations -frounding-math -fsignaling-nans -std=f2018 -Wall -Wextra -Wpedantic> + $<$,$>:-check all -fp-model=precise -stand f18 -traceback -warn all> + $<$,$>:-check all -fp-model=precise -stand f18 -traceback -warn all> +) diff --git a/schemes/mmm/cu_ntiedtke_compat.F90 b/schemes/mmm/cu_ntiedtke_compat.F90 index 19717226..e98a8e25 100644 --- a/schemes/mmm/cu_ntiedtke_compat.F90 +++ b/schemes/mmm/cu_ntiedtke_compat.F90 @@ -14,21 +14,19 @@ module cu_ntiedtke_compat !! \htmlinclude cu_ntiedtke_compat_pre_run.html subroutine cu_ntiedtke_compat_pre_run( & cflx, exner, landfrac, & - lhf, shf, & rthdynten, rthblten, rthratenlw, rthratensw, & rqvdynten, rqvblten, & lndj, & - ptf, pqvf, hfx, evap, & + ptf, pqvf, evap, & errmsg, errflg) use ccpp_kinds, only: kind_phys use ccpp_scheme_utils, only: ccpp_constituent_index real(kind_phys), intent(in) :: cflx(:, :), exner(:, :), landfrac(:), & - lhf(:), shf(:), & rthdynten(:, :), rthblten(:, :), rthratenlw(:, :), rthratensw(:, :), & rqvdynten(:, :), rqvblten(:, :) integer, intent(out) :: lndj(:) - real(kind_phys), intent(out) :: ptf(:, :), pqvf(:, :), hfx(:), evap(:) + real(kind_phys), intent(out) :: ptf(:, :), pqvf(:, :), evap(:) character(*), intent(out) :: errmsg integer, intent(out) :: errflg @@ -42,7 +40,6 @@ subroutine cu_ntiedtke_compat_pre_run( & ptf(:, :) = (rthdynten(:, :) + rthblten(:, :) + rthratenlw(:, :) + rthratensw(:, :)) * exner(:, :) pqvf(:, :) = rqvdynten(:, :) + rqvblten(:, :) - hfx(:) = lhf(:) + shf(:) evap(:) = 0.0_kind_phys call ccpp_constituent_index( & @@ -50,7 +47,7 @@ subroutine cu_ntiedtke_compat_pre_run( & if (errflg /= 0 .or. & water_vapor_mixing_ratio_index < lbound(cflx, 2) .or. water_vapor_mixing_ratio_index > ubound(cflx, 2)) then - errmsg = 'Failed to find desired constituent flux from cflx' + errmsg = 'cu_ntiedtke_compat_pre_run: Failed to find desired constituent flux from cflx' errflg = 1 return @@ -126,36 +123,54 @@ subroutine cu_ntiedtke_compat_run( & allocate(pu_local, source=pu, errmsg=errmsg, stat=errflg) if (errflg /= 0) then + errmsg = 'cu_ntiedtke_compat_run: Failed to allocate "pu_local"' // new_line('') // & + 'Allocation returned with error: ' // trim(adjustl(errmsg)) + return end if allocate(pv_local, source=pv, errmsg=errmsg, stat=errflg) if (errflg /= 0) then + errmsg = 'cu_ntiedtke_compat_run: Failed to allocate "pv_local"' // new_line('') // & + 'Allocation returned with error: ' // trim(adjustl(errmsg)) + return end if allocate(pt_local, source=pt, errmsg=errmsg, stat=errflg) if (errflg /= 0) then + errmsg = 'cu_ntiedtke_compat_run: Failed to allocate "pt_local"' // new_line('') // & + 'Allocation returned with error: ' // trim(adjustl(errmsg)) + return end if allocate(pqv_local, source=pqv, errmsg=errmsg, stat=errflg) if (errflg /= 0) then + errmsg = 'cu_ntiedtke_compat_run: Failed to allocate "pqv_local"' // new_line('') // & + 'Allocation returned with error: ' // trim(adjustl(errmsg)) + return end if allocate(pqc_local, source=pqc, errmsg=errmsg, stat=errflg) if (errflg /= 0) then + errmsg = 'cu_ntiedtke_compat_run: Failed to allocate "pqc_local"' // new_line('') // & + 'Allocation returned with error: ' // trim(adjustl(errmsg)) + return end if allocate(pqi_local, source=pqi, errmsg=errmsg, stat=errflg) if (errflg /= 0) then + errmsg = 'cu_ntiedtke_compat_run: Failed to allocate "pqi_local"' // new_line('') // & + 'Allocation returned with error: ' // trim(adjustl(errmsg)) + return end if diff --git a/schemes/mmm/cu_ntiedtke_compat.meta b/schemes/mmm/cu_ntiedtke_compat.meta index 6a09d240..5e7d5ed1 100644 --- a/schemes/mmm/cu_ntiedtke_compat.meta +++ b/schemes/mmm/cu_ntiedtke_compat.meta @@ -23,18 +23,6 @@ type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = in -[ lhf ] - standard_name = surface_upward_latent_heat_flux_from_coupler - units = W m-2 - type = real | kind = kind_phys - dimensions = (horizontal_loop_extent) - intent = in -[ shf ] - standard_name = surface_upward_sensible_heat_flux_from_coupler - units = W m-2 - type = real | kind = kind_phys - dimensions = (horizontal_loop_extent) - intent = in [ rthdynten ] standard_name = tendency_of_air_potential_temperature_due_to_dynamics units = K s-1 @@ -89,12 +77,6 @@ type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out -[ hfx ] - standard_name = surface_upward_heat_flux - units = W m-2 - type = real | kind = kind_phys - dimensions = (horizontal_loop_extent) - intent = out [ evap ] standard_name = surface_upward_water_vapor_flux units = kg m-2 s-1 @@ -271,7 +253,7 @@ dimensions = (horizontal_loop_extent) intent = in [ hfx ] - standard_name = surface_upward_heat_flux + standard_name = surface_upward_sensible_heat_flux_from_coupler units = W m-2 type = real | kind = kind_phys dimensions = (horizontal_loop_extent) diff --git a/schemes/mmm/mmm_physics b/schemes/mmm/mmm_physics index a4baf7f3..6cb29bc8 160000 --- a/schemes/mmm/mmm_physics +++ b/schemes/mmm/mmm_physics @@ -1 +1 @@ -Subproject commit a4baf7f3243d1db0dbc5f63473f895bdbdc05c30 +Subproject commit 6cb29bc8f17bc3efdfaaa8a268ca53e2504aadbd diff --git a/schemes/mmm/mmm_physics_compat.F90 b/schemes/mmm/mmm_physics_compat.F90 index 1bd0dfcc..8ab26573 100644 --- a/schemes/mmm/mmm_physics_compat.F90 +++ b/schemes/mmm/mmm_physics_compat.F90 @@ -3,6 +3,7 @@ module mmm_physics_compat implicit none private + public :: mmm_physics_compat_init public :: mmm_physics_compat_run public :: mmm_physics_accumulate_tendencies_timestep_init public :: mmm_physics_accumulate_tendencies_run @@ -12,22 +13,53 @@ module mmm_physics_compat public :: geopotential_height_wrt_sfc_at_if_to_msl_run public :: geopotential_height_wrt_sfc_to_msl_run contains + !> \section arg_table_mmm_physics_compat_init Argument Table + !! \htmlinclude mmm_physics_compat_init.html + pure subroutine mmm_physics_compat_init( & + isfflx, isftcflx, iz0tlnd, & + spp_pbl, & + xice_threshold, & + errmsg, errflg) + use ccpp_kinds, only: kind_phys + + integer, intent(out) :: isfflx, isftcflx, iz0tlnd + logical, intent(out) :: spp_pbl + real(kind_phys), intent(out) :: xice_threshold + character(*), intent(out) :: errmsg + integer, intent(out) :: errflg + + errmsg = '' + errflg = 0 + + ! These options are hardcoded to the same values as in the MPAS physics driver. + ! There are other possible values for them in WRF, but the following combination is the only supported one in MPAS. + isfflx = 1 + isftcflx = 0 + iz0tlnd = 0 + spp_pbl = .false. + xice_threshold = 0.02_kind_phys + end subroutine mmm_physics_compat_init + !> \section arg_table_mmm_physics_compat_run Argument Table !! \htmlinclude mmm_physics_compat_run.html pure subroutine mmm_physics_compat_run( & nstep, & dt, & theta_curr, theta_prev, qv_curr, qv_prev, & + icefrac, xice_threshold, landfrac, & scheme_name, & rthdynten, rqvdynten, & + xland, & errmsg, errflg) use ccpp_kinds, only: kind_phys integer, intent(in) :: nstep real(kind_phys), intent(in) :: dt, & - theta_curr(:, :), theta_prev(:, :), qv_curr(:, :), qv_prev(:, :) + theta_curr(:, :), theta_prev(:, :), qv_curr(:, :), qv_prev(:, :), & + icefrac(:), xice_threshold, landfrac(:) character(256), intent(out) :: scheme_name - real(kind_phys), intent(out) :: rthdynten(:, :), rqvdynten(:, :) + real(kind_phys), intent(out) :: rthdynten(:, :), rqvdynten(:, :), & + xland(:) character(*), intent(out) :: errmsg integer, intent(out) :: errflg @@ -43,6 +75,16 @@ pure subroutine mmm_physics_compat_run( & rthdynten(:, :) = (theta_curr(:, :) - theta_prev(:, :)) / dt rqvdynten(:, :) = (qv_curr(:, :) - qv_prev(:, :)) / dt end if + + ! For MMM physics, land mask (`xland`) is defined as + ! * xland = 1.0 for land cells, including sea ice cells. + ! * xland = 2.0 for water cells. + where (landfrac >= 0.5_kind_phys .or. & + icefrac >= xice_threshold) + xland = 1.0_kind_phys + elsewhere + xland = 2.0_kind_phys + end where end subroutine mmm_physics_compat_run !> \section arg_table_mmm_physics_accumulate_tendencies_timestep_init Argument Table @@ -196,7 +238,8 @@ end subroutine mmm_physics_persist_states_timestep_final !> \section arg_table_compute_characteristic_grid_length_scale_init Argument Table !! \htmlinclude compute_characteristic_grid_length_scale_init.html pure subroutine compute_characteristic_grid_length_scale_init( & - omega, rearth, dx, & + omega, rearth, & + dx, & errmsg, errflg) use ccpp_kinds, only: kind_phys diff --git a/schemes/mmm/mmm_physics_compat.meta b/schemes/mmm/mmm_physics_compat.meta index 5cd2ae93..f6c74782 100644 --- a/schemes/mmm/mmm_physics_compat.meta +++ b/schemes/mmm/mmm_physics_compat.meta @@ -2,6 +2,54 @@ name = mmm_physics_compat type = scheme +[ccpp-arg-table] + name = mmm_physics_compat_init + type = scheme +[ isfflx ] + standard_name = control_for_surface_flux_for_mmm_scheme + units = 1 + type = integer + dimensions = () + intent = out +[ isftcflx ] + standard_name = control_for_surface_roughness_length_over_water_for_mmm_scheme + units = 1 + type = integer + dimensions = () + intent = out +[ iz0tlnd ] + standard_name = control_for_surface_roughness_length_over_land_for_mmm_scheme + units = 1 + type = integer + dimensions = () + intent = out +[ spp_pbl ] + standard_name = flag_for_stochastically_perturbed_parameterization_for_mynn_scheme + units = flag + type = logical + dimensions = () + intent = out +[ xice_threshold ] + standard_name = sea_ice_area_fraction_threshold_for_mmm_scheme + units = fraction + type = real | kind = kind_phys + dimensions = () + intent = out +[ errmsg ] + standard_name = ccpp_error_message + long_name = Error message for error handling in CCPP + units = none + type = character | kind = len=* + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + long_name = Error flag for error handling in CCPP + units = 1 + type = integer + dimensions = () + intent = out + [ccpp-arg-table] name = mmm_physics_compat_run type = scheme @@ -41,6 +89,24 @@ type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in +[ icefrac ] + standard_name = sea_ice_area_fraction_from_coupler + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ xice_threshold ] + standard_name = sea_ice_area_fraction_threshold_for_mmm_scheme + units = fraction + type = real | kind = kind_phys + dimensions = () + intent = in +[ landfrac ] + standard_name = land_area_fraction_from_coupler + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in [ scheme_name ] standard_name = scheme_name units = none @@ -59,6 +125,12 @@ type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out +[ xland ] + standard_name = land_binary_mask_for_mmm_scheme + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out [ errmsg ] standard_name = ccpp_error_message long_name = Error message for error handling in CCPP diff --git a/schemes/mmm/sf_mynn_compat.F90 b/schemes/mmm/sf_mynn_compat.F90 new file mode 100644 index 00000000..80440a42 --- /dev/null +++ b/schemes/mmm/sf_mynn_compat.F90 @@ -0,0 +1,541 @@ +!> This module contains interstitial schemes that are specific to MYNN surface layer scheme, +!> which is part of MMM physics. +module sf_mynn_compat + use ccpp_kinds, only: kind_phys + + implicit none + + private + public :: sf_mynn_compat_pre_run + public :: sf_mynn_compat_init + public :: sf_mynn_compat_run + public :: sf_mynn_diagnostics_init + public :: sf_mynn_diagnostics_run +contains + !> \section arg_table_sf_mynn_compat_pre_run Argument Table + !! \htmlinclude sf_mynn_compat_pre_run.html + subroutine sf_mynn_compat_pre_run( & + itimestep, & + spp_pbl, & + u, v, t, qv, p, dz, rho, & + icefrac, xice_threshold, landfrac, snowhice, snowhland, & + u1d, v1d, t1d, qv1d, p1d, dz8w1d, rho1d, & + u1d2, v1d2, dz2w1d, & + chs, chs2, cqs2, cpm, rmol, & + znt, ust, zol, mol, regime, psim, & + psih, qfx, & + flhc, flqc, snowh, qgh, qsfc, & + gz1oz0, wspd, br, svp1, svp2, & + svp3, svpt0, qcg, & + rstoch1d, & + errmsg, errflg) + use ccpp_kinds, only: kind_phys + + integer, intent(in) :: itimestep + logical, intent(in) :: spp_pbl + real(kind_phys), intent(in) :: u(:, :), v(:, :), t(:, :), qv(:, :), p(:, :), dz(:, :), rho(:, :), & + icefrac(:), xice_threshold, landfrac(:), snowhice(:), snowhland(:) + real(kind_phys), intent(out) :: u1d(:), v1d(:), t1d(:), qv1d(:), p1d(:), dz8w1d(:), rho1d(:), & + u1d2(:), v1d2(:), dz2w1d(:), & + chs(:), chs2(:), cqs2(:), cpm(:), rmol(:), & + znt(:), ust(:), zol(:), mol(:), regime(:), psim(:), & + psih(:), qfx(:), & + flhc(:), flqc(:), snowh(:), qgh(:), qsfc(:), & + gz1oz0(:), wspd(:), br(:), svp1, svp2, & + svp3, svpt0, qcg(:), & + rstoch1d(:) + character(*), intent(out) :: errmsg + integer, intent(out) :: errflg + + ! Provide first guess at the first time step. + if (itimestep == 1) then + ust(:) = max(0.04_kind_phys * sqrt(u(:, 1) ** 2 + v(:, 1) ** 2), 0.001_kind_phys) + mol(:) = 0.0_kind_phys + qsfc(:) = qv(:, 1) ! Note that this `qv` is wet. + end if + + ! In CAM-SIMA, the first vertical index is at top of atmosphere. + ! The last one is at bottom of atmosphere, which is what we want here. + + u1d(:) = u(:, size(u, 2)) + v1d(:) = v(:, size(v, 2)) + t1d(:) = t(:, size(t, 2)) + qv1d(:) = qv(:, size(qv, 2)) + p1d(:) = p(:, size(p, 2)) + dz8w1d(:) = dz(:, size(dz, 2)) + rho1d(:) = rho(:, size(rho, 2)) + + u1d2(:) = u(:, size(u, 2) - 1) + v1d2(:) = v(:, size(v, 2) - 1) + dz2w1d(:) = dz(:, size(dz, 2) - 1) + + chs(:) = 0.0_kind_phys + chs2(:) = 0.0_kind_phys + cqs2(:) = 0.0_kind_phys + cpm(:) = 0.0_kind_phys + rmol(:) = 0.0_kind_phys + + znt(:) = 0.0_kind_phys + zol(:) = 0.0_kind_phys + regime(:) = 0.0_kind_phys + psim(:) = 0.0_kind_phys + + psih(:) = 0.0_kind_phys + qfx(:) = 0.0_kind_phys + + flhc(:) = 0.0_kind_phys + flqc(:) = 0.0_kind_phys + snowh(:) = 0.0_kind_phys + + where (landfrac >= 0.5_kind_phys) + snowh = snowhland + end where + + where (icefrac >= xice_threshold) + snowh = snowhice + end where + + qgh(:) = 0.0_kind_phys + + gz1oz0(:) = 0.0_kind_phys + wspd(:) = 0.0_kind_phys + br(:) = 0.0_kind_phys + + ! Constants in equation 10 from Bolton (1980). See + ! doi:10.1175/1520-0493(1980)108<1046:TCOEPT>2.0.CO;2. + svp1 = 6.112_kind_phys + svp2 = 17.67_kind_phys + svp3 = 29.65_kind_phys + svpt0 = 273.15_kind_phys + + qcg(:) = 0.0_kind_phys ! Not used but still appear in the argument list... + + if (spp_pbl) then + errmsg = 'sf_mynn_compat_pre_run: Stochastically perturbed parameterization is not supported' + errflg = 1 + + return + else + rstoch1d(:) = 0.0_kind_phys + end if + + errmsg = '' + errflg = 0 + end subroutine sf_mynn_compat_pre_run + + !> \section arg_table_sf_mynn_compat_init Argument Table + !! \htmlinclude sf_mynn_compat_init.html + subroutine sf_mynn_compat_init( & + ust, mol, qsfc, & + errmsg, errflg) + use ccpp_kinds, only: kind_phys + use sf_mynn, only: sf_mynn_init + + real(kind_phys), intent(out) :: ust(:), mol(:), qsfc(:) + character(*), intent(out) :: errmsg + integer, intent(out) :: errflg + + ! Precompute lookup tables in MYNN surface layer scheme. + call sf_mynn_init(errmsg, errflg) + + if (errflg /= 0) then + return + end if + + ! MYNN surface layer scheme takes time averages of these variables internally. + ! As a result, they must be able to persist across time steps. + ust(:) = 0.0_kind_phys + mol(:) = 0.0_kind_phys + qsfc(:) = 0.0_kind_phys + + errmsg = '' + errflg = 0 + end subroutine sf_mynn_compat_init + + !> \section arg_table_sf_mynn_compat_run Argument Table + !! \htmlinclude sf_mynn_compat_run.html + subroutine sf_mynn_compat_run( & + ncol, cflx, icefrac, xice_threshold, sst, & + u1d, v1d, t1d, qv1d, p1d, dz8w1d, rho1d, & + u1d2, v1d2, dz2w1d, cp, g, rovcp, r, xlv, & + psfcpa, chs, chs2, cqs2, cpm, pblh, rmol, & + znt, ust, mavail, zol, mol, regime, psim, & + psih, xland, hfx, qfx, tsk, u10, v10, th2, & + t2, q2, flhc, flqc, snowh, qgh, qsfc, lh, & + gz1oz0, wspd, br, isfflx, dx, svp1, svp2, & + svp3, svpt0, ep1, ep2, karman, qcg, & + itimestep, wstar, qstar, ustm, ck, cka, & + cd, cda, spp_pbl, rstoch1d, isftcflx, & + iz0tlnd, its, ite, & + errmsg, errflg) + use ccpp_kinds, only: kind_phys + use ccpp_scheme_utils, only: ccpp_constituent_index + use sf_mynn, only: sf_mynn_run + + ! Typical threshold between sea surface temperature and ice surface temperature. See + ! Algorithm Theoretical Basis Document (ATBD) for the MODIS Snow and Sea Ice-Mapping Algorithms, + ! Section 4.4.3 Ice Surface Temperature (IST) Algorithm. + real(kind_phys), parameter :: sea_ice_temperature_threshold = 271.4_kind_phys + + integer, intent(in) :: ncol, & + isfflx, & + itimestep, & + isftcflx, & + iz0tlnd, its, ite + logical, intent(in) :: spp_pbl + real(kind_phys), intent(in) :: icefrac(:), xice_threshold, sst(:), & + u1d(:), v1d(:), t1d(:), qv1d(:), p1d(:), dz8w1d(:), rho1d(:), & + u1d2(:), v1d2(:), dz2w1d(:), cp, g, rovcp, r, xlv, & + psfcpa(:), pblh(:), & + mavail(:), & + xland(:), tsk(:), & + snowh(:), & + dx(:), svp1, svp2, & + svp3, svpt0, ep1, ep2, karman, qcg(:), & + rstoch1d(:) + real(kind_phys), intent(inout) :: cflx(:, :), & + chs(:), chs2(:), cqs2(:), cpm(:), rmol(:), & + znt(:), ust(:), zol(:), mol(:), regime(:), psim(:), & + psih(:), hfx(:), qfx(:), & + flhc(:), flqc(:), qgh(:), qsfc(:), lh(:), & + gz1oz0(:), wspd(:), br(:) + real(kind_phys), intent(out) :: u10(:), v10(:), th2(:), & + t2(:), q2(:), & + wstar(:), qstar(:), ustm(:), ck(:), cka(:), & + cd(:), cda(:) + character(*), intent(out) :: errmsg + integer, intent(out) :: errflg + + integer :: water_vapor_mixing_ratio_index + real(kind_phys), allocatable :: ch(:) + + ! Special handling for sea ice cells like in MMM physics. + logical, allocatable :: mask_sea_ice_cell(:) + real(kind_phys), allocatable :: mavail_sea(:), & + xland_sea(:), tsk_sea(:) + real(kind_phys), allocatable :: chs_sea(:), chs2_sea(:), cqs2_sea(:), cpm_sea(:), rmol_sea(:), & + znt_sea(:), ust_sea(:), zol_sea(:), mol_sea(:), regime_sea(:), psim_sea(:), & + psih_sea(:), hfx_sea(:), qfx_sea(:), & + flhc_sea(:), flqc_sea(:), qgh_sea(:), qsfc_sea(:), lh_sea(:), & + gz1oz0_sea(:), wspd_sea(:), br_sea(:), & + ch_sea(:) + real(kind_phys), allocatable :: u10_sea(:), v10_sea(:), th2_sea(:), & + t2_sea(:), q2_sea(:), & + wstar_sea(:), qstar_sea(:), ustm_sea(:), ck_sea(:), cka_sea(:), & + cd_sea(:), cda_sea(:) + + ! `ch` is duplicate of `chs`, but for unknown reasons it is passed separately in the argument list + ! to MYNN surface layer scheme. + allocate(ch(ncol), errmsg=errmsg, stat=errflg) + + if (errflg /= 0) then + errmsg = 'sf_mynn_compat_run: Failed to allocate "ch"' // new_line('') // & + 'Allocation returned with error: ' // trim(adjustl(errmsg)) + + return + end if + + ch(:) = chs(:) + + qfx(:) = 0.0_kind_phys + + call ccpp_constituent_index( & + 'water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water', water_vapor_mixing_ratio_index, errflg, errmsg) + + if (errflg /= 0 .or. & + water_vapor_mixing_ratio_index < lbound(cflx, 2) .or. water_vapor_mixing_ratio_index > ubound(cflx, 2)) then + errmsg = 'sf_mynn_compat_run: Failed to find desired constituent flux from cflx' + errflg = 1 + + return + end if + + qfx(:) = cflx(:, water_vapor_mixing_ratio_index) + + allocate(mask_sea_ice_cell(ncol), errmsg=errmsg, stat=errflg) + + if (errflg /= 0) then + errmsg = 'sf_mynn_compat_run: Failed to allocate "mask_sea_ice_cell"' // new_line('') // & + 'Allocation returned with error: ' // trim(adjustl(errmsg)) + + return + end if + + mask_sea_ice_cell(:) = (icefrac >= xice_threshold) + + ! If there are sea ice cells, make local copies of the variables in preparation for the second pass. + if (any(mask_sea_ice_cell)) then + allocate(mavail_sea(ncol), xland_sea(ncol), tsk_sea(ncol), & + errmsg=errmsg, stat=errflg) + + if (errflg /= 0) then + errmsg = 'sf_mynn_compat_run: Failed to allocate "mavail_sea", "xland_sea", "tsk_sea"' // new_line('') // & + 'Allocation returned with error: ' // trim(adjustl(errmsg)) + + return + end if + + mavail_sea(:) = mavail(:) + xland_sea(:) = xland(:) + tsk_sea(:) = tsk(:) + + allocate(chs_sea(ncol), chs2_sea(ncol), cqs2_sea(ncol), cpm_sea(ncol), rmol_sea(ncol), & + znt_sea(ncol), ust_sea(ncol), zol_sea(ncol), mol_sea(ncol), regime_sea(ncol), psim_sea(ncol), & + psih_sea(ncol), hfx_sea(ncol), qfx_sea(ncol), & + flhc_sea(ncol), flqc_sea(ncol), qgh_sea(ncol), qsfc_sea(ncol), lh_sea(ncol), & + gz1oz0_sea(ncol), wspd_sea(ncol), br_sea(ncol), & + ch_sea(ncol), & + errmsg=errmsg, stat=errflg) + + if (errflg /= 0) then + errmsg = 'sf_mynn_compat_run: Failed to allocate "chs_sea", "chs2_sea", "cqs2_sea", ...' // new_line('') // & + 'Allocation returned with error: ' // trim(adjustl(errmsg)) + + return + end if + + chs_sea(:) = chs(:) + chs2_sea(:) = chs2(:) + cqs2_sea(:) = cqs2(:) + cpm_sea(:) = cpm(:) + rmol_sea(:) = rmol(:) + znt_sea(:) = znt(:) + ust_sea(:) = ust(:) + zol_sea(:) = zol(:) + mol_sea(:) = mol(:) + regime_sea(:) = regime(:) + psim_sea(:) = psim(:) + psih_sea(:) = psih(:) + hfx_sea(:) = hfx(:) + qfx_sea(:) = qfx(:) + flhc_sea(:) = flhc(:) + flqc_sea(:) = flqc(:) + qgh_sea(:) = qgh(:) + qsfc_sea(:) = qsfc(:) + lh_sea(:) = lh(:) + gz1oz0_sea(:) = gz1oz0(:) + wspd_sea(:) = wspd(:) + br_sea(:) = br(:) + ch_sea(:) = ch(:) + + allocate(u10_sea(ncol), v10_sea(ncol), th2_sea(ncol), & + t2_sea(ncol), q2_sea(ncol), & + wstar_sea(ncol), qstar_sea(ncol), ustm_sea(ncol), ck_sea(ncol), cka_sea(ncol), & + cd_sea(ncol), cda_sea(ncol), & + errmsg=errmsg, stat=errflg) + + if (errflg /= 0) then + errmsg = 'sf_mynn_compat_run: Failed to allocate "u10_sea", "v10_sea", "th2_sea", ...' // new_line('') // & + 'Allocation returned with error: ' // trim(adjustl(errmsg)) + + return + end if + + u10_sea(:) = u10(:) + v10_sea(:) = v10(:) + th2_sea(:) = th2(:) + t2_sea(:) = t2(:) + q2_sea(:) = q2(:) + wstar_sea(:) = wstar(:) + qstar_sea(:) = qstar(:) + ustm_sea(:) = ustm(:) + ck_sea(:) = ck(:) + cka_sea(:) = cka(:) + cd_sea(:) = cd(:) + cda_sea(:) = cda(:) + + where (mask_sea_ice_cell) + ! Set surface moisture availability to maximum. + mavail_sea = 1.0_kind_phys + + ! Impose minimum skin temperature. + tsk_sea = max(sea_ice_temperature_threshold, sst) + + ! Treat as water cells. + xland_sea = 2.0_kind_phys + + ! Set surface roughness length to calm water. + znt_sea = 0.0001_kind_phys + end where + end if + + ! First pass for all cells. + call sf_mynn_run( & + u1d, v1d, t1d, qv1d, p1d, dz8w1d, rho1d, & + u1d2, v1d2, dz2w1d, cp, g, rovcp, r, xlv, & + psfcpa, chs, chs2, cqs2, cpm, pblh, rmol, & + znt, ust, mavail, zol, mol, regime, psim, & + psih, xland, hfx, qfx, tsk, u10, v10, th2, & + t2, q2, flhc, flqc, snowh, qgh, qsfc, lh, & + gz1oz0, wspd, br, isfflx, dx, svp1, svp2, & + svp3, svpt0, ep1, ep2, karman, ch, qcg, & + itimestep, wstar, qstar, ustm, ck, cka, & + cd, cda, spp_pbl, rstoch1d, isftcflx, & + iz0tlnd, its, ite, & + errmsg, errflg) + + if (errflg /= 0) then + return + end if + + ! The first pass treated sea ice cells as land cells due to how `xland` is defined. + ! The second pass treats sea ice cells as water cells instead. + ! Then, for sea ice cells only, the final results are weighted averages according to their area fractions. + if (any(mask_sea_ice_cell)) then + call sf_mynn_run( & + u1d, v1d, t1d, qv1d, p1d, dz8w1d, rho1d, & + u1d2, v1d2, dz2w1d, cp, g, rovcp, r, xlv, & + psfcpa, chs_sea, chs2_sea, cqs2_sea, cpm_sea, pblh, rmol_sea, & + znt_sea, ust_sea, mavail_sea, zol_sea, mol_sea, regime_sea, psim_sea, & + psih_sea, xland_sea, hfx_sea, qfx_sea, tsk_sea, u10_sea, v10_sea, th2_sea, & + t2_sea, q2_sea, flhc_sea, flqc_sea, snowh, qgh_sea, qsfc_sea, lh_sea, & + gz1oz0_sea, wspd_sea, br_sea, isfflx, dx, svp1, svp2, & + svp3, svpt0, ep1, ep2, karman, ch_sea, qcg, & + itimestep, wstar_sea, qstar_sea, ustm_sea, ck_sea, cka_sea, & + cd_sea, cda_sea, spp_pbl, rstoch1d, isftcflx, & + iz0tlnd, its, ite, & + errmsg, errflg) + + if (errflg /= 0) then + return + end if + + ! Blend the final results between sea ice and sea water. + where (mask_sea_ice_cell) + chs = chs * icefrac + (1.0_kind_phys - icefrac) * chs_sea + chs2 = chs2 * icefrac + (1.0_kind_phys - icefrac) * chs2_sea + cqs2 = cqs2 * icefrac + (1.0_kind_phys - icefrac) * cqs2_sea + cpm = cpm * icefrac + (1.0_kind_phys - icefrac) * cpm_sea + rmol = rmol * icefrac + (1.0_kind_phys - icefrac) * rmol_sea + znt = znt * icefrac + (1.0_kind_phys - icefrac) * znt_sea + ust = ust * icefrac + (1.0_kind_phys - icefrac) * ust_sea + zol = zol * icefrac + (1.0_kind_phys - icefrac) * zol_sea + mol = mol * icefrac + (1.0_kind_phys - icefrac) * mol_sea + psim = psim * icefrac + (1.0_kind_phys - icefrac) * psim_sea + psih = psih * icefrac + (1.0_kind_phys - icefrac) * psih_sea + hfx = hfx * icefrac + (1.0_kind_phys - icefrac) * hfx_sea + qfx = qfx * icefrac + (1.0_kind_phys - icefrac) * qfx_sea + flhc = flhc * icefrac + (1.0_kind_phys - icefrac) * flhc_sea + flqc = flqc * icefrac + (1.0_kind_phys - icefrac) * flqc_sea + qgh = qgh * icefrac + (1.0_kind_phys - icefrac) * qgh_sea + qsfc = qsfc * icefrac + (1.0_kind_phys - icefrac) * qsfc_sea + lh = lh * icefrac + (1.0_kind_phys - icefrac) * lh_sea + gz1oz0 = gz1oz0 * icefrac + (1.0_kind_phys - icefrac) * gz1oz0_sea + wspd = wspd * icefrac + (1.0_kind_phys - icefrac) * wspd_sea + br = br * icefrac + (1.0_kind_phys - icefrac) * br_sea + + u10 = u10 * icefrac + (1.0_kind_phys - icefrac) * u10_sea + v10 = v10 * icefrac + (1.0_kind_phys - icefrac) * v10_sea + th2 = th2 * icefrac + (1.0_kind_phys - icefrac) * th2_sea + t2 = t2 * icefrac + (1.0_kind_phys - icefrac) * t2_sea + q2 = q2 * icefrac + (1.0_kind_phys - icefrac) * q2_sea + wstar = wstar * icefrac + (1.0_kind_phys - icefrac) * wstar_sea + qstar = qstar * icefrac + (1.0_kind_phys - icefrac) * qstar_sea + ustm = ustm * icefrac + (1.0_kind_phys - icefrac) * ustm_sea + ck = ck * icefrac + (1.0_kind_phys - icefrac) * ck_sea + cka = cka * icefrac + (1.0_kind_phys - icefrac) * cka_sea + cd = cd * icefrac + (1.0_kind_phys - icefrac) * cd_sea + cda = cda * icefrac + (1.0_kind_phys - icefrac) * cda_sea + end where + + ! `regime` is a categorical variable. Assign according to whether sea ice or sea water is dominant. + where (mask_sea_ice_cell .and. icefrac < 0.5_kind_phys) + regime = regime_sea + end where + end if + + cflx(:, water_vapor_mixing_ratio_index) = qfx(:) + + errmsg = '' + errflg = 0 + end subroutine sf_mynn_compat_run + + !> \section arg_table_sf_mynn_diagnostics_init Argument Table + !! \htmlinclude sf_mynn_diagnostics_init.html + subroutine sf_mynn_diagnostics_init( & + errmsg, errflg) + use cam_history, only: history_add_field + use cam_history_support, only: horiz_only + + character(*), intent(out) :: errmsg + integer, intent(out) :: errflg + + call history_add_field('sf_mynn_lh', & + 'surface_upward_latent_heat_flux_from_coupler', horiz_only, 'avg', 'W m-2') + call history_add_field('sf_mynn_hfx', & + 'surface_upward_sensible_heat_flux_from_coupler', horiz_only, 'avg', 'W m-2') + call history_add_field('sf_mynn_qfx', & + 'surface_upward_water_vapor_flux', horiz_only, 'avg', 'kg m-2 s-1') + + call history_add_field('sf_mynn_cd', & + 'drag_coefficient_for_momentum_at_10m', horiz_only, 'avg', '1') + call history_add_field('sf_mynn_cda', & + 'drag_coefficient_for_momentum_at_surface_adjacent_layer', horiz_only, 'avg', '1') + call history_add_field('sf_mynn_ck', & + 'bulk_exchange_coefficient_for_enthalpy_at_2m', horiz_only, 'avg', '1') + call history_add_field('sf_mynn_cka', & + 'bulk_exchange_coefficient_for_enthalpy_at_surface_adjacent_layer', horiz_only, 'avg', '1') + + call history_add_field('sf_mynn_q2', & + 'water_vapor_mixing_ratio_wrt_dry_air_at_2m', horiz_only, 'avg', 'kg kg-1') + call history_add_field('sf_mynn_t2', & + 'air_temperature_at_2m', horiz_only, 'avg', 'K') + call history_add_field('sf_mynn_th2', & + 'air_potential_temperature_at_2m', horiz_only, 'avg', 'K') + call history_add_field('sf_mynn_u10', & + 'eastward_wind_at_10m', horiz_only, 'avg', 'm s-1') + call history_add_field('sf_mynn_v10', & + 'northward_wind_at_10m', horiz_only, 'avg', 'm s-1') + + call history_add_field('sf_mynn_ustm', & + 'surface_friction_velocity_assuming_no_correction_for_surface_convective_velocity_scale', horiz_only, 'avg', 'm s-1') + call history_add_field('sf_mynn_wstar', & + 'surface_convective_velocity_scale', horiz_only, 'avg', 'm s-1') + call history_add_field('sf_mynn_qstar', & + 'surface_moisture_scale', horiz_only, 'avg', 'g kg-1') + + errmsg = '' + errflg = 0 + end subroutine sf_mynn_diagnostics_init + + !> \section arg_table_sf_mynn_diagnostics_run Argument Table + !! \htmlinclude sf_mynn_diagnostics_run.html + subroutine sf_mynn_diagnostics_run( & + lh, hfx, qfx, & + cd, cda, ck, cka, & + q2, t2, th2, u10, v10, & + ustm, wstar, qstar, & + errmsg, errflg) + use cam_history, only: history_out_field + use ccpp_kinds, only: kind_phys + + real(kind_phys), intent(in) :: lh(:), hfx(:), qfx(:), & + cd(:), cda(:), ck(:), cka(:), & + q2(:), t2(:), th2(:), u10(:), v10(:), & + ustm(:), wstar(:), qstar(:) + character(*), intent(out) :: errmsg + integer, intent(out) :: errflg + + call history_out_field('sf_mynn_lh', lh) + call history_out_field('sf_mynn_hfx', hfx) + call history_out_field('sf_mynn_qfx', qfx) + + call history_out_field('sf_mynn_cd', cd) + call history_out_field('sf_mynn_cda', cda) + call history_out_field('sf_mynn_ck', ck) + call history_out_field('sf_mynn_cka', cka) + + call history_out_field('sf_mynn_q2', q2) + call history_out_field('sf_mynn_t2', t2) + call history_out_field('sf_mynn_th2', th2) + call history_out_field('sf_mynn_u10', u10) + call history_out_field('sf_mynn_v10', v10) + + call history_out_field('sf_mynn_ustm', ustm) + call history_out_field('sf_mynn_wstar', wstar) + call history_out_field('sf_mynn_qstar', qstar) + + errmsg = '' + errflg = 0 + end subroutine sf_mynn_diagnostics_run +end module sf_mynn_compat diff --git a/schemes/mmm/sf_mynn_compat.meta b/schemes/mmm/sf_mynn_compat.meta new file mode 100644 index 00000000..53463d22 --- /dev/null +++ b/schemes/mmm/sf_mynn_compat.meta @@ -0,0 +1,982 @@ +[ccpp-table-properties] + name = sf_mynn_compat_pre + type = scheme + +[ccpp-arg-table] + name = sf_mynn_compat_pre_run + type = scheme +[ itimestep ] + standard_name = current_timestep_number + units = count + type = integer + dimensions = () + intent = in +[ spp_pbl ] + standard_name = flag_for_stochastically_perturbed_parameterization_for_mynn_scheme + units = flag + type = logical + dimensions = () + intent = in +[ u ] + standard_name = eastward_wind + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ v ] + standard_name = northward_wind + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ t ] + standard_name = air_temperature + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ qv ] + standard_name = water_vapor_mixing_ratio_wrt_dry_air + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ p ] + standard_name = air_pressure + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ dz ] + standard_name = atmosphere_layer_thickness + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ rho ] + standard_name = air_density + units = kg m-3 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ icefrac ] + standard_name = sea_ice_area_fraction_from_coupler + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ xice_threshold ] + standard_name = sea_ice_area_fraction_threshold_for_mmm_scheme + units = fraction + type = real | kind = kind_phys + dimensions = () + intent = in +[ landfrac ] + standard_name = land_area_fraction_from_coupler + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ snowhice ] + standard_name = lwe_surface_snow_depth_over_ice_from_coupler + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ snowhland ] + standard_name = lwe_surface_snow_depth_over_land_from_coupler + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ u1d ] + standard_name = eastward_wind_at_surface_adjacent_layer + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ v1d ] + standard_name = northward_wind_at_surface_adjacent_layer + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ t1d ] + standard_name = air_temperature_at_surface_adjacent_layer + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ qv1d ] + standard_name = water_vapor_mixing_ratio_wrt_dry_air_at_surface_adjacent_layer + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ p1d ] + standard_name = air_pressure_at_surface_adjacent_layer + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ dz8w1d ] + standard_name = atmosphere_layer_thickness_at_surface_adjacent_layer + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ rho1d ] + standard_name = air_density_at_surface_adjacent_layer + units = kg m-3 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ u1d2 ] + standard_name = eastward_wind_at_second_surface_adjacent_layer + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ v1d2 ] + standard_name = northward_wind_at_second_surface_adjacent_layer + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ dz2w1d ] + standard_name = atmosphere_layer_thickness_at_second_surface_adjacent_layer + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ chs ] + standard_name = exchange_coefficient_for_heat_at_surface_adjacent_layer + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ chs2 ] + standard_name = exchange_coefficient_for_heat_at_2m + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ cqs2 ] + standard_name = exchange_coefficient_for_moisture_at_2m + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ cpm ] + standard_name = composition_dependent_specific_heat_of_dry_air_at_constant_pressure_at_surface_adjacent_layer + units = J kg-1 K-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ rmol ] + standard_name = reciprocal_of_monin_obukhov_length + units = m-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ znt ] + standard_name = surface_roughness_length + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ ust ] + standard_name = surface_friction_velocity + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ zol ] + standard_name = ratio_of_height_at_surface_adjacent_layer_to_monin_obukhov_length + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ mol ] + standard_name = surface_temperature_scale + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ regime ] + standard_name = control_for_pbl_stability_regime + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ psim ] + standard_name = monin_obukhov_similarity_function_for_momentum + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ psih ] + standard_name = monin_obukhov_similarity_function_for_heat + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ qfx ] + standard_name = surface_upward_water_vapor_flux + units = kg m-2 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ flhc ] + standard_name = surface_kinematic_exchange_coefficient_for_heat + units = W m-2 K-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ flqc ] + standard_name = surface_kinematic_exchange_coefficient_for_moisture + units = kg m-2 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ snowh ] + standard_name = surface_snow_thickness + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ qgh ] + standard_name = water_vapor_mixing_ratio_wrt_dry_air_at_surface_adjacent_layer_assuming_saturation + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ qsfc ] + standard_name = water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water_at_surface + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ gz1oz0 ] + standard_name = ln_ratio_of_height_at_surface_adjacent_layer_to_surface_roughness_length + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ wspd ] + standard_name = wind_speed_at_surface_adjacent_layer + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ br ] + standard_name = bulk_richardson_number_at_surface_adjacent_layer + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ svp1 ] + standard_name = constant_1_in_formula_for_water_vapor_partial_pressure_assuming_saturation + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = out +[ svp2 ] + standard_name = constant_2_in_formula_for_water_vapor_partial_pressure_assuming_saturation + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = out +[ svp3 ] + standard_name = constant_3_in_formula_for_water_vapor_partial_pressure_assuming_saturation + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = out +[ svpt0 ] + standard_name = constant_4_in_formula_for_water_vapor_partial_pressure_assuming_saturation + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = out +[ qcg ] + standard_name = cloud_liquid_water_mixing_ratio_wrt_dry_air_at_surface + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ rstoch1d ] + standard_name = stochastically_perturbed_weights_for_mynn_scheme + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ errmsg ] + standard_name = ccpp_error_message + long_name = Error message for error handling in CCPP + units = none + type = character | kind = len=* + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + long_name = Error flag for error handling in CCPP + units = 1 + type = integer + dimensions = () + intent = out + +# ---------- + +[ccpp-table-properties] + name = sf_mynn_compat + type = scheme + dependencies = ccpp_kind_types.F90, mmm_physics/mynn_shared.F90, mmm_physics/sf_mynn.F90 + +[ccpp-arg-table] + name = sf_mynn_compat_init + type = scheme +[ ust ] + standard_name = surface_friction_velocity + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_dimension) + intent = out +[ mol ] + standard_name = surface_temperature_scale + units = K + type = real | kind = kind_phys + dimensions = (horizontal_dimension) + intent = out +[ qsfc ] + standard_name = water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water_at_surface + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_dimension) + intent = out +[ errmsg ] + standard_name = ccpp_error_message + long_name = Error message for error handling in CCPP + units = none + type = character | kind = len=* + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + long_name = Error flag for error handling in CCPP + units = 1 + type = integer + dimensions = () + intent = out + +[ccpp-arg-table] + name = sf_mynn_compat_run + type = scheme +[ ncol ] + standard_name = horizontal_loop_extent + units = count + type = integer + dimensions = () + intent = in +[ cflx ] + standard_name = surface_upward_ccpp_constituent_fluxes_from_coupler + units = kg m-2 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, number_of_ccpp_constituents) + intent = inout +[ icefrac ] + standard_name = sea_ice_area_fraction_from_coupler + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ xice_threshold ] + standard_name = sea_ice_area_fraction_threshold_for_mmm_scheme + units = fraction + type = real | kind = kind_phys + dimensions = () + intent = in +[ sst ] + standard_name = sea_surface_temperature_from_coupler + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ u1d ] + standard_name = eastward_wind_at_surface_adjacent_layer + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ v1d ] + standard_name = northward_wind_at_surface_adjacent_layer + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ t1d ] + standard_name = air_temperature_at_surface_adjacent_layer + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ qv1d ] + standard_name = water_vapor_mixing_ratio_wrt_dry_air_at_surface_adjacent_layer + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ p1d ] + standard_name = air_pressure_at_surface_adjacent_layer + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ dz8w1d ] + standard_name = atmosphere_layer_thickness_at_surface_adjacent_layer + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ rho1d ] + standard_name = air_density_at_surface_adjacent_layer + units = kg m-3 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ u1d2 ] + standard_name = eastward_wind_at_second_surface_adjacent_layer + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ v1d2 ] + standard_name = northward_wind_at_second_surface_adjacent_layer + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ dz2w1d ] + standard_name = atmosphere_layer_thickness_at_second_surface_adjacent_layer + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ cp ] + standard_name = specific_heat_of_dry_air_at_constant_pressure + units = J kg-1 K-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ g ] + standard_name = standard_gravitational_acceleration + units = m s-2 + type = real | kind = kind_phys + dimensions = () + intent = in +[ rovcp ] + standard_name = ratio_of_dry_air_gas_constant_to_specific_heat_of_dry_air_at_constant_pressure + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ r ] + standard_name = gas_constant_of_dry_air + units = J kg-1 K-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ xlv ] + standard_name = latent_heat_of_vaporization_of_water_at_0c + units = J kg-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ psfcpa ] + standard_name = surface_air_pressure + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ chs ] + standard_name = exchange_coefficient_for_heat_at_surface_adjacent_layer + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ chs2 ] + standard_name = exchange_coefficient_for_heat_at_2m + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ cqs2 ] + standard_name = exchange_coefficient_for_moisture_at_2m + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ cpm ] + standard_name = composition_dependent_specific_heat_of_dry_air_at_constant_pressure_at_surface_adjacent_layer + units = J kg-1 K-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ pblh ] + standard_name = atmosphere_boundary_layer_thickness + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ rmol ] + standard_name = reciprocal_of_monin_obukhov_length + units = m-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ znt ] + standard_name = surface_roughness_length + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ ust ] + standard_name = surface_friction_velocity + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ mavail ] + standard_name = surface_moisture_availability + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ zol ] + standard_name = ratio_of_height_at_surface_adjacent_layer_to_monin_obukhov_length + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ mol ] + standard_name = surface_temperature_scale + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ regime ] + standard_name = control_for_pbl_stability_regime + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ psim ] + standard_name = monin_obukhov_similarity_function_for_momentum + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ psih ] + standard_name = monin_obukhov_similarity_function_for_heat + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ xland ] + standard_name = land_binary_mask_for_mmm_scheme + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ hfx ] + standard_name = surface_upward_sensible_heat_flux_from_coupler + units = W m-2 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ qfx ] + standard_name = surface_upward_water_vapor_flux + units = kg m-2 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ tsk ] + standard_name = skin_temperature_at_surface + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ u10 ] + standard_name = eastward_wind_at_10m + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ v10 ] + standard_name = northward_wind_at_10m + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ th2 ] + standard_name = air_potential_temperature_at_2m + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ t2 ] + standard_name = air_temperature_at_2m + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ q2 ] + standard_name = water_vapor_mixing_ratio_wrt_dry_air_at_2m + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ flhc ] + standard_name = surface_kinematic_exchange_coefficient_for_heat + units = W m-2 K-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ flqc ] + standard_name = surface_kinematic_exchange_coefficient_for_moisture + units = kg m-2 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ snowh ] + standard_name = surface_snow_thickness + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ qgh ] + standard_name = water_vapor_mixing_ratio_wrt_dry_air_at_surface_adjacent_layer_assuming_saturation + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ qsfc ] + standard_name = water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water_at_surface + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ lh ] + standard_name = surface_upward_latent_heat_flux_from_coupler + units = W m-2 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ gz1oz0 ] + standard_name = ln_ratio_of_height_at_surface_adjacent_layer_to_surface_roughness_length + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ wspd ] + standard_name = wind_speed_at_surface_adjacent_layer + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ br ] + standard_name = bulk_richardson_number_at_surface_adjacent_layer + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ isfflx ] + standard_name = control_for_surface_flux_for_mmm_scheme + units = 1 + type = integer + dimensions = () + intent = in +[ dx ] + standard_name = characteristic_grid_lengthscale + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ svp1 ] + standard_name = constant_1_in_formula_for_water_vapor_partial_pressure_assuming_saturation + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ svp2 ] + standard_name = constant_2_in_formula_for_water_vapor_partial_pressure_assuming_saturation + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ svp3 ] + standard_name = constant_3_in_formula_for_water_vapor_partial_pressure_assuming_saturation + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ svpt0 ] + standard_name = constant_4_in_formula_for_water_vapor_partial_pressure_assuming_saturation + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ ep1 ] + standard_name = ratio_of_water_vapor_to_dry_air_gas_constants_minus_one + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ ep2 ] + standard_name = ratio_of_water_vapor_to_dry_air_molecular_weights + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ karman ] + standard_name = von_karman_constant + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ qcg ] + standard_name = cloud_liquid_water_mixing_ratio_wrt_dry_air_at_surface + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ itimestep ] + standard_name = current_timestep_number + units = count + type = integer + dimensions = () + intent = in +[ wstar ] + standard_name = surface_convective_velocity_scale + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ qstar ] + standard_name = surface_moisture_scale + units = g kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ ustm ] + standard_name = surface_friction_velocity_assuming_no_correction_for_surface_convective_velocity_scale + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ ck ] + standard_name = bulk_exchange_coefficient_for_enthalpy_at_2m + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ cka ] + standard_name = bulk_exchange_coefficient_for_enthalpy_at_surface_adjacent_layer + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ cd ] + standard_name = drag_coefficient_for_momentum_at_10m + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ cda ] + standard_name = drag_coefficient_for_momentum_at_surface_adjacent_layer + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ spp_pbl ] + standard_name = flag_for_stochastically_perturbed_parameterization_for_mynn_scheme + units = flag + type = logical + dimensions = () + intent = in +[ rstoch1d ] + standard_name = stochastically_perturbed_weights_for_mynn_scheme + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ isftcflx ] + standard_name = control_for_surface_roughness_length_over_water_for_mmm_scheme + units = 1 + type = integer + dimensions = () + intent = in +[ iz0tlnd ] + standard_name = control_for_surface_roughness_length_over_land_for_mmm_scheme + units = 1 + type = integer + dimensions = () + intent = in +[ its ] + standard_name = horizontal_loop_begin + units = count + type = integer + dimensions = () + intent = in +[ ite ] + standard_name = horizontal_loop_end + units = count + type = integer + dimensions = () + intent = in +[ errmsg ] + standard_name = ccpp_error_message + long_name = Error message for error handling in CCPP + units = none + type = character | kind = len=* + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + long_name = Error flag for error handling in CCPP + units = 1 + type = integer + dimensions = () + intent = out + +# ---------- + +[ccpp-table-properties] + name = sf_mynn_diagnostics + type = scheme + +[ccpp-arg-table] + name = sf_mynn_diagnostics_init + type = scheme +[ errmsg ] + standard_name = ccpp_error_message + long_name = Error message for error handling in CCPP + units = none + type = character | kind = len=* + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + long_name = Error flag for error handling in CCPP + units = 1 + type = integer + dimensions = () + intent = out + +[ccpp-arg-table] + name = sf_mynn_diagnostics_run + type = scheme +[ lh ] + standard_name = surface_upward_latent_heat_flux_from_coupler + units = W m-2 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ hfx ] + standard_name = surface_upward_sensible_heat_flux_from_coupler + units = W m-2 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ qfx ] + standard_name = surface_upward_water_vapor_flux + units = kg m-2 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ cd ] + standard_name = drag_coefficient_for_momentum_at_10m + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ cda ] + standard_name = drag_coefficient_for_momentum_at_surface_adjacent_layer + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ ck ] + standard_name = bulk_exchange_coefficient_for_enthalpy_at_2m + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ cka ] + standard_name = bulk_exchange_coefficient_for_enthalpy_at_surface_adjacent_layer + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ q2 ] + standard_name = water_vapor_mixing_ratio_wrt_dry_air_at_2m + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ t2 ] + standard_name = air_temperature_at_2m + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ th2 ] + standard_name = air_potential_temperature_at_2m + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ u10 ] + standard_name = eastward_wind_at_10m + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ v10 ] + standard_name = northward_wind_at_10m + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ ustm ] + standard_name = surface_friction_velocity_assuming_no_correction_for_surface_convective_velocity_scale + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ wstar ] + standard_name = surface_convective_velocity_scale + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ qstar ] + standard_name = surface_moisture_scale + units = g kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ errmsg ] + standard_name = ccpp_error_message + long_name = Error message for error handling in CCPP + units = none + type = character | kind = len=* + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + long_name = Error flag for error handling in CCPP + units = 1 + type = integer + dimensions = () + intent = out diff --git a/schemes/radiation_utils/prescribe_radiative_gas_concentrations.F90 b/schemes/radiation_utils/prescribe_radiative_gas_concentrations.F90 new file mode 100644 index 00000000..3fe7411a --- /dev/null +++ b/schemes/radiation_utils/prescribe_radiative_gas_concentrations.F90 @@ -0,0 +1,184 @@ +!------------------------------------------------------------------------------- +! This module uses namelist variable to set prescribed concentrations +! for radiatively-active gases. + +! Eventually this module should be replaced with a more comprehensive atmospheric +! composition/chemistry system, but is fine to use for now when running low-top, +! non-exoplanet CAM-SIMA configurations with minimal chemistry. +!------------------------------------------------------------------------------- +module prescribe_radiative_gas_concentrations + + implicit none + + private + public :: prescribe_radiative_gas_concentrations_init + + +!------------------------------------------------------------------------------- +contains +!------------------------------------------------------------------------------- + +!> \section arg_table_prescribe_radiative_gas_concentrations_init Argument Table +!! \htmlinclude prescribe_radiative_gas_concentrations_init.html +!! + subroutine prescribe_radiative_gas_concentrations_init(ch4_vmr, co2_vmr, cfc11_vmr, & + cfc12_vmr, n2o_vmr, const_array, & + errmsg, errcode) + + ! Use statements + use ccpp_constituent_prop_mod, only: int_unassigned + use ccpp_scheme_utils, only: ccpp_constituent_index + use ccpp_kinds, only: kind_phys + + ! Use statement from RRTMGP, + ! which should hopefully be replaced once + ! molar masses for these species are included + ! in the constituents properties themselves: + use radiation_utils, only: get_molar_mass_ratio + + + ! Input arguments + real(kind_phys), intent(in) :: ch4_vmr + real(kind_phys), intent(in) :: co2_vmr + real(kind_phys), intent(in) :: cfc11_vmr + real(kind_phys), intent(in) :: cfc12_vmr + real(kind_phys), intent(in) :: n2o_vmr + + ! Input/output arguments + real(kind_phys), intent(inout) :: const_array(:,:,:) ! Constituents array + + ! Output arguments + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errcode + + ! Local variables + integer :: const_idx !Constituents object index + real(kind_phys) :: dry_air_to_const_molar_mass_ratio !Ratio of dry air molar mass to constituent molar mass + + !+++++++++++++++++++++++++++++++++++ + ! Convert number/mole fraction into + ! mass mixing ratio w.r.t dry air + !+++++++++++++++++++++++++++++++++++ + + !---- + ! CH4: + !---- + + ! Check if CH4 is present in constituents object: + call ccpp_constituent_index('CH4', const_idx, errcode, errmsg) + if (errcode /= 0) then + return + else if (const_idx /= int_unassigned) then + + ! Get ratio of molar mass of dry air / constituent molar mass + call get_molar_mass_ratio('CH4', dry_air_to_const_molar_mass_ratio, errmsg, errcode) + if (errcode /= 0) then + return + end if + + ! Convert namelist-provided number/mole fraction to + ! mass mixing ratio w.r.t. dry air, and set constituents + ! array to new coonverted value: + const_array(:,:,const_idx) = ch4_vmr*dry_air_to_const_molar_mass_ratio + + end if + + !---- + ! CO2: + !---- + + ! Check if CO2 is present in constituents object: + call ccpp_constituent_index('CO2', const_idx, errcode, errmsg) + if (errcode /= 0) then + return + else if (const_idx /= int_unassigned) then + + ! Get ratio of molar mass of dry air / constituent molar mass + call get_molar_mass_ratio('CO2', dry_air_to_const_molar_mass_ratio, errmsg, errcode) + if (errcode /= 0) then + return + end if + + ! Convert namelist-provided number/mole fraction to + ! mass mixing ratio w.r.t. dry air, and set constituents + ! array to new coonverted value: + const_array(:,:,const_idx) = co2_vmr*dry_air_to_const_molar_mass_ratio + + end if + + !------ + ! CFC11: + !------ + + ! Check if CFC-11 is present in constituents object: + call ccpp_constituent_index('CFC11', const_idx, errcode, errmsg) + if (errcode /= 0) then + return + else if (const_idx /= int_unassigned) then + + ! Get ratio of molar mass of dry air / constituent molar mass + call get_molar_mass_ratio('CFC11', dry_air_to_const_molar_mass_ratio, errmsg, errcode) + if (errcode /= 0) then + return + end if + + ! Convert namelist-provided number/mole fraction to + ! mass mixing ratio w.r.t. dry air, and set constituents + ! array to new coonverted value: + const_array(:,:,const_idx) = cfc11_vmr*dry_air_to_const_molar_mass_ratio + + end if + + !------ + ! CFC12: + !------ + + ! Check if CFC-12 is present in constituents object: + call ccpp_constituent_index('CFC12', const_idx, errcode, errmsg) + if (errcode /= 0) then + return + else if (const_idx /= int_unassigned) then + + ! Get ratio of molar mass of dry air / constituent molar mass + call get_molar_mass_ratio('CFC12', dry_air_to_const_molar_mass_ratio, errmsg, errcode) + if (errcode /= 0) then + return + end if + + ! Convert namelist-provided number/mole fraction to + ! mass mixing ratio w.r.t. dry air, and set constituents + ! array to new coonverted value: + const_array(:,:,const_idx) = cfc12_vmr*dry_air_to_const_molar_mass_ratio + + end if + + !---- + ! N2O: + !---- + + ! Check if N2O is present in constituents object: + call ccpp_constituent_index('N2O', const_idx, errcode, errmsg) + if (errcode /= 0) then + return + else if (const_idx /= int_unassigned) then + + ! Get ratio of molar mass of dry air / constituent molar mass + call get_molar_mass_ratio('N2O', dry_air_to_const_molar_mass_ratio, errmsg, errcode) + if (errcode /= 0) then + return + end if + + ! Convert namelist-provided number/mole fraction to + ! mass mixing ratio w.r.t. dry air, and set constituents + ! array to new coonverted value: + const_array(:,:,const_idx) = n2o_vmr*dry_air_to_const_molar_mass_ratio + + end if + + ! Set error variables + errmsg = '' + errcode = 0 + + end subroutine prescribe_radiative_gas_concentrations_init + +end module prescribe_radiative_gas_concentrations \ No newline at end of file diff --git a/schemes/radiation_utils/prescribe_radiative_gas_concentrations.meta b/schemes/radiation_utils/prescribe_radiative_gas_concentrations.meta new file mode 100644 index 00000000..55be49a4 --- /dev/null +++ b/schemes/radiation_utils/prescribe_radiative_gas_concentrations.meta @@ -0,0 +1,56 @@ +[ccpp-table-properties] + name = prescribe_radiative_gas_concentrations + type = scheme + dependencies = ../rrtmgp/utils/radiation_utils.F90 + +[ccpp-arg-table] + name = prescribe_radiative_gas_concentrations_init + type = scheme +[ ch4_vmr ] + standard_name = prescribed_volume_mixing_ratio_of_ch4 + units = mol mol-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ co2_vmr ] + standard_name = prescribed_volume_mixing_ratio_of_co2 + units = mol mol-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ cfc11_vmr ] + standard_name = prescribed_volume_mixing_ratio_of_cfc11 + units = mol mol-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ cfc12_vmr ] + standard_name = prescribed_volume_mixing_ratio_of_cfc12 + units = mol mol-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ n2o_vmr ] + standard_name = prescribed_volume_mixing_ratio_of_n2o + units = mol mol-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ const_array ] + standard_name = ccpp_constituents + units = none + type = real | kind = kind_phys + dimensions = (horizontal_dimension,vertical_layer_dimension,number_of_ccpp_constituents) + intent = inout +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errcode ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out diff --git a/schemes/radiation_utils/prescribe_radiative_gas_concentrations_namelist.xml b/schemes/radiation_utils/prescribe_radiative_gas_concentrations_namelist.xml new file mode 100644 index 00000000..7134e532 --- /dev/null +++ b/schemes/radiation_utils/prescribe_radiative_gas_concentrations_namelist.xml @@ -0,0 +1,157 @@ + + + + + + + + + real + kind_phys + ghg_cam + chem_surfvals + prescribed_volume_mixing_ratio_of_ch4 + mol mol-1 + + CH4 volume mixing ratio. This is used as the time invariant value + of CH4 if no time varying values are specified. + + + 1760.0e-9 + 1650.0e-9 + + + + real + kind_phys + ghg_cam + chem_surfvals + prescribed_volume_mixing_ratio_of_co2 + mol mol-1 + + CO2 volume mixing ratio. This is used as the time invariant value + of CO2 if no time varying values are specified. + + + 367.0e-6 + 348.0e-6 + + + + real + kind_phys + ghg_cam + chem_surfvals + prescribed_volume_mixing_ratio_of_cfc11 + mol mol-1 + + CFC-11 volume mixing ratio. This is used as the time invariant value + of CFC-11 if no time varying values are specified. + + + 653.45e-12 + + + + real + kind_phys + ghg_cam + chem_surfvals + prescribed_volume_mixing_ratio_of_cfc12 + mol mol-1 + + CFC-12 volume mixing ratio. This is used as the time invariant value + of CFC-12 if no time varying values are specified. + + + 535.0e-12 + + + + real + kind_phys + ghg_cam + chem_surfvals + prescribed_volume_mixing_ratio_of_n2o + mol mol-1 + + N2O volume mixing ratio. This is used as the time invariant value + of N2O if no time varying values are specified. + + + 316.0e-9 + 306.0e-9 + + + + diff --git a/schemes/radiation_utils/solar_irradiance_data_namelist.xml b/schemes/radiation_utils/solar_irradiance_data_namelist.xml index f1bfce2c..680eaeef 100644 --- a/schemes/radiation_utils/solar_irradiance_data_namelist.xml +++ b/schemes/radiation_utils/solar_irradiance_data_namelist.xml @@ -82,10 +82,13 @@ filename_of_solar_irradiance_data none - The filename of the solar irradiance data. + The filename of the solar irradiance data. If the file + path is set to "NONE" then it is assumed that a + constant solar irradiance is being used. ${DIN_LOC_ROOT}/atm/cam/solar/SolarForcingCMIP7piControl_c20250103.nc + NONE @@ -112,6 +115,7 @@ .true. + .false. @@ -152,6 +156,7 @@ -9999D0 + 1365.0 diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 index d2f4d117..b239b42d 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 @@ -513,9 +513,13 @@ subroutine prognostic_cloud_water_run( & ! The cloud microphysics is highly nonlinear and coupled with qme ! Both rain processes and qme are calculated iteratively. qme_iter_loop: do l = 1, iter + + ! Adjust relative humidity above the tropopause in higher + ! latitude regions: + call relhum_min_adj(ncol, pver, tropLev, dlat, rhu00, rhu_adj) + qme_update_loop: do i = 1, ncol ! calculation of qme has 4 scenarios - call relhum_min_adj(ncol, pver, tropLev, dlat, rhu00, rhu_adj) if(relhum(i) > rhu_adj(i,k)) then ! 1. whole grid saturation diff --git a/schemes/rrtmgp/rrtmgp_constituents_namelist.xml b/schemes/rrtmgp/rrtmgp_constituents_namelist.xml index 670c2c82..8720ed53 100644 --- a/schemes/rrtmgp/rrtmgp_constituents_namelist.xml +++ b/schemes/rrtmgp/rrtmgp_constituents_namelist.xml @@ -86,7 +86,24 @@ calculation in RRTMGP (H2O not included because it is assumed to be advected if present). - 'N:O2:O2', 'A:CO2:CO2', 'N:ozone:O3', 'A:N2O:N2O', 'A:CH4:CH4', 'N:CFC11STAR:CFC11', 'A:CFC12:CFC12' + + 'N:O2:O2', + 'A:CO2:CO2', + 'N:ozone:O3', + 'A:N2O:N2O', + 'A:CH4:CH4', + 'N:CFC11STAR:CFC11', + 'A:CFC12:CFC12' + + + 'N:O2:O2', + 'N:CO2:CO2', + 'N:ozone:O3', + 'N:N2O:N2O', + 'N:CH4:CH4', + 'N:CFC11:CFC11', + 'N:CFC12:CFC12' + diff --git a/schemes/utilities/set_surface_coupling_vars.F90 b/schemes/utilities/set_surface_coupling_vars.F90 new file mode 100644 index 00000000..6e2eed6f --- /dev/null +++ b/schemes/utilities/set_surface_coupling_vars.F90 @@ -0,0 +1,201 @@ +!----------------------------------------------------------------------- +! Module to handle data that is exchanged between the atmosphere +! model and the surface models (land, sea-ice, ocean, etc.). + +! Please note that currently this is a SIMA-specific module, +! but could be made more host model-independent in the future. +!----------------------------------------------------------------------- +module set_surface_coupling_vars + + implicit none + private + + ! Public interfaces + public :: set_surface_coupling_vars_run + +!=============================================================================== +CONTAINS +!=============================================================================== + +!> \section arg_table_set_surface_coupling_vars_run Argument Table +!! \htmlinclude set_surface_coupling_vars_run.html +!! +subroutine set_surface_coupling_vars_run(ncol, pver, ncnst, gravit, rair, phis, & + surf_pres, air_temp, inv_ps_exner, zm, & + rho, uwnd, vwnd, air_pres, cnst_array, & + prec_dp, snow_dp, prec_sh, snow_sh, & + prec_str, snow_str, air_temp_bot, & + pot_temp_bot, zm_bot, rho_bot, & + uwnd_bot, vwnd_bot, air_pres_bot, & + topo_height, sea_lev_pres, cnst_bot, & + conv_prec, conv_snow, strat_prec, & + strat_snow, errmsg, errcode) + + ! Set surface variables needed for atmosphere-surface coupling. + + ! Use statements + use ccpp_kinds, only: kind_phys + + ! Input arguments + integer, intent(in) :: ncol + integer, intent(in) :: pver + integer, intent(in) :: ncnst + + real(kind_phys), intent(in) :: gravit ! Gravitational acceleration [m s-2] + real(kind_phys), intent(in) :: rair ! Dry air gas constant [J kg-1 K-1] + real(kind_phys), intent(in) :: phis(:) ! Surface geopotential [m2 s-2] + real(kind_phys), intent(in) :: surf_pres(:) ! Surface pressure [Pa] + real(kind_phys), intent(in) :: air_temp(:,:) ! Air temperature [K] + real(kind_phys), intent(in) :: inv_ps_exner(:,:) ! Inverse Exner function w.r.t. surface pressure [1] + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height wrt surface [m] + real(kind_phys), intent(in) :: rho(:,:) ! Dry air density [kg m-3] + real(kind_phys), intent(in) :: uwnd(:,:) ! Eastward wind [m s-1] + real(kind_phys), intent(in) :: vwnd(:,:) ! Northward wind [m s-1] + real(kind_phys), intent(in) :: air_pres(:,:) ! Air pressure [Pa] + real(kind_phys), intent(in) :: cnst_array(:,:,:) ! CCPP constituents array [none] + + real(kind_phys), intent(in) :: prec_dp(:) ! LWE deep convective precipitation (all phases) [m s-1] + real(kind_phys), intent(in) :: snow_dp(:) ! LWE deep convective frozen precipitation (e.g. snow) [m s-1] + real(kind_phys), intent(in) :: prec_sh(:) ! LWE shallow convective precipitation (all phases) [m s-1] + real(kind_phys), intent(in) :: snow_sh(:) ! LWE shallow convective frozen precipitation (all phases) [m s-1] + real(kind_phys), intent(in) :: prec_str(:) ! LWE stratiform precipitation (all phases) [m s-1] + real(kind_phys), intent(in) :: snow_str(:) ! LWE stratiform frozen precipitation (e.g. snow) [m s-1] + + ! Output arguments + real(kind_phys), intent(out) :: air_temp_bot(:) ! Air temperature at bottom of atmosphere for coupling [K] + real(kind_phys), intent(out) :: pot_temp_bot(:) ! Potential air temprature at bottom of atmosphere for coupling [K] + real(kind_phys), intent(out) :: zm_bot(:) ! Geopotential height wrt surface at bottom of atmosphere for coupling [m] + real(kind_phys), intent(out) :: rho_bot(:) ! Dry air density at bottom of atmosphere for coupling [kg m-3] + real(kind_phys), intent(out) :: uwnd_bot(:) ! Eastward wind at bottom of atmosphere for coupling [m s-1] + real(kind_phys), intent(out) :: vwnd_bot(:) ! Northward wind at bottom of atmosphere for coupling [m s-1] + real(kind_phys), intent(out) :: air_pres_bot(:) ! Air pressure at bottom of atmosphere for coupling [Pa] + real(kind_phys), intent(out) :: topo_height(:) ! Geopotential height of surface topography [m] + real(kind_phys), intent(out) :: sea_lev_pres(:) ! Sea Level Pressure [Pa] + real(kind_phys), intent(out) :: cnst_bot(:,:) ! Constituent mixing ratios at bottom of atmosphere for coupling [kg kg-1] + + real(kind_phys), intent(out) :: conv_prec(:) ! LWE Convective precipitation (all phases) [m s-1] + real(kind_phys), intent(out) :: conv_snow(:) ! LWE Frozen convective precipitation (e.g. snow) [m s-1] + real(kind_phys), intent(out) :: strat_prec(:) ! LWE Stratiform (large-scale) precipitation (all phases) [m s-1] + real(kind_phys), intent(out) :: strat_snow(:) ! LWE Frozen stratiform (large-scale)precipitation (e.g. snow) [m s-1] + + character(len=512), intent(out) :: errmsg ! CCPP error message + integer, intent(out) :: errcode ! CCPP error code + + ! Local variables + + integer :: i ! column index + integer :: m ! constituent index + + !----------------------------------------------------------------------- + + errmsg = '' + errcode = 0 + + ! Copy over atmospheric 3-D variables to surface fields: + do i=1,ncol + air_temp_bot(i) = air_temp(i,pver) + pot_temp_bot(i) = air_temp(i,pver) * inv_ps_exner(i,pver) + zm_bot(i) = zm(i,pver) + rho_bot(i) = rho(i,pver) + uwnd_bot(i) = uwnd(i,pver) + vwnd_bot(i) = vwnd(i,pver) + air_pres_bot(i) = air_pres(i,pver) + topo_height(i) = phis(i)/gravit + end do + + ! Calculate Sea Level Pressure (PSL): + call calc_sea_level_pressure(ncol, gravit, rair, air_pres_bot, phis, & + surf_pres, air_temp_bot, sea_lev_pres) + + ! Set surface constituent values: + do m = 1, ncnst + do i = 1, ncol + cnst_bot(i,m) = cnst_array(i,pver,m) + end do + end do + + ! + ! Precipation and snow rates from shallow convection, deep convection and stratiform processes. + ! Compute total convective and stratiform precipitation and snow rates + ! + do i=1,ncol + conv_prec(i) = prec_dp(i) + prec_sh(i) + conv_snow(i) = snow_dp(i) + snow_sh(i) + + strat_prec(i) = prec_str(i) !Might be better to have microphysics set these directly + strat_snow(i) = snow_str(i) + end do + +end subroutine set_surface_coupling_vars_run + +!*************************************************** +! private subroutine to calculate sea level pressure +!*************************************************** + +subroutine calc_sea_level_pressure(ncol, gravit, rair, pbot, phis, ps, tbot, psl) + +!----------------------------------------------------------------------- +! +! Compute sea level pressure. +! +! Uses ECMWF formulation Algorithm: See section 3.1.b in NCAR NT-396 "Vertical +! Interpolation and Truncation of Model-Coordinate Data +! +!----------------------------------------------------------------------- + + ! Use statements + use ccpp_kinds, only: kind_phys + + !-----------------------------Arguments--------------------------------- + integer , intent(in) :: ncol ! longitude dimension + + real(kind_phys), intent(in) :: gravit ! Gravitational acceleration [m s-2] + real(kind_phys), intent(in) :: rair ! gas constant for dry air [J kg-1 K-1] + real(kind_phys), intent(in) :: pbot(:) ! Bottom layer atmospheric pressure [Pa] + real(kind_phys), intent(in) :: phis(:) ! Surface geopotential [m2 s-2] + real(kind_phys), intent(in) :: ps(:) ! Surface air pressure [Pa] + real(kind_phys), intent(in) :: Tbot(:) ! Bottom layer Atmospheric temperature [K] + + real(kind_phys), intent(out):: psl(:) ! Sea level pressures [Pa] + + !-----------------------------Parameters-------------------------------- + real(kind_phys), parameter :: xlapse = 6.5e-3_kind_phys ! Temperature lapse rate [K m-1] + + !-----------------------------Local Variables--------------------------- + integer :: i ! Loop index + real(kind_phys) :: alpha ! Temperature lapse rate in terms of pressure ratio (unitless) + real(kind_phys) :: Tstar ! Computed surface temperature + real(kind_phys) :: TT0 ! Computed temperature at sea-level + real(kind_phys) :: alph ! Power to raise P/Ps to get rate of increase of T with pressure + real(kind_phys) :: beta ! alpha*phis/(R*T) term used in approximation of PSL + !----------------------------------------------------------------------- + + alpha = rair*xlapse/gravit + do i=1,ncol + if ( abs(phis(i)/gravit) < 1.e-4_kind_phys )then + psl(i)=ps(i) + else + Tstar=Tbot(i)*(1._kind_phys+alpha*(ps(i)/pbot(i)-1._kind_phys)) ! pg 7 eq 5 + + TT0=Tstar + xlapse*phis(i)/gravit ! pg 8 eq 13 + + if ( Tstar<=290.5_kind_phys .and. TT0>290.5_kind_phys ) then ! pg 8 eq 14.1 + alph=rair/phis(i)*(290.5_kind_phys-Tstar) + else if (Tstar>290.5_kind_phys .and. TT0>290.5_kind_phys) then ! pg 8 eq 14.2 + alph=0._kind_phys + Tstar= 0.5_kind_phys * (290.5_kind_phys + Tstar) + else + alph=alpha + if (Tstar<255._kind_phys) then + Tstar= 0.5_kind_phys * (255._kind_phys + Tstar) ! pg 8 eq 14.3 + end if + end if + + beta = phis(i)/(rair*Tstar) + psl(i)=ps(i)*exp( beta*(1._kind_phys-alph*beta/2._kind_phys+((alph*beta)**2)/3._kind_phys)) + end if + end do + +end subroutine calc_sea_level_pressure + +end module set_surface_coupling_vars diff --git a/schemes/utilities/set_surface_coupling_vars.meta b/schemes/utilities/set_surface_coupling_vars.meta new file mode 100644 index 00000000..73f32544 --- /dev/null +++ b/schemes/utilities/set_surface_coupling_vars.meta @@ -0,0 +1,240 @@ +[ccpp-table-properties] + name = set_surface_coupling_vars + type = scheme + +[ccpp-arg-table] + name = set_surface_coupling_vars_run + type = scheme + +#---------------- +#Input Arguments +#---------------- + +[ ncol ] + standard_name = horizontal_loop_extent + units = count + type = integer + dimensions = () + intent = in +[ pver ] + standard_name = vertical_layer_dimension + units = count + type = integer + dimensions = () + intent = in +[ ncnst ] + standard_name = number_of_ccpp_constituents + units = count + type = integer + dimensions = () + intent = in +[ gravit ] + standard_name = standard_gravitational_acceleration + units = m s-2 + type = real | kind = kind_phys + dimensions = () + intent = in +[ rair ] + standard_name = gas_constant_of_dry_air + units = J kg-1 K-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ phis ] + standard_name = surface_geopotential + type = real | kind = kind_phys + units = m2 s-2 + dimensions = (horizontal_loop_extent) + intent = in +[ surf_pres ] + standard_name = surface_air_pressure + type = real | kind = kind_phys + units = Pa + dimensions = (horizontal_loop_extent) + intent = in +[ air_temp ] + standard_name = air_temperature + type = real | kind = kind_phys + units = K + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ inv_ps_exner ] + standard_name = reciprocal_of_dimensionless_exner_function_wrt_surface_air_pressure + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ zm ] + standard_name = geopotential_height_wrt_surface + type = real | kind = kind_phys + units = m + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ rho ] + standard_name = dry_air_density + units = kg m-3 + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + type = real | kind = kind_phys + intent = in +[ uwnd ] + standard_name = eastward_wind + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ vwnd ] + standard_name = northward_wind + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ air_pres ] + standard_name = air_pressure + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ cnst_array ] + standard_name = ccpp_constituents + units = none + dimensions = (horizontal_loop_extent, vertical_layer_dimension, number_of_ccpp_constituents) + type = real | kind = kind_phys + intent = in +[ prec_dp ] + standard_name = lwe_precipitation_rate_at_surface_due_to_deep_convection + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ snow_dp ] + standard_name = lwe_frozen_precipitation_rate_at_surface_due_to_deep_convection + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ prec_sh ] + standard_name = lwe_precipitation_rate_at_surface_due_to_shallow_convection + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ snow_sh ] + standard_name = lwe_frozen_precipitation_rate_at_surface_due_to_shallow_convection + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ prec_str ] + standard_name = lwe_large_scale_precipitation_rate_at_surface + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ snow_str ] + standard_name = lwe_snow_and_cloud_ice_precipitation_rate_at_surface_due_to_microphysics + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in + +#---------------- +#Output Arguments +#---------------- + +[ air_temp_bot ] + standard_name = air_temperature_at_bottom_layer_to_coupler + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ pot_temp_bot ] + standard_name = potential_temperature_wrt_surface_pressure_at_bottom_layer_to_coupler + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ zm_bot ] + standard_name = geopotential_height_wrt_surface_at_bottom_layer_to_coupler + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ rho_bot ] + standard_name = dry_air_density_at_bottom_layer_to_coupler + units = kg m-3 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ uwnd_bot ] + standard_name = eastward_wind_at_bottom_layer_to_coupler + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ vwnd_bot ] + standard_name = northward_wind_at_bottom_layer_to_coupler + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ air_pres_bot ] + standard_name = air_pressure_at_bottom_layer_to_coupler + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ topo_height ] + standard_name = surface_topographic_height_to_coupler + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ sea_lev_pres ] + standard_name = air_pressure_at_sea_level_to_coupler + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ cnst_bot ] + standard_name = constituent_mixing_ratio_at_bottom_layer_to_coupler + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, number_of_ccpp_constituents) + intent = out +[ conv_prec ] + standard_name = lwe_convective_precipitation_rate_at_surface_to_coupler + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ conv_snow ] + standard_name = lwe_convective_snowfall_rate_at_surface_to_coupler + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ strat_prec ] + standard_name = lwe_large_scale_precipitation_rate_at_surface_to_coupler + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ strat_snow ] + standard_name = lwe_large_scale_snowfall_rate_at_surface_to_coupler + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errcode ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out + diff --git a/schemes/utilities/state_converters.F90 b/schemes/utilities/state_converters.F90 index 5d49ec97..a4b5c578 100644 --- a/schemes/utilities/state_converters.F90 +++ b/schemes/utilities/state_converters.F90 @@ -10,9 +10,15 @@ module state_converters public :: temp_to_potential_temp_run public :: potential_temp_to_temp_run - ! Calculate density from equation of state/ideal gas law + ! Calculate dry air density by equation of state/ideal gas law public :: calc_dry_air_ideal_gas_density_run + ! Calculate air density by hydrostatic equation + public :: calc_hydrostatic_air_density_run + + ! Calculate atmosphere layer thickness + public :: calc_atmosphere_layer_thickness_run + ! Calculate exner public :: calc_exner_run @@ -75,7 +81,7 @@ end subroutine potential_temp_to_temp_run subroutine calc_dry_air_ideal_gas_density_run(ncol, nz, rair, pmiddry, temp, rho, errmsg, errflg) integer, intent(in) :: ncol ! Number of columns integer, intent(in) :: nz ! Number of vertical levels - real(kind_phys), intent(in) :: rair(:,:) ! gas constant for dry air (J kg-1) + real(kind_phys), intent(in) :: rair(:,:) ! Gas constant of dry air (J kg-1 K-1) real(kind_phys), intent(in) :: pmiddry(:,:) ! Air pressure of dry air (Pa) real(kind_phys), intent(in) :: temp(:,:) ! Air temperature (K) real(kind_phys), intent(out) :: rho(:,:) ! Dry air density (kg m-3) @@ -93,6 +99,53 @@ subroutine calc_dry_air_ideal_gas_density_run(ncol, nz, rair, pmiddry, temp, rho end subroutine calc_dry_air_ideal_gas_density_run + !> \section arg_table_calc_hydrostatic_air_density_run Argument Table + !! \htmlinclude calc_hydrostatic_air_density_run.html + pure subroutine calc_hydrostatic_air_density_run( & + pdel, gravit, dz, & + rho, & + errmsg, errflg) + use ccpp_kinds, only: kind_phys + + real(kind_phys), intent(in) :: pdel(:, :), gravit, dz(:, :) + real(kind_phys), intent(out) :: rho(:, :) + character(*), intent(out) :: errmsg + integer, intent(out) :: errflg + + ! Calculate air density by hydrostatic equation. + rho(:, :) = pdel(:, :) / (gravit * dz(:, :)) + + errmsg = '' + errflg = 0 + end subroutine calc_hydrostatic_air_density_run + + !> \section arg_table_calc_atmosphere_layer_thickness_run Argument Table + !! \htmlinclude calc_atmosphere_layer_thickness_run.html + pure subroutine calc_atmosphere_layer_thickness_run( & + ncol, & + zisfc, & + dz, & + errmsg, errflg) + use ccpp_kinds, only: kind_phys + + integer, intent(in) :: ncol + real(kind_phys), intent(in) :: zisfc(:, :) + real(kind_phys), intent(out) :: dz(:, :) + character(*), intent(out) :: errmsg + integer, intent(out) :: errflg + + integer :: i + + ! In CAM-SIMA, the first vertical index is at top of atmosphere. + ! The last one is at bottom of atmosphere. The resulting `dz` is positive. + do i = 1, ncol + dz(i, :) = zisfc(i, 1:size(zisfc, 2) - 1) - zisfc(i, 2:size(zisfc, 2)) + end do + + errmsg = '' + errflg = 0 + end subroutine calc_atmosphere_layer_thickness_run + !> \section arg_table_calc_exner_run Argument Table !! \htmlinclude calc_exner_run.html subroutine calc_exner_run(ncol, nz, cpair, rair, ref_pres, pmid, exner, & diff --git a/schemes/utilities/state_converters.meta b/schemes/utilities/state_converters.meta index 1bbfc5bb..9389d8f5 100644 --- a/schemes/utilities/state_converters.meta +++ b/schemes/utilities/state_converters.meta @@ -173,6 +173,94 @@ type = integer intent = out +######################################################### +[ccpp-table-properties] + name = calc_hydrostatic_air_density + type = scheme + +[ccpp-arg-table] + name = calc_hydrostatic_air_density_run + type = scheme +[ pdel ] + standard_name = air_pressure_thickness + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ gravit ] + standard_name = standard_gravitational_acceleration + units = m s-2 + type = real | kind = kind_phys + dimensions = () + intent = in +[ dz ] + standard_name = atmosphere_layer_thickness + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ rho ] + standard_name = air_density + units = kg m-3 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ errmsg ] + standard_name = ccpp_error_message + long_name = Error message for error handling in CCPP + units = none + type = character | kind = len=* + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + long_name = Error flag for error handling in CCPP + units = 1 + type = integer + dimensions = () + intent = out + +######################################################### +[ccpp-table-properties] + name = calc_atmosphere_layer_thickness + type = scheme + +[ccpp-arg-table] + name = calc_atmosphere_layer_thickness_run + type = scheme +[ ncol ] + standard_name = horizontal_loop_extent + units = count + type = integer + dimensions = () + intent = in +[ zisfc ] + standard_name = geopotential_height_wrt_surface_at_interface + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_interface_dimension) + intent = in +[ dz ] + standard_name = atmosphere_layer_thickness + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ errmsg ] + standard_name = ccpp_error_message + long_name = Error message for error handling in CCPP + units = none + type = character | kind = len=* + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + long_name = Error flag for error handling in CCPP + units = 1 + type = integer + dimensions = () + intent = out + ######################################################### [ccpp-table-properties] name = calc_exner diff --git a/schemes/vertical_diffusion/vertical_diffusion_sponge_layer.meta b/schemes/vertical_diffusion/vertical_diffusion_sponge_layer.meta index d091f95c..9ee426cf 100644 --- a/schemes/vertical_diffusion/vertical_diffusion_sponge_layer.meta +++ b/schemes/vertical_diffusion/vertical_diffusion_sponge_layer.meta @@ -23,6 +23,12 @@ dimensions = () type = real | kind = kind_phys intent = in +[ diff_sponge_fac ] + standard_name = scale_factor_for_sponge_layer_vertical_diffusion + units = 1 + dimensions = () + type = real | kind = kind_phys + intent = in [ errmsg ] standard_name = ccpp_error_message units = none @@ -51,6 +57,12 @@ dimensions = () type = integer intent = in +[ diff_sponge_fac ] + standard_name = scale_factor_for_sponge_layer_vertical_diffusion + units = 1 + dimensions = () + type = real | kind = kind_phys + intent = in [ kvm ] standard_name = eddy_momentum_diffusivity_at_interfaces units = m2 s-1 diff --git a/schemes/zhang_mcfarlane/zm_conv_options_namelist.xml b/schemes/zhang_mcfarlane/zm_conv_options_namelist.xml index 001fde77..2ed47487 100644 --- a/schemes/zhang_mcfarlane/zm_conv_options_namelist.xml +++ b/schemes/zhang_mcfarlane/zm_conv_options_namelist.xml @@ -14,6 +14,7 @@ Autoconversion coefficient over land in ZM deep convection scheme. 0.0075D0 + 0.0035D0 @@ -27,6 +28,7 @@ Autoconversion coefficient over ocean in ZM deep convection scheme. 0.0300D0 + 0.0035D0 @@ -66,6 +68,8 @@ Tunable evaporation efficiency for land in ZM deep convection scheme. 1.0E-5 + 3.0E-6 + 3.0E-6 diff --git a/suites/suite_cam4.xml b/suites/suite_cam4.xml index 3a3f41c5..de4f1484 100644 --- a/suites/suite_cam4.xml +++ b/suites/suite_cam4.xml @@ -7,15 +7,15 @@ Shallow convection Hack Macrophysics RK Microphysics RK - Radiation RRTMGP (commented out) + Radiation RRTMGP Chemistry None (not implemented) Vertical Diffusion HB Gravity Wave Drag Orographic --> - - initialize_constituents + to_be_ccppized_temporary + prescribe_radiative_gas_concentrations zm_conv_options @@ -215,16 +215,16 @@ sima_state_diagnostics - + rrtmgp_cloud_diagnostics - + rrtmgp_lw_mcica_subcol_gen - + - + rrtmgp_diagnostics - + apply_heating_rate + geopotential_temp @@ -269,6 +269,12 @@ tropopause_find tropopause_diagnostics + + + calc_dry_air_ideal_gas_density + set_surface_coupling_vars + @@ -359,6 +365,7 @@ + gravity_wave_drag_common @@ -394,6 +401,7 @@ + check_energy_save_teout diff --git a/suites/suite_cam7.xml b/suites/suite_cam7.xml index b39cebe4..e7508b7f 100644 --- a/suites/suite_cam7.xml +++ b/suites/suite_cam7.xml @@ -5,7 +5,6 @@ - initialize_constituents to_be_ccppized_temporary @@ -75,6 +74,13 @@ check_energy_scaling check_energy_chng + + + + + diff --git a/test/test_suites/suite_convection_permitting.xml b/test/test_suites/suite_convection_permitting.xml index 4c91fda1..884a0c1f 100644 --- a/test/test_suites/suite_convection_permitting.xml +++ b/test/test_suites/suite_convection_permitting.xml @@ -2,7 +2,10 @@ + + calc_atmosphere_layer_thickness calc_exner + calc_hydrostatic_air_density compute_characteristic_grid_length_scale geopotential_height_wrt_sfc_at_if_to_msl geopotential_height_wrt_sfc_to_msl @@ -13,14 +16,22 @@ mmm_physics_compat + + sf_mynn_compat_pre + sf_mynn_compat + sf_mynn_diagnostics + + bl_gwdo_compat_pre bl_gwdo_compat bl_gwdo_diagnostics + cu_ntiedtke_compat_pre cu_ntiedtke_compat cu_ntiedtke_diagnostics + mmm_physics_accumulate_tendencies apply_tendency_of_eastward_wind apply_tendency_of_northward_wind diff --git a/test/unit-test/tests/mmm/CMakeLists.txt b/test/unit-test/tests/mmm/CMakeLists.txt index 69528847..269c7b6e 100644 --- a/test/unit-test/tests/mmm/CMakeLists.txt +++ b/test/unit-test/tests/mmm/CMakeLists.txt @@ -6,3 +6,9 @@ add_pfunit_ctest(mmm_physics_compat_tests LINK_LIBRARIES mmm_physics_compat ) +target_compile_options(mmm_physics_compat_tests + PRIVATE + $<$,$>:-fbacktrace -fcheck=all -ffpe-trap=invalid,overflow,zero -fno-unsafe-math-optimizations -frounding-math -fsignaling-nans -std=f2018 -Wall -Wextra -Wpedantic> + $<$,$>:-check all -fp-model=precise -stand f18 -traceback -warn all> + $<$,$>:-check all -fp-model=precise -stand f18 -traceback -warn all> +) diff --git a/test/unit-test/tests/mmm/mmm_physics_compat_tests.pf b/test/unit-test/tests/mmm/mmm_physics_compat_tests.pf index 0160fd60..d1e3e0af 100644 --- a/test/unit-test/tests/mmm/mmm_physics_compat_tests.pf +++ b/test/unit-test/tests/mmm/mmm_physics_compat_tests.pf @@ -1,3 +1,37 @@ +@test +subroutine test_mmm_physics_compat_init() + use ccpp_kinds, only: kind_phys + use funit + use mmm_physics_compat, only: mmm_physics_compat_init + + integer :: isfflx, isftcflx, iz0tlnd + logical :: spp_pbl + real(kind_phys) :: xice_threshold + character(100) :: errmsg + integer :: errflg + + isfflx = huge(0) + isftcflx = huge(0) + iz0tlnd = huge(0) + spp_pbl = .false. + xice_threshold = huge(0.0_kind_phys) + + call mmm_physics_compat_init( & + isfflx, isftcflx, iz0tlnd, & + spp_pbl, & + xice_threshold, & + errmsg, errflg) + + ! Should set options to the same values as in the MPAS physics driver. + @assertEqual(1, isfflx) + @assertEqual(0, isftcflx) + @assertEqual(0, iz0tlnd) + @assertEqual(.false., spp_pbl) + @assertEqual(0.02_kind_phys, xice_threshold) + @assertEqual('', errmsg) + @assertEqual(0, errflg) +end subroutine test_mmm_physics_compat_init + @test subroutine test_mmm_physics_compat_run() use ccpp_kinds, only: kind_phys @@ -8,11 +42,15 @@ subroutine test_mmm_physics_compat_run() integer :: nstep real(kind_phys) :: dt real(kind_phys) :: theta_curr(ncol, pver), theta_prev(ncol, pver), qv_curr(ncol, pver), qv_prev(ncol, pver) + real(kind_phys) :: icefrac(ncol), xice_threshold, landfrac(ncol) character(256) :: scheme_name real(kind_phys) :: rthdynten(ncol, pver), rqvdynten(ncol, pver) + real(kind_phys) :: xland(ncol) character(100) :: errmsg integer :: errflg + integer :: i + nstep = 0 dt = 20.0_kind_phys @@ -20,41 +58,66 @@ subroutine test_mmm_physics_compat_run() theta_prev(:, :) = 273.15_kind_phys qv_curr(:, :) = 0.03_kind_phys qv_prev(:, :) = 0.01_kind_phys + icefrac(1:50) = 0.0_kind_phys + icefrac(51:100) = [(0.01_kind_phys + real(i - 1, kind_phys) * 0.02_kind_phys, i = 1, 50)] + xice_threshold = 0.02_kind_phys + landfrac(1:50) = [(0.01_kind_phys + real(i - 1, kind_phys) * 0.02_kind_phys, i = 1, 50)] + landfrac(51:100) = 0.0_kind_phys + scheme_name = '' rthdynten(:, :) = huge(0.0_kind_phys) rqvdynten(:, :) = huge(0.0_kind_phys) + xland(:) = huge(0.0_kind_phys) call mmm_physics_compat_run( & nstep, & dt, & theta_curr, theta_prev, qv_curr, qv_prev, & + icefrac, xice_threshold, landfrac, & scheme_name, & rthdynten, rqvdynten, & + xland, & errmsg, errflg) - ! Tendencies should be zero at start (nstep = 0). + ! Should set scheme name. @assertEqual('mmm_physics_compat_run', scheme_name) + ! Tendencies should be zero at start (nstep = 0). @assertEqual(0.0_kind_phys, rthdynten) @assertEqual(0.0_kind_phys, rqvdynten) + ! Should set land mask according to ice and land fractions. + @assertEqual(2.0_kind_phys, xland(1:25)) + @assertEqual(1.0_kind_phys, xland(26:50)) + @assertEqual(2.0_kind_phys, xland(51)) + @assertEqual(1.0_kind_phys, xland(52:100)) @assertEqual('', errmsg) @assertEqual(0, errflg) nstep = 1 + scheme_name = '' rthdynten(:, :) = huge(0.0_kind_phys) rqvdynten(:, :) = huge(0.0_kind_phys) + xland(:) = huge(0.0_kind_phys) call mmm_physics_compat_run( & nstep, & dt, & theta_curr, theta_prev, qv_curr, qv_prev, & + icefrac, xice_threshold, landfrac, & scheme_name, & rthdynten, rqvdynten, & + xland, & errmsg, errflg) - ! Should compute tendencies correctly afterwards (nstep > 0). + ! Should set scheme name. @assertEqual('mmm_physics_compat_run', scheme_name) + ! Should compute tendencies correctly afterwards (nstep > 0). @assertEqual(1.0_kind_phys, rthdynten, epsilon(0.0_kind_phys)) @assertEqual(0.001_kind_phys, rqvdynten, epsilon(0.0_kind_phys)) + ! Should set land mask according to ice and land fractions. + @assertEqual(2.0_kind_phys, xland(1:25)) + @assertEqual(1.0_kind_phys, xland(26:50)) + @assertEqual(2.0_kind_phys, xland(51)) + @assertEqual(1.0_kind_phys, xland(52:100)) @assertEqual('', errmsg) @assertEqual(0, errflg) end subroutine test_mmm_physics_compat_run diff --git a/test/unit-test/tests/utilities/test_state_converters.pf b/test/unit-test/tests/utilities/test_state_converters.pf index bc56f038..dcd7bc8e 100644 --- a/test/unit-test/tests/utilities/test_state_converters.pf +++ b/test/unit-test/tests/utilities/test_state_converters.pf @@ -25,3 +25,63 @@ subroutine test_temp_to_potential_temp() @assertEqual(0, errflg) end subroutine test_temp_to_potential_temp + +@test +subroutine test_calc_hydrostatic_air_density_run() + use ccpp_kinds, only: kind_phys + use funit + use state_converters, only: calc_hydrostatic_air_density_run + + integer, parameter :: ncol = 100, pver = 10 + real(kind_phys) :: pdel(ncol, pver), gravit, dz(ncol, pver) + real(kind_phys) :: rho(ncol, pver) + character(100) :: errmsg + integer :: errflg + + pdel(:, :) = 98.0_kind_phys + gravit = 9.8_kind_phys + dz(:, :) = 10.0_kind_phys + rho(:, :) = huge(0.0_kind_phys) + + call calc_hydrostatic_air_density_run( & + pdel, gravit, dz, & + rho, & + errmsg, errflg) + + ! Should compute air density correctly. + @assertEqual(1.0_kind_phys, rho, spacing(1.0_kind_phys)) + @assertEqual('', errmsg) + @assertEqual(0, errflg) +end subroutine test_calc_hydrostatic_air_density_run + +@test +subroutine test_calc_atmosphere_layer_thickness_run() + use ccpp_kinds, only: kind_phys + use funit + use state_converters, only: calc_atmosphere_layer_thickness_run + + integer, parameter :: ncol = 100, pver = 10, pverp = 11 + real(kind_phys) :: zisfc(ncol, pverp) + real(kind_phys) :: dz(ncol, pver) + character(100) :: errmsg + integer :: errflg + + integer :: i + + do i = 1, pverp + zisfc(:, i) = 10000.0_kind_phys - real(i - 1, kind_phys) * 1000.0_kind_phys + end do + + dz(:, :) = huge(0.0_kind_phys) + + call calc_atmosphere_layer_thickness_run( & + ncol, & + zisfc, & + dz, & + errmsg, errflg) + + ! Should compute atmosphere layer thickness correctly. + @assertEqual(1000.0_kind_phys, dz, spacing(1000.0_kind_phys)) + @assertEqual('', errmsg) + @assertEqual(0, errflg) +end subroutine test_calc_atmosphere_layer_thickness_run