From a4968920ea7e34acc8fae0dd14683c8e37ef684e Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Tue, 14 Jan 2025 15:54:20 -0500 Subject: [PATCH 01/39] Initial commit (will be continuously force-pushed) - prognostic_cloud_water sketch out --- .../prognostic_cloud_water.F90 | 1177 +++++++++++++++++ .../prognostic_cloud_water_namelist.xml | 92 ++ schemes/rasch_kristjansson/rk_stratiform.F90 | 25 + to_be_ccppized/cloud_optical_properties.F90 | 384 ++++++ 4 files changed, 1678 insertions(+) create mode 100644 schemes/rasch_kristjansson/prognostic_cloud_water.F90 create mode 100644 schemes/rasch_kristjansson/prognostic_cloud_water_namelist.xml create mode 100644 schemes/rasch_kristjansson/rk_stratiform.F90 create mode 100644 to_be_ccppized/cloud_optical_properties.F90 diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 new file mode 100644 index 00000000..000a9387 --- /dev/null +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 @@ -0,0 +1,1177 @@ +! Copyright (C) 2025 National Science Foundation-National Center for Atmospheric Research +! SPDX-License-Identifier: Apache-2.0 +! +! Prognostic cloud water data and methods (cldwat) +! CCPP-ized: Haipeng Lin, January 2025 +module prognostic_cloud_water + use ccpp_kinds, only: kind_phys + + implicit none + private + save + + ! public CCPP-compliant subroutines + public :: prognostic_cloud_water_init + public :: prognostic_cloud_water_run + + ! tuning parameters used by prognostic cloud water (RK stratiform) + real(kind_phys), public :: icritc ! threshold for autoconversion of cold ice [kg kg-1] + ! REMOVECAM: icritc does not have to be public after CAM is retired (namelist option; CCPP framework can provide it) + real(kind_phys) :: icritw ! threshold for autoconversion of warm ice [kg kg-1] + real(kind_phys) :: conke ! tunable constant for evaporation of precipitation [kg-0.5 m s-0.5] + real(kind_phys) :: r3lcrit ! critical radius where liq conversion begins [m] + + logical :: do_psrhmin ! set rh in stratosphere poleward of 50 degrees [flag] + real(kind_phys) :: psrhmin ! rh set in stratosphere poleward of 50 degrees [%] + + ! module private variables + real(kind_phys) :: rhonot ! air density at surface [g cm-3] + real(kind_phys) :: rhos ! assumed snow density [g cm-3] + real(kind_phys) :: rhow ! water density [g cm-3] + real(kind_phys) :: rhoi ! ice density [g cm-3] + real(kind_phys) :: esi ! Collection efficiency for ice by snow [1] + real(kind_phys) :: esw ! Collection efficiency for water by snow [1] + real(kind_phys) :: t0 ! Approx. freezing temperature [K] + real(kind_phys) :: cldmin ! Assumed minimum cloud amount [1] + real(kind_phys) :: small ! Small number compared to unity [1] + real(kind_phys) :: c ! Constant for graupel-like snow [cm^(1-d)/s] + + real(kind_phys) :: d ! Constant for graupel-like snow [1] + real(kind_phys) :: thrpd ! 3+d + real(kind_phys) :: gam3pd ! gamma(3+d) + real(kind_phys) :: gam4pd ! gamma(4+d) + + real(kind_phys) :: nos ! Particles snow concentration [cm^-4] + real(kind_phys) :: prhonos ! pi * rhos * nos + + ! cloud microphysics constants + real(kind_phys) :: mcon01 + real(kind_phys) :: mcon02 + real(kind_phys) :: mcon03 + real(kind_phys) :: mcon04 + real(kind_phys) :: mcon05 + real(kind_phys) :: mcon06 + real(kind_phys) :: mcon07 + real(kind_phys) :: mcon08 + + ! Parameters for findmcnew + real(kind_phys) :: capnw ! Warm continental cloud particle number concentration [cm-3] + real(kind_phys) :: capnc ! Cold/oceanic cloud particle number concentration [cm-3] + real(kind_phys) :: capnsi ! Sea ice cloud particle number concentration [cm-3] + real(kind_phys) :: kconst ! Terminal velocity constant (Stokes regime) [1] + real(kind_phys) :: effc ! Autoconv collection efficiency [1] + real(kind_phys) :: alpha ! Ratio of 3rd moment radius to 2nd [1] + real(kind_phys) :: capc ! Autoconversion constant [1] + real(kind_phys) :: convfw ! Fall velocity calculation constant [1] + real(kind_phys) :: cracw ! Rain accreting water constant [1] + real(kind_phys) :: critpr ! Critical precip rate for collection efficiency [mm day-1] + real(kind_phys) :: ciautb ! Ice autoconversion coefficient [s-1] + +contains + + ! Initialize prognostic cloud water module and calculate microphysical constants +!> \section arg_table_prognostic_cloud_water_init Argument Table +!! \htmlinclude arg_table_prognostic_cloud_water_init.html + subroutine prognostic_cloud_water_init( & + amIRoot, iulog, & + tmelt, rhodair, pi, & + icritc_in, icritw_in, & + conke_in, r3lcrit_in, & + do_psrhmin_in, psrhmin_in, & + errmsg, errflg) + + ! Input arguments + logical, intent(in) :: amIRoot ! are we on the MPI root task? + integer, intent(in) :: iulog ! log output unit + + real(kind_phys), intent(in) :: tmelt ! freezing_point_of_water [K] + real(kind_phys), intent(in) :: rhodair ! density_of_dry_air_at_stp [kg m-3] + real(kind_phys), intent(in) :: pi + + real(kind_phys), intent(in) :: icritc_in + real(kind_phys), intent(in) :: icritw_in + real(kind_phys), intent(in) :: conke_in + real(kind_phys), intent(in) :: r3lcrit_in + logical, intent(in) :: do_psrhmin_in + real(kind_phys), intent(in) :: psrhmin_in + + ! Output arguments + character(len=512), intent(out) :: errmsg ! error message + integer, intent(out) :: errflg ! error flag + + errmsg = '' + errflg = 0 + + ! First populate tuning parameters in-module + icritc = icritc_in + icritw = icritw_in + conke = conke_in + r3lcrit = r3lcrit_in + do_psrhmin = do_psrhmin_in + psrhmin = psrhmin_in + + if(amIRoot) then + write(iulog,*) 'tuning parameters cldwat: icritw',icritw,'icritc',icritc,'conke',conke,'r3lcrit',r3lcrit + endif + + !-------------------------------------------------- + ! Initialize constants used for prognostic condensate (inimc) + ! Original author: P. Rasch, April 1997 + !-------------------------------------------------- + + rhonot = rhodair/1000.0_kind_phys ! convert from kg m-3 to g cm-3 + + ! assumed densities of snow, water, ice [g cm-3] + rhos = 0.1_kind_phys + rhow = 1._kind_phys + rhoi = 1._kind_phys + + esi = 1._kind_phys + esw = 0.1_kind_phys + t0 = tmelt + cldmin = 0.02_kind_phys + small = 1.e-22_kind_phys + c = 152.93_kind_phys + d = 0.25_kind_phys ! constant for graupel like snow + ! values other than 0.25 are not supported. + if(d == 0.25_kind_phys) then + gam3pd = 2.549256966718531_kind_phys + gam4pd = 8.285085141835282_kind_phys + + ! on cray machines this can be calculated using gamma function: + ! call gamma(3._kind_phys+d, signgam, gam3pd) + ! gam3pd = sign(exp(gam3pd),signgam) + ! call gamma(4._kind_phys+d, signgam, gam4pd) + ! gam4pd = sign(exp(gam4pd),signgam) + ! write(iulog,*) ' d, gamma(3+d), gamma(4+d) =', gam3pd, gam4pd + else + errflg = 1 + errmsg = 'prognostic_cloud_water_init: cannot use d /= 0.25' + endif + + nos = 3.e-2_kind_phys + + ! note: pi was originally calculated here as 4._kind_phys * atan(1.0_kind_phys) + ! changed in ccpp-ization to use physconst value. + prhonos = pi*rhos*nos + thrpd = 3._kind_phys + d + + mcon01 = pi*nos*c*gam3pd/4._kind_phys + mcon02 = 1._kind_phys/(c*gam4pd*sqrt(rhonot)/(6*prhonos**(d/4._kind_phys))) + mcon03 = -(0.5_kind_phys+d/4._kind_phys) + mcon04 = 4._kind_phys/(4._kind_phys+d) + mcon05 = (3+d)/(4+d) + mcon06 = (3+d)/4._kind_phys + mcon07 = mcon01*sqrt(rhonot)*mcon02**mcon05/prhonos**mcon06 + mcon08 = -0.5_kind_phys/(4._kind_phys+d) + + ! Initialize parameters used by findmcnew + ! Cloud particle densities [cm-3] for ... + capnw = 400._kind_phys ! ...warm continental + capnc = 150._kind_phys ! ...cold and oceanic + capnsi = 75._kind_phys ! ...sea ice + + kconst = 1.18e6_kind_phys + + ! Autoconv collection efficiencies. + ! Tripoli and Cotton (default) = 0.55 + ! Boucher 96 = 1. + ! Baker 93 = 0.55*0.05 + ! Turn off = 0 + effc = 0.55_kind_phys + + alpha = 1.1_kind_phys ** 4 + ! constant for autoconversion + capc = pi**(-.333_kind_phys)*kconst*effc *(0.75_kind_phys)**(1.333_kind_phys)*alpha + + ! critical precip rate at which we assume the collector drops can change the + ! drop size enough to enhance the auto-conversion process (mm/day) + critpr = 0.5_kind_phys + convfw = 1.94_kind_phys*2.13_kind_phys*sqrt(rhow*1000._kind_phys*9.81_kind_phys*2.7e-4_kind_phys) + + ! liquid microphysics - rain accreting water constant + ! Tripoli and Cotton = default + ! Beheng = 6. + cracw = .884_kind_phys*sqrt(9.81_kind_phys/(rhow*1000._kind_phys*2.7e-4_kind_phys)) ! tripoli and cotton + + ! ice microphysics autoconversion coefficient + ciautb = 5.e-4_kind_phys + + if(amIRoot) then + write(iulog,*) 'tuning parameters cldwat: capnw',capnw,'capnc',capnc,'capnsi',capnsi,'kconst',kconst + write(iulog,*) 'tuning parameters cldwat: effc',effc,'alpha',alpha,'capc',capc + write(iulog,*) 'tuning parameters cldwat: critpr',critpr,'convfw',convfw,'cracw',cracw,'ciautb',ciautb + endif + + end subroutine prognostic_cloud_water_init + + ! Calculate prognostic condensate. + ! Cloud water parameterization, returns tendencies to water vapor, temperature, + ! and cloud water variables. + ! + ! Rasch, P. J., and J. E. Kristjánsson, 1998: A Comparison of the CCM3 Model Climate Using Diagnosed and Predicted Condensate Parameterizations. J. Climate, 11, 1587–1614 + ! https://doi.org/10.1175/1520-0442(1998)011<1587:ACOTCM>2.0.CO;2 + ! + ! with modifications to improve the method of determining condensation/evaporation + ! Zhang et al. (2001?) -- citation unknown. + ! + ! Original authors: M. Zhang, W. Lin, P. Rasch and J.E. Kristjansson + ! B. A. Boville (latent heat of fusion) +!> \section arg_table_prognostic_cloud_water_run Argument Table +!! \htmlinclude arg_table_prognostic_cloud_water_run.html + subroutine prognostic_cloud_water_run( & + ncol, pver, top_lev, deltat, & + iulog, & + pi, gravit, rh2o, epsilo, latvap, latice, cpair, & + dlat, rlat, & + p, pdel, & + zi, & + troplev, & + ttend, tn, & + qtend, qn, & + lctend, cwat, & + omega, & + cldn, & + fice, fsnow, & + rhdfda, rhu00, & + landm, seaicef, snowh, & + cme, & + prodprec, prodsnow, & + evapprec, evapsnow, & + evapheat, prfzheat, meltheat, & + precip, snowab, & + ice2pr, liq2pr, liq2snow, & + lsflxprc, & + lsflxsnw, & + pracwo, psacwo, psacio, & + errmsg, errflg) + ! Dependencies to-be-ccppized. + use wv_saturation, only: qsat, estblf, svp_to_qsat, findsp_vc + + ! Input arguments + integer, intent(in) :: ncol + integer, intent(in) :: pver + integer, intent(in) :: top_lev ! index_of_pressure_at_troposphere_cloud_top [index] + real(kind_phys), intent(in) :: deltat ! timestep [s] + integer, intent(in) :: iulog ! log output unit [1] + real(kind_phys), intent(in) :: pi ! pi_constant [1] + real(kind_phys), intent(in) :: gravit ! gravitational acceleration [m s-2] + real(kind_phys), intent(in) :: rh2o ! gas_constant_of_water_vapor [J K-1 kg-1] + real(kind_phys), intent(in) :: epsilo ! ratio_of_water_vapor_to_dry_air_molecular_weights [1] + real(kind_phys), intent(in) :: latvap ! latent_heat_of_vaporization_of_water_at_0c [J kg-1] + real(kind_phys), intent(in) :: latice ! latent_heat_of_fusion_of_water_at_0c [J kg-1] + real(kind_phys), intent(in) :: cpair ! specific_heat_of_dry_air_at_constant_pressure [J K-1 kg-1] + real(kind_phys), intent(in) :: dlat(:) ! latitude_degrees_north [degrees] + real(kind_phys), intent(in) :: rlat(:) ! latitude [rad] + real(kind_phys), intent(in) :: p(:,:) ! Pressure [Pa] + real(kind_phys), intent(in) :: pdel(:,:) ! Layer thickness [Pa] + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height at interfaces [m] + integer, intent(in) :: tropLev(:) ! Tropopause level [index] + + real(kind_phys), intent(in) :: ttend(:,:) ! Temperature tendency [K s-1] -- from what...? + real(kind_phys), intent(in) :: tn(:,:) ! New Temperature [K] + real(kind_phys), intent(in) :: qtend(:,:) ! Water vapor tendency [kg kg-1 s-1] -- from what...? + real(kind_phys), intent(in) :: qn(:,:) ! New Water vapor mixing ratio [kg kg-1] + real(kind_phys), intent(in) :: lctend(:,:) ! Cloud liquid water tendency [kg kg-1 s-1] -- from what...? + real(kind_phys), intent(in) :: cwat(:,:) ! Cloud water mixing ratio [kg kg-1] + + real(kind_phys), intent(in) :: omega(:,:) ! lagrangian_tendency_of_air_pressure [Pa s-1] + real(kind_phys), intent(in) :: cldn(:,:) ! New Cloud fraction [1 (fraction)] + real(kind_phys), intent(in) :: fice(:,:) ! Ice fraction within cwat [1 (fraction)] + real(kind_phys), intent(in) :: fsnow(:,:) ! Fraction of rain that freezes to show [1 (fraction)] + + real(kind_phys), intent(in) :: rhdfda(:,:) ! dG(a)/da, rh=G(a), when rh>u00 [??] + real(kind_phys), intent(in) :: rhu00(:,:) ! Rhlim for cloud [??] + real(kind_phys), intent(in) :: landm(:) ! smoothed_land_area_fraction [1 (fraction)] + real(kind_phys), intent(in) :: seaicef(:) ! Sea ice fraction [1 (fraction)] + real(kind_phys), intent(in) :: snowh(:) ! Snow depth over land, water equivalent [m] + + ! Output arguments + real(kind_phys), intent(out) :: cme(:,:) ! Rate of condensation-evaporation of condensate (net_condensation_rate_due_to_microphysics) [s-1] + real(kind_phys), intent(out) :: prodprec(:,:) ! Conversion rate of condensate to precip (precipitation_production_due_to_microphysics) [s-1] + real(kind_phys), intent(out) :: prodsnow(:,:) ! Snow production rate (ignored in RK?) [s-1] + real(kind_phys), intent(out) :: evapprec(:,:) ! Falling precipitation evaporation rate (precipitation_evaporation_due_to_microphysics) [s-1] -- & apply q(wv) tendency + real(kind_phys), intent(out) :: evapsnow(:,:) ! Falling snow evaporation rate [s-1] + real(kind_phys), intent(out) :: evapheat(:,:) ! heating rate due to evaporation of precipitation [W kg-1] + real(kind_phys), intent(out) :: prfzheat(:,:) ! heating rate due to freezing of precipitation [W kg-1] + real(kind_phys), intent(out) :: meltheat(:,:) ! heating rate due to snow melt [W kg-1] + real(kind_phys), intent(out) :: precip(:) ! Precipitation rate (lwe_stratiform_precipitation_rate_at_surface) [kg m-2 s-1] + real(kind_phys), intent(out) :: snowab(:) ! Snow rate (lwe_snow_precipitation_rate_at_surface_due_to_microphysics) [kg m-2 s-1] + real(kind_phys), intent(out) :: ice2pr(:,:) ! Conversion rate of ice to precip [kg kg-1 s-1] -- apply q(cldice) tendency + real(kind_phys), intent(out) :: liq2pr(:,:) ! Conversion rate of liquid to precip [kg kg-1 s-1] -- apply q(cldliq) tendency + real(kind_phys), intent(out) :: liq2snow(:,:) ! Conversion rate of liquid to snow [kg kg-1 s-1] -- discard?? + real(kind_phys), intent(out) :: lsflxprc(:,:) ! Grid-box mean, flux large scale cloud rain+snow at interfaces (stratiform_rain_and_snow_flux_at_interface) [kg m-2 s-1] + real(kind_phys), intent(out) :: lsflxsnw(:,:) ! Grid-box mean, flux large scale cloud snow at interfaces (stratiform_snow_flux_at_interface) [kg m-2 s-1] + real(kind_phys), intent(out) :: pracwo(:,:) ! accretion of cloud water by rain [s-1] + real(kind_phys), intent(out) :: psacwo(:,:) ! accretion of cloud water by snow [s-1] + real(kind_phys), intent(out) :: psacio(:,:) ! accretion of cloud ice by snow [s-1] + + ! Output arguments + character(len=512), intent(out) :: errmsg ! error message + integer, intent(out) :: errflg ! error flag + + ! Local variables + integer :: i, k, l ! Iteration index [1] + integer :: iter ! # of iterations for precipitation calculation [1] + logical :: error_found ! Flag for error detection [flag] + + ! Precipitation and conversion rates + real(kind_phys) :: nice2pr ! Rate of conversion from ice to snow [kg kg-1 s-1] + real(kind_phys) :: nliq2pr ! Rate of conversion from liquid to precipitation [kg kg-1 s-1] + real(kind_phys) :: nliq2snow ! Rate of conversion from liquid to snow [kg kg-1 s-1] + real(kind_phys) :: precab(ncol) ! Rate of precipitation entering layer [kg m-2 s-1] + real(kind_phys) :: prprov(ncol) ! Provisional precipitation at bottom of layer [kg m-2 s-1] + + ! Cloud properties + real(kind_phys) :: cldm(ncol) ! Mean cloud fraction over timestep [1] + real(kind_phys) :: cldmax(ncol) ! Maximum cloud fraction above current level [1] + real(kind_phys) :: icwc(ncol) ! In-cloud water content [kg kg-1] + real(kind_phys) :: cwm(ncol) ! Cloud water mixing ratio at midpoint of timestep [kg kg-1] + real(kind_phys) :: cwn(ncol) ! Cloud water mixing ratio at end of timestep [kg kg-1] + real(kind_phys) :: coef(ncol) ! Conversion timescale for condensate to rain [s-1] + !real(kind_phys) :: ice(ncol,pver) ! Ice mixing ratio [kg kg-1] + !real(kind_phys) :: liq(ncol,pver) ! Liquid water mixing ratio [kg kg-1] + + ! Relative importance factors + real(kind_phys) :: fracw(ncol,pver) ! Relative importance of liquid collection by rain [1] + real(kind_phys) :: fsaci(ncol,pver) ! Relative importance of ice collection by snow [1] + real(kind_phys) :: fsacw(ncol,pver) ! Relative importance of liquid collection by snow [1] + real(kind_phys) :: fsaut(ncol,pver) ! Relative importance of ice autoconversion [1] + real(kind_phys) :: fwaut(ncol,pver) ! Relative importance of warm cloud autoconversion [1] + + ! Thermodynamic variables + real(kind_phys) :: t(ncol,pver) ! Temperature before timestep [K] + real(kind_phys) :: tsp(ncol,pver) ! Saturation point temperature [K] + real(kind_phys) :: es(ncol) ! Saturation vapor pressure [Pa] + real(kind_phys) :: q(ncol,pver) ! Water vapor mixing ratio [kg kg-1] + real(kind_phys) :: qs(ncol) ! Saturation specific humidity [kg kg-1] + real(kind_phys) :: qsp(ncol,pver) ! Saturation point mixing ratio [kg kg-1] + real(kind_phys) :: relhum(ncol) ! Relative humidity [1] + real(kind_phys) :: relhum1(ncol) ! Updated relative humidity [1] + real(kind_phys) :: rhu_adj(ncol,pver) ! Adjusted relative humidity limit for strat dehydration [1] + + ! Cloud-Evaporation scheme variables + real(kind_phys) :: calpha(ncol) ! Alpha term in C-E formulation [1] + real(kind_phys) :: cbeta(ncol) ! Beta term in C-E formulation [1] + real(kind_phys) :: cbetah(ncol) ! Beta-hat at saturation portion [1] + real(kind_phys) :: cgamma(ncol) ! Gamma term in C-E formulation [1] + real(kind_phys) :: cgamah(ncol) ! Gamma-hat at saturation portion [1] + real(kind_phys) :: rcgama(ncol) ! Ratio of gamma to gamma-hat [1] + real(kind_phys) :: csigma(ncol) ! Sigma term in C-E formulation [1] + real(kind_phys) :: cmeres(ncol) ! Residual condensation after C-E and evapprec [kg kg-1 s-1] + real(kind_phys) :: cmec1(ncol) ! Cloud condensation coefficient 1 C-E formulation [1] + real(kind_phys) :: cmec2(ncol) ! Cloud condensation coefficient 2 C-E formulation [1] + real(kind_phys) :: cmec3(ncol) ! Cloud condensation coefficient 3 C-E formulation [1] + real(kind_phys) :: cmec4(ncol) ! Cloud condensation coefficient 4 C-E formulation [1] + + + ! Diagnostic arrays for cloud water budget + ! Hardcoded 2 here = number of iterations (iter below) + real(kind_phys) :: rcwn(ncol,2,pver) ! Cloud water ratio evolution [kg kg-1] + real(kind_phys) :: rliq(ncol,2,pver) ! Liquid water ratio evolution [kg kg-1] + real(kind_phys) :: rice(ncol,2,pver) ! Ice ratio evolution [kg kg-1] + + ! Constants and parameters + real(kind_phys), parameter :: omsm = 0.99999_kind_phys ! unity minus small number for rounding + real(kind_phys) :: mincld ! Minimum cloud fraction [1] + real(kind_phys) :: cpohl ! Ratio of specific heat to latent heat [K-1] + real(kind_phys) :: hlocp ! Ratio of latent heat to specific heat [K] + real(kind_phys) :: clrh2o ! Ratio of latent heat to water vapor gas constant [K] + real(kind_phys) :: dto2 ! Half timestep [s] + + ! Work variables + real(kind_phys) :: denom ! Denominator work variable [1] + real(kind_phys) :: dqsdt ! Change in saturation specific humidity with temperature [kg kg-1 K-1] + real(kind_phys) :: gamma(ncol) ! Temperature derivative of saturation specific humidity [kg kg-1 K-1] + real(kind_phys) :: qtl(ncol) ! Saturation tendency [kg kg-1 s-1] + real(kind_phys) :: qtmp ! Temporary mixing ratio [kg kg-1] + real(kind_phys) :: ttmp ! Temporary temperature [K] + real(kind_phys) :: qsn ! Updated saturation specific humidity [kg kg-1] + real(kind_phys) :: esn ! Updated saturation vapor pressure [Pa] + real(kind_phys) :: prtmp ! Temporary precipitation rate [kg m-2 s-1] + real(kind_phys) :: ctmp ! Temporary condensation rate [kg kg-1 s-1] + real(kind_phys) :: cdt ! Timestep factor [1] + real(kind_phys) :: wtthick ! Layer thickness weight [1] + real(kind_phys) :: pol ! Production over loss ratio [1] + + errmsg = '' + errflg = 0 + error_found = .false. + + clrh2o = latvap/rh2o + cpohl = cpair/latvap + hlocp = latvap/cpair + dto2 = 0.5_kind_phys * deltat + +#ifdef PERGRO + mincld = 1.e-4_kind_phys + iter = 1 ! number of times to iterate the precipitation calculation +#else + mincld = 1.e-4_kind_phys + iter = 2 +#endif + + ! initialize single level and multi level fields + do i = 1, ncol + precip(i) = 0.0_kind_phys + precab(i) = 0.0_kind_phys + snowab(i) = 0.0_kind_phys + cldmax(i) = 0.0_kind_phys + end do + + do k = 1, pver + do i = 1, ncol + q(i,k) = qn(i,k) + t(i,k) = tn(i,k) + ! q(i,k)=qn(i,k)-qtend(i,k)*deltat + ! t(i,k)=tn(i,k)-ttend(i,k)*deltat + end do + end do + + cme (:ncol,:) = 0._kind_phys + evapprec(:ncol,:) = 0._kind_phys + prodprec(:ncol,:) = 0._kind_phys + evapsnow(:ncol,:) = 0._kind_phys + prodsnow(:ncol,:) = 0._kind_phys + evapheat(:ncol,:) = 0._kind_phys + meltheat(:ncol,:) = 0._kind_phys + prfzheat(:ncol,:) = 0._kind_phys + ice2pr(:ncol,:) = 0._kind_phys + liq2pr(:ncol,:) = 0._kind_phys + liq2snow(:ncol,:) = 0._kind_phys + fwaut(:ncol,:) = 0._kind_phys + fsaut(:ncol,:) = 0._kind_phys + fracw(:ncol,:) = 0._kind_phys + fsacw(:ncol,:) = 0._kind_phys + fsaci(:ncol,:) = 0._kind_phys + lsflxprc(:ncol,:) = 0._kind_phys + lsflxsnw(:ncol,:) = 0._kind_phys + pracwo(:ncol,:) = 0._kind_phys + psacwo(:ncol,:) = 0._kind_phys + psacio(:ncol,:) = 0._kind_phys + + ! find the wet bulb temp and saturation value + ! for the provisional t and q without condensation + mp_level_loop: do k = top_lev, pver + ! "True" means that ice will be taken into account. + call findsp_vc(qn(:ncol,k), tn(:ncol,k), p(:ncol,k), .true., & + tsp(:ncol,k), qsp(:ncol,k)) + + call qsat(t(1:ncol,k), p(1:ncol,k), es(1:ncol), qs(1:ncol), ncol, gam=gamma(1:ncol)) + + do i = 1, ncol + relhum(i) = q(i,k)/qs(i) + cldm(i) = max(cldn(i,k),mincld) + + ! the max cloud fraction above this level + cldmax(i) = max(cldmax(i), cldm(i)) + + ! define the coefficients for C - E calculation + calpha(i) = 1.0_kind_phys/qs(i) + cbeta (i) = q(i,k)/qs(i)**2*gamma(i)*cpohl + cbetah(i) = 1.0_kind_phys/qs(i)*gamma(i)*cpohl + cgamma(i) = calpha(i)+latvap*cbeta(i)/cpair + cgamah(i) = calpha(i)+latvap*cbetah(i)/cpair + rcgama(i) = cgamma(i)/cgamah(i) + + if(cldm(i) > mincld) then + icwc(i) = max(0._kind_phys,cwat(i,k)/cldm(i)) + else + icwc(i) = 0.0_kind_phys + endif + ! PJR the above logic give zero icwc with nonzero cwat, dont like it! + ! PJR generates problems with csigma + ! PJR set the icwc to a very small number, so we can start from zero cloud cover and make some clouds + ! icwc(i) = max(1.e-8_kind_phys,cwat(i,k)/cldm(i)) + + ! initial guess of evaporation, will be updated within iteration + evapprec(i,k) = conke*(1._kind_phys - cldm(i))*sqrt(precab(i)) & + *(1._kind_phys - min(relhum(i),1._kind_phys)) + + ! zero cmeres before iteration for each level + cmeres(i) = 0.0_kind_phys + end do + + do i = 1, ncol + ! calculate the cooling due to a phase change of the rainwater from above + if (t(i,k) >= t0) then + meltheat(i,k) = -latice * snowab(i) * gravit/pdel(i,k) + snowab(i) = 0._kind_phys + else + meltheat(i,k) = 0._kind_phys + endif + end do + + ! calculate cme and formation of precip. + ! + ! The cloud microphysics is highly nonlinear and coupled with cme + ! Both rain processes and cme are calculated iteratively. + cme_iter_loop: do l = 1, iter + cme_update_loop: do i = 1, ncol + ! calculation of cme 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 + if(relhum(i) >= 0.999_kind_phys .or. cldm(i) >= 0.999_kind_phys) then + cme(i,k) = (calpha(i)*qtend(i,k)-cbetah(i)*ttend(i,k))/cgamah(i) + ! 2. fractional saturation + else + if (rhdfda(i,k) .eq. 0._kind_phys .and. icwc(i) .eq. 0._kind_phys) then + write(iulog,*) 'prognostic_cloud_water: empty rh cloud @ ', i, k + write(iulog,*) 'relhum, iter ', relhum(i), l, rhu_adj(i,k), cldm(i), cldn(i,k) + + errflg = 1 + errmsg = 'prognostic_cloud_water: empty RH cloud' + return + endif + + csigma(i) = 1.0_kind_phys/(rhdfda(i,k)+cgamma(i)*icwc(i)) + cmec1(i) = (1.0_kind_phys-cldm(i))*csigma(i)*rhdfda(i,k) + cmec2(i) = cldm(i)*calpha(i)/cgamah(i)+(1.0_kind_phys-rcgama(i)*cldm(i))* & + csigma(i)*calpha(i)*icwc(i) + cmec3(i) = cldm(i)*cbetah(i)/cgamah(i) + & + (cbeta(i)-rcgama(i)*cldm(i)*cbetah(i))*csigma(i)*icwc(i) + cmec4(i) = csigma(i)*cgamma(i)*icwc(i) + + ! Q = C-E = -C1*Al + C2*Aq - C3*At + C4*Er + cme(i,k) = -cmec1(i)*lctend(i,k) + cmec2(i)*qtend(i,k) & + -cmec3(i)*ttend(i,k) + cmec4(i)*evapprec(i,k) + endif + ! 3. when rh < rhu00, evaporate existing cloud water + else if(cwat(i,k) > 0.0_kind_phys) then + ! liquid water should be evaporated but not to exceed + ! saturation point. if qn > qsp, not to evaporate cwat + cme(i,k) = -min(max(0._kind_phys,qsp(i,k)-qn(i,k)),cwat(i,k))/deltat + ! 4. no condensation nor evaporation + else + cme(i,k) = 0.0_kind_phys + endif + end do cme_update_loop + + ! Because of the finite time step, place a bound here not to exceed wet bulb point + ! and not to evaporate more than available water + do i = 1, ncol + qtmp = qn(i,k) - cme(i,k)*deltat + + ! possibilities to have qtmp > qsp + ! + ! 1. if qn > qs(tn), it condenses; + ! if after applying cme, qtmp > qsp, more condensation is applied. + ! + ! 2. if qn < qs, evaporation should not exceed qsp, + if(qtmp > qsp(i,k)) then + cme(i,k) = cme(i,k) + (qtmp-qsp(i,k))/deltat + endif + + ! if net evaporation, it should not exceed available cwat + if(cme(i,k) < -cwat(i,k)/deltat) then + cme(i,k) = -cwat(i,k)/deltat + endif + + ! addition of residual condensation from previous step of iteration + cme(i,k) = cme(i,k) + cmeres(i) + + ! limit cme for roundoff errors (multiply by slightly less than unity) + cme(i,k) = cme(i,k) * omsm + end do + + do i = 1, ncol + ! as a safe limit, condensation should not reduce grid mean rh below rhu00 + if(cme(i,k) > 0.0_kind_phys .and. relhum(i) > rhu_adj(i,k)) then + cme(i,k) = min(cme(i,k), (qn(i,k)-qs(i)*rhu_adj(i,k))/deltat) + endif + + ! initial guess for cwm (mean cloud water over time step) if 1st iteration + if(l < 2) then + cwm(i) = max(cwat(i,k)+cme(i,k)*dto2, 0._kind_phys) + endif + enddo + + ! provisional precipitation falling through model layer + do i = 1, ncol + ! prprov(i) = precab(i) + prodprec(i,k)*pdel(i,k)/gravit + ! rain produced in this layer not too effective in collection process + wtthick = max(0._kind_phys,min(0.5_kind_phys,((zi(i,k)-zi(i,k+1))/1000._kind_phys)**2)) + prprov(i) = precab(i) + wtthick*prodprec(i,k)*pdel(i,k)/gravit + end do + + ! calculate conversion of condensate to precipitation by cloud microphysics + call findmcnew( & + ncol = ncol, & + pver = pver, & + rlat = rlat(:ncol), & + pi = pi, & + k = k, & + precab = prprov(:ncol), & + snowab = snowab(:ncol), & + t = t(:ncol,:), & + p = p(:ncol,:), & + cwm = cwm(:ncol), & + cldm = cldm(:ncol), & + cldmax = cldmax(:ncol), & + fice = fice(:ncol,k), & + landm = landm(:ncol), & + seaicef = seaicef(:ncol), & + snowh = snowh(:ncol), & + ! below output + coef = coef(:ncol), & + fwaut = fwaut(:ncol,k), & + fsaut = fsaut(:ncol,k), & + fracw = fracw(:ncol,k), & + fsacw = fsacw(:ncol,k), & + fsaci = fsaci(:ncol,k), & + pracwo = pracwo(:ncol,k),& + psacwo = psacwo(:ncol,k),& + psacio = psacio(:ncol,k)) + + ! calculate the precip rate + error_found = .false. + do i = 1, ncol + if (cldm(i) > 0) then + ! first predict the cloud water + cdt = coef(i)*deltat + if(cdt > 0.01_kind_phys) then + pol = cme(i,k)/coef(i) ! production over loss + cwn(i) = max(0._kind_phys,(cwat(i,k)-pol)*exp(-cdt)+ pol) + else + cwn(i) = max(0._kind_phys,(cwat(i,k) + cme(i,k)*deltat)/(1+cdt)) + endif + + ! now back out the tendency of net rain production + prodprec(i,k) = max(0._kind_phys,cme(i,k)-(cwn(i)-cwat(i,k))/deltat) + else + prodprec(i,k) = 0.0_kind_phys + cwn(i) = 0._kind_phys + endif + + ! provisional calculation of conversion terms + ice2pr(i,k) = prodprec(i,k)*(fsaut(i,k)+fsaci(i,k)) + liq2pr(i,k) = prodprec(i,k)*(fwaut(i,k)+fsacw(i,k)+fracw(i,k)) + + + ! revision suggested by Jim McCaa + ! it controls the amount of snow hitting the sfc + ! by forcing a lot of conversion of cloud liquid to snow phase + ! it might be better done later by an explicit representation of + ! rain accreting ice (and freezing), or by an explicit freezing of raindrops + ! + ! old: + ! liq2snow(i,k) = prodprec(i,k)*fsacw(i,k) + liq2snow(i,k) = max(prodprec(i,k)*fsacw(i,k), fsnow(i,k)*liq2pr(i,k)) + + ! bounds + nice2pr = min(ice2pr(i,k),(cwat(i,k)+cme(i,k)*deltat)*fice(i,k)/deltat) + nliq2pr = min(liq2pr(i,k),(cwat(i,k)+cme(i,k)*deltat)*(1._kind_phys-fice(i,k))/deltat) + + if (liq2pr(i,k) .ne. 0._kind_phys) then + nliq2snow = liq2snow(i,k)*nliq2pr/liq2pr(i,k) ! correction + else + nliq2snow = liq2snow(i,k) + endif + + ! avoid roundoff problems generating negatives + nliq2snow = nliq2snow*omsm + nliq2pr = nliq2pr*omsm + nice2pr = nice2pr*omsm + + ! final estimates of conversion to precip and snow + prodprec(i,k) = (nliq2pr + nice2pr) + prodsnow(i,k) = (nice2pr + nliq2snow) + + rcwn(i,l,k) = cwat(i,k) + (cme(i,k) - prodprec(i,k))*deltat + rliq(i,l,k) = (cwat(i,k) + cme(i,k)*deltat)*(1._kind_phys-fice(i,k)) - nliq2pr*deltat + rice(i,l,k) = (cwat(i,k) + cme(i,k)*deltat) * fice(i,k) - nice2pr*deltat + + ! Sanity checks + if(abs(rcwn(i,l,k)) < 1.e-300_kind_phys) rcwn(i,l,k) = 0._kind_phys + if(abs(rliq(i,l,k)) < 1.e-300_kind_phys) rliq(i,l,k) = 0._kind_phys + if(abs(rice(i,l,k)) < 1.e-300_kind_phys) rice(i,l,k) = 0._kind_phys + if(rcwn(i,l,k) < 0._kind_phys) error_found = .true. + if(rliq(i,l,k) < 0._kind_phys) error_found = .true. + if(rice(i,l,k) < 0._kind_phys) error_found = .true. + if(error_found) then + if(rcwn(i,l,k) < 0._kind_phys) then + write(iulog,*) 'prognostic_cloud_water: prob with neg rcwn1 ', rcwn(i,l,k), cwn(i) + write(iulog,*) ' cwat, cme*deltat, prodprec*deltat ', & + cwat(i,k), cme(i,k)*deltat, & + prodprec(i,k)*deltat, & + (cme(i,k)-prodprec(i,k))*deltat + + errflg = 1 + errmsg = 'prognostic_cloud_water: negative rcwn1' + return + endif + + if (rliq(i,l,k) < 0._kind_phys) then + write(iulog,*) 'prognostic_cloud_water: prob with neg rliq1 ', rliq(i,l,k) + errflg = 1 + errmsg = 'prognostic_cloud_water: negative rliq1' + return + endif + + if (rice(i,l,k) < 0._kind_phys) then + write(iulog,*) 'prognostic_cloud_water: prob with neg rice ', rice(i,l,k) + errflg = 1 + errmsg = 'prognostic_cloud_water: negative rice' + return + endif + endif + + ! Final version of condensate to precip terms + liq2pr(i,k) = nliq2pr + liq2snow(i,k) = nliq2snow + ice2pr(i,k) = nice2pr + cwn(i) = rcwn(i,l,k) + + ! update any remaining provisional values + cwm(i) = (cwn(i) + cwat(i,k))*0.5_kind_phys + + ! update in cloud water + if(cldm(i) > mincld) then + icwc(i) = cwm(i)/cldm(i) + else + icwc(i) = 0.0_kind_phys + endif + ! PJR the above logic give zero icwc with nonzero cwat, dont like it! + ! PJR generates problems with csigma + ! PJR set the icwc to a very small number, so we can start from zero cloud cover and make some clouds + ! icwc(i) = max(1.e-8_kind_phys,cwm(i)/cldm(i)) + end do + + ! calculate provisional value of cloud water for + ! evaporation of precipitate (evapprec) calculation + do i = 1,ncol + qtmp = qn(i,k) - cme(i,k)*deltat + ttmp = tn(i,k) + deltat/cpair * ( meltheat(i,k) + (latvap + latice*fice(i,k)) * cme(i,k) ) + esn = estblf(ttmp) + qsn = svp_to_qsat(esn, p(i,k)) + qtl(i) = max((qsn - qtmp)/deltat,0._kind_phys) + relhum1(i) = qtmp/qsn + end do + + do i = 1,ncol +#ifdef PERGRO + evapprec(i,k) = conke*(1._kind_phys - max(cldm(i),mincld))* & + sqrt(precab(i))*(1._kind_phys - min(relhum1(i),1._kind_phys)) +#else + evapprec(i,k) = conke*(1._kind_phys - cldm(i))*sqrt(precab(i)) & + *(1._kind_phys - min(relhum1(i),1._kind_phys)) +#endif + + ! limit the evaporation to the amount which is entering the box + ! or saturates the box + prtmp = precab(i)*gravit/pdel(i,k) + evapprec(i,k) = min(evapprec(i,k), prtmp, qtl(i))*omsm +#ifdef PERGRO + ! zeroing needed for pert growth + evapprec(i,k) = 0._kind_phys +#endif + + ! Partition evaporation of precipitate between rain and snow using + ! the fraction of snow falling into the box. Determine the heating + ! due to evaporation. Note that evaporation is positive (loss of precip, + ! gain of vapor) and that heating is negative. + if (evapprec(i,k) > 0._kind_phys) then + evapsnow(i,k) = evapprec(i,k) * snowab(i) / precab(i) + evapheat(i,k) = -latvap * evapprec(i,k) - latice * evapsnow(i,k) + else + evapsnow(i,k) = 0._kind_phys + evapheat(i,k) = 0._kind_phys + end if + + ! Account for the latent heat of fusion for liquid drops collected by falling snow + prfzheat(i,k) = latice * liq2snow(i,k) + end do + + ! now remove the residual of any over-saturation. Normally, + ! the oversaturated water vapor should have been removed by + ! cme formulation plus constraints by wet bulb tsp/qsp + ! as computed above. However, because of non-linearity, + ! addition of (cme-evapprec) to update t and q may still cause + ! a very small amount of over saturation. It is called a + ! residual of over-saturation because theoretically, cme + ! should have taken care of all of large scale condensation. + do i = 1,ncol + qtmp = qn(i,k)-(cme(i,k)-evapprec(i,k))*deltat + ttmp = tn(i,k) + deltat/cpair * ( meltheat(i,k) + evapheat(i,k) + prfzheat(i,k) & + + (latvap + latice*fice(i,k)) * cme(i,k) ) + + call qsat(ttmp, p(i,k), esn, qsn, dqsdt=dqsdt) + + if(qtmp > qsn) then + ! now extra condensation to bring air to just saturation + ctmp = (qtmp-qsn)/(1._kind_phys+hlocp*dqsdt)/deltat + cme(i,k) = cme(i,k)+ctmp + ! save residual on cmeres to addtion to cme on entering next iteration + ! cme exit here contain the residual but overrided if back to iteration + cmeres(i) = ctmp + else + cmeres(i) = 0.0_kind_phys + endif + end do + end do cme_iter_loop ! loop over l (iteration) + + ! precipitation + do i = 1,ncol + precip(i) = precip(i) + pdel(i,k)/gravit * (prodprec(i,k) - evapprec(i,k)) + precab(i) = precab(i) + pdel(i,k)/gravit * (prodprec(i,k) - evapprec(i,k)) + if(precab(i) < 0._kind_phys) then + precab(i) = 0._kind_phys + endif + + ! snowab(i) = snowab(i) + pdel(i,k)/gravit * (prodprec(i,k)*fice(i,k) - evapsnow(i,k)) + snowab(i) = snowab(i) + pdel(i,k)/gravit * (prodsnow(i,k) - evapsnow(i,k)) + + ! If temperature above freezing, all precip is rain flux. if temperature below freezing, all precip is snow flux. + lsflxprc(i,k+1) = precab(i) !! making this consistent with other precip fluxes. prc = rain + snow + ! lsflxprc(i,k+1) = precab(i) - snowab(i) + lsflxsnw(i,k+1) = snowab(i) + end do + end do mp_level_loop ! loop over k (level) + end subroutine prognostic_cloud_water_run + + ! Calculate the conversion of condensate to precipitate + ! Rasch, P. J., and J. E. Kristjánsson, 1998: A Comparison of the CCM3 Model Climate Using Diagnosed and Predicted Condensate Parameterizations. J. Climate, 11, 1587–1614 + ! https://doi.org/10.1175/1520-0442(1998)011<1587:ACOTCM>2.0.CO;2 + ! + ! Original author: P. Rasch + subroutine findmcnew( & + ncol, pver, & + rlat, & ! was get_rlat_all_p + pi, & + k, & + precab, snowab, t, p, cwm, cldm, cldmax, fice, & + landm, seaicef, snowh, & + coef, fwaut, fsaut, & + fracw, fsacw, fsaci, & + pracwo, psacwo, psacio) + + ! input arguments + integer, intent(in) :: ncol ! number of atmospheric columns + integer, intent(in) :: pver ! number of levels + real(kind_phys), intent(in) :: rlat(:) ! latitudes [rad] + real(kind_phys), intent(in) :: pi ! pi_constant [1] + integer, intent(in) :: k ! level index + + real(kind_phys), intent(in) :: precab(:) ! rate of precipitation from above [kg m-2 s-1] + real(kind_phys), intent(in) :: t(:,:) ! temperature [K] + real(kind_phys), intent(in) :: p(:,:) ! pressure [Pa] + real(kind_phys), intent(in) :: cwm(:) ! condensate mixing ratio [kg kg-1] + real(kind_phys), intent(in) :: cldm(:) ! cloud fraction + real(kind_phys), intent(in) :: cldmax(:) ! max cloud fraction above this level + real(kind_phys), intent(in) :: fice(:) ! fraction of cwat that is ice + real(kind_phys), intent(in) :: landm(:) ! Land fraction ramped over water + real(kind_phys), intent(in) :: seaicef(:) ! sea ice fraction + real(kind_phys), intent(in) :: snowab(:) ! rate of snow from above [kg m-2 s-1] + real(kind_phys), intent(in) :: snowh(:) ! Snow depth over land, water equivalent [m] + + ! output arguments + real(kind_phys), intent(out) :: coef(:) ! conversion rate [s-1] + real(kind_phys), intent(out) :: fwaut(:) ! relative importance of liquid autoconversion (a diagnostic) + real(kind_phys), intent(out) :: fsaut(:) ! relative importance of ice autoconversion (a diagnostic) + real(kind_phys), intent(out) :: fracw(:) ! relative importance of rain accreting liquid (a diagnostic) + real(kind_phys), intent(out) :: fsacw(:) ! relative importance of snow accreting liquid (a diagnostic) + real(kind_phys), intent(out) :: fsaci(:) ! relative importance of snow accreting ice (a diagnostic) + real(kind_phys), intent(out) :: pracwo(:) ! accretion of cloud water by rain [s-1] + real(kind_phys), intent(out) :: psacwo(:) ! accretion of cloud water by snow [s-1] + real(kind_phys), intent(out) :: psacio(:) ! accretion of cloud ice by snow [s-1] + + ! local variables + integer :: i, ii ! Loop index [index] + integer :: ncols ! Number of active columns for microphysics (different from ncol!!) [count] + integer :: ind(ncol) ! Active column indices [index] + real(kind_phys), parameter :: degrad = 57.296_kind_phys ! Degrees per radian [deg rad-1] + real(kind_phys) :: capn ! Local cloud particle number concentration [cm-3] + real(kind_phys) :: capnoice ! Cloud particle concentration excluding sea ice [cm-3] + real(kind_phys) :: cldloc(ncol) ! Non-zero cloud fraction [1] + real(kind_phys) :: cldpr(ncol) ! Cloud fraction for precipitation [1] + real(kind_phys) :: totmr(ncol) ! In-cloud total water mixing ratio [kg kg-1] + real(kind_phys) :: icemr(ncol) ! In-cloud ice mixing ratio [kg kg-1] + real(kind_phys) :: liqmr(ncol) ! In-cloud liquid water mixing ratio [kg kg-1] + real(kind_phys) :: rainmr(ncol) ! In-cloud rain mixing ratio [kg kg-1] + real(kind_phys) :: ciaut ! Ice autoconversion coefficient [s-1] + real(kind_phys) :: pracw ! Rate of rain collecting cloud water [s-1] + real(kind_phys) :: psaci ! Rate of snow collecting cloud ice [s-1] + real(kind_phys) :: psacw ! Rate of snow collecting cloud water [s-1] + real(kind_phys) :: psaut ! Rate of ice autoconversion [s-1] + real(kind_phys) :: pwaut ! Rate of liquid water autoconversion [s-1] + real(kind_phys) :: ptot ! Total conversion rate [s-1] + real(kind_phys) :: prlloc(ncol) ! Local rain flux [mm day-1] + real(kind_phys) :: prscgs(ncol) ! Local snow amount [g cm-2] + real(kind_phys) :: snowfr ! Snow fraction of precipitation [1] + real(kind_phys) :: vfallw ! Fall speed of liquid precipitation [m s-1] + real(kind_phys) :: rho(ncol) ! Air density [kg m-3] + real(kind_phys) :: rhocgs ! Air density in CGS units [g cm-3] + real(kind_phys) :: r3l ! Cloud droplet volume radius [m] + real(kind_phys) :: icrit ! Ice autoconversion threshold [kg kg-1] + real(kind_phys) :: wsi ! Sea ice weight factor [1] + real(kind_phys) :: wt ! Ice fraction weight [1] + real(kind_phys) :: wland ! Land fraction weight [1] + real(kind_phys) :: wp ! Pressure dependence weight [1] + real(kind_phys) :: ftot ! Total fraction for conversion processes [1] + real(kind_phys) :: con1 ! Work constant for radius calculation [m] + real(kind_phys) :: con2 ! Work constant for density ratios [1] + real(kind_phys) :: csacx ! Constant used for snow accreting liquid or ice [??] + real(kind_phys) :: rat1 ! Density ratio work variable [1] + real(kind_phys) :: rat2 ! Mixing ratio ratio work variable [1] + + ! find all the points where we need to do the microphysics + ! and set the output variables to zero + ncols = 0 + do i = 1, ncol + coef(i) = 0._kind_phys + fwaut(i) = 0._kind_phys + fsaut(i) = 0._kind_phys + fracw(i) = 0._kind_phys + fsacw(i) = 0._kind_phys + fsaci(i) = 0._kind_phys + liqmr(i) = 0._kind_phys + rainmr(i) = 0._kind_phys + if (cwm(i) > 1.e-20_kind_phys) then + ncols = ncols + 1 + ind(ncols) = i + endif + end do + + do ii = 1, ncols + ! map from active microphysics columns to physics columns + i = ind(ii) + + ! the local cloudiness at this level + cldloc(i) = max(cldmin,cldm(i)) + + ! a weighted mean between max cloudiness above, and this layer + cldpr(i) = max(cldmin,(cldmax(i)+cldm(i))*0.5_kind_phys) + + ! decompose the suspended condensate into + ! an incloud liquid and ice phase component + totmr(i) = cwm(i)/cldloc(i) + icemr(i) = totmr(i)*fice(i) + liqmr(i) = totmr(i)*(1._kind_phys-fice(i)) + + ! density + rho(i) = p(i,k)/(287._kind_phys*t(i,k)) + rhocgs = rho(i)*1.e-3_kind_phys ! density in cgs units + + ! decompose the precipitate into a liquid and ice phase + if (t(i,k) > t0) then + vfallw = convfw/sqrt(rho(i)) + rainmr(i) = precab(i)/(rho(i)*vfallw*cldpr(i)) + snowfr = 0 + else + snowfr = 1 + rainmr(i) = 0._kind_phys + endif + + ! local snow amount in cgs units + prscgs(i) = precab(i)/cldpr(i)*0.1_kind_phys*snowfr + + ! local rain amount in mm/day + prlloc(i) = precab(i)*86400._kind_phys/cldpr(i) + end do + + con1 = 1._kind_phys/(1.333_kind_phys*pi)**0.333_kind_phys * 0.01_kind_phys ! meters + + ! calculate the conversion terms + do ii = 1, ncols + i = ind(ii) + rhocgs = rho(i)*1.e-3_kind_phys ! density in cgs units + + ! exponential temperature factor + ! efact = exp(0.025*(t(i,k)-t0)) + + ! some temperature dependent constants + wt = fice(i) + icrit = icritc*wt + icritw*(1-wt) + + ! jrm Reworked droplet number concentration algorithm + ! Start with pressure-dependent value appropriate for continental air + ! Note: reltab has a temperature dependence here + capn = capnw + (capnc-capnw) * min(1._kind_phys,max(0._kind_phys,1.0_kind_phys-(p(i,k)-0.8_kind_phys*p(i,pver))/(0.2_kind_phys*p(i,pver)))) + ! Modify for snow depth over land + capn = capn + (capnc-capn) * min(1.0_kind_phys,max(0.0_kind_phys,snowh(i)*10._kind_phys)) + ! Ramp between polluted value over land to clean value over ocean. + capn = capn + (capnc-capn) * min(1.0_kind_phys,max(0.0_kind_phys,1.0_kind_phys-landm(i))) + ! Ramp between the resultant value and a sea ice value in the presence of ice. + capn = capn + (capnsi-capn) * min(1.0_kind_phys,max(0.0_kind_phys,seaicef(i))) + ! end jrm + + ! useful terms in following calculations + rat1 = rhocgs/rhow + rat2 = liqmr(i)/capn + con2 = (rat1*rat2)**0.333_kind_phys + + ! volume radius + r3l = con1*con2 + + ! critical threshold for autoconversion if modified for mixed phase + ! clouds to mimic a bergeron findeisen process + ! r3lc2 = r3lcrit*(1.-0.5*fice(i)*(1-fice(i))) + ! + ! autoconversion of liquid + ! + ! cwaut = 2.e-4 + ! cwaut = 1.e-3 + ! lcrit = 2.e-4 + ! lcrit = 5.e-4 + ! pwaut = max(0._kind_phys,liqmr(i)-lcrit)*cwaut + ! + ! pwaut is following tripoli and cotton (and many others) + ! we reduce the autoconversion below critpr, because these are regions where + ! the drop size distribution is likely to imply much smaller collector drops than + ! those relevant for a cloud distribution corresponding to the value of effc = 0.55 + ! suggested by cotton (see austin 1995 JAS, baker 1993) + + ! easy to follow form + ! pwaut = capc*liqmr(i)**2*rhocgs/rhow + ! *(liqmr(i)*rhocgs/(rhow*capn))**(.333) + ! *heavy(r3l,r3lcrit) + ! *max(0.10_kind_phys,min(1._kind_phys,prlloc(i)/critpr)) + ! somewhat faster form + + ! using modified Heaviside function: + pwaut = capc*liqmr(i)**2*rat1*con2*heavymp(r3l,r3lcrit) * & + max(0.10_kind_phys,min(1._kind_phys,prlloc(i)/critpr)) + + ! not using modified Heaviside function: + ! pwaut = capc*liqmr(i)**2*rat1*con2*heavym(r3l,r3lcrit)* & + ! max(0.10_kind_phys,min(1._kind_phys,prlloc(i)/critpr)) + + ! autoconversion of ice + ciaut = ciautb + + ! autoconversion of ice condensate +#ifdef PERGRO + psaut = heavyp(icemr(i),icrit)*icemr(i)*ciaut +#else + psaut = max(0._kind_phys,icemr(i)-icrit)*ciaut +#endif + + ! collection of liquid by rain + ! pracw = cracw*rho(i)*liqmr(i)*rainmr(i) !(beheng 1994) + pracw = cracw*rho(i)*sqrt(rho(i))*liqmr(i)*rainmr(i) !(tripoli and cotton) + pracwo(i) = pracw + + ! the following lines calculate the slope parameter and snow mixing ratio + ! from the precip rate using the equations found in lin et al 83 + ! in the most natural form, but it is expensive, so after some tedious + ! algebraic manipulation you can use the cheaper form found below + ! vfalls = c*gam4pd/(6*lamdas**d)*sqrt(rhonot/rhocgs) + ! $ *0.01 ! convert from cm/s to m/s + ! snowmr(i) = snowfr*precab(i)/(rho(i)*vfalls*cldpr(i)) + ! snowmr(i) = ( prscgs(i)*mcon02 * (rhocgs**mcon03) )**mcon04 + ! lamdas = (prhonos/max(rhocgs*snowmr(i),small))**0.25 + ! csacw = mcon01*sqrt(rhonot/rhocgs)/(lamdas**thrpd) + ! + ! coefficient for collection by snow independent of phase + csacx = mcon07*rhocgs**mcon08*prscgs(i)**mcon05 + + ! collection of liquid by snow (lin et al 1983) + psacw = csacx*liqmr(i)*esw + +#ifdef PERGRO + ! this is necessary for pergro + psacw = 0._kind_phys +#endif + + psacwo(i) = psacw + + ! collection of ice by snow (lin et al 1983) + psaci = csacx*icemr(i)*esi + psacio(i) = psaci + + ! total conversion of condensate to precipitate + ptot = pwaut + psaut + pracw + psacw + psaci + + ! the recipricol of cloud water amnt (or zero if no cloud water) + ! rcwm = totmr(i)/(max(totmr(i),small)**2) + + ! turn the tendency back into a loss rate [s-1] + if (totmr(i) > 0._kind_phys) then + coef(i) = ptot/totmr(i) + else + coef(i) = 0._kind_phys + endif + + if (ptot.gt.0._kind_phys) then + fwaut(i) = pwaut/ptot + fsaut(i) = psaut/ptot + fracw(i) = pracw/ptot + fsacw(i) = psacw/ptot + fsaci(i) = psaci/ptot + else + fwaut(i) = 0._kind_phys + fsaut(i) = 0._kind_phys + fracw(i) = 0._kind_phys + fsacw(i) = 0._kind_phys + fsaci(i) = 0._kind_phys + endif + + ftot = fwaut(i)+fsaut(i)+fracw(i)+fsacw(i)+fsaci(i) + end do + + end subroutine findmcnew + + ! For special WACCM/CAM-chem cases with CAM4 physics: + ! Sets rhu to a different value poleward of +/- 50 deg latitude and + ! levels above the tropopause if polstrat_rhmin is specified + subroutine relhum_min_adj(ncol, pver, tropLev, dlat, rhu, rhu_adj) + integer, intent(in) :: ncol + integer, intent(in) :: pver + integer, intent(in) :: tropLev(:) + real(kind_phys), intent(in) :: dlat(:) ! latitudes in degrees + real(kind_phys), intent(in) :: rhu(:,:) + real(kind_phys), intent(out) :: rhu_adj(:,:) + + integer :: i, k + + rhu_adj(:,:) = rhu(:,:) + if (.not. do_psrhmin) return + + do k = 1, pver + do i = 1, ncol + ! assumption that up is lower index + if ((k .lt. tropLev(i)) .and. (abs(dlat(i)) .gt. 50._kind_phys)) then + rhu_adj(i,k) = psrhmin + endif + enddo + enddo + end subroutine relhum_min_adj + + ! Heavyside step functions used in findmcnew + ! Heavyside step function + pure function heavy(a1, a2) result(h) + ! h: 1 if a1 > a2, 0 otherwise + real(kind_phys), intent(in) :: a1, a2 + real(kind_phys) :: h + h = max(0.0_kind_phys, sign(1.0_kind_phys, a1-a2)) + end function heavy + + ! Modified Heavyside function with minimum value of 0.01 + pure function heavym(a1, a2) result(h) + ! h: 1 if a1 > a2, 0.01 otherwise + real(kind_phys), intent(in) :: a1, a2 + real(kind_phys) :: h + h = max(0.01_kind_phys, sign(1.0_kind_phys, a1-a2)) + end function heavym + + ! Smoothed Heavyside function using ratio formulation + pure function heavyp(a1, a2) result(h) + ! h: Ratio of a1/(a1+a2+eps) + real(kind_phys), intent(in) :: a1, a2 + real(kind_phys) :: h + real(kind_phys), parameter :: eps = 1.0e-36_kind_phys + h = a1/(a2 + a1 + eps) + end function heavyp + + ! Modified smooth Heavyside with offset term + pure function heavymp(a1, a2) result(h) + ! h: Ratio (a1 + 0.01*a2)/(a1+a2+eps) + real(kind_phys), intent(in) :: a1, a2 + real(kind_phys) :: h + real(kind_phys), parameter :: eps = 1.0e-36_kind_phys + h = (a1 + 0.01_kind_phys*a2)/(a2 + a1 + eps) + end function heavymp + +end module prognostic_cloud_water diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water_namelist.xml b/schemes/rasch_kristjansson/prognostic_cloud_water_namelist.xml new file mode 100644 index 00000000..7d9078df --- /dev/null +++ b/schemes/rasch_kristjansson/prognostic_cloud_water_namelist.xml @@ -0,0 +1,92 @@ + + + + + + + real + conv + rk_stratiform_nl + tunable_parameter_for_autoconversion_of_cold_ice_for_rk_microphysics + kg kg-1 + + Threshold for autoconversion of cold ice in RK microphysics scheme. + + + 5.0e-6 + + + + real + conv + rk_stratiform_nl + tunable_parameter_for_autoconversion_of_warm_ice_for_rk_microphysics + kg kg-1 + + Threshold for autoconversion of cold ice in RK microphysics scheme. + + + 4.0e-4 + + + + real + conv + rk_stratiform_nl + tunable_parameter_for_precipitation_evaporation_for_rk_microphysics + 1 + + + Tunable constant for evaporation of precip in RK microphysics scheme. + + + 5.0e-6 + + + + real + conv + rk_stratiform_nl + tunable_parameter_for_cloud_water_autoconversion_for_rk_microphysics + m + + Critical radius at which autoconversion become efficient in RK microphysics scheme. + + + 10.0e-6 + + + + real + conv + rk_stratiform_nl + relative_humidity_threshold_for_cloud_formation_in_polar_stratosphere_for_rk_microphysics + 1 + + Relative humidity threshold for stratospheric cloud water condensation in RK microphysics + poleward of 50 degrees. Used if rk_strat_polstrat_dorhmin is set to true. + + + 1.200e0 + + + + real + conv + rk_stratiform_nl + flag_for_relative_humidity_threshold_for_cloud_formation_in_polar_stratosphere_for_rk_microphysics + flag + + Flag to set rhu to a different value in the stratosphere poleward of 50 degrees for stratospheric + cloud water condensation. Used for special WACCM/CAM-chem cases with CAM4 physics. + + + false + + + diff --git a/schemes/rasch_kristjansson/rk_stratiform.F90 b/schemes/rasch_kristjansson/rk_stratiform.F90 new file mode 100644 index 00000000..9b1f93df --- /dev/null +++ b/schemes/rasch_kristjansson/rk_stratiform.F90 @@ -0,0 +1,25 @@ +! Copyright (C) 2025 National Science Foundation-National Center for Atmospheric Research +! SPDX-License-Identifier: Apache-2.0 +! +! Rasch and Kristjansson prognostic cloud microphysics and CAM4 macrophysics +! CCPP-ized: Haipeng Lin, January 2025 +module rk_stratiform + use ccpp_kinds, only: kind_phys + + implicit none + private + save + + ! public CCPP-compliant subroutines + public :: rk_stratiform_init + public :: rk_stratiform_run + + ! namelist variables for tuning of RK stratiform scheme + + +contains + + + + +end module rk_stratiform diff --git a/to_be_ccppized/cloud_optical_properties.F90 b/to_be_ccppized/cloud_optical_properties.F90 new file mode 100644 index 00000000..4e76e7d2 --- /dev/null +++ b/to_be_ccppized/cloud_optical_properties.F90 @@ -0,0 +1,384 @@ +! Copyright (C) 2002-2025 National Science Foundation-National Center for Atmospheric Research +! SPDX-License-Identifier: Apache-2.0 +! +! Cloud optical properties (to-be-ccppized utility module) +! Computes liquid and ice particle size and emissivity +! Author: Byron Boville, Sept 2002 assembled from existing subroutines +module cloud_optical_properties + + use shr_kind_mod, only: r8=>shr_kind_r8 + use ppgrid, only: pcols, pver, pverp + + implicit none + private + save + + public :: cldefr, cldovrlap, cldclw, reitab, reltab + public :: cldems_rk, cldems + +contains + +!=============================================================================== + subroutine cldefr( & + ncol, pver, & + tmelt, & + landfrac,t ,rel ,rei ,ps ,pmid , landm, icefrac, snowh) +!----------------------------------------------------------------------- +! +! Purpose: +! Compute cloud water and ice particle size +! +! Method: +! use empirical formulas to construct effective radii +! +! Author: J.T. Kiehl, B. A. Boville, P. Rasch +! +!----------------------------------------------------------------------- + +!------------------------------Arguments-------------------------------- +! +! Input arguments +! + integer, intent(in) :: ncol ! number of atmospheric columns + integer, intent(in) :: pver + real(r8), intent(in) :: tmelt + + real(r8), intent(in) :: landfrac(pcols) ! Land fraction + real(r8), intent(in) :: icefrac(pcols) ! Ice fraction + real(r8), intent(in) :: t(pcols,pver) ! Temperature + real(r8), intent(in) :: ps(pcols) ! Surface pressure + real(r8), intent(in) :: pmid(pcols,pver) ! Midpoint pressures + real(r8), intent(in) :: landm(pcols) + real(r8), intent(in) :: snowh(pcols) ! Snow depth over land, water equivalent (m) +! +! Output arguments +! + real(r8), intent(out) :: rel(pcols,pver) ! Liquid effective drop size (microns) + real(r8), intent(out) :: rei(pcols,pver) ! Ice effective drop size (microns) +! +! following Kiehl + call reltab(ncol, pver, tmelt, t, landfrac, landm, icefrac, rel, snowh) + +! following Kristjansson and Mitchell + call reitab(ncol, t, rei) + end subroutine cldefr + + ! Compute cloud emissivity using cloud liquid water path [g m-2] + ! Original author: J.T. Kiehl + ! + ! Variant 1 used for RK and SPCAM_sam1mom + subroutine cldems_rk(ncol, pver, clwp, fice, rei, emis, cldtau) + integer, intent(in) :: ncol ! number of atmospheric columns + integer, intent(in) :: pver ! number of vertical levels + real(r8), intent(in) :: clwp(pcols,pver) ! cloud liquid water path (g/m**2) + real(r8), intent(in) :: rei(pcols,pver) ! ice effective drop size (microns) + real(r8), intent(in) :: fice(pcols,pver) ! fractional ice content within cloud + + real(r8), intent(out) :: emis(pcols,pver) ! cloud emissivity (fraction) + real(r8), intent(out) :: cldtau(pcols,pver) ! cloud optical depth + + integer :: i,k ! longitude, level indices + real(r8) :: kabs ! longwave absorption coeff (m**2/g) + real(r8) :: kabsi ! ice absorption coefficient + real(r8) :: kabsl ! longwave liquid absorption coeff (m**2/g) + parameter (kabsl = 0.090361_r8) + + do k = 1, pver + do i = 1, ncol + ! note that optical properties for ice valid only + ! in range of 13 > rei > 130 micron (Ebert and Curry 92) + kabsi = 0.005_r8 + 1._r8/rei(i,k) + kabs = kabsl*(1._r8-fice(i,k)) + kabsi*fice(i,k) + emis(i,k) = 1._r8 - exp(-1.66_r8*kabs*clwp(i,k)) + cldtau(i,k) = kabs*clwp(i,k) + end do + end do + end subroutine cldems_rk + + ! Variant 2 used for other microphysical schemes + subroutine cldems(ncol, pver, clwp, fice, rei, emis, cldtau) + integer, intent(in) :: ncol ! number of atmospheric columns + integer, intent(in) :: pver ! number of vertical levels + real(r8), intent(in) :: clwp(pcols,pver) ! cloud liquid water path (g/m**2) + real(r8), intent(in) :: rei(pcols,pver) ! ice effective drop size (microns) + real(r8), intent(in) :: fice(pcols,pver) ! fractional ice content within cloud + + real(r8), intent(out) :: emis(pcols,pver) ! cloud emissivity (fraction) + real(r8), intent(out) :: cldtau(pcols,pver) ! cloud optical depth + + integer :: i,k ! longitude, level indices + real(r8) :: kabs ! longwave absorption coeff (m**2/g) + real(r8) :: kabsi ! ice absorption coefficient + real(r8) :: kabsl ! longwave liquid absorption coeff (m**2/g) + parameter (kabsl = 0.090361_r8) + + do k = 1, pver + do i = 1, ncol + ! note that optical properties for ice valid only + ! in range of 13 > rei > 130 micron (Ebert and Curry 92) + kabsi = 0.005_r8 + 1._r8/min(max(13._r8,rei(i,k)),130._r8) + kabs = kabsl*(1._r8-fice(i,k)) + kabsi*fice(i,k) + emis(i,k) = 1._r8 - exp(-1.66_r8*kabs*clwp(i,k)) + cldtau(i,k) = kabs*clwp(i,k) + end do + end do + end subroutine cldems + +!=============================================================================== + subroutine cldovrlap(ncol ,pint ,cld ,nmxrgn ,pmxrgn ) +!----------------------------------------------------------------------- +! +! Purpose: +! Partitions each column into regions with clouds in neighboring layers. +! This information is used to implement maximum overlap in these regions +! with random overlap between them. +! On output, +! nmxrgn contains the number of regions in each column +! pmxrgn contains the interface pressures for the lower boundaries of +! each region! +! Method: + +! +! Author: W. Collins +! +!----------------------------------------------------------------------- + +! +! Input arguments +! + integer, intent(in) :: ncol ! number of atmospheric columns + + real(r8), intent(in) :: pint(pcols,pverp) ! Interface pressure + real(r8), intent(in) :: cld(pcols,pver) ! Fractional cloud cover +! +! Output arguments +! + integer, intent(out) :: nmxrgn(pcols) ! Number of maximally overlapped regions + real(r8), intent(out) :: pmxrgn(pcols,pverp)! Maximum values of pressure for each +! maximally overlapped region. +! 0->pmxrgn(i,1) is range of pressure for +! 1st region,pmxrgn(i,1)->pmxrgn(i,2) for +! 2nd region, etc +! +!---------------------------Local variables----------------------------- +! + integer i ! Longitude index + integer k ! Level index + integer n ! Max-overlap region counter + + real(r8) pnm(pcols,pverp) ! Interface pressure + + logical cld_found ! Flag for detection of cloud + logical cld_layer(pver) ! Flag for cloud in layer +! +!------------------------------------------------------------------------ +! + + do i = 1, ncol + cld_found = .false. + cld_layer(:) = cld(i,:) > 0.0_r8 + pmxrgn(i,:) = 0.0_r8 + pnm(i,:)=pint(i,:)*10._r8 + n = 1 + do k = 1, pver + if (cld_layer(k) .and. .not. cld_found) then + cld_found = .true. + else if ( .not. cld_layer(k) .and. cld_found) then + cld_found = .false. + if (count(cld_layer(k:pver)) == 0) then + exit + endif + pmxrgn(i,n) = pnm(i,k) + n = n + 1 + endif + end do + pmxrgn(i,n) = pnm(i,pverp) + nmxrgn(i) = n + end do + end subroutine cldovrlap + +!=============================================================================== + subroutine cldclw(ncol ,zi ,clwp ,tpw ,hl ) +!----------------------------------------------------------------------- +! +! Purpose: +! Evaluate cloud liquid water path clwp (g/m**2) +! +! Method: +! +! +! +! Author: J.T. Kiehl +! +!----------------------------------------------------------------------- + + +! +! Input arguments +! + integer, intent(in) :: ncol ! number of atmospheric columns + + real(r8), intent(in) :: zi(pcols,pverp) ! height at layer interfaces(m) + real(r8), intent(in) :: tpw(pcols) ! total precipitable water (mm) +! +! Output arguments +! + real(r8), intent(out) :: clwp(pcols,pver) ! cloud liquid water path (g/m**2) + real(r8), intent(out) :: hl(pcols) ! liquid water scale height + +! +!---------------------------Local workspace----------------------------- +! + integer :: i,k ! longitude, level indices + real(r8) :: clwc0 ! reference liquid water concentration (g/m**3) + real(r8) :: emziohl(pcols,pverp) ! exp(-zi/hl) + real(r8) :: rhl(pcols) ! 1/hl +! +!----------------------------------------------------------------------- +! +! Set reference liquid water concentration +! + clwc0 = 0.21_r8 +! +! Diagnose liquid water scale height from precipitable water +! + do i=1,ncol + hl(i) = 700.0_r8*log(max(tpw(i)+1.0_r8,1.0_r8)) + rhl(i) = 1.0_r8/hl(i) + end do +! +! Evaluate cloud liquid water path (vertical integral of exponential fn) +! + do k=1,pverp + do i=1,ncol + emziohl(i,k) = exp(-zi(i,k)*rhl(i)) + end do + end do + do k=1,pver + do i=1,ncol + clwp(i,k) = clwc0*hl(i)*(emziohl(i,k+1) - emziohl(i,k)) + end do + end do + end subroutine cldclw + + +!=============================================================================== + subroutine reltab(ncol, pver, tmelt, t, landfrac, landm, icefrac, rel, snowh) +!----------------------------------------------------------------------- +! +! Purpose: +! Compute cloud water size +! +! Method: +! analytic formula following the formulation originally developed by J. T. Kiehl +! +! Author: Phil Rasch +! +!----------------------------------------------------------------------- +! +! Input arguments +! + integer, intent(in) :: ncol + integer, intent(in) :: pver + real(r8), intent(in) :: tmelt + real(r8), intent(in) :: landfrac(pcols) ! Land fraction + real(r8), intent(in) :: icefrac(pcols) ! Ice fraction + real(r8), intent(in) :: snowh(pcols) ! Snow depth over land, water equivalent (m) + real(r8), intent(in) :: landm(pcols) ! Land fraction ramping to zero over ocean + real(r8), intent(in) :: t(pcols,pver) ! Temperature + +! +! Output arguments +! + real(r8), intent(out) :: rel(pcols,pver) ! Liquid effective drop size (microns) +! +!---------------------------Local workspace----------------------------- +! + integer i,k ! Lon, lev indices + real(r8) :: rliqland ! liquid drop size if over land + real(r8) :: rliqocean ! liquid drop size if over ocean + real(r8) :: rliqice ! liquid drop size if over sea ice +! +!----------------------------------------------------------------------- +! + rliqocean = 14.0_r8 + rliqice = 14.0_r8 + rliqland = 8.0_r8 + do k=1,pver + do i=1,ncol +! jrm Reworked effective radius algorithm + ! Start with temperature-dependent value appropriate for continental air + ! Note: findmcnew has a pressure dependence here + rel(i,k) = rliqland + (rliqocean-rliqland) * min(1.0_r8,max(0.0_r8,(tmelt-t(i,k))*0.05_r8)) + ! Modify for snow depth over land + rel(i,k) = rel(i,k) + (rliqocean-rel(i,k)) * min(1.0_r8,max(0.0_r8,snowh(i)*10._r8)) + ! Ramp between polluted value over land to clean value over ocean. + rel(i,k) = rel(i,k) + (rliqocean-rel(i,k)) * min(1.0_r8,max(0.0_r8,1.0_r8-landm(i))) + ! Ramp between the resultant value and a sea ice value in the presence of ice. + rel(i,k) = rel(i,k) + (rliqice-rel(i,k)) * min(1.0_r8,max(0.0_r8,icefrac(i))) +! end jrm + end do + end do + end subroutine reltab + +!=============================================================================== + subroutine reitab(ncol, t, re) + + integer, intent(in) :: ncol + real(r8), intent(out) :: re(pcols,pver) + real(r8), intent(in) :: t(pcols,pver) + integer , parameter :: len_retab = 138 + real(r8), parameter :: min_retab = 136._r8 + real(r8) :: retab(len_retab) + real(r8) :: corr + integer :: i + integer :: k + integer :: index + ! + ! Tabulated values of re(T) in the temperature interval + ! 180 K -- 274 K; hexagonal columns assumed: + ! + ! Modified for pmc formation: 136K -- 274K + ! + data retab / & + 0.05_r8, 0.05_r8, 0.05_r8, 0.05_r8, 0.05_r8, 0.05_r8, & + 0.055_r8, 0.06_r8, 0.07_r8, 0.08_r8, 0.09_r8, 0.1_r8, & + 0.2_r8, 0.3_r8, 0.40_r8, 0.50_r8, 0.60_r8, 0.70_r8, & + 0.8_r8 , 0.9_r8, 1.0_r8, 1.1_r8, 1.2_r8, 1.3_r8, & + 1.4_r8, 1.5_r8, 1.6_r8, 1.8_r8, 2.0_r8, 2.2_r8, & + 2.4_r8, 2.6_r8, 2.8_r8, 3.0_r8, 3.2_r8, 3.5_r8, & + 3.8_r8, 4.1_r8, 4.4_r8, 4.7_r8, 5.0_r8, 5.3_r8, & + 5.6_r8, & + 5.92779_r8, 6.26422_r8, 6.61973_r8, 6.99539_r8, 7.39234_r8, & + 7.81177_r8, 8.25496_r8, 8.72323_r8, 9.21800_r8, 9.74075_r8, 10.2930_r8, & + 10.8765_r8, 11.4929_r8, 12.1440_r8, 12.8317_r8, 13.5581_r8, 14.2319_r8, & + 15.0351_r8, 15.8799_r8, 16.7674_r8, 17.6986_r8, 18.6744_r8, 19.6955_r8, & + 20.7623_r8, 21.8757_r8, 23.0364_r8, 24.2452_r8, 25.5034_r8, 26.8125_r8, & + 27.7895_r8, 28.6450_r8, 29.4167_r8, 30.1088_r8, 30.7306_r8, 31.2943_r8, & + 31.8151_r8, 32.3077_r8, 32.7870_r8, 33.2657_r8, 33.7540_r8, 34.2601_r8, & + 34.7892_r8, 35.3442_r8, 35.9255_r8, 36.5316_r8, 37.1602_r8, 37.8078_r8, & + 38.4720_r8, 39.1508_r8, 39.8442_r8, 40.5552_r8, 41.2912_r8, 42.0635_r8, & + 42.8876_r8, 43.7863_r8, 44.7853_r8, 45.9170_r8, 47.2165_r8, 48.7221_r8, & + 50.4710_r8, 52.4980_r8, 54.8315_r8, 57.4898_r8, 60.4785_r8, 63.7898_r8, & + 65.5604_r8, 71.2885_r8, 75.4113_r8, 79.7368_r8, 84.2351_r8, 88.8833_r8, & + 93.6658_r8, 98.5739_r8, 103.603_r8, 108.752_r8, 114.025_r8, 119.424_r8, & + 124.954_r8, 130.630_r8, 136.457_r8, 142.446_r8, 148.608_r8, 154.956_r8, & + 161.503_r8, 168.262_r8, 175.248_r8, 182.473_r8, 189.952_r8, 197.699_r8, & + 205.728_r8, 214.055_r8, 222.694_r8, 231.661_r8, 240.971_r8, 250.639_r8/ + ! + save retab + ! + + do k=1,pver + do i=1,ncol + index = int(t(i,k)-min_retab) + index = min(max(index,1),len_retab-1) + corr = t(i,k) - int(t(i,k)) + re(i,k) = retab(index)*(1._r8-corr) & + +retab(index+1)*corr + ! re(i,k) = amax1(amin1(re(i,k),30.),10.) + end do + end do + end subroutine reitab + +end module cloud_optical_properties From f95ea51f0226e691e2f29fc65dae83462211f3f2 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Fri, 17 Jan 2025 18:01:17 -0500 Subject: [PATCH 02/39] Sketch out cloud_particle_sedimentation Reformat cloud_optical_properties Stub rk_stratiform sub-schemes --- .../cloud_particle_sedimentation.F90 | 669 ++++++++++++++++++ .../cloud_particle_sedimentation_namelist.xml | 19 + .../prognostic_cloud_water.F90 | 1 + schemes/rasch_kristjansson/rk_stratiform.F90 | 22 +- to_be_ccppized/cloud_optical_properties.F90 | 385 +++++----- 5 files changed, 894 insertions(+), 202 deletions(-) create mode 100644 schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 create mode 100644 schemes/rasch_kristjansson/cloud_particle_sedimentation_namelist.xml diff --git a/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 b/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 new file mode 100644 index 00000000..a9bc997e --- /dev/null +++ b/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 @@ -0,0 +1,669 @@ +! Copyright (C) 2002-2025 National Science Foundation-National Center for Atmospheric Research +! SPDX-License-Identifier: Apache-2.0 +! +! Compute tendencies from sedimentation of cloud liquid and ice particles +! Original authors: Byron Boville, September 2002 from code by P.J. Rasch +! CCPP-ized: Haipeng Lin, January 2025 +module cloud_particle_sedimentation + + use ccpp_kinds, only: kind_phys + + implicit none + private + save + + ! public CCPP-compliant subroutines + public :: cloud_particle_sedimentation_init + public :: cloud_particle_sedimentation_run + + ! tuning parameters for cloud liquid and ice particle sedimentation + real(kind_phys), parameter :: vland = 1.5_kind_phys ! liquid fall velocity over land [cm s-1] + real(kind_phys), parameter :: vocean = 2.8_kind_phys ! liquid fall velocity over ocean [cm s-1] + real(kind_phys), parameter :: mxsedfac = 0.99_kind_phys ! maximum sedimentation flux factor + + ! tuning parameters for Stokes terminal velocity + logical, parameter :: stokes = .true. ! use Stokes velocity instead of McFarquhar and Heymsfield + real(kind_phys) :: cldsed_ice_stokes_fac ! factor applied to ice fall vel + ! from Stokes terminal velocity + real(kind_phys), parameter :: eta = 1.7e-5_kind_phys ! viscosity of air [kg m s-1] + real(kind_phys), parameter :: r40 = 40._kind_phys ! 40 micron radius + real(kind_phys), parameter :: r400 = 400._kind_phys ! 400 micron radius + real(kind_phys), parameter :: v400 = 1.00_kind_phys ! fall velocity of 400 micron sphere [m s-1] + real(kind_phys) :: v40 ! Stokes fall velocity of 40 micron sphere (m/s) + ! v40 = (2._kind_phys/9._kind_phys) * rhoh2o * gravit/eta * r40**2 * 1.e-12_kind_phys + real(kind_phys) :: vslope ! linear slope for large particles [m s-1 micron-1] + ! vslope = (v400 - v40)/(r400 -r40) + + ! tuning parameters for McFarquhar and Heymsfield terminal velocity + real(kind_phys), parameter :: vice_small = 1._kind_phys ! ice fall velocity for small concentration [cm s-1] + real(kind_phys) :: lbound ! lower bound for iciwc + + ! misc + real(kind_phys), parameter :: um_to_m = 1.e-12_kind_phys + +contains + +!> \section arg_table_cloud_particle_sedimentation_init Argument Table +!! \htmlinclude arg_table_cloud_particle_sedimentation_init.html + subroutine cloud_particle_sedimentation_init(& + amIRoot, iulog, & + cldsed_ice_stokes_fac_in, & + rhoh2o, gravit, & + errmsg, errflg) + + ! Input arguments + logical :: amIRoot + integer :: iulog ! log output unit + real(kind_phys), intent(in) :: cldsed_ice_stokes_fac_in + real(kind_phys), intent(in) :: gravit + real(kind_phys), intent(in) :: rhoh2o + + ! Output arguments + character(len=512), intent(out) :: errmsg ! error message + integer, intent(out) :: errflg ! error flag + + ! Local variables + real(kind_phys) :: ac, bc, cc ! constants for McFarquhar and Heymsfield method + + errmsg = '' + errflg = 0 + cldsed_ice_stokes_fac = cldsed_ice_stokes_fac_in + + ! linear ramp variables for fall velocity + v40 = (2._kind_phys/9._kind_phys)*rhoh2o*gravit/eta*r40**2*1.e-12_kind_phys + vslope = (v400 - v40)/(r400 - r40) + + ! McFarquhar and Heymsfield lower bound for iciwc + cc = 128.64_kind_phys + bc = 53.242_kind_phys + ac = 5.4795_kind_phys + lbound = (-bc + sqrt(bc*bc - 4*ac*cc))/(2*ac) + lbound = 10._kind_phys**lbound + + if(amIRoot) then + write(iulog,*) 'cloud_particle_sedimentation_init: cldsed_ice_stokes_fac = ', cldsed_ice_stokes_fac + endif + + end subroutine cloud_particle_sedimentation_init + + ! Compute gravitational sedimentation velocities for cloud liquid water + ! and ice, based on Lawrence and Crutzen (1998). + ! https://doi.org/10.3402/tellusb.v50i3.16129 + ! + ! and apply cloud particle gravitational sedimentation to condensate. + ! + ! Original authors: mgl, March 1998 (MATCH-MPIC version 2.0) + ! adapted by P.J. Rasch + ! B.A. Boville, September 2002 + ! P.J. Rasch, May 2003 +!> \section arg_table_cloud_particle_sedimentation_run Argument Table +!! \htmlinclude arg_table_cloud_particle_sedimentation_run.html + subroutine cloud_particle_sedimentation_run( & + ncol, pver, pverp, dtime, & + tmelt, gravit, latvap, latice, rair, rhoh2o, & + icritc, & ! from prognostic_cloud_water namelist + pint, pmid, pdel, t, cloud, & + icefrac, landfrac, ocnfrac, & + cldliq, cldice, snowh, landm, & + ! below output for sedimentation velocity + pvliq, pvice, & + ! below output for sedimentation to condensate + liqtend, icetend, wvtend, htend, sfliq, sfice, & + errmsg, errflg) + ! To-be-CCPPized dependencies + use cloud_optical_properties, only: reltab, reitab + + ! Input arguments + integer, intent(in) :: ncol + integer, intent(in) :: pver + integer, intent(in) :: pverp + real(kind_phys), intent(in) :: dtime + real(kind_phys), intent(in) :: tmelt + real(kind_phys), intent(in) :: gravit + real(kind_phys), intent(in) :: latvap + real(kind_phys), intent(in) :: latice + real(kind_phys), intent(in) :: rair + real(kind_phys), intent(in) :: rhoh2o + real(kind_phys), intent(in) :: icritc ! tunable_parameter_for_autoconversion_of_cold_ice_for_rk_microphysics [kg kg-1] + real(kind_phys), intent(in) :: pint(:,:) ! air_pressure_at_interface [Pa] + real(kind_phys), intent(in) :: pmid(:,:) ! air_pressure [Pa] + real(kind_phys), intent(in) :: pdel(:,:) ! air_pressure_thickness [Pa] + real(kind_phys), intent(in) :: t(:,:) ! air_temperature [K] + real(kind_phys), intent(in) :: cloud(:,:) ! cloud_area_fraction [fraction] + real(kind_phys), intent(in) :: icefrac(:) ! sea_ice_area_fraction [fraction] + real(kind_phys), intent(in) :: landfrac(:) ! land_area_fraction [fraction] + real(kind_phys), intent(in) :: ocnfrac(:) ! ocean_area_fraction [fraction] + real(kind_phys), intent(in) :: cldliq(:,:) ! adv: cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + real(kind_phys), intent(in) :: cldice(:,:) ! adv: cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + real(kind_phys), intent(in) :: snowh(:) ! lwe_surface_snow_depth_over_land [m] + real(kind_phys), intent(in) :: landm(:) ! smoothed_land_area_fraction [fraction] + + ! Output arguments + ! note: pvel is at the interfaces (loss from cell is based on pvel(k+1)) + real(kind_phys), intent(out) :: pvliq(:,:) ! vertical velocity of cloud liquid drops [Pa s-1] pverp + real(kind_phys), intent(out) :: pvice(:,:) ! vertical velocity of cloud ice particles [Pa s-1] pverp + real(kind_phys), intent(out) :: liqtend(:,:) ! liquid condensate tendency -- to apply cldliq tendency + real(kind_phys), intent(out) :: icetend(:,:) ! ice condensate tendency -- to apply cldice tendency + real(kind_phys), intent(out) :: wvtend(:,:) ! water vapor tendency -- to apply wv tendency + real(kind_phys), intent(out) :: htend(:,:) ! heating rate [J kg-1 s-1] -- to apply s tendency + real(kind_phys), intent(out) :: sfliq(:) ! surface flux of liquid (rain) [kg m-2 s-1] + real(kind_phys), intent(out) :: sfice(:) ! surface flux of ice (snow) [kg m-2 s-1] + character(len=512), intent(out) :: errmsg ! error message + integer, intent(out) :: errflg ! error flag + + ! Local variables + real(kind_phys) :: rho(ncol, pver) ! air density [kg m-3] + real(kind_phys) :: vfall ! settling velocity of cloud particles [m s-1] + real(kind_phys) :: icice ! in cloud ice water content [kg kg-1] + real(kind_phys) :: iciwc ! in cloud ice water content [g m-3] + real(kind_phys) :: icefac + real(kind_phys) :: logiwc + real(kind_phys) :: rei(ncol, pver) ! effective radius of ice particles [um] + real(kind_phys) :: rel(ncol, pver) ! effective radius of liquid particles [um] + real(kind_phys) :: fxliq(ncol, pverp) ! fluxes at interface, liquid (positive is down) [Pa] + real(kind_phys) :: fxice(ncol, pverp) ! fluxes at interface, ice (positive is down) [Pa] + real(kind_phys) :: cldab(ncol) ! cloud in layer above [fraction] + real(kind_phys) :: evapliq ! evaporation of cloud liquid into environment [kg kg-1 s-1] + real(kind_phys) :: evapice ! evaporation of cloud ice into environment [kg kg-1 s-1] + real(kind_phys) :: cldovrl ! cloud overlap factor + integer :: i, k + + errmsg = '' + errflg = 0 + + !-------------------------------------------------- + ! COMPUTE GRAVITATIONAL SEDIMENTATION VELOCITIES + !-------------------------------------------------- + ! NEED TO BE CAREFUL - VELOCITIES SHOULD BE AT THE *LOWER* INTERFACE + ! (THAT IS, FOR K+1), FLUXES ARE ALSO AT THE LOWER INTERFACE (K+1), + ! BUT MIXING RATIOS ARE AT THE MIDPOINTS (K)... + ! + ! NOTE THAT PVEL IS ON INTERFACES, WHEREAS VFALL IS FOR THE CELL + ! AVERAGES (I.E., MIDPOINTS); ASSUME THE FALL VELOCITY APPLICABLE TO THE + ! LOWER INTERFACE (K+1) IS THE SAME AS THAT APPLICABLE FOR THE CELL (V(K)) + + ! LIQUID: + ! The fall velocities assume that droplets have a gamma distribution + ! with effective radii for land and ocean as assessed by Han et al.; + ! see Lawrence and Crutzen (1998) for a derivation. + rho(:ncol,:) = pmid(:ncol,:)/(rair*t(:ncol,:)) + pvliq(:ncol,:) = 0._kind_phys + + ! get effective radius of liquid drop (rel) + call reltab(ncol=ncol, pver=pver, tmelt=tmelt, t=t(:ncol,:), landfrac=landfrac(:ncol), landm=landm(:ncol), icefrac=icefrac(:ncol), snowh=snowh(:ncol), rel=rel(:ncol,:)) + + do k = 1, pver + do i = 1, ncol + if (cloud(i, k) > 0._kind_phys .and. cldliq(i, k) > 0._kind_phys) then + if (rel(i, k) < 40._kind_phys) then + vfall = 2._kind_phys/9._kind_phys*rhoh2o*gravit*rel(i, k)**2/eta*um_to_m ! um^2 -> m^2 + else + vfall = v40 + vslope*(rel(i, k) - r40) ! linear above 40 microns + end if + ! convert the fall speed to pressure units, but do not apply the traditional + ! negative convention for pvel. + pvliq(i, k + 1) = vfall*rho(i, k)*gravit ! m s-1 to Pa s-1 + end if + end do + end do + + ! ICE: + ! The fall velocities are based on data from McFarquhar and Heymsfield + ! or on Stokes terminal velocity for spheres and the effective radius. + pvice(:ncol,:) = 0._kind_phys + + if(stokes) then + ! stokes terminal velocity < 40 microns + + ! get effective radius (rei) + call reitab(ncol=ncol, pver=pver, t=t(:ncol,:), re=rei(:ncol,:)) + + do k = 1, pver + do i = 1, ncol + if (cloud(i, k) > 0._kind_phys .and. cldice(i, k) > 0._kind_phys) then + if (rei(i, k) < 40._kind_phys) then + vfall = 2._kind_phys/9._kind_phys*rhoh2o*gravit*rei(i, k)**2/eta*um_to_m ! microns^2 -> m^2 + vfall = vfall*cldsed_ice_stokes_fac + else + vfall = v40 + vslope*(rei(i, k) - r40) ! linear above 40 microns + end if + + ! convert the fall speed to pressure units, but do not apply the traditional + ! negative convention for pvel. + pvice(i, k + 1) = vfall*rho(i, k)*gravit ! m s-1 to Pa s-1 + end if + end do + end do + + else + ! McFarquhar and Heymsfield > icritc + do k = 1, pver + do i = 1, ncol + if (cloud(i, k) > 0._kind_phys .and. cldice(i, k) > 0._kind_phys) then + + ! compute the in-cloud ice concentration (kg/kg) + icice = cldice(i, k)/cloud(i, k) + + ! compute the ice water content in g/m3 + iciwc = icice*rho(i, k)*1.e3_kind_phys + + ! set the fall velocity (cm/s) to depend on the ice water content in g/m3, + if (iciwc > lbound) then ! need this because of log10 + logiwc = log10(iciwc) + ! Median - + vfall = 128.64_kind_phys + 53.242_kind_phys*logiwc + 5.4795_kind_phys*logiwc**2 + ! Average - + ! vfall = 122.63 + 44.111*logiwc + 4.2144*logiwc**2 + else + vfall = 0._kind_phys + end if + + ! set ice velocity to 1 cm/s if ice mixing ratio < icritc, ramp to value + ! calculated above at 2*icritc + if (icice <= icritc) then + vfall = vice_small + else if (icice < 2*icritc) then + icefac = (icice - icritc)/icritc + vfall = vice_small*(1._kind_phys - icefac) + vfall*icefac + end if + + ! bound the terminal velocity of ice particles at high concentration + vfall = min(100.0_kind_phys, vfall) + + ! convert the fall speed to pressure units, but do not apply the traditional + ! negative convention for pvel. + pvice(i, k + 1) = vfall & + *0.01_kind_phys & ! cm to meters + *rho(i, k)*gravit ! m s-1 to Pa s-1 + end if + end do + end do + endif + + !-------------------------------------------------- + ! APPLY CLOUD PARTICLE GRAVITATIONAL SEDIMENTATION TO CONDENSATE + !-------------------------------------------------- + ! Initialize variables + fxliq(:ncol, :) = 0._kind_phys ! flux at interfaces (liquid) + fxice(:ncol, :) = 0._kind_phys ! flux at interfaces (ice) + liqtend(:ncol, :) = 0._kind_phys ! condensate tend (liquid) + icetend(:ncol, :) = 0._kind_phys ! condensate tend (ice) + wvtend(:ncol, :) = 0._kind_phys ! environmental moistening + htend(:ncol, :) = 0._kind_phys ! evaporative cooling + sfliq(:ncol) = 0._kind_phys ! condensate sedimentation flux out bot of column (liquid) + sfice(:ncol) = 0._kind_phys ! condensate sedimentation flux out bot of column (ice) + + ! Get fluxes at interior points + call getflx(ncol, pver, pverp, pint, cldliq, pvliq, dtime, fxliq, errmsg, errflg) + if(errflg /= 0) then + return + endif + call getflx(ncol, pver, pverp, pint, cldice, pvice, dtime, fxice, errmsg, errflg) + if(errflg /= 0) then + return + endif + + ! Calculate fluxes at boundaries + do i = 1, ncol + fxliq(i, 1) = 0._kind_phys + fxice(i, 1) = 0._kind_phys + ! surface flux by upstream scheme + fxliq(i, pverp) = cldliq(i, pver)*pvliq(i, pverp)*dtime + fxice(i, pverp) = cldice(i, pver)*pvice(i, pverp)*dtime + end do + + ! filter out any negative fluxes from the getflx routine + ! (typical fluxes are of order > 1e-3 when clouds are present) + do k = 2, pver + fxliq(:ncol, k) = max(0._kind_phys, fxliq(:ncol, k)) + fxice(:ncol, k) = max(0._kind_phys, fxice(:ncol, k)) + end do + + ! Limit the flux out of the bottom of each cell to the water content in each phase. + ! Apply mxsedfac to prevent generating very small negative cloud water/ice + ! NOTE, REMOVED CLOUD FACTOR FROM AVAILABLE WATER. ALL CLOUD WATER IS IN CLOUDS. + ! ***Should we include the flux in the top, to allow for thin surface layers? + ! ***Requires simple treatment of cloud overlap, already included below. + do k = 1, pver + do i = 1, ncol + fxliq(i, k + 1) = min(fxliq(i, k + 1), mxsedfac*cldliq(i, k)*pdel(i, k)) + fxice(i, k + 1) = min(fxice(i, k + 1), mxsedfac*cldice(i, k)*pdel(i, k)) + ! fxliq(i,k+1) = min( fxliq(i,k+1), cldliq(i,k) * pdel(i,k) + fxliq(i,k)) + ! fxice(i,k+1) = min( fxice(i,k+1), cldice(i,k) * pdel(i,k) + fxice(i,k)) + ! fxliq(i,k+1) = min( fxliq(i,k+1), cloud(i,k) * cldliq(i,k) * pdel(i,k) ) + ! fxice(i,k+1) = min( fxice(i,k+1), cloud(i,k) * cldice(i,k) * pdel(i,k) ) + end do + end do + + ! Now calculate the tendencies assuming that condensate evaporates when + ! it falls into environment, and does not when it falls into cloud. + ! All flux out of the layer comes from the cloudy part. + ! Assume maximum overlap for stratiform clouds + ! if cloud above < cloud, all water falls into cloud below + ! if cloud above > cloud, water split between cloud and environment + do k = 1, pver + cldab(:ncol) = 0._kind_phys + do i = 1, ncol + ! cloud overlap cloud factor + cldovrl = min(cloud(i, k)/(cldab(i) + .0001_kind_phys), 1._kind_phys) + cldab(i) = cloud(i, k) + ! evaporation into environment cause moistening and cooling + evapliq = fxliq(i, k)*(1._kind_phys - cldovrl)/(dtime*pdel(i, k)) ! into env [kg kg-1 s-1] + evapice = fxice(i, k)*(1._kind_phys - cldovrl)/(dtime*pdel(i, k)) ! into env [kg kg-1 s-1] + wvtend(i, k) = evapliq + evapice ! evaporation into environment [kg kg-1 s-1] + htend(i, k) = -latvap*evapliq - (latvap + latice)*evapice ! evaporation [W kg-1] + ! net flux into cloud changes cloud liquid/ice (all flux is out of cloud) + liqtend(i, k) = (fxliq(i, k)*cldovrl - fxliq(i, k + 1))/(dtime*pdel(i, k)) + icetend(i, k) = (fxice(i, k)*cldovrl - fxice(i, k + 1))/(dtime*pdel(i, k)) + end do + end do + +! convert flux out the bottom to mass units Pa -> kg/m2/s + sfliq(:ncol) = fxliq(:ncol, pverp)/(dtime*gravit) + sfice(:ncol) = fxice(:ncol, pverp)/(dtime*gravit) + + end subroutine cloud_particle_sedimentation_run + + ! Compute fluxes at interior points + subroutine getflx(ncol, pver, pverp, & + xw, phi, vel, deltat, flux, & + errmsg, errflg) + !.....xw1.......xw2.......xw3.......xw4.......xw5.......xw6 + !....psiw1.....psiw2.....psiw3.....psiw4.....psiw5.....psiw6 + !....velw1.....velw2.....velw3.....velw4.....velw5.....velw6 + !.........phi1......phi2.......phi3.....phi4.......phi5....... + + integer, intent(in) :: ncol + integer, intent(in) :: pver + integer, intent(in) :: pverp + real(kind_phys), intent(in) :: xw(ncol, pverp) + real(kind_phys), intent(in) :: phi(ncol, pver) + real(kind_phys), intent(in) :: vel(ncol, pverp) + real(kind_phys), intent(in) :: deltat + + real(kind_phys), intent(out) :: flux(ncol, pverp) + character(len=512), intent(out) :: errmsg ! error message + integer, intent(out) :: errflg ! error flag + + integer :: i, k + real(kind_phys) :: psi(ncol, pverp) + real(kind_phys) :: fdot(ncol, pverp) + real(kind_phys) :: xx(ncol) + real(kind_phys) :: fxdot(ncol) + real(kind_phys) :: fxdd(ncol) + real(kind_phys) :: psistar(ncol) + real(kind_phys) :: xxk(ncol, pver) + + do i = 1, ncol + ! integral of phi + psi(i, 1) = 0._kind_phys + ! fluxes at boundaries + flux(i, 1) = 0._kind_phys + flux(i, pverp) = 0._kind_phys + end do + + ! integral function + do k = 2, pverp + do i = 1, ncol + psi(i, k) = phi(i, k - 1)*(xw(i, k) - xw(i, k - 1)) + psi(i, k - 1) + end do + end do + + ! Calculate the derivatives for the interpolating polynomial + call cfdotmc(ncol, pver, pverp, xw, psi, fdot) + + ! NEW WAY + ! calculate fluxes at interior pts + do k = 2, pver + do i = 1, ncol + xxk(i, k) = xw(i, k) - vel(i, k)*deltat + end do + end do + do k = 2, pver + call cfint2(ncol, pverp, xw, psi, fdot, xxk(1, k), fxdot, fxdd, psistar, errmsg, errflg) + if(errflg /= 0) then + return + endif + do i = 1, ncol + flux(i, k) = (psi(i, k) - psistar(i)) + end do + end do + end subroutine getflx + + ! Vertical level interpolation + subroutine cfint2(ncol, pverp, & + x, f, fdot, xin, fxdot, fxdd, psistar, & + errmsg, errflg) + + integer, intent(in) :: ncol + integer, intent(in) :: pverp + real(kind_phys), intent(in) :: x(ncol, pverp) + real(kind_phys), intent(in) :: f(ncol, pverp) + real(kind_phys), intent(in) :: fdot(ncol, pverp) + real(kind_phys), intent(in) :: xin(ncol) + + real(kind_phys), intent(out) :: fxdot(ncol) + real(kind_phys), intent(out) :: fxdd(ncol) + real(kind_phys), intent(out) :: psistar(ncol) + character(len=512), intent(out) :: errmsg ! error message + integer, intent(out) :: errflg ! error flag + + integer :: i, k + integer :: intz(ncol) + real(kind_phys) :: dx + real(kind_phys) :: s + real(kind_phys) :: c2 + real(kind_phys) :: c3 + real(kind_phys) :: xx + real(kind_phys) :: xinf + real(kind_phys) :: psi1, psi2, psi3, psim + real(kind_phys) :: cfint + real(kind_phys) :: cfnew + real(kind_phys) :: xins(ncol) + logical :: found_error + + do i = 1, ncol + xins(i) = medan(x(i, 1), xin(i), x(i, pverp)) + intz(i) = 0 + end do + + ! first find the interval + do k = 1, pverp - 1 + do i = 1, ncol + if ((xins(i) - x(i, k))*(x(i, k + 1) - xins(i)) .ge. 0) then + intz(i) = k + end if + end do + end do + + found_error = .false. + do i = 1, ncol + if (intz(i) .eq. 0._kind_phys) found_error = .true. + end do + if (found_error) then + do i = 1, ncol + if (intz(i) .eq. 0._kind_phys) then + write(errmsg,'(a,i0)') 'cloud_particle_sedimentation/cfint2: interval was not found for column ', i + errflg = 1 + end if + end do + end if + + ! now interpolate + do i = 1, ncol + k = intz(i) + dx = (x(i, k + 1) - x(i, k)) + s = (f(i, k + 1) - f(i, k))/dx + c2 = (3*s - 2*fdot(i, k) - fdot(i, k + 1))/dx + c3 = (fdot(i, k) + fdot(i, k + 1) - 2*s)/dx**2 + xx = (xins(i) - x(i, k)) + fxdot(i) = (3*c3*xx + 2*c2)*xx + fdot(i, k) + fxdd(i) = 6*c3*xx + 2*c2 + cfint = ((c3*xx + c2)*xx + fdot(i, k))*xx + f(i, k) + + ! limit the interpolant + psi1 = f(i, k) + (f(i, k + 1) - f(i, k))*xx/dx + if (k .eq. 1) then + psi2 = f(i, 1) + else + psi2 = f(i, k) + (f(i, k) - f(i, k - 1))*xx/(x(i, k) - x(i, k - 1)) + end if + if (k + 1 .eq. pverp) then + psi3 = f(i, pverp) + else + psi3 = f(i, k + 1) - (f(i, k + 2) - f(i, k + 1))*(dx - xx)/(x(i, k + 2) - x(i, k + 1)) + end if + psim = medan(psi1, psi2, psi3) + cfnew = medan(cfint, psi1, psim) + !if (abs(cfnew - cfint)/(abs(cfnew) + abs(cfint) + 1.e-36_kind_phys) .gt. .03_kind_phys) then + ! CHANGE THIS BACK LATER!!! + ! $ .gt..1) then + ! UNCOMMENT THIS LATER!!! + ! write(iulog,*) ' cfint2 limiting important ', cfint, cfnew + !end if + psistar(i) = cfnew + end do + end subroutine cfint2 + + ! Calculate the derivative for the interpolating polynomial, multi-column version + subroutine cfdotmc(ncol, pver, pverp, x, f, fdot) + ! assumed variable distribution + ! x1.......x2.......x3.......x4.......x5.......x6 1,pverp points + ! f1.......f2.......f3.......f4.......f5.......f6 1,pverp points + ! ...sh1.......sh2......sh3......sh4......sh5.... 1,pver points + ! .........d2.......d3.......d4.......d5......... 2,pver points + ! .........s2.......s3.......s4.......s5......... 2,pver points + ! .............dh2......dh3......dh4............. 2,pver-1 points + ! .............eh2......eh3......eh4............. 2,pver-1 points + ! ..................e3.......e4.................. 3,pver-1 points + ! .................ppl3......ppl4................ 3,pver-1 points + ! .................ppr3......ppr4................ 3,pver-1 points + ! .................t3........t4.................. 3,pver-1 points + ! ................fdot3.....fdot4................ 3,pver-1 points + integer, intent(in) :: ncol + integer, intent(in) :: pver + integer, intent(in) :: pverp + real(kind_phys), intent(in) :: x(ncol, pverp) + real(kind_phys), intent(in) :: f(ncol, pverp) + + real(kind_phys), intent(out) :: fdot(ncol, pverp) ! derivative at nodes + + integer :: i, k + real(kind_phys) :: a, b, c ! work var + real(kind_phys) :: s(ncol, pverp) ! first divided differences at nodes + real(kind_phys) :: sh(ncol, pverp) ! first divided differences between nodes + real(kind_phys) :: d(ncol, pverp) ! second divided differences at nodes + real(kind_phys) :: dh(ncol, pverp) ! second divided differences between nodes + real(kind_phys) :: e(ncol, pverp) ! third divided differences at nodes + real(kind_phys) :: eh(ncol, pverp) ! third divided differences between nodes + real(kind_phys) :: pp ! p prime + real(kind_phys) :: ppl(ncol, pverp) ! p prime on left + real(kind_phys) :: ppr(ncol, pverp) ! p prime on right + real(kind_phys) :: qpl + real(kind_phys) :: qpr + real(kind_phys) :: ttt + real(kind_phys) :: t + real(kind_phys) :: tmin + real(kind_phys) :: tmax + real(kind_phys) :: delxh(ncol, pverp) + + do k = 1, pver + ! first divided differences between nodes + do i = 1, ncol + delxh(i, k) = (x(i, k + 1) - x(i, k)) + sh(i, k) = (f(i, k + 1) - f(i, k))/delxh(i, k) + end do + + ! first and second divided differences at nodes + if (k .ge. 2) then + do i = 1, ncol + d(i, k) = (sh(i, k) - sh(i, k - 1))/(x(i, k + 1) - x(i, k - 1)) + s(i, k) = minmod(sh(i, k), sh(i, k - 1)) + end do + end if + end do + + ! second and third divided diffs between nodes + do k = 2, pver - 1 + do i = 1, ncol + eh(i, k) = (d(i, k + 1) - d(i, k))/(x(i, k + 2) - x(i, k - 1)) + dh(i, k) = minmod(d(i, k), d(i, k + 1)) + end do + end do + + ! treat the boundaries + do i = 1, ncol + e(i, 2) = eh(i, 2) + e(i, pver) = eh(i, pver - 1) + ! outside level + fdot(i, 1) = sh(i, 1) - d(i, 2)*delxh(i, 1) & + - eh(i, 2)*delxh(i, 1)*(x(i, 1) - x(i, 3)) + fdot(i, 1) = minmod(fdot(i, 1), 3*sh(i, 1)) + fdot(i, pverp) = sh(i, pver) + d(i, pver)*delxh(i, pver) & + + eh(i, pver - 1)*delxh(i, pver)*(x(i, pverp) - x(i, pver - 1)) + fdot(i, pverp) = minmod(fdot(i, pverp), 3*sh(i, pver)) + ! one in from boundary + fdot(i, 2) = sh(i, 1) + d(i, 2)*delxh(i, 1) - eh(i, 2)*delxh(i, 1)*delxh(i, 2) + fdot(i, 2) = minmod(fdot(i, 2), 3*s(i, 2)) + fdot(i, pver) = sh(i, pver) - d(i, pver)*delxh(i, pver) & + - eh(i, pver - 1)*delxh(i, pver)*delxh(i, pver - 1) + fdot(i, pver) = minmod(fdot(i, pver), 3*s(i, pver)) + end do + + do k = 3, pver - 1 + do i = 1, ncol + e(i, k) = minmod(eh(i, k), eh(i, k - 1)) + end do + end do + + do k = 3, pver - 1 + do i = 1, ncol + ! p prime at k-0.5 + ppl(i, k) = sh(i, k - 1) + dh(i, k - 1)*delxh(i, k - 1) + ! p prime at k+0.5 + ppr(i, k) = sh(i, k) - dh(i, k)*delxh(i, k) + + t = minmod(ppl(i, k), ppr(i, k)) + + ! derivate from parabola thru f(i,k-1), f(i,k), and f(i,k+1) + pp = sh(i, k - 1) + d(i, k)*delxh(i, k - 1) + + ! quartic estimate of fdot + fdot(i, k) = pp & + - delxh(i, k - 1)*delxh(i, k) & + *(eh(i, k - 1)*(x(i, k + 2) - x(i, k)) & + + eh(i, k)*(x(i, k) - x(i, k - 2)) & + )/(x(i, k + 2) - x(i, k - 2)) + + ! now limit it + qpl = sh(i, k - 1) & + + delxh(i, k - 1)*minmod(d(i, k - 1) + e(i, k - 1)*(x(i, k) - x(i, k - 2)), & + d(i, k) - e(i, k)*delxh(i, k)) + qpr = sh(i, k) & + + delxh(i, k)*minmod(d(i, k) + e(i, k)*delxh(i, k - 1), & + d(i, k + 1) + e(i, k + 1)*(x(i, k) - x(i, k + 2))) + + fdot(i, k) = medan(fdot(i, k), qpl, qpr) + + ttt = minmod(qpl, qpr) + tmin = min(0._kind_phys, 3*s(i, k), 1.5_kind_phys*t, ttt) + tmax = max(0._kind_phys, 3*s(i, k), 1.5_kind_phys*t, ttt) + + fdot(i, k) = fdot(i, k) + minmod(tmin - fdot(i, k), tmax - fdot(i, k)) + end do + end do + end subroutine cfdotmc + + pure function minmod(a, b) result(res) + real(kind_phys), intent(in) :: a, b + real(kind_phys) :: res + res = 0.5_kind_phys*(sign(1._kind_phys, a) + sign(1._kind_phys, b))*min(abs(a), abs(b)) + end function minmod + + pure function medan(a, b, c) result(res) + real(kind_phys), intent(in) :: a, b, c + real(kind_phys) :: res + res = a + minmod(b - a, c - a) + end function medan + +end module cloud_particle_sedimentation diff --git a/schemes/rasch_kristjansson/cloud_particle_sedimentation_namelist.xml b/schemes/rasch_kristjansson/cloud_particle_sedimentation_namelist.xml new file mode 100644 index 00000000..209c580e --- /dev/null +++ b/schemes/rasch_kristjansson/cloud_particle_sedimentation_namelist.xml @@ -0,0 +1,19 @@ + + + + + + + real + cldsed + cldsed_nl + tunable_parameter_for_ice_fall_velocity_for_cloud_sedimentation + 1 + + Factor applied to the ice fall velocity computed from Stokes terminal velocity. + + + 1.0 + + + diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 index 000a9387..ab49294a 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 @@ -2,6 +2,7 @@ ! SPDX-License-Identifier: Apache-2.0 ! ! Prognostic cloud water data and methods (cldwat) +! Original authors as marked in subroutines ! CCPP-ized: Haipeng Lin, January 2025 module prognostic_cloud_water use ccpp_kinds, only: kind_phys diff --git a/schemes/rasch_kristjansson/rk_stratiform.F90 b/schemes/rasch_kristjansson/rk_stratiform.F90 index 9b1f93df..8c1ffa2c 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.F90 +++ b/schemes/rasch_kristjansson/rk_stratiform.F90 @@ -12,13 +12,31 @@ module rk_stratiform ! public CCPP-compliant subroutines public :: rk_stratiform_init - public :: rk_stratiform_run + public :: rk_stratiform_sedimentation_run + public :: rk_stratiform_cloud_fractions_run + public :: rk_stratiform_microphysics_run + public :: rk_stratiform_prognostic_cloud_water_tendencies_run + public :: rk_stratiform_microphysics_tendencies_run + public :: rk_stratiform_cloud_optical_properties_run + + ! + + ! temp: convect_shallow_use_shfrc() is not available so set it to + ! false for now. it is used for UW and UNICON shallow convection schemes + ! but is unavailable in the pbuf anyway... + logical :: use_shfrc = .false. - ! namelist variables for tuning of RK stratiform scheme contains + ! Initialize rk_stratiform + subroutine rk_stratiform_init(& + errmsg, errflg) + ! If qcwat, tcwat, lcwat are not initialized, eventually init them + + end subroutine rk_stratiform_init + diff --git a/to_be_ccppized/cloud_optical_properties.F90 b/to_be_ccppized/cloud_optical_properties.F90 index 4e76e7d2..670be7bd 100644 --- a/to_be_ccppized/cloud_optical_properties.F90 +++ b/to_be_ccppized/cloud_optical_properties.F90 @@ -6,8 +6,8 @@ ! Author: Byron Boville, Sept 2002 assembled from existing subroutines module cloud_optical_properties - use shr_kind_mod, only: r8=>shr_kind_r8 - use ppgrid, only: pcols, pver, pverp + use shr_kind_mod, only: r8 => shr_kind_r8 + use ppgrid, only: pcols, pver, pverp implicit none private @@ -18,49 +18,35 @@ module cloud_optical_properties contains -!=============================================================================== + ! Compute cloud water and ice particle size [um] + ! using empirical formulas to construct effective radii + ! Original author: J.T. Kiehl, B.A. Boville, P. Rasch subroutine cldefr( & ncol, pver, & tmelt, & - landfrac,t ,rel ,rei ,ps ,pmid , landm, icefrac, snowh) -!----------------------------------------------------------------------- -! -! Purpose: -! Compute cloud water and ice particle size -! -! Method: -! use empirical formulas to construct effective radii -! -! Author: J.T. Kiehl, B. A. Boville, P. Rasch -! -!----------------------------------------------------------------------- - -!------------------------------Arguments-------------------------------- -! -! Input arguments -! - integer, intent(in) :: ncol ! number of atmospheric columns - integer, intent(in) :: pver + landfrac, t, rel, rei, ps, pmid, landm, icefrac, snowh) + ! Input arguments + integer, intent(in) :: ncol ! number of atmospheric columns + integer, intent(in) :: pver real(r8), intent(in) :: tmelt - real(r8), intent(in) :: landfrac(pcols) ! Land fraction - real(r8), intent(in) :: icefrac(pcols) ! Ice fraction - real(r8), intent(in) :: t(pcols,pver) ! Temperature - real(r8), intent(in) :: ps(pcols) ! Surface pressure - real(r8), intent(in) :: pmid(pcols,pver) ! Midpoint pressures - real(r8), intent(in) :: landm(pcols) - real(r8), intent(in) :: snowh(pcols) ! Snow depth over land, water equivalent (m) -! -! Output arguments -! - real(r8), intent(out) :: rel(pcols,pver) ! Liquid effective drop size (microns) - real(r8), intent(out) :: rei(pcols,pver) ! Ice effective drop size (microns) -! -! following Kiehl - call reltab(ncol, pver, tmelt, t, landfrac, landm, icefrac, rel, snowh) + real(r8), intent(in) :: landfrac(:) ! Land fraction + real(r8), intent(in) :: icefrac(:) ! Ice fraction + real(r8), intent(in) :: t(:, :) ! Temperature + real(r8), intent(in) :: ps(:) ! Surface pressure + real(r8), intent(in) :: pmid(:, :) ! Midpoint pressures + real(r8), intent(in) :: landm(:) + real(r8), intent(in) :: snowh(:) ! Snow depth over land, water equivalent [m] + + ! Output arguments + real(r8), intent(out) :: rel(:, :) ! Liquid effective drop size [um] + real(r8), intent(out) :: rei(:, :) ! Ice effective drop size [um] -! following Kristjansson and Mitchell - call reitab(ncol, t, rei) + ! following Kiehl + call reltab(ncol, pver, tmelt, t(:ncol,:), landfrac(:ncol), landm(:ncol), icefrac(:ncol), snowh(:), rel(:ncol,:)) + + ! following Kristjansson and Mitchell + call reitab(ncol, pver, t(:ncol,:), rei(:ncol,:)) end subroutine cldefr ! Compute cloud emissivity using cloud liquid water path [g m-2] @@ -70,28 +56,28 @@ end subroutine cldefr subroutine cldems_rk(ncol, pver, clwp, fice, rei, emis, cldtau) integer, intent(in) :: ncol ! number of atmospheric columns integer, intent(in) :: pver ! number of vertical levels - real(r8), intent(in) :: clwp(pcols,pver) ! cloud liquid water path (g/m**2) - real(r8), intent(in) :: rei(pcols,pver) ! ice effective drop size (microns) - real(r8), intent(in) :: fice(pcols,pver) ! fractional ice content within cloud + real(r8), intent(in) :: clwp(pcols, pver) ! cloud liquid water path (g/m**2) + real(r8), intent(in) :: rei(pcols, pver) ! ice effective drop size (microns) + real(r8), intent(in) :: fice(pcols, pver) ! fractional ice content within cloud - real(r8), intent(out) :: emis(pcols,pver) ! cloud emissivity (fraction) - real(r8), intent(out) :: cldtau(pcols,pver) ! cloud optical depth + real(r8), intent(out) :: emis(pcols, pver) ! cloud emissivity (fraction) + real(r8), intent(out) :: cldtau(pcols, pver) ! cloud optical depth - integer :: i,k ! longitude, level indices + integer :: i, k ! longitude, level indices real(r8) :: kabs ! longwave absorption coeff (m**2/g) real(r8) :: kabsi ! ice absorption coefficient real(r8) :: kabsl ! longwave liquid absorption coeff (m**2/g) - parameter (kabsl = 0.090361_r8) + parameter(kabsl=0.090361_r8) do k = 1, pver - do i = 1, ncol - ! note that optical properties for ice valid only - ! in range of 13 > rei > 130 micron (Ebert and Curry 92) - kabsi = 0.005_r8 + 1._r8/rei(i,k) - kabs = kabsl*(1._r8-fice(i,k)) + kabsi*fice(i,k) - emis(i,k) = 1._r8 - exp(-1.66_r8*kabs*clwp(i,k)) - cldtau(i,k) = kabs*clwp(i,k) - end do + do i = 1, ncol + ! note that optical properties for ice valid only + ! in range of 13 > rei > 130 micron (Ebert and Curry 92) + kabsi = 0.005_r8 + 1._r8/rei(i, k) + kabs = kabsl*(1._r8 - fice(i, k)) + kabsi*fice(i, k) + emis(i, k) = 1._r8 - exp(-1.66_r8*kabs*clwp(i, k)) + cldtau(i, k) = kabs*clwp(i, k) + end do end do end subroutine cldems_rk @@ -99,48 +85,48 @@ end subroutine cldems_rk subroutine cldems(ncol, pver, clwp, fice, rei, emis, cldtau) integer, intent(in) :: ncol ! number of atmospheric columns integer, intent(in) :: pver ! number of vertical levels - real(r8), intent(in) :: clwp(pcols,pver) ! cloud liquid water path (g/m**2) - real(r8), intent(in) :: rei(pcols,pver) ! ice effective drop size (microns) - real(r8), intent(in) :: fice(pcols,pver) ! fractional ice content within cloud + real(r8), intent(in) :: clwp(pcols, pver) ! cloud liquid water path (g/m**2) + real(r8), intent(in) :: rei(pcols, pver) ! ice effective drop size (microns) + real(r8), intent(in) :: fice(pcols, pver) ! fractional ice content within cloud - real(r8), intent(out) :: emis(pcols,pver) ! cloud emissivity (fraction) - real(r8), intent(out) :: cldtau(pcols,pver) ! cloud optical depth + real(r8), intent(out) :: emis(pcols, pver) ! cloud emissivity (fraction) + real(r8), intent(out) :: cldtau(pcols, pver) ! cloud optical depth - integer :: i,k ! longitude, level indices + integer :: i, k ! longitude, level indices real(r8) :: kabs ! longwave absorption coeff (m**2/g) real(r8) :: kabsi ! ice absorption coefficient real(r8) :: kabsl ! longwave liquid absorption coeff (m**2/g) - parameter (kabsl = 0.090361_r8) + parameter(kabsl=0.090361_r8) do k = 1, pver - do i = 1, ncol - ! note that optical properties for ice valid only - ! in range of 13 > rei > 130 micron (Ebert and Curry 92) - kabsi = 0.005_r8 + 1._r8/min(max(13._r8,rei(i,k)),130._r8) - kabs = kabsl*(1._r8-fice(i,k)) + kabsi*fice(i,k) - emis(i,k) = 1._r8 - exp(-1.66_r8*kabs*clwp(i,k)) - cldtau(i,k) = kabs*clwp(i,k) - end do + do i = 1, ncol + ! note that optical properties for ice valid only + ! in range of 13 > rei > 130 micron (Ebert and Curry 92) + kabsi = 0.005_r8 + 1._r8/min(max(13._r8, rei(i, k)), 130._r8) + kabs = kabsl*(1._r8 - fice(i, k)) + kabsi*fice(i, k) + emis(i, k) = 1._r8 - exp(-1.66_r8*kabs*clwp(i, k)) + cldtau(i, k) = kabs*clwp(i, k) + end do end do end subroutine cldems !=============================================================================== - subroutine cldovrlap(ncol ,pint ,cld ,nmxrgn ,pmxrgn ) -!----------------------------------------------------------------------- -! -! Purpose: + subroutine cldovrlap(ncol, pint, cld, nmxrgn, pmxrgn) +!----------------------------------------------------------------------- +! +! Purpose: ! Partitions each column into regions with clouds in neighboring layers. ! This information is used to implement maximum overlap in these regions ! with random overlap between them. ! On output, ! nmxrgn contains the number of regions in each column ! pmxrgn contains the interface pressures for the lower boundaries of -! each region! -! Method: +! each region! +! Method: -! +! ! Author: W. Collins -! +! !----------------------------------------------------------------------- ! @@ -148,13 +134,13 @@ subroutine cldovrlap(ncol ,pint ,cld ,nmxrgn ,pmxrgn ) ! integer, intent(in) :: ncol ! number of atmospheric columns - real(r8), intent(in) :: pint(pcols,pverp) ! Interface pressure - real(r8), intent(in) :: cld(pcols,pver) ! Fractional cloud cover + real(r8), intent(in) :: pint(pcols, pverp) ! Interface pressure + real(r8), intent(in) :: cld(pcols, pver) ! Fractional cloud cover ! ! Output arguments ! - integer, intent(out) :: nmxrgn(pcols) ! Number of maximally overlapped regions - real(r8), intent(out) :: pmxrgn(pcols,pverp)! Maximum values of pressure for each + integer, intent(out) :: nmxrgn(pcols) ! Number of maximally overlapped regions + real(r8), intent(out) :: pmxrgn(pcols, pverp)! Maximum values of pressure for each ! maximally overlapped region. ! 0->pmxrgn(i,1) is range of pressure for ! 1st region,pmxrgn(i,1)->pmxrgn(i,2) for @@ -166,7 +152,7 @@ subroutine cldovrlap(ncol ,pint ,cld ,nmxrgn ,pmxrgn ) integer k ! Level index integer n ! Max-overlap region counter - real(r8) pnm(pcols,pverp) ! Interface pressure + real(r8) pnm(pcols, pverp) ! Interface pressure logical cld_found ! Flag for detection of cloud logical cld_layer(pver) ! Flag for cloud in layer @@ -175,63 +161,62 @@ subroutine cldovrlap(ncol ,pint ,cld ,nmxrgn ,pmxrgn ) ! do i = 1, ncol - cld_found = .false. - cld_layer(:) = cld(i,:) > 0.0_r8 - pmxrgn(i,:) = 0.0_r8 - pnm(i,:)=pint(i,:)*10._r8 - n = 1 - do k = 1, pver - if (cld_layer(k) .and. .not. cld_found) then - cld_found = .true. - else if ( .not. cld_layer(k) .and. cld_found) then - cld_found = .false. - if (count(cld_layer(k:pver)) == 0) then - exit - endif - pmxrgn(i,n) = pnm(i,k) - n = n + 1 - endif - end do - pmxrgn(i,n) = pnm(i,pverp) - nmxrgn(i) = n + cld_found = .false. + cld_layer(:) = cld(i, :) > 0.0_r8 + pmxrgn(i, :) = 0.0_r8 + pnm(i, :) = pint(i, :)*10._r8 + n = 1 + do k = 1, pver + if (cld_layer(k) .and. .not. cld_found) then + cld_found = .true. + else if (.not. cld_layer(k) .and. cld_found) then + cld_found = .false. + if (count(cld_layer(k:pver)) == 0) then + exit + end if + pmxrgn(i, n) = pnm(i, k) + n = n + 1 + end if + end do + pmxrgn(i, n) = pnm(i, pverp) + nmxrgn(i) = n end do end subroutine cldovrlap !=============================================================================== - subroutine cldclw(ncol ,zi ,clwp ,tpw ,hl ) -!----------------------------------------------------------------------- -! -! Purpose: + subroutine cldclw(ncol, zi, clwp, tpw, hl) +!----------------------------------------------------------------------- +! +! Purpose: ! Evaluate cloud liquid water path clwp (g/m**2) -! -! Method: -! -! -! +! +! Method: +! +! +! ! Author: J.T. Kiehl -! +! !----------------------------------------------------------------------- - ! ! Input arguments ! integer, intent(in) :: ncol ! number of atmospheric columns - real(r8), intent(in) :: zi(pcols,pverp) ! height at layer interfaces(m) + real(r8), intent(in) :: zi(pcols, pverp) ! height at layer interfaces(m) real(r8), intent(in) :: tpw(pcols) ! total precipitable water (mm) ! ! Output arguments ! - real(r8), intent(out) :: clwp(pcols,pver) ! cloud liquid water path (g/m**2) + real(r8), intent(out) :: clwp(pcols, pver) ! cloud liquid water path (g/m**2) real(r8), intent(out) :: hl(pcols) ! liquid water scale height ! !---------------------------Local workspace----------------------------- ! - integer :: i,k ! longitude, level indices + integer :: i, k ! longitude, level indices real(r8) :: clwc0 ! reference liquid water concentration (g/m**3) - real(r8) :: emziohl(pcols,pverp) ! exp(-zi/hl) + real(r8) :: emziohl(pcols, pverp) ! exp(-zi/hl) real(r8) :: rhl(pcols) ! 1/hl ! !----------------------------------------------------------------------- @@ -242,59 +227,58 @@ subroutine cldclw(ncol ,zi ,clwp ,tpw ,hl ) ! ! Diagnose liquid water scale height from precipitable water ! - do i=1,ncol - hl(i) = 700.0_r8*log(max(tpw(i)+1.0_r8,1.0_r8)) - rhl(i) = 1.0_r8/hl(i) + do i = 1, ncol + hl(i) = 700.0_r8*log(max(tpw(i) + 1.0_r8, 1.0_r8)) + rhl(i) = 1.0_r8/hl(i) end do ! ! Evaluate cloud liquid water path (vertical integral of exponential fn) ! - do k=1,pverp - do i=1,ncol - emziohl(i,k) = exp(-zi(i,k)*rhl(i)) - end do + do k = 1, pverp + do i = 1, ncol + emziohl(i, k) = exp(-zi(i, k)*rhl(i)) + end do end do - do k=1,pver - do i=1,ncol - clwp(i,k) = clwc0*hl(i)*(emziohl(i,k+1) - emziohl(i,k)) - end do + do k = 1, pver + do i = 1, ncol + clwp(i, k) = clwc0*hl(i)*(emziohl(i, k + 1) - emziohl(i, k)) + end do end do end subroutine cldclw - !=============================================================================== - subroutine reltab(ncol, pver, tmelt, t, landfrac, landm, icefrac, rel, snowh) -!----------------------------------------------------------------------- -! -! Purpose: + subroutine reltab(ncol, pver, tmelt, t, landfrac, landm, icefrac, snowh, rel) +!----------------------------------------------------------------------- +! +! Purpose: ! Compute cloud water size -! -! Method: +! +! Method: ! analytic formula following the formulation originally developed by J. T. Kiehl -! +! ! Author: Phil Rasch -! +! !----------------------------------------------------------------------- ! ! Input arguments ! - integer, intent(in) :: ncol - integer, intent(in) :: pver + integer, intent(in) :: ncol + integer, intent(in) :: pver real(r8), intent(in) :: tmelt - real(r8), intent(in) :: landfrac(pcols) ! Land fraction - real(r8), intent(in) :: icefrac(pcols) ! Ice fraction - real(r8), intent(in) :: snowh(pcols) ! Snow depth over land, water equivalent (m) - real(r8), intent(in) :: landm(pcols) ! Land fraction ramping to zero over ocean - real(r8), intent(in) :: t(pcols,pver) ! Temperature + real(r8), intent(in) :: landfrac(:) ! Land fraction + real(r8), intent(in) :: landm(:) ! Land fraction ramping to zero over ocean + real(r8), intent(in) :: icefrac(:) ! Ice fraction + real(r8), intent(in) :: t(:, :) ! Temperature [K] + real(r8), intent(in) :: snowh(:) ! Snow depth over land, water equivalent [m] ! ! Output arguments ! - real(r8), intent(out) :: rel(pcols,pver) ! Liquid effective drop size (microns) + real(r8), intent(out) :: rel(:, :) ! Liquid effective drop size (microns) ! !---------------------------Local workspace----------------------------- ! - integer i,k ! Lon, lev indices + integer i, k ! Lon, lev indices real(r8) :: rliqland ! liquid drop size if over land real(r8) :: rliqocean ! liquid drop size if over ocean real(r8) :: rliqice ! liquid drop size if over sea ice @@ -302,32 +286,33 @@ subroutine reltab(ncol, pver, tmelt, t, landfrac, landm, icefrac, rel, snowh) !----------------------------------------------------------------------- ! rliqocean = 14.0_r8 - rliqice = 14.0_r8 - rliqland = 8.0_r8 - do k=1,pver - do i=1,ncol -! jrm Reworked effective radius algorithm - ! Start with temperature-dependent value appropriate for continental air - ! Note: findmcnew has a pressure dependence here - rel(i,k) = rliqland + (rliqocean-rliqland) * min(1.0_r8,max(0.0_r8,(tmelt-t(i,k))*0.05_r8)) - ! Modify for snow depth over land - rel(i,k) = rel(i,k) + (rliqocean-rel(i,k)) * min(1.0_r8,max(0.0_r8,snowh(i)*10._r8)) - ! Ramp between polluted value over land to clean value over ocean. - rel(i,k) = rel(i,k) + (rliqocean-rel(i,k)) * min(1.0_r8,max(0.0_r8,1.0_r8-landm(i))) - ! Ramp between the resultant value and a sea ice value in the presence of ice. - rel(i,k) = rel(i,k) + (rliqice-rel(i,k)) * min(1.0_r8,max(0.0_r8,icefrac(i))) -! end jrm - end do + rliqice = 14.0_r8 + rliqland = 8.0_r8 + do k = 1, pver + do i = 1, ncol + ! jrm Reworked effective radius algorithm + ! Start with temperature-dependent value appropriate for continental air + ! Note: findmcnew has a pressure dependence here + rel(i, k) = rliqland + (rliqocean - rliqland)*min(1.0_r8, max(0.0_r8, (tmelt - t(i, k))*0.05_r8)) + ! Modify for snow depth over land + rel(i, k) = rel(i, k) + (rliqocean - rel(i, k))*min(1.0_r8, max(0.0_r8, snowh(i)*10._r8)) + ! Ramp between polluted value over land to clean value over ocean. + rel(i, k) = rel(i, k) + (rliqocean - rel(i, k))*min(1.0_r8, max(0.0_r8, 1.0_r8 - landm(i))) + ! Ramp between the resultant value and a sea ice value in the presence of ice. + rel(i, k) = rel(i, k) + (rliqice - rel(i, k))*min(1.0_r8, max(0.0_r8, icefrac(i))) + ! end jrm + end do end do end subroutine reltab !=============================================================================== - subroutine reitab(ncol, t, re) + subroutine reitab(ncol, pver, t, re) integer, intent(in) :: ncol - real(r8), intent(out) :: re(pcols,pver) - real(r8), intent(in) :: t(pcols,pver) - integer , parameter :: len_retab = 138 + integer, intent(in) :: pver + real(r8), intent(in) :: t(:, :) + real(r8), intent(out) :: re(:, :) + integer, parameter :: len_retab = 138 real(r8), parameter :: min_retab = 136._r8 real(r8) :: retab(len_retab) real(r8) :: corr @@ -338,46 +323,46 @@ subroutine reitab(ncol, t, re) ! Tabulated values of re(T) in the temperature interval ! 180 K -- 274 K; hexagonal columns assumed: ! - ! Modified for pmc formation: 136K -- 274K + ! Modified for pmc formation: 136K -- 274K ! - data retab / & - 0.05_r8, 0.05_r8, 0.05_r8, 0.05_r8, 0.05_r8, 0.05_r8, & - 0.055_r8, 0.06_r8, 0.07_r8, 0.08_r8, 0.09_r8, 0.1_r8, & - 0.2_r8, 0.3_r8, 0.40_r8, 0.50_r8, 0.60_r8, 0.70_r8, & - 0.8_r8 , 0.9_r8, 1.0_r8, 1.1_r8, 1.2_r8, 1.3_r8, & - 1.4_r8, 1.5_r8, 1.6_r8, 1.8_r8, 2.0_r8, 2.2_r8, & - 2.4_r8, 2.6_r8, 2.8_r8, 3.0_r8, 3.2_r8, 3.5_r8, & - 3.8_r8, 4.1_r8, 4.4_r8, 4.7_r8, 5.0_r8, 5.3_r8, & - 5.6_r8, & - 5.92779_r8, 6.26422_r8, 6.61973_r8, 6.99539_r8, 7.39234_r8, & - 7.81177_r8, 8.25496_r8, 8.72323_r8, 9.21800_r8, 9.74075_r8, 10.2930_r8, & - 10.8765_r8, 11.4929_r8, 12.1440_r8, 12.8317_r8, 13.5581_r8, 14.2319_r8, & - 15.0351_r8, 15.8799_r8, 16.7674_r8, 17.6986_r8, 18.6744_r8, 19.6955_r8, & - 20.7623_r8, 21.8757_r8, 23.0364_r8, 24.2452_r8, 25.5034_r8, 26.8125_r8, & - 27.7895_r8, 28.6450_r8, 29.4167_r8, 30.1088_r8, 30.7306_r8, 31.2943_r8, & - 31.8151_r8, 32.3077_r8, 32.7870_r8, 33.2657_r8, 33.7540_r8, 34.2601_r8, & - 34.7892_r8, 35.3442_r8, 35.9255_r8, 36.5316_r8, 37.1602_r8, 37.8078_r8, & - 38.4720_r8, 39.1508_r8, 39.8442_r8, 40.5552_r8, 41.2912_r8, 42.0635_r8, & - 42.8876_r8, 43.7863_r8, 44.7853_r8, 45.9170_r8, 47.2165_r8, 48.7221_r8, & - 50.4710_r8, 52.4980_r8, 54.8315_r8, 57.4898_r8, 60.4785_r8, 63.7898_r8, & - 65.5604_r8, 71.2885_r8, 75.4113_r8, 79.7368_r8, 84.2351_r8, 88.8833_r8, & - 93.6658_r8, 98.5739_r8, 103.603_r8, 108.752_r8, 114.025_r8, 119.424_r8, & - 124.954_r8, 130.630_r8, 136.457_r8, 142.446_r8, 148.608_r8, 154.956_r8, & - 161.503_r8, 168.262_r8, 175.248_r8, 182.473_r8, 189.952_r8, 197.699_r8, & - 205.728_r8, 214.055_r8, 222.694_r8, 231.661_r8, 240.971_r8, 250.639_r8/ + data retab/ & + 0.05_r8, 0.05_r8, 0.05_r8, 0.05_r8, 0.05_r8, 0.05_r8, & + 0.055_r8, 0.06_r8, 0.07_r8, 0.08_r8, 0.09_r8, 0.1_r8, & + 0.2_r8, 0.3_r8, 0.40_r8, 0.50_r8, 0.60_r8, 0.70_r8, & + 0.8_r8, 0.9_r8, 1.0_r8, 1.1_r8, 1.2_r8, 1.3_r8, & + 1.4_r8, 1.5_r8, 1.6_r8, 1.8_r8, 2.0_r8, 2.2_r8, & + 2.4_r8, 2.6_r8, 2.8_r8, 3.0_r8, 3.2_r8, 3.5_r8, & + 3.8_r8, 4.1_r8, 4.4_r8, 4.7_r8, 5.0_r8, 5.3_r8, & + 5.6_r8, & + 5.92779_r8, 6.26422_r8, 6.61973_r8, 6.99539_r8, 7.39234_r8, & + 7.81177_r8, 8.25496_r8, 8.72323_r8, 9.21800_r8, 9.74075_r8, 10.2930_r8, & + 10.8765_r8, 11.4929_r8, 12.1440_r8, 12.8317_r8, 13.5581_r8, 14.2319_r8, & + 15.0351_r8, 15.8799_r8, 16.7674_r8, 17.6986_r8, 18.6744_r8, 19.6955_r8, & + 20.7623_r8, 21.8757_r8, 23.0364_r8, 24.2452_r8, 25.5034_r8, 26.8125_r8, & + 27.7895_r8, 28.6450_r8, 29.4167_r8, 30.1088_r8, 30.7306_r8, 31.2943_r8, & + 31.8151_r8, 32.3077_r8, 32.7870_r8, 33.2657_r8, 33.7540_r8, 34.2601_r8, & + 34.7892_r8, 35.3442_r8, 35.9255_r8, 36.5316_r8, 37.1602_r8, 37.8078_r8, & + 38.4720_r8, 39.1508_r8, 39.8442_r8, 40.5552_r8, 41.2912_r8, 42.0635_r8, & + 42.8876_r8, 43.7863_r8, 44.7853_r8, 45.9170_r8, 47.2165_r8, 48.7221_r8, & + 50.4710_r8, 52.4980_r8, 54.8315_r8, 57.4898_r8, 60.4785_r8, 63.7898_r8, & + 65.5604_r8, 71.2885_r8, 75.4113_r8, 79.7368_r8, 84.2351_r8, 88.8833_r8, & + 93.6658_r8, 98.5739_r8, 103.603_r8, 108.752_r8, 114.025_r8, 119.424_r8, & + 124.954_r8, 130.630_r8, 136.457_r8, 142.446_r8, 148.608_r8, 154.956_r8, & + 161.503_r8, 168.262_r8, 175.248_r8, 182.473_r8, 189.952_r8, 197.699_r8, & + 205.728_r8, 214.055_r8, 222.694_r8, 231.661_r8, 240.971_r8, 250.639_r8/ ! save retab ! - do k=1,pver - do i=1,ncol - index = int(t(i,k)-min_retab) - index = min(max(index,1),len_retab-1) - corr = t(i,k) - int(t(i,k)) - re(i,k) = retab(index)*(1._r8-corr) & - +retab(index+1)*corr - ! re(i,k) = amax1(amin1(re(i,k),30.),10.) - end do + do k = 1, pver + do i = 1, ncol + index = int(t(i, k) - min_retab) + index = min(max(index, 1), len_retab - 1) + corr = t(i, k) - int(t(i, k)) + re(i, k) = retab(index)*(1._r8 - corr) & + + retab(index + 1)*corr + ! re(i,k) = amax1(amin1(re(i,k),30.),10.) + end do end do end subroutine reitab From 28e941be3b01f0516a60f44b47f8b4dd400284ab Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Wed, 22 Jan 2025 17:37:17 -0500 Subject: [PATCH 03/39] Sketch out metadata; revert some to precip units --- .../cloud_particle_sedimentation.F90 | 4 +- .../cloud_particle_sedimentation.meta | 256 +++++++++++ .../prognostic_cloud_water.F90 | 59 +-- .../prognostic_cloud_water.meta | 407 ++++++++++++++++++ 4 files changed, 700 insertions(+), 26 deletions(-) create mode 100644 schemes/rasch_kristjansson/cloud_particle_sedimentation.meta create mode 100644 schemes/rasch_kristjansson/prognostic_cloud_water.meta diff --git a/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 b/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 index a9bc997e..0fa8d625 100644 --- a/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 +++ b/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 @@ -52,8 +52,8 @@ subroutine cloud_particle_sedimentation_init(& errmsg, errflg) ! Input arguments - logical :: amIRoot - integer :: iulog ! log output unit + logical, intent(in) :: amIRoot + integer, intent(in) :: iulog ! log output unit real(kind_phys), intent(in) :: cldsed_ice_stokes_fac_in real(kind_phys), intent(in) :: gravit real(kind_phys), intent(in) :: rhoh2o diff --git a/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta b/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta new file mode 100644 index 00000000..bbbbb0bd --- /dev/null +++ b/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta @@ -0,0 +1,256 @@ +[ccpp-table-properties] + name = cloud_particle_sedimentation + type = scheme + +[ccpp-arg-table] + name = cloud_particle_sedimentation_init + type = scheme +[ amIRoot ] + standard_name = flag_for_mpi_root + units = flag + type = logical + dimensions = () + intent = in +[ iulog ] + standard_name = log_output_unit + units = 1 + type = integer + dimensions = () + intent = in +[ cldsed_ice_stokes_fac_in ] + standard_name = tunable_parameter_for_ice_fall_velocity_for_cloud_sedimentation + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ rhoh2o ] + standard_name = fresh_liquid_water_density_at_0c + units = kg m-3 + type = real | kind = kind_phys + dimensions = () + intent = in +[ gravit ] + standard_name = standard_gravitational_acceleration + units = m s-2 + type = real | kind = kind_phys + dimensions = () + intent = in +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out + +[ccpp-arg-table] + name = cloud_particle_sedimentation_run + type = scheme +[ 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 +[ pverp ] + standard_name = vertical_interface_dimension + units = count + type = integer + dimensions = () + intent = in +[ dtime ] + standard_name = timestep_for_physics + units = s + type = real | kind = kind_phys + dimensions = () + intent = in +[ tmelt ] + standard_name = freezing_point_of_water + units = K + type = real | kind = kind_phys + dimensions = () + intent = in +[ gravit ] + standard_name = standard_gravitational_acceleration + units = m s-2 + type = real | kind = kind_phys + dimensions = () + intent = in +[ latvap ] + standard_name = latent_heat_of_vaporization_of_water_at_0c + units = J kg-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ latice ] + standard_name = latent_heat_of_fusion_of_water_at_0c + units = J kg-1 + 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 +[ rhoh2o ] + standard_name = fresh_liquid_water_density_at_0c + units = kg m-3 + type = real | kind = kind_phys + dimensions = () + intent = in +[ icritc ] + standard_name = tunable_parameter_for_autoconversion_of_cold_ice_for_rk_microphysics + units = kg kg-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ pint ] + standard_name = air_pressure_at_interface + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_interface_dimension) + intent = in +[ pmid ] + standard_name = air_pressure + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ pdel ] + standard_name = air_pressure_thickness + units = Pa + 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 +[ cloud ] + standard_name = cloud_area_fraction + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ icefrac ] + standard_name = sea_ice_area_fraction + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ landfrac ] + standard_name = land_area_fraction + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ ocnfrac ] + standard_name = ocean_area_fraction + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ cldliq ] + standard_name = cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 + advected = True + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ cldice ] + standard_name = cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 + advected = True + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ snowh ] + standard_name = lwe_surface_snow_depth_over_land + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ landm ] + standard_name = smoothed_land_area_fraction + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ pvliq ] + standard_name = enter_standard_name_31 + units = Pa s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_interface_dimension) + intent = out +[ pvice ] + standard_name = enter_standard_name_32 + units = Pa s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_interface_dimension) + intent = out +[ liqtend ] + standard_name = tendency_of_cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out + constituent = True +[ icetend ] + standard_name = tendency_of_cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out + constituent = True +[ wvtend ] + standard_name = tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out + constituent = True +[ htend ] + standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure + units = J kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ sfliq ] + standard_name = enter_standard_name_37 + units = kg m-2 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ sfice ] + standard_name = enter_standard_name_38 + units = kg m-2 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 +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 index ab49294a..f18298f8 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 @@ -225,7 +225,7 @@ subroutine prognostic_cloud_water_run( & iulog, & pi, gravit, rh2o, epsilo, latvap, latice, cpair, & dlat, rlat, & - p, pdel, & + pmid, pdel, & zi, & troplev, & ttend, tn, & @@ -264,26 +264,26 @@ subroutine prognostic_cloud_water_run( & real(kind_phys), intent(in) :: cpair ! specific_heat_of_dry_air_at_constant_pressure [J K-1 kg-1] real(kind_phys), intent(in) :: dlat(:) ! latitude_degrees_north [degrees] real(kind_phys), intent(in) :: rlat(:) ! latitude [rad] - real(kind_phys), intent(in) :: p(:,:) ! Pressure [Pa] - real(kind_phys), intent(in) :: pdel(:,:) ! Layer thickness [Pa] - real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height at interfaces [m] - integer, intent(in) :: tropLev(:) ! Tropopause level [index] + real(kind_phys), intent(in) :: pmid(:,:) ! air_pressure [Pa] + real(kind_phys), intent(in) :: pdel(:,:) ! air_pressure_thickness [Pa] + real(kind_phys), intent(in) :: zi(:,:) ! geopotential_height_wrt_surface_at_interface [m] + integer, intent(in) :: tropLev(:) ! tropopause_vertical_layer_index [index] real(kind_phys), intent(in) :: ttend(:,:) ! Temperature tendency [K s-1] -- from what...? real(kind_phys), intent(in) :: tn(:,:) ! New Temperature [K] real(kind_phys), intent(in) :: qtend(:,:) ! Water vapor tendency [kg kg-1 s-1] -- from what...? real(kind_phys), intent(in) :: qn(:,:) ! New Water vapor mixing ratio [kg kg-1] real(kind_phys), intent(in) :: lctend(:,:) ! Cloud liquid water tendency [kg kg-1 s-1] -- from what...? - real(kind_phys), intent(in) :: cwat(:,:) ! Cloud water mixing ratio [kg kg-1] + real(kind_phys), intent(in) :: cwat(:,:) ! Cloud water mixing ratio (ixcldice+ixcldliq) [kg kg-1] real(kind_phys), intent(in) :: omega(:,:) ! lagrangian_tendency_of_air_pressure [Pa s-1] - real(kind_phys), intent(in) :: cldn(:,:) ! New Cloud fraction [1 (fraction)] - real(kind_phys), intent(in) :: fice(:,:) ! Ice fraction within cwat [1 (fraction)] - real(kind_phys), intent(in) :: fsnow(:,:) ! Fraction of rain that freezes to show [1 (fraction)] + real(kind_phys), intent(in) :: cldn(:,:) ! New Cloud fraction [fraction] + real(kind_phys), intent(in) :: fice(:,:) ! Ice fraction within cwat [fraction] + real(kind_phys), intent(in) :: fsnow(:,:) ! Fraction of rain that freezes to show [fraction] real(kind_phys), intent(in) :: rhdfda(:,:) ! dG(a)/da, rh=G(a), when rh>u00 [??] - real(kind_phys), intent(in) :: rhu00(:,:) ! Rhlim for cloud [??] - real(kind_phys), intent(in) :: landm(:) ! smoothed_land_area_fraction [1 (fraction)] + real(kind_phys), intent(in) :: rhu00(:,:) ! Rhlim for cloud [percent] + real(kind_phys), intent(in) :: landm(:) ! smoothed_land_area_fraction [fraction] real(kind_phys), intent(in) :: seaicef(:) ! Sea ice fraction [1 (fraction)] real(kind_phys), intent(in) :: snowh(:) ! Snow depth over land, water equivalent [m] @@ -291,13 +291,15 @@ subroutine prognostic_cloud_water_run( & real(kind_phys), intent(out) :: cme(:,:) ! Rate of condensation-evaporation of condensate (net_condensation_rate_due_to_microphysics) [s-1] real(kind_phys), intent(out) :: prodprec(:,:) ! Conversion rate of condensate to precip (precipitation_production_due_to_microphysics) [s-1] real(kind_phys), intent(out) :: prodsnow(:,:) ! Snow production rate (ignored in RK?) [s-1] - real(kind_phys), intent(out) :: evapprec(:,:) ! Falling precipitation evaporation rate (precipitation_evaporation_due_to_microphysics) [s-1] -- & apply q(wv) tendency + real(kind_phys), intent(out) :: evapprec(:,:) ! Falling precipitation evaporation rate (precipitation_evaporation_due_to_microphysics) [s-1] -- & combined to apply q(wv) tendency real(kind_phys), intent(out) :: evapsnow(:,:) ! Falling snow evaporation rate [s-1] - real(kind_phys), intent(out) :: evapheat(:,:) ! heating rate due to evaporation of precipitation [W kg-1] - real(kind_phys), intent(out) :: prfzheat(:,:) ! heating rate due to freezing of precipitation [W kg-1] - real(kind_phys), intent(out) :: meltheat(:,:) ! heating rate due to snow melt [W kg-1] - real(kind_phys), intent(out) :: precip(:) ! Precipitation rate (lwe_stratiform_precipitation_rate_at_surface) [kg m-2 s-1] - real(kind_phys), intent(out) :: snowab(:) ! Snow rate (lwe_snow_precipitation_rate_at_surface_due_to_microphysics) [kg m-2 s-1] + real(kind_phys), intent(out) :: evapheat(:,:) ! heating rate due to evaporation of precipitation [J kg-1 s-1] + real(kind_phys), intent(out) :: prfzheat(:,:) ! heating rate due to freezing of precipitation [J kg-1 s-1] + real(kind_phys), intent(out) :: meltheat(:,:) ! heating rate due to snow melt [J kg-1 s-1] + ! note -- these are precip units for atmosphere-surface exchange. + real(kind_phys), intent(out) :: precip(:) ! Precipitation rate (lwe_stratiform_precipitation_rate_at_surface) [m s-1] + real(kind_phys), intent(out) :: snowab(:) ! Snow rate (lwe_snow_precipitation_rate_at_surface_due_to_microphysics) [m s-1] + ! / note real(kind_phys), intent(out) :: ice2pr(:,:) ! Conversion rate of ice to precip [kg kg-1 s-1] -- apply q(cldice) tendency real(kind_phys), intent(out) :: liq2pr(:,:) ! Conversion rate of liquid to precip [kg kg-1 s-1] -- apply q(cldliq) tendency real(kind_phys), intent(out) :: liq2snow(:,:) ! Conversion rate of liquid to snow [kg kg-1 s-1] -- discard?? @@ -455,10 +457,10 @@ subroutine prognostic_cloud_water_run( & ! for the provisional t and q without condensation mp_level_loop: do k = top_lev, pver ! "True" means that ice will be taken into account. - call findsp_vc(qn(:ncol,k), tn(:ncol,k), p(:ncol,k), .true., & + call findsp_vc(qn(:ncol,k), tn(:ncol,k), pmid(:ncol,k), .true., & tsp(:ncol,k), qsp(:ncol,k)) - call qsat(t(1:ncol,k), p(1:ncol,k), es(1:ncol), qs(1:ncol), ncol, gam=gamma(1:ncol)) + call qsat(t(1:ncol,k), pmid(1:ncol,k), es(1:ncol), qs(1:ncol), ncol, gam=gamma(1:ncol)) do i = 1, ncol relhum(i) = q(i,k)/qs(i) @@ -607,7 +609,7 @@ subroutine prognostic_cloud_water_run( & precab = prprov(:ncol), & snowab = snowab(:ncol), & t = t(:ncol,:), & - p = p(:ncol,:), & + p = pmid(:ncol,:), & cwm = cwm(:ncol), & cldm = cldm(:ncol), & cldmax = cldmax(:ncol), & @@ -746,7 +748,7 @@ subroutine prognostic_cloud_water_run( & qtmp = qn(i,k) - cme(i,k)*deltat ttmp = tn(i,k) + deltat/cpair * ( meltheat(i,k) + (latvap + latice*fice(i,k)) * cme(i,k) ) esn = estblf(ttmp) - qsn = svp_to_qsat(esn, p(i,k)) + qsn = svp_to_qsat(esn, pmid(i,k)) qtl(i) = max((qsn - qtmp)/deltat,0._kind_phys) relhum1(i) = qtmp/qsn end do @@ -798,7 +800,7 @@ subroutine prognostic_cloud_water_run( & ttmp = tn(i,k) + deltat/cpair * ( meltheat(i,k) + evapheat(i,k) + prfzheat(i,k) & + (latvap + latice*fice(i,k)) * cme(i,k) ) - call qsat(ttmp, p(i,k), esn, qsn, dqsdt=dqsdt) + call qsat(ttmp, pmid(i,k), esn, qsn, dqsdt=dqsdt) if(qtmp > qsn) then ! now extra condensation to bring air to just saturation @@ -814,7 +816,7 @@ subroutine prognostic_cloud_water_run( & end do cme_iter_loop ! loop over l (iteration) ! precipitation - do i = 1,ncol + do i = 1, ncol precip(i) = precip(i) + pdel(i,k)/gravit * (prodprec(i,k) - evapprec(i,k)) precab(i) = precab(i) + pdel(i,k)/gravit * (prodprec(i,k) - evapprec(i,k)) if(precab(i) < 0._kind_phys) then @@ -830,6 +832,15 @@ subroutine prognostic_cloud_water_run( & lsflxsnw(i,k+1) = snowab(i) end do end do mp_level_loop ! loop over k (level) + + ! Convert precip (lwe_stratiform_precipitation_rate_at_surface) + ! and snowab (lwe_snow_precipitation_rate_at_surface_due_to_microphysics) + ! from kg m-2 s-1 to m s-1 (precipitation units) for surface exchange. + ! + ! If this conversion is removed in the future, the metadata needs to + ! be updated. + precip(:ncol) = precip(:ncol)/1000._r8 + snowab(:ncol) = snowab(:ncol)/1000._r8 end subroutine prognostic_cloud_water_run ! Calculate the conversion of condensate to precipitate @@ -857,7 +868,7 @@ subroutine findmcnew( & real(kind_phys), intent(in) :: precab(:) ! rate of precipitation from above [kg m-2 s-1] real(kind_phys), intent(in) :: t(:,:) ! temperature [K] - real(kind_phys), intent(in) :: p(:,:) ! pressure [Pa] + real(kind_phys), intent(in) :: p(:,:) ! air_pressure [Pa] real(kind_phys), intent(in) :: cwm(:) ! condensate mixing ratio [kg kg-1] real(kind_phys), intent(in) :: cldm(:) ! cloud fraction real(kind_phys), intent(in) :: cldmax(:) ! max cloud fraction above this level diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.meta b/schemes/rasch_kristjansson/prognostic_cloud_water.meta new file mode 100644 index 00000000..5355230e --- /dev/null +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.meta @@ -0,0 +1,407 @@ +[ccpp-table-properties] + name = prognostic_cloud_water + type = scheme + +[ccpp-arg-table] + name = prognostic_cloud_water_init + type = scheme +[ amIRoot ] + standard_name = flag_for_mpi_root + units = flag + type = logical + dimensions = () + intent = in +[ iulog ] + standard_name = log_output_unit + units = 1 + type = integer + dimensions = () + intent = in +[ tmelt ] + standard_name = freezing_point_of_water + units = K + type = real | kind = kind_phys + dimensions = () + intent = in +[ rhodair ] + standard_name = density_of_dry_air_at_stp + units = kg m-3 + type = real | kind = kind_phys + dimensions = () + intent = in +[ pi ] + standard_name = pi_constant + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ icritc_in ] + standard_name = tunable_parameter_for_autoconversion_of_cold_ice_for_rk_microphysics + units = kg kg-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ icritw_in ] + standard_name = tunable_parameter_for_autoconversion_of_warm_ice_for_rk_microphysics + units = kg kg-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ conke_in ] + standard_name = tunable_parameter_for_precipitation_evaporation_for_rk_microphysics + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ r3lcrit_in ] + standard_name = tunable_parameter_for_cloud_water_autoconversion_for_rk_microphysics + units = m + type = real | kind = kind_phys + dimensions = () + intent = in +[ do_psrhmin_in ] + standard_name = flag_for_relative_humidity_threshold_for_cloud_formation_in_polar_stratosphere_for_rk_microphysics + units = flag + type = logical + dimensions = () + intent = in +[ psrhmin_in ] + standard_name = relative_humidity_threshold_for_cloud_formation_in_polar_stratosphere_for_rk_microphysics + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out + +[ccpp-arg-table] + name = prognostic_cloud_water_run + type = scheme +[ 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 +[ top_lev ] + standard_name = index_of_pressure_at_troposhere_cloud_top + units = index + type = integer + dimensions = () + intent = in +[ deltat ] + standard_name = timestep_for_physics + units = s + type = real | kind = kind_phys + dimensions = () + intent = in +[ iulog ] + standard_name = log_output_unit + units = 1 + type = integer + dimensions = () + intent = in +[ pi ] + standard_name = pi_constant + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ gravit ] + standard_name = standard_gravitational_acceleration + units = m s-2 + type = real | kind = kind_phys + dimensions = () + intent = in +[ rh2o ] + standard_name = gas_constant_of_water_vapor + units = J kg-1 K-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ epsilo ] + standard_name = ratio_of_water_vapor_to_dry_air_molecular_weights + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ latvap ] + standard_name = latent_heat_of_vaporization_of_water_at_0c + units = J kg-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ latice ] + standard_name = latent_heat_of_fusion_of_water_at_0c + units = J kg-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ cpair ] + standard_name = specific_heat_of_dry_air_at_constant_pressure + units = J kg-1 K-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ dlat ] + standard_name = latitude_degrees_north + units = degrees + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ rlat ] + standard_name = latitude + units = rad + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ pmid ] + standard_name = air_pressure + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ pdel ] + standard_name = air_pressure_thickness + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ zi ] + standard_name = geopotential_height_wrt_surface_at_interface + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_interface_dimension) + intent = in +[ tropLev ] + standard_name = tropopause_vertical_layer_index + units = index + type = integer + dimensions = (horizontal_loop_extent) + intent = in +[ ttend ] + standard_name = enter_standard_name_32 + units = enter_units + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ tn ] + standard_name = enter_standard_name_33 + units = enter_units + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ qtend ] + standard_name = enter_standard_name_34 + units = enter_units + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ qn ] + standard_name = enter_standard_name_35 + units = enter_units + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ lctend ] + standard_name = enter_standard_name_36 + units = enter_units + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ cwat ] + standard_name = enter_standard_name_37 + units = enter_units + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ omega ] + standard_name = lagrangian_tendency_of_air_pressure + units = Pa s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ cldn ] + standard_name = enter_standard_name_39 + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ fice ] + standard_name = enter_standard_name_40 + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ fsnow ] + standard_name = enter_standard_name_41 + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ rhdfda ] + standard_name = enter_standard_name_42 + units = enter_units + type = real | kind = kind_phys + dimensions = (enter_standard_name_125:enter_standard_name_126,enter_standard_name_127:enter_standard_name_128) + intent = in +[ rhu00 ] + standard_name = enter_standard_name_43 + units = percent + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ landm ] + standard_name = smoothed_land_area_fraction + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ seaicef ] + standard_name = sea_ice_area_fraction + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ snowh ] + standard_name = lwe_surface_snow_depth_over_land + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ cme ] + standard_name = net_condensation_rate_due_to_microphysics + units = s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ prodprec ] + standard_name = precipitation_production_due_to_microphysics + units = s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ prodsnow ] + standard_name = snow_production_due_to_microphysics + units = s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ evapprec ] + standard_name = precipitation_evaporation_due_to_microphysics + units = s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ evapsnow ] + standard_name = enter_standard_name_51 + units = s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ evapheat ] + standard_name = enter_standard_name_52 + units = J kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ prfzheat ] + standard_name = enter_standard_name_53 + units = J kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ meltheat ] + standard_name = enter_standard_name_54 + units = J kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ precip ] + standard_name = lwe_stratiform_precipitation_rate_at_surface + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ snowab ] + standard_name = lwe_snow_precipitation_rate_at_surface_due_to_microphysics + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ ice2pr ] + standard_name = enter_standard_name_57 + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ liq2pr ] + standard_name = enter_standard_name_58 + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ liq2snow ] + standard_name = enter_standard_name_59 + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ lsflxprc ] + standard_name = stratiform_rain_and_snow_flux_at_interface + units = kg m-2 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_interface_dimension) + intent = out +[ lsflxsnw ] + standard_name = stratiform_snow_flux_at_interface + units = kg m-2 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_interface_dimension) + intent = out +[ pracwo ] + standard_name = enter_standard_name_62 + units = s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ psacwo ] + standard_name = enter_standard_name_63 + units = s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ psacio ] + standard_name = enter_standard_name_64 + units = s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out From 9db88293328a75dd106ada6334dc50cf27300b36 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Wed, 22 Jan 2025 18:05:26 -0500 Subject: [PATCH 04/39] Sketch out suite --- test/test_suites/suite_rasch_kristjansson.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 test/test_suites/suite_rasch_kristjansson.xml diff --git a/test/test_suites/suite_rasch_kristjansson.xml b/test/test_suites/suite_rasch_kristjansson.xml new file mode 100644 index 00000000..9a7232e3 --- /dev/null +++ b/test/test_suites/suite_rasch_kristjansson.xml @@ -0,0 +1,16 @@ + + + + + + tropopause_find + + + cloud_particle_sedimentation + + apply_constituent_tendencies + apply_heating_rate + qneg + geopotential_temp + + From 4d261ac69c4e9808ebfd9cbe244f7219a7b6bd3f Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Wed, 22 Jan 2025 20:18:18 -0500 Subject: [PATCH 05/39] Further sketch out suite; update cloud_particle_sedimentation --- .../cloud_particle_sedimentation.F90 | 7 ++- .../cloud_particle_sedimentation.meta | 6 +- schemes/rasch_kristjansson/rk_stratiform.F90 | 56 +++++++++++++++++-- test/test_suites/suite_rasch_kristjansson.xml | 40 +++++++++++++ 4 files changed, 99 insertions(+), 10 deletions(-) diff --git a/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 b/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 index 0fa8d625..fe0df2d7 100644 --- a/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 +++ b/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 @@ -147,7 +147,7 @@ subroutine cloud_particle_sedimentation_run( & real(kind_phys), intent(out) :: wvtend(:,:) ! water vapor tendency -- to apply wv tendency real(kind_phys), intent(out) :: htend(:,:) ! heating rate [J kg-1 s-1] -- to apply s tendency real(kind_phys), intent(out) :: sfliq(:) ! surface flux of liquid (rain) [kg m-2 s-1] - real(kind_phys), intent(out) :: sfice(:) ! surface flux of ice (snow) [kg m-2 s-1] + real(kind_phys), intent(out) :: sfice(:) ! lwe_cloud_ice_sedimentation_rate_at_surface_due_to_microphysics [m s-1] character(len=512), intent(out) :: errmsg ! error message integer, intent(out) :: errflg ! error flag @@ -358,10 +358,13 @@ subroutine cloud_particle_sedimentation_run( & end do end do -! convert flux out the bottom to mass units Pa -> kg/m2/s + ! convert flux out the bottom to mass units Pa -> kg/m2/s sfliq(:ncol) = fxliq(:ncol, pverp)/(dtime*gravit) sfice(:ncol) = fxice(:ncol, pverp)/(dtime*gravit) + ! Convert lwe_cloud_ice_sedimentation_rate_at_surface_due_to_microphysics from kg m-2 s-1 to precip units m s-1 + sfice(:ncol) = sfice(:ncol)/1000._kind_phys + end subroutine cloud_particle_sedimentation_run ! Compute fluxes at interior points diff --git a/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta b/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta index bbbbb0bd..2a4b06f2 100644 --- a/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta +++ b/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta @@ -231,14 +231,14 @@ dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out [ sfliq ] - standard_name = enter_standard_name_37 + standard_name = stratiform_rain_surface_flux_due_to_sedimentation units = kg m-2 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out [ sfice ] - standard_name = enter_standard_name_38 - units = kg m-2 s-1 + standard_name = lwe_cloud_ice_sedimentation_rate_at_surface_due_to_microphysics + units = m s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out diff --git a/schemes/rasch_kristjansson/rk_stratiform.F90 b/schemes/rasch_kristjansson/rk_stratiform.F90 index 8c1ffa2c..9b3b175a 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.F90 +++ b/schemes/rasch_kristjansson/rk_stratiform.F90 @@ -12,12 +12,13 @@ module rk_stratiform ! public CCPP-compliant subroutines public :: rk_stratiform_init + public :: rk_stratiform_timestep_init public :: rk_stratiform_sedimentation_run - public :: rk_stratiform_cloud_fractions_run - public :: rk_stratiform_microphysics_run - public :: rk_stratiform_prognostic_cloud_water_tendencies_run - public :: rk_stratiform_microphysics_tendencies_run - public :: rk_stratiform_cloud_optical_properties_run + ! public :: rk_stratiform_cloud_fractions_run + ! public :: rk_stratiform_microphysics_run + ! public :: rk_stratiform_prognostic_cloud_water_tendencies_run + ! public :: rk_stratiform_microphysics_tendencies_run + ! public :: rk_stratiform_cloud_optical_properties_run ! @@ -34,9 +35,54 @@ module rk_stratiform subroutine rk_stratiform_init(& errmsg, errflg) ! If qcwat, tcwat, lcwat are not initialized, eventually init them + character(len=512), intent(out) :: errmsg ! error message + integer, intent(out) :: errflg ! error flag + + errmsg = '' + errflg = 0 end subroutine rk_stratiform_init + subroutine rk_stratiform_timestep_init(& + errmsg, errflg) + character(len=512), intent(out) :: errmsg ! error message + integer, intent(out) :: errflg ! error flag + + errmsg = '' + errflg = 0 + + + end subroutine rk_stratiform_timestep_init + + + subroutine rk_stratiform_sedimentation_run(& + sfliq, snow_sed, & + prec_sed, & + prec_str, snow_str, & + errmsg, errflg) + + real(kind_phys), intent(in) :: sfliq(:) ! stratiform_rain_surface_flux_due_to_sedimentation [kg m-2 s-1] + real(kind_phys), intent(in) :: snow_sed(:) ! lwe_cloud_ice_sedimentation_rate_at_surface_due_to_microphysics [m s-1] + real(kind_phys), intent(out) :: prec_sed(:) ! stratiform_cloud_water_surface_flux_due_to_sedimentation [m s-1] + real(kind_phys), intent(out) :: prec_str(:) ! stratiform_rain_and_snow_surface_flux [m s-1] + real(kind_phys), intent(out) :: snow_str(:) ! lwe_snow_and_cloud_ice_precipitation_rate_at_surface_due_to_microphysics [m s-1] + character(len=512), intent(out) :: errmsg ! error message + integer, intent(out) :: errflg ! error flag + + errmsg = '' + errflg = 0 + + ! Convert rain flux to precip units from mass units + ! and create cloud water surface flux (rain + snow) + prec_sed(:ncol) = sfliq(:ncol)/1000._kind_phys + snow_sed(:ncol) + + ! Start accumulation of precipitation and snow flux [m s-1] + prec_str(:ncol) = 0._kind_phys + prec_sed(:ncol) + snow_str(:ncol) = 0._kind_phys + snow_sed(:ncol) + + + end subroutine rk_stratiform_sedimentation_run + diff --git a/test/test_suites/suite_rasch_kristjansson.xml b/test/test_suites/suite_rasch_kristjansson.xml index 9a7232e3..9bd73c4f 100644 --- a/test/test_suites/suite_rasch_kristjansson.xml +++ b/test/test_suites/suite_rasch_kristjansson.xml @@ -12,5 +12,45 @@ apply_heating_rate qneg geopotential_temp + rk_stratiform_sedimentation + + + rk_stratiform_detrain_convective_condensate + + + + + + + + + prognostic_cloud_water + + + + + + + + + + + + From 13db10c00de02e000b4388188badade71268d3e6 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Fri, 24 Jan 2025 11:35:31 -0500 Subject: [PATCH 06/39] Updates to suite and further rk_stratiform_ ccppization --- .../prognostic_cloud_water.F90 | 4 +- .../prognostic_cloud_water.meta | 2 +- schemes/rasch_kristjansson/rk_stratiform.F90 | 112 +++++++++++++++++- test/test_suites/suite_rasch_kristjansson.xml | 4 +- 4 files changed, 115 insertions(+), 7 deletions(-) diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 index f18298f8..4e6a2d07 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 @@ -839,8 +839,8 @@ subroutine prognostic_cloud_water_run( & ! ! If this conversion is removed in the future, the metadata needs to ! be updated. - precip(:ncol) = precip(:ncol)/1000._r8 - snowab(:ncol) = snowab(:ncol)/1000._r8 + precip(:ncol) = precip(:ncol)/1000._kind_phys + snowab(:ncol) = snowab(:ncol)/1000._kind_phys end subroutine prognostic_cloud_water_run ! Calculate the conversion of condensate to precipitate diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.meta b/schemes/rasch_kristjansson/prognostic_cloud_water.meta index 5355230e..fc07203c 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.meta +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.meta @@ -227,7 +227,7 @@ intent = in [ cwat ] standard_name = enter_standard_name_37 - units = enter_units + units = kg kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in diff --git a/schemes/rasch_kristjansson/rk_stratiform.F90 b/schemes/rasch_kristjansson/rk_stratiform.F90 index 9b3b175a..a7b3d283 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.F90 +++ b/schemes/rasch_kristjansson/rk_stratiform.F90 @@ -14,6 +14,7 @@ module rk_stratiform public :: rk_stratiform_init public :: rk_stratiform_timestep_init public :: rk_stratiform_sedimentation_run + public :: rk_stratiform_detrain_convective_condensate_run ! public :: rk_stratiform_cloud_fractions_run ! public :: rk_stratiform_microphysics_run ! public :: rk_stratiform_prognostic_cloud_water_tendencies_run @@ -55,14 +56,19 @@ subroutine rk_stratiform_timestep_init(& end subroutine rk_stratiform_timestep_init - subroutine rk_stratiform_sedimentation_run(& + subroutine rk_stratiform_sedimentation_run( & + ncol, & sfliq, snow_sed, & prec_sed, & prec_str, snow_str, & errmsg, errflg) + ! Input arguments + integer, intent(in) :: ncol real(kind_phys), intent(in) :: sfliq(:) ! stratiform_rain_surface_flux_due_to_sedimentation [kg m-2 s-1] - real(kind_phys), intent(in) :: snow_sed(:) ! lwe_cloud_ice_sedimentation_rate_at_surface_due_to_microphysics [m s-1] + real(kind_phys), intent(in) :: snow_sed(:) ! sfice = lwe_cloud_ice_sedimentation_rate_at_surface_due_to_microphysics [m s-1] + + ! Output arguments real(kind_phys), intent(out) :: prec_sed(:) ! stratiform_cloud_water_surface_flux_due_to_sedimentation [m s-1] real(kind_phys), intent(out) :: prec_str(:) ! stratiform_rain_and_snow_surface_flux [m s-1] real(kind_phys), intent(out) :: snow_str(:) ! lwe_snow_and_cloud_ice_precipitation_rate_at_surface_due_to_microphysics [m s-1] @@ -83,6 +89,108 @@ subroutine rk_stratiform_sedimentation_run(& end subroutine rk_stratiform_sedimentation_run + subroutine rk_stratiform_detrain_convective_condensate_run( & + ncol, & + dlf, & + rliq, & + prec_str, & + tend_cldliq, & + errmsg, errflg) + + ! Input arguments + integer, intent(in) :: ncol + real(kind_phys), intent(in) :: dlf(:,:) ! detrainment_of_water_due_to_all_convection [kg kg-1 s-1] + real(kind_phys), intent(in) :: rliq(:,:) ! vertically_integrated_liquid_water_tendency_due_to_all_convection_to_be_applied_later_in_time_loop [kg kg-1 s-1] + + ! Input/output arguments + real(kind_phys), intent(inout) :: prec_str(:) ! stratiform_rain_and_snow_surface_flux [m s-1] + + ! Output arguments + real(kind_phys), intent(out) :: tend_cldliq(:,:) ! tendency_of_cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1 s-1] + character(len=512), intent(out) :: errmsg ! error message + integer, intent(out) :: errflg ! error flag + + errmsg = '' + errflg = 0 + + ! Apply detrainment tendency to cloud liquid water + tend_cldliq(:ncol,:) = dlf(:ncol,:) + + ! Accumulate precipitation and snow after + ! reserved liquid (vertical integral) has now been used + ! (snow contribution is zero) + prec_str(:ncol) = prec_str(:ncol) - rliq(:ncol) + + end subroutine rk_stratiform_detrain_convective_condensate_run + + ! Determine tendencies from prognostic cloud water + subroutine rk_stratiform_prognostic_cloud_water_tendencies_run( & + ncol, pver, & + dtime, & + latvap, latice, & + cme, fice, & + evapheat, prfzheat, meltheat, & + repartht, & + evapprec, & + ice2pr, liq2pr, & + tend_s, & + tend_q, & + tend_cldice, & + tend_cldliq, & + errmsg, errflg) + + ! Input arguments + integer, intent(in) :: ncol + integer, intent(in) :: pver + real(kind_phys), intent(in) :: latvap + real(kind_phys), intent(in) :: latice + real(kind_phys), intent(in) :: cme(:,:) ! net_condensation_rate_due_to_microphysics [s-1] + real(kind_phys), intent(in) :: fice(:,:) ! from cldfrc_fice -- to fill + real(kind_phys), intent(in) :: evapheat(:,:) ! + real(kind_phys), intent(in) :: prfzheat(:,:) ! + real(kind_phys), intent(in) :: meltheat(:,:) ! + real(kind_phys), intent(in) :: repartht(:,:) ! (from microphysical tend) + real(kind_phys), intent(in) :: evapprec(:,:) ! + real(kind_phys), intent(in) :: ice2pr(:,:) ! + real(kind_phys), intent(in) :: liq2pr(:,:) ! + + ! Output arguments + real(kind_phys), intent(out) :: cmeheat(:,:) ! ... [J kg-1 s-1] + real(kind_phys), intent(out) :: cmeice(:,:) ! ... [kg kg-1 s-1] + real(kind_phys), intent(out) :: cmeliq(:,:) ! ... [kg kg-1 s-1] + real(kind_phys), intent(out) :: tend_s(:,:) ! tendency_of_dry_air_enthalpy_at_constant_pressure [J kg-1 s-1] + real(kind_phys), intent(out) :: tend_q(:,:) ! tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1 s-1] + real(kind_phys), intent(out) :: tend_cldice(:,:) ! tendency_of_cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1 s-1] + real(kind_phys), intent(out) :: tend_cldliq(:,:) ! tendency_of_cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1 s-1] + character(len=512), intent(out) :: errmsg ! error message + integer, intent(out) :: errflg ! error flag + + errmsg = '' + errflg = 0 + + do k = 1, pver + do i = 1, ncol + ! Heating from cond-evap within the cloud [J kg-1 s-1] + cmeheat(i,k) = cme(i,k)*(latvap + latice*fice(i,k)) + + ! Rate of cond-evap of ice within the cloud [kg kg-1 s-1] + cmeice(i,k) = cme(i,k)*fice(i,k) + + ! Rate of cond-evap of liq within the cloud [kg kg-1 s-1] + cmeliq(i,k) = cme(i,k)*(1._kind_phys-fice(i,k)) + + tend_s(i,k) = cmeheat(i,k) + & + evapheat(i,k) + prfzheat(i,k) + meltheat(i,k) + repartht(i,k) + tend_q(i,k) = - cme(i,k) + evapprec(i,k) + tend_cldice(i,k) = cmeice(i,k) - ice2pr(i,k) + tend_cldliq(i,k) = cmeliq(i,k) - liq2pr(i,k) + end do + end do + + + + end subroutine rk_stratiform_prognostic_cloud_water_tendencies_run + diff --git a/test/test_suites/suite_rasch_kristjansson.xml b/test/test_suites/suite_rasch_kristjansson.xml index 9bd73c4f..b5da3147 100644 --- a/test/test_suites/suite_rasch_kristjansson.xml +++ b/test/test_suites/suite_rasch_kristjansson.xml @@ -30,14 +30,14 @@ prognostic_cloud_water - apply_constituent_tendencies apply_heating_rate qneg geopotential_temp - --> From a2cd40772b8f0ca4adefa3aa2371ea7e3fa04306 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Fri, 24 Jan 2025 14:03:20 -0500 Subject: [PATCH 07/39] Sketch out some more standard names; finish cloud_particle_sedimentation --- .../cloud_particle_sedimentation.meta | 4 +- .../prognostic_cloud_water.F90 | 4 +- .../prognostic_cloud_water.meta | 56 +++++++++---------- schemes/rasch_kristjansson/rk_stratiform.F90 | 2 +- test/test_suites/suite_rasch_kristjansson.xml | 14 +++-- 5 files changed, 43 insertions(+), 37 deletions(-) diff --git a/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta b/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta index 2a4b06f2..bb60ba0a 100644 --- a/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta +++ b/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta @@ -192,13 +192,13 @@ dimensions = (horizontal_loop_extent) intent = in [ pvliq ] - standard_name = enter_standard_name_31 + standard_name = vertical_velocity_of_cloud_liquid_water_due_to_sedimentation_tbd units = Pa s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_interface_dimension) intent = out [ pvice ] - standard_name = enter_standard_name_32 + standard_name = vertical_velocity_of_cloud_ice_due_to_sedimentation_tbd units = Pa s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_interface_dimension) diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 index 4e6a2d07..2881b733 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 @@ -322,8 +322,8 @@ subroutine prognostic_cloud_water_run( & real(kind_phys) :: nice2pr ! Rate of conversion from ice to snow [kg kg-1 s-1] real(kind_phys) :: nliq2pr ! Rate of conversion from liquid to precipitation [kg kg-1 s-1] real(kind_phys) :: nliq2snow ! Rate of conversion from liquid to snow [kg kg-1 s-1] - real(kind_phys) :: precab(ncol) ! Rate of precipitation entering layer [kg m-2 s-1] - real(kind_phys) :: prprov(ncol) ! Provisional precipitation at bottom of layer [kg m-2 s-1] + real(kind_phys) :: precab(ncol) ! Rate of precipitation entering layer [kg m-2 s-1] + real(kind_phys) :: prprov(ncol) ! Provisional precipitation at bottom of layer [kg m-2 s-1] ! Cloud properties real(kind_phys) :: cldm(ncol) ! Mean cloud fraction over timestep [1] diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.meta b/schemes/rasch_kristjansson/prognostic_cloud_water.meta index fc07203c..62b6e391 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.meta +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.meta @@ -196,37 +196,37 @@ dimensions = (horizontal_loop_extent) intent = in [ ttend ] - standard_name = enter_standard_name_32 - units = enter_units + standard_name = tendency_of_air_temperature_not_due_to_microphysics_tbd + units = K s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in [ tn ] - standard_name = enter_standard_name_33 - units = enter_units + standard_name = air_temperature + units = K type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in [ qtend ] - standard_name = enter_standard_name_34 - units = enter_units + standard_name = tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water_not_due_to_microphysics? + units = kg kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in [ qn ] - standard_name = enter_standard_name_35 - units = enter_units + standard_name = water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in [ lctend ] - standard_name = enter_standard_name_36 - units = enter_units + standard_name = tendency_of_cloud_water_mixing_ratio_wrt_moist_air_and_condensed_water_not_due_to_microphysics? + units = kg kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in [ cwat ] - standard_name = enter_standard_name_37 + standard_name = cloud_water_mixing_ratio_wrt_moist_air_and_condensed_water_tbd units = kg kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) @@ -238,31 +238,31 @@ dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in [ cldn ] - standard_name = enter_standard_name_39 + standard_name = cloud_area_fraction units = fraction type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in [ fice ] - standard_name = enter_standard_name_40 + standard_name = mass_fraction_of_ice_content_within_stratiform_cloud units = fraction type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in [ fsnow ] - standard_name = enter_standard_name_41 + standard_name = mass_fraction_of_snow_content_within_stratiform_cloud units = fraction type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in [ rhdfda ] - standard_name = enter_standard_name_42 - units = enter_units + standard_name = derivative_of_relative_humidity_wrt_cloud_fraction_tbd + units = percent type = real | kind = kind_phys - dimensions = (enter_standard_name_125:enter_standard_name_126,enter_standard_name_127:enter_standard_name_128) + dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in [ rhu00 ] - standard_name = enter_standard_name_43 + standard_name = relative_humidity_threshold_for_prognostic_cloud_water_tbd units = percent type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) @@ -310,25 +310,25 @@ dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out [ evapsnow ] - standard_name = enter_standard_name_51 + standard_name = rate_of_evaporation_of_falling_snow_due_to_microphysics_tbd units = s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out [ evapheat ] - standard_name = enter_standard_name_52 + standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure_due_to_precipitation_evaporation_tbd units = J kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out [ prfzheat ] - standard_name = enter_standard_name_53 + standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure_due_to_precipitation_freezing_tbd units = J kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out [ meltheat ] - standard_name = enter_standard_name_54 + standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure_due_to_precipitation_phase_change_tbd units = J kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) @@ -346,19 +346,19 @@ dimensions = (horizontal_loop_extent) intent = out [ ice2pr ] - standard_name = enter_standard_name_57 + standard_name = tendency_of_cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water_due_to_microphysics_tbd units = kg kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out [ liq2pr ] - standard_name = enter_standard_name_58 + standard_name = tendency_of_cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water_due_to_microphysics_tbd units = kg kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out [ liq2snow ] - standard_name = enter_standard_name_59 + standard_name = tendency_of_cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water_due_to_conversion_to_snow_tbd units = kg kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) @@ -376,19 +376,19 @@ dimensions = (horizontal_loop_extent, vertical_interface_dimension) intent = out [ pracwo ] - standard_name = enter_standard_name_62 + standard_name = accretion_of_cloud_liquid_water_by_rain_tbd units = s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out [ psacwo ] - standard_name = enter_standard_name_63 + standard_name = accretion_of_cloud_liquid_water_by_snow_tbd units = s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out [ psacio ] - standard_name = enter_standard_name_64 + standard_name = accretion_of_cloud_ice_by_snow_tbd units = s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) diff --git a/schemes/rasch_kristjansson/rk_stratiform.F90 b/schemes/rasch_kristjansson/rk_stratiform.F90 index a7b3d283..66bc3cdd 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.F90 +++ b/schemes/rasch_kristjansson/rk_stratiform.F90 @@ -145,7 +145,7 @@ subroutine rk_stratiform_prognostic_cloud_water_tendencies_run( & real(kind_phys), intent(in) :: latvap real(kind_phys), intent(in) :: latice real(kind_phys), intent(in) :: cme(:,:) ! net_condensation_rate_due_to_microphysics [s-1] - real(kind_phys), intent(in) :: fice(:,:) ! from cldfrc_fice -- to fill + real(kind_phys), intent(in) :: fice(:,:) ! mass_fraction_of_ice_content_within_stratiform_cloud [fraction] real(kind_phys), intent(in) :: evapheat(:,:) ! real(kind_phys), intent(in) :: prfzheat(:,:) ! real(kind_phys), intent(in) :: meltheat(:,:) ! diff --git a/test/test_suites/suite_rasch_kristjansson.xml b/test/test_suites/suite_rasch_kristjansson.xml index b5da3147..92898876 100644 --- a/test/test_suites/suite_rasch_kristjansson.xml +++ b/test/test_suites/suite_rasch_kristjansson.xml @@ -17,12 +17,19 @@ rk_stratiform_detrain_convective_condensate - + + cldfrc_fice - - + From 564b79200e88214072df33301d37e5ce47e4a62a Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Tue, 4 Feb 2025 13:25:39 -0500 Subject: [PATCH 08/39] Cleanup cloud_optical_properties; prognostic_cloud_water; rk --- .../prognostic_cloud_water.F90 | 125 ++++++------- .../prognostic_cloud_water.meta | 2 +- schemes/rasch_kristjansson/rk_stratiform.F90 | 77 ++++++-- to_be_ccppized/cloud_optical_properties.F90 | 171 ++++++------------ 4 files changed, 187 insertions(+), 188 deletions(-) diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 index 2881b733..1a666ca1 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 @@ -214,7 +214,8 @@ end subroutine prognostic_cloud_water_init ! https://doi.org/10.1175/1520-0442(1998)011<1587:ACOTCM>2.0.CO;2 ! ! with modifications to improve the method of determining condensation/evaporation - ! Zhang et al. (2001?) -- citation unknown. + ! Zhang, M., W. Lin, C. Bretherton, J. Hack, and P. J. Rasch, 2003, A modified formulation of fractional stratiform condensation rate in the NCAR Community Atmospheric Model (CAM2), J. Geophys. Res., 108(D1), 4035 + ! https://doi.org/10.1029/2002JD002523 ! ! Original authors: M. Zhang, W. Lin, P. Rasch and J.E. Kristjansson ! B. A. Boville (latent heat of fusion) @@ -236,7 +237,7 @@ subroutine prognostic_cloud_water_run( & fice, fsnow, & rhdfda, rhu00, & landm, seaicef, snowh, & - cme, & + qme, & prodprec, prodsnow, & evapprec, evapsnow, & evapheat, prfzheat, meltheat, & @@ -288,7 +289,7 @@ subroutine prognostic_cloud_water_run( & real(kind_phys), intent(in) :: snowh(:) ! Snow depth over land, water equivalent [m] ! Output arguments - real(kind_phys), intent(out) :: cme(:,:) ! Rate of condensation-evaporation of condensate (net_condensation_rate_due_to_microphysics) [s-1] + real(kind_phys), intent(out) :: qme(:,:) ! Rate of condensation-evaporation of condensate (net_condensation_rate_due_to_microphysics) [s-1] real(kind_phys), intent(out) :: prodprec(:,:) ! Conversion rate of condensate to precip (precipitation_production_due_to_microphysics) [s-1] real(kind_phys), intent(out) :: prodsnow(:,:) ! Snow production rate (ignored in RK?) [s-1] real(kind_phys), intent(out) :: evapprec(:,:) ! Falling precipitation evaporation rate (precipitation_evaporation_due_to_microphysics) [s-1] -- & combined to apply q(wv) tendency @@ -361,11 +362,11 @@ subroutine prognostic_cloud_water_run( & real(kind_phys) :: cgamah(ncol) ! Gamma-hat at saturation portion [1] real(kind_phys) :: rcgama(ncol) ! Ratio of gamma to gamma-hat [1] real(kind_phys) :: csigma(ncol) ! Sigma term in C-E formulation [1] - real(kind_phys) :: cmeres(ncol) ! Residual condensation after C-E and evapprec [kg kg-1 s-1] - real(kind_phys) :: cmec1(ncol) ! Cloud condensation coefficient 1 C-E formulation [1] - real(kind_phys) :: cmec2(ncol) ! Cloud condensation coefficient 2 C-E formulation [1] - real(kind_phys) :: cmec3(ncol) ! Cloud condensation coefficient 3 C-E formulation [1] - real(kind_phys) :: cmec4(ncol) ! Cloud condensation coefficient 4 C-E formulation [1] + real(kind_phys) :: qmeres(ncol) ! Residual condensation after C-E and evapprec [kg kg-1 s-1] + real(kind_phys) :: qmec1(ncol) ! Cloud condensation coefficient 1 C-E formulation [1] + real(kind_phys) :: qmec2(ncol) ! Cloud condensation coefficient 2 C-E formulation [1] + real(kind_phys) :: qmec3(ncol) ! Cloud condensation coefficient 3 C-E formulation [1] + real(kind_phys) :: qmec4(ncol) ! Cloud condensation coefficient 4 C-E formulation [1] ! Diagnostic arrays for cloud water budget @@ -431,7 +432,7 @@ subroutine prognostic_cloud_water_run( & end do end do - cme (:ncol,:) = 0._kind_phys + qme (:ncol,:) = 0._kind_phys evapprec(:ncol,:) = 0._kind_phys prodprec(:ncol,:) = 0._kind_phys evapsnow(:ncol,:) = 0._kind_phys @@ -491,8 +492,8 @@ subroutine prognostic_cloud_water_run( & evapprec(i,k) = conke*(1._kind_phys - cldm(i))*sqrt(precab(i)) & *(1._kind_phys - min(relhum(i),1._kind_phys)) - ! zero cmeres before iteration for each level - cmeres(i) = 0.0_kind_phys + ! zero qmeres before iteration for each level + qmeres(i) = 0.0_kind_phys end do do i = 1, ncol @@ -505,19 +506,19 @@ subroutine prognostic_cloud_water_run( & endif end do - ! calculate cme and formation of precip. + ! calculate qme and formation of precip. ! - ! The cloud microphysics is highly nonlinear and coupled with cme - ! Both rain processes and cme are calculated iteratively. - cme_iter_loop: do l = 1, iter - cme_update_loop: do i = 1, ncol - ! calculation of cme has 4 scenarios + ! 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 + 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 if(relhum(i) >= 0.999_kind_phys .or. cldm(i) >= 0.999_kind_phys) then - cme(i,k) = (calpha(i)*qtend(i,k)-cbetah(i)*ttend(i,k))/cgamah(i) + qme(i,k) = (calpha(i)*qtend(i,k)-cbetah(i)*ttend(i,k))/cgamah(i) ! 2. fractional saturation else if (rhdfda(i,k) .eq. 0._kind_phys .and. icwc(i) .eq. 0._kind_phys) then @@ -530,64 +531,64 @@ subroutine prognostic_cloud_water_run( & endif csigma(i) = 1.0_kind_phys/(rhdfda(i,k)+cgamma(i)*icwc(i)) - cmec1(i) = (1.0_kind_phys-cldm(i))*csigma(i)*rhdfda(i,k) - cmec2(i) = cldm(i)*calpha(i)/cgamah(i)+(1.0_kind_phys-rcgama(i)*cldm(i))* & + qmec1(i) = (1.0_kind_phys-cldm(i))*csigma(i)*rhdfda(i,k) + qmec2(i) = cldm(i)*calpha(i)/cgamah(i)+(1.0_kind_phys-rcgama(i)*cldm(i))* & csigma(i)*calpha(i)*icwc(i) - cmec3(i) = cldm(i)*cbetah(i)/cgamah(i) + & + qmec3(i) = cldm(i)*cbetah(i)/cgamah(i) + & (cbeta(i)-rcgama(i)*cldm(i)*cbetah(i))*csigma(i)*icwc(i) - cmec4(i) = csigma(i)*cgamma(i)*icwc(i) + qmec4(i) = csigma(i)*cgamma(i)*icwc(i) ! Q = C-E = -C1*Al + C2*Aq - C3*At + C4*Er - cme(i,k) = -cmec1(i)*lctend(i,k) + cmec2(i)*qtend(i,k) & - -cmec3(i)*ttend(i,k) + cmec4(i)*evapprec(i,k) + qme(i,k) = -qmec1(i)*lctend(i,k) + qmec2(i)*qtend(i,k) & + -qmec3(i)*ttend(i,k) + qmec4(i)*evapprec(i,k) endif ! 3. when rh < rhu00, evaporate existing cloud water else if(cwat(i,k) > 0.0_kind_phys) then ! liquid water should be evaporated but not to exceed ! saturation point. if qn > qsp, not to evaporate cwat - cme(i,k) = -min(max(0._kind_phys,qsp(i,k)-qn(i,k)),cwat(i,k))/deltat + qme(i,k) = -min(max(0._kind_phys,qsp(i,k)-qn(i,k)),cwat(i,k))/deltat ! 4. no condensation nor evaporation else - cme(i,k) = 0.0_kind_phys + qme(i,k) = 0.0_kind_phys endif - end do cme_update_loop + end do qme_update_loop ! Because of the finite time step, place a bound here not to exceed wet bulb point ! and not to evaporate more than available water do i = 1, ncol - qtmp = qn(i,k) - cme(i,k)*deltat + qtmp = qn(i,k) - qme(i,k)*deltat ! possibilities to have qtmp > qsp ! ! 1. if qn > qs(tn), it condenses; - ! if after applying cme, qtmp > qsp, more condensation is applied. + ! if after applying qme, qtmp > qsp, more condensation is applied. ! ! 2. if qn < qs, evaporation should not exceed qsp, if(qtmp > qsp(i,k)) then - cme(i,k) = cme(i,k) + (qtmp-qsp(i,k))/deltat + qme(i,k) = qme(i,k) + (qtmp-qsp(i,k))/deltat endif ! if net evaporation, it should not exceed available cwat - if(cme(i,k) < -cwat(i,k)/deltat) then - cme(i,k) = -cwat(i,k)/deltat + if(qme(i,k) < -cwat(i,k)/deltat) then + qme(i,k) = -cwat(i,k)/deltat endif ! addition of residual condensation from previous step of iteration - cme(i,k) = cme(i,k) + cmeres(i) + qme(i,k) = qme(i,k) + qmeres(i) - ! limit cme for roundoff errors (multiply by slightly less than unity) - cme(i,k) = cme(i,k) * omsm + ! limit qme for roundoff errors (multiply by slightly less than unity) + qme(i,k) = qme(i,k) * omsm end do do i = 1, ncol ! as a safe limit, condensation should not reduce grid mean rh below rhu00 - if(cme(i,k) > 0.0_kind_phys .and. relhum(i) > rhu_adj(i,k)) then - cme(i,k) = min(cme(i,k), (qn(i,k)-qs(i)*rhu_adj(i,k))/deltat) + if(qme(i,k) > 0.0_kind_phys .and. relhum(i) > rhu_adj(i,k)) then + qme(i,k) = min(qme(i,k), (qn(i,k)-qs(i)*rhu_adj(i,k))/deltat) endif ! initial guess for cwm (mean cloud water over time step) if 1st iteration if(l < 2) then - cwm(i) = max(cwat(i,k)+cme(i,k)*dto2, 0._kind_phys) + cwm(i) = max(cwat(i,k)+qme(i,k)*dto2, 0._kind_phys) endif enddo @@ -635,14 +636,14 @@ subroutine prognostic_cloud_water_run( & ! first predict the cloud water cdt = coef(i)*deltat if(cdt > 0.01_kind_phys) then - pol = cme(i,k)/coef(i) ! production over loss + pol = qme(i,k)/coef(i) ! production over loss cwn(i) = max(0._kind_phys,(cwat(i,k)-pol)*exp(-cdt)+ pol) else - cwn(i) = max(0._kind_phys,(cwat(i,k) + cme(i,k)*deltat)/(1+cdt)) + cwn(i) = max(0._kind_phys,(cwat(i,k) + qme(i,k)*deltat)/(1+cdt)) endif ! now back out the tendency of net rain production - prodprec(i,k) = max(0._kind_phys,cme(i,k)-(cwn(i)-cwat(i,k))/deltat) + prodprec(i,k) = max(0._kind_phys,qme(i,k)-(cwn(i)-cwat(i,k))/deltat) else prodprec(i,k) = 0.0_kind_phys cwn(i) = 0._kind_phys @@ -664,8 +665,8 @@ subroutine prognostic_cloud_water_run( & liq2snow(i,k) = max(prodprec(i,k)*fsacw(i,k), fsnow(i,k)*liq2pr(i,k)) ! bounds - nice2pr = min(ice2pr(i,k),(cwat(i,k)+cme(i,k)*deltat)*fice(i,k)/deltat) - nliq2pr = min(liq2pr(i,k),(cwat(i,k)+cme(i,k)*deltat)*(1._kind_phys-fice(i,k))/deltat) + nice2pr = min(ice2pr(i,k),(cwat(i,k)+qme(i,k)*deltat)*fice(i,k)/deltat) + nliq2pr = min(liq2pr(i,k),(cwat(i,k)+qme(i,k)*deltat)*(1._kind_phys-fice(i,k))/deltat) if (liq2pr(i,k) .ne. 0._kind_phys) then nliq2snow = liq2snow(i,k)*nliq2pr/liq2pr(i,k) ! correction @@ -682,9 +683,9 @@ subroutine prognostic_cloud_water_run( & prodprec(i,k) = (nliq2pr + nice2pr) prodsnow(i,k) = (nice2pr + nliq2snow) - rcwn(i,l,k) = cwat(i,k) + (cme(i,k) - prodprec(i,k))*deltat - rliq(i,l,k) = (cwat(i,k) + cme(i,k)*deltat)*(1._kind_phys-fice(i,k)) - nliq2pr*deltat - rice(i,l,k) = (cwat(i,k) + cme(i,k)*deltat) * fice(i,k) - nice2pr*deltat + rcwn(i,l,k) = cwat(i,k) + (qme(i,k) - prodprec(i,k))*deltat + rliq(i,l,k) = (cwat(i,k) + qme(i,k)*deltat)*(1._kind_phys-fice(i,k)) - nliq2pr*deltat + rice(i,l,k) = (cwat(i,k) + qme(i,k)*deltat) * fice(i,k) - nice2pr*deltat ! Sanity checks if(abs(rcwn(i,l,k)) < 1.e-300_kind_phys) rcwn(i,l,k) = 0._kind_phys @@ -696,10 +697,10 @@ subroutine prognostic_cloud_water_run( & if(error_found) then if(rcwn(i,l,k) < 0._kind_phys) then write(iulog,*) 'prognostic_cloud_water: prob with neg rcwn1 ', rcwn(i,l,k), cwn(i) - write(iulog,*) ' cwat, cme*deltat, prodprec*deltat ', & - cwat(i,k), cme(i,k)*deltat, & + write(iulog,*) ' cwat, qme*deltat, prodprec*deltat ', & + cwat(i,k), qme(i,k)*deltat, & prodprec(i,k)*deltat, & - (cme(i,k)-prodprec(i,k))*deltat + (qme(i,k)-prodprec(i,k))*deltat errflg = 1 errmsg = 'prognostic_cloud_water: negative rcwn1' @@ -745,8 +746,8 @@ subroutine prognostic_cloud_water_run( & ! calculate provisional value of cloud water for ! evaporation of precipitate (evapprec) calculation do i = 1,ncol - qtmp = qn(i,k) - cme(i,k)*deltat - ttmp = tn(i,k) + deltat/cpair * ( meltheat(i,k) + (latvap + latice*fice(i,k)) * cme(i,k) ) + qtmp = qn(i,k) - qme(i,k)*deltat + ttmp = tn(i,k) + deltat/cpair * ( meltheat(i,k) + (latvap + latice*fice(i,k)) * qme(i,k) ) esn = estblf(ttmp) qsn = svp_to_qsat(esn, pmid(i,k)) qtl(i) = max((qsn - qtmp)/deltat,0._kind_phys) @@ -789,31 +790,31 @@ subroutine prognostic_cloud_water_run( & ! now remove the residual of any over-saturation. Normally, ! the oversaturated water vapor should have been removed by - ! cme formulation plus constraints by wet bulb tsp/qsp + ! qme formulation plus constraints by wet bulb tsp/qsp ! as computed above. However, because of non-linearity, - ! addition of (cme-evapprec) to update t and q may still cause + ! addition of (qme-evapprec) to update t and q may still cause ! a very small amount of over saturation. It is called a - ! residual of over-saturation because theoretically, cme + ! residual of over-saturation because theoretically, qme ! should have taken care of all of large scale condensation. do i = 1,ncol - qtmp = qn(i,k)-(cme(i,k)-evapprec(i,k))*deltat + qtmp = qn(i,k)-(qme(i,k)-evapprec(i,k))*deltat ttmp = tn(i,k) + deltat/cpair * ( meltheat(i,k) + evapheat(i,k) + prfzheat(i,k) & - + (latvap + latice*fice(i,k)) * cme(i,k) ) + + (latvap + latice*fice(i,k)) * qme(i,k) ) call qsat(ttmp, pmid(i,k), esn, qsn, dqsdt=dqsdt) if(qtmp > qsn) then ! now extra condensation to bring air to just saturation ctmp = (qtmp-qsn)/(1._kind_phys+hlocp*dqsdt)/deltat - cme(i,k) = cme(i,k)+ctmp - ! save residual on cmeres to addtion to cme on entering next iteration - ! cme exit here contain the residual but overrided if back to iteration - cmeres(i) = ctmp + qme(i,k) = qme(i,k)+ctmp + ! save residual on qmeres to addtion to qme on entering next iteration + ! qme exit here contain the residual but overrided if back to iteration + qmeres(i) = ctmp else - cmeres(i) = 0.0_kind_phys + qmeres(i) = 0.0_kind_phys endif end do - end do cme_iter_loop ! loop over l (iteration) + end do qme_iter_loop ! loop over l (iteration) ! precipitation do i = 1, ncol diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.meta b/schemes/rasch_kristjansson/prognostic_cloud_water.meta index 62b6e391..a1ca174c 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.meta +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.meta @@ -285,7 +285,7 @@ type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = in -[ cme ] +[ qme ] standard_name = net_condensation_rate_due_to_microphysics units = s-1 type = real | kind = kind_phys diff --git a/schemes/rasch_kristjansson/rk_stratiform.F90 b/schemes/rasch_kristjansson/rk_stratiform.F90 index 66bc3cdd..8622613b 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.F90 +++ b/schemes/rasch_kristjansson/rk_stratiform.F90 @@ -17,9 +17,10 @@ module rk_stratiform public :: rk_stratiform_detrain_convective_condensate_run ! public :: rk_stratiform_cloud_fractions_run ! public :: rk_stratiform_microphysics_run - ! public :: rk_stratiform_prognostic_cloud_water_tendencies_run - ! public :: rk_stratiform_microphysics_tendencies_run + public :: rk_stratiform_prognostic_cloud_water_tendencies_run + ! public :: rk_stratiform_ice_and_liquid_water_content_run ! public :: rk_stratiform_cloud_optical_properties_run + ! public :: rk_stratiform_save_qtlcwat_run ! @@ -100,7 +101,7 @@ subroutine rk_stratiform_detrain_convective_condensate_run( & ! Input arguments integer, intent(in) :: ncol real(kind_phys), intent(in) :: dlf(:,:) ! detrainment_of_water_due_to_all_convection [kg kg-1 s-1] - real(kind_phys), intent(in) :: rliq(:,:) ! vertically_integrated_liquid_water_tendency_due_to_all_convection_to_be_applied_later_in_time_loop [kg kg-1 s-1] + real(kind_phys), intent(in) :: rliq(:) ! vertically_integrated_liquid_water_tendency_due_to_all_convection_to_be_applied_later_in_time_loop [kg kg-1 s-1] ! Input/output arguments real(kind_phys), intent(inout) :: prec_str(:) ! stratiform_rain_and_snow_surface_flux [m s-1] @@ -128,11 +129,14 @@ subroutine rk_stratiform_prognostic_cloud_water_tendencies_run( & ncol, pver, & dtime, & latvap, latice, & - cme, fice, & + qme, fice, & evapheat, prfzheat, meltheat, & repartht, & evapprec, & ice2pr, liq2pr, & + prec_pcw, snow_pcw, & + prec_str, snow_str, & + cmeheat, cmeice, cmeliq, & tend_s, & tend_q, & tend_cldice, & @@ -142,9 +146,10 @@ subroutine rk_stratiform_prognostic_cloud_water_tendencies_run( & ! Input arguments integer, intent(in) :: ncol integer, intent(in) :: pver + real(kind_phys), intent(in) :: dtime real(kind_phys), intent(in) :: latvap real(kind_phys), intent(in) :: latice - real(kind_phys), intent(in) :: cme(:,:) ! net_condensation_rate_due_to_microphysics [s-1] + real(kind_phys), intent(in) :: qme(:,:) ! net_condensation_rate_due_to_microphysics [s-1] real(kind_phys), intent(in) :: fice(:,:) ! mass_fraction_of_ice_content_within_stratiform_cloud [fraction] real(kind_phys), intent(in) :: evapheat(:,:) ! real(kind_phys), intent(in) :: prfzheat(:,:) ! @@ -153,6 +158,12 @@ subroutine rk_stratiform_prognostic_cloud_water_tendencies_run( & real(kind_phys), intent(in) :: evapprec(:,:) ! real(kind_phys), intent(in) :: ice2pr(:,:) ! real(kind_phys), intent(in) :: liq2pr(:,:) ! + real(kind_phys), intent(inout) :: prec_pcw(:) ! lwe_stratiform_precipitation_rate_at_surface [m s-1] + real(kind_phys), intent(inout) :: snow_pcw(:) ! lwe_snow_precipitation_rate_at_surface_due_to_microphysics [m s-1] + + ! Input/output arguments + real(kind_phys), intent(inout) :: prec_str(:) ! stratiform_rain_and_snow_surface_flux [m s-1] + real(kind_phys), intent(inout) :: snow_str(:) ! lwe_snow_and_cloud_ice_precipitation_rate_at_surface_due_to_microphysics [m s-1] ! Output arguments real(kind_phys), intent(out) :: cmeheat(:,:) ! ... [J kg-1 s-1] @@ -165,33 +176,77 @@ subroutine rk_stratiform_prognostic_cloud_water_tendencies_run( & character(len=512), intent(out) :: errmsg ! error message integer, intent(out) :: errflg ! error flag + integer :: i, k errmsg = '' errflg = 0 do k = 1, pver do i = 1, ncol ! Heating from cond-evap within the cloud [J kg-1 s-1] - cmeheat(i,k) = cme(i,k)*(latvap + latice*fice(i,k)) + cmeheat(i,k) = qme(i,k)*(latvap + latice*fice(i,k)) ! Rate of cond-evap of ice within the cloud [kg kg-1 s-1] - cmeice(i,k) = cme(i,k)*fice(i,k) + cmeice(i,k) = qme(i,k)*fice(i,k) ! Rate of cond-evap of liq within the cloud [kg kg-1 s-1] - cmeliq(i,k) = cme(i,k)*(1._kind_phys-fice(i,k)) + cmeliq(i,k) = qme(i,k)*(1._kind_phys-fice(i,k)) tend_s(i,k) = cmeheat(i,k) + & evapheat(i,k) + prfzheat(i,k) + meltheat(i,k) + repartht(i,k) - tend_q(i,k) = - cme(i,k) + evapprec(i,k) + tend_q(i,k) = - qme(i,k) + evapprec(i,k) tend_cldice(i,k) = cmeice(i,k) - ice2pr(i,k) tend_cldliq(i,k) = cmeliq(i,k) - liq2pr(i,k) end do end do - + prec_str(:ncol) = prec_str(:ncol) + prec_pcw(:ncol) + snow_str(:ncol) = snow_str(:ncol) + snow_pcw(:ncol) end subroutine rk_stratiform_prognostic_cloud_water_tendencies_run - + ! might be better suited for diagnostics ... + ! subroutine rk_stratiform_ice_and_liquid_water_content_run( & + ! ncol, pver, & + ! pmid, & + ! t, & + ! cldice, cldliq, & + ! rhcloud, & + ! iwc, lwc, & + ! icimr, icwmr, & + ! errmsg, errflg) + + ! ! Input arguments + ! integer, intent(in) :: ncol + ! integer, intent(in) :: pver + ! real(kind_phys), intent(in) :: pmid(:,:) ! air_pressure [Pa] + ! real(kind_phys), intent(in) :: t(:,:) ! air_temperature [K] + ! real(kind_phys), intent(in) :: cldliq(:,:) ! adv: cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + ! real(kind_phys), intent(in) :: cldice(:,:) ! adv: cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + ! real(kind_phys), intent(in) :: rhcloud(:,:) ! ? [fraction] + + ! ! Output arguments + ! real(kind_phys), intent(out) :: iwc(:) ! stratiform_cloud_ice_water_content [kg m-3] + ! real(kind_phys), intent(out) :: lwc(:) ! stratiform_cloud_liquid_water_content [kg m-3] + ! real(kind_phys), intent(out) :: icimr(:) ! stratiform_cloud_ice_water_mixing_ratio [kg kg-1] + ! real(kind_phys), intent(out) :: icwmr(:) ! stratiform_cloud_liquid_water_mixing_ratio [kg kg-1] + ! character(len=512), intent(out) :: errmsg ! error message + ! integer, intent(out) :: errflg ! error flag + + ! integer :: i, k + ! errmsg = '' + ! errflg = 0 + + ! do k = 1, pver + ! do i = 1, ncol + ! iwc(i,k) = cldice(i,k)*pmid(i,k)/(287.15_kind_phys*t(i,k)) + ! lwc(i,k) = cldliq(i,k)*pmid(i,k) / & + ! (287.15_kind_phys*t(i,k)) + ! icimr(i,k) = cldice(i,k) / max(0.01_kind_phys,rhcloud(i,k)) + ! icwmr(i,k) = cldliq(i,k) / max(0.01_kind_phys,rhcloud(i,k)) + ! end do + ! end do + + ! end subroutine rk_stratiform_ice_and_liquid_water_content_run end module rk_stratiform diff --git a/to_be_ccppized/cloud_optical_properties.F90 b/to_be_ccppized/cloud_optical_properties.F90 index 670be7bd..21bd259f 100644 --- a/to_be_ccppized/cloud_optical_properties.F90 +++ b/to_be_ccppized/cloud_optical_properties.F90 @@ -110,55 +110,37 @@ subroutine cldems(ncol, pver, clwp, fice, rei, emis, cldtau) end do end subroutine cldems -!=============================================================================== - subroutine cldovrlap(ncol, pint, cld, nmxrgn, pmxrgn) -!----------------------------------------------------------------------- -! -! Purpose: -! Partitions each column into regions with clouds in neighboring layers. -! This information is used to implement maximum overlap in these regions -! with random overlap between them. -! On output, -! nmxrgn contains the number of regions in each column -! pmxrgn contains the interface pressures for the lower boundaries of -! each region! -! Method: - -! -! Author: W. Collins -! -!----------------------------------------------------------------------- + ! Partitions each column into regions with clouds in neighboring layers. + ! This information is used to implement maximum overlap in these regions + ! with random overlap between them. + ! On output, + ! nmxrgn contains the number of regions in each column + ! pmxrgn contains the interface pressures for the lower boundaries of + ! each region! + subroutine cldovrlap(ncol, pver, pverp, pint, cld, nmxrgn, pmxrgn) -! -! Input arguments -! - integer, intent(in) :: ncol ! number of atmospheric columns - - real(r8), intent(in) :: pint(pcols, pverp) ! Interface pressure - real(r8), intent(in) :: cld(pcols, pver) ! Fractional cloud cover -! -! Output arguments -! - integer, intent(out) :: nmxrgn(pcols) ! Number of maximally overlapped regions - real(r8), intent(out) :: pmxrgn(pcols, pverp)! Maximum values of pressure for each -! maximally overlapped region. -! 0->pmxrgn(i,1) is range of pressure for -! 1st region,pmxrgn(i,1)->pmxrgn(i,2) for -! 2nd region, etc -! -!---------------------------Local variables----------------------------- -! - integer i ! Longitude index - integer k ! Level index - integer n ! Max-overlap region counter + ! Input arguments + integer, intent(in) :: ncol + integer, intent(in) :: pver + integer, intent(in) :: pverp - real(r8) pnm(pcols, pverp) ! Interface pressure + real(r8), intent(in) :: pint(:, :) ! Interface pressure + real(r8), intent(in) :: cld(:, :) ! Fractional cloud cover - logical cld_found ! Flag for detection of cloud - logical cld_layer(pver) ! Flag for cloud in layer -! -!------------------------------------------------------------------------ -! + ! Output arguments + integer, intent(out) :: nmxrgn(:) ! Number of maximally overlapped regions + real(r8), intent(out) :: pmxrgn(:, :) ! Maximum values of pressure for each + ! maximally overlapped region. + ! 0->pmxrgn(i,1) is range of pressure for + ! 1st region,pmxrgn(i,1)->pmxrgn(i,2) for + ! 2nd region, etc + ! (ncol, pverp) + + integer :: i, k + integer :: n ! Max-overlap region counter + real(r8) :: pnm(ncol, pverp) ! Interface pressure + logical :: cld_found ! Flag for detection of cloud + logical :: cld_layer(pver) ! Flag for cloud in layer do i = 1, ncol cld_found = .false. @@ -183,57 +165,35 @@ subroutine cldovrlap(ncol, pint, cld, nmxrgn, pmxrgn) end do end subroutine cldovrlap -!=============================================================================== + ! Evaluate cloud liquid water path clwp [g m-2] + ! Original author: Author: J.T. Kiehl subroutine cldclw(ncol, zi, clwp, tpw, hl) -!----------------------------------------------------------------------- -! -! Purpose: -! Evaluate cloud liquid water path clwp (g/m**2) -! -! Method: -! -! -! -! Author: J.T. Kiehl -! -!----------------------------------------------------------------------- -! -! Input arguments -! - integer, intent(in) :: ncol ! number of atmospheric columns + ! Input arguments + integer, intent(in) :: ncol ! number of atmospheric columns - real(r8), intent(in) :: zi(pcols, pverp) ! height at layer interfaces(m) - real(r8), intent(in) :: tpw(pcols) ! total precipitable water (mm) -! -! Output arguments -! + real(r8), intent(in) :: zi(pcols, pverp) ! height at layer interfaces(m) + real(r8), intent(in) :: tpw(pcols) ! total precipitable water (mm) + + ! Output arguments real(r8), intent(out) :: clwp(pcols, pver) ! cloud liquid water path (g/m**2) - real(r8), intent(out) :: hl(pcols) ! liquid water scale height + real(r8), intent(out) :: hl(pcols) ! liquid water scale height -! -!---------------------------Local workspace----------------------------- -! integer :: i, k ! longitude, level indices - real(r8) :: clwc0 ! reference liquid water concentration (g/m**3) + real(r8) :: clwc0 ! reference liquid water concentration (g/m**3) real(r8) :: emziohl(pcols, pverp) ! exp(-zi/hl) - real(r8) :: rhl(pcols) ! 1/hl -! -!----------------------------------------------------------------------- -! -! Set reference liquid water concentration -! + real(r8) :: rhl(pcols) ! 1/hl + + ! Set reference liquid water concentration clwc0 = 0.21_r8 -! -! Diagnose liquid water scale height from precipitable water -! + + ! Diagnose liquid water scale height from precipitable water do i = 1, ncol hl(i) = 700.0_r8*log(max(tpw(i) + 1.0_r8, 1.0_r8)) rhl(i) = 1.0_r8/hl(i) end do -! -! Evaluate cloud liquid water path (vertical integral of exponential fn) -! + + ! Evaluate cloud liquid water path (vertical integral of exponential fn) do k = 1, pverp do i = 1, ncol emziohl(i, k) = exp(-zi(i, k)*rhl(i)) @@ -246,22 +206,13 @@ subroutine cldclw(ncol, zi, clwp, tpw, hl) end do end subroutine cldclw -!=============================================================================== + + ! Compute cloud water size + ! analytic formula following the formulation originally developed by J. T. Kiehl + ! Author: Phil Rasch subroutine reltab(ncol, pver, tmelt, t, landfrac, landm, icefrac, snowh, rel) -!----------------------------------------------------------------------- -! -! Purpose: -! Compute cloud water size -! -! Method: -! analytic formula following the formulation originally developed by J. T. Kiehl -! -! Author: Phil Rasch -! -!----------------------------------------------------------------------- -! -! Input arguments -! + + ! Input arguments integer, intent(in) :: ncol integer, intent(in) :: pver real(r8), intent(in) :: tmelt @@ -271,23 +222,18 @@ subroutine reltab(ncol, pver, tmelt, t, landfrac, landm, icefrac, snowh, rel) real(r8), intent(in) :: t(:, :) ! Temperature [K] real(r8), intent(in) :: snowh(:) ! Snow depth over land, water equivalent [m] -! -! Output arguments -! + ! Output arguments real(r8), intent(out) :: rel(:, :) ! Liquid effective drop size (microns) -! -!---------------------------Local workspace----------------------------- -! - integer i, k ! Lon, lev indices + + integer i, k real(r8) :: rliqland ! liquid drop size if over land real(r8) :: rliqocean ! liquid drop size if over ocean real(r8) :: rliqice ! liquid drop size if over sea ice -! -!----------------------------------------------------------------------- -! + rliqocean = 14.0_r8 rliqice = 14.0_r8 rliqland = 8.0_r8 + do k = 1, pver do i = 1, ncol ! jrm Reworked effective radius algorithm @@ -305,7 +251,6 @@ subroutine reltab(ncol, pver, tmelt, t, landfrac, landm, icefrac, snowh, rel) end do end subroutine reltab -!=============================================================================== subroutine reitab(ncol, pver, t, re) integer, intent(in) :: ncol @@ -325,7 +270,7 @@ subroutine reitab(ncol, pver, t, re) ! ! Modified for pmc formation: 136K -- 274K ! - data retab/ & + data retab / & 0.05_r8, 0.05_r8, 0.05_r8, 0.05_r8, 0.05_r8, 0.05_r8, & 0.055_r8, 0.06_r8, 0.07_r8, 0.08_r8, 0.09_r8, 0.1_r8, & 0.2_r8, 0.3_r8, 0.40_r8, 0.50_r8, 0.60_r8, 0.70_r8, & @@ -350,9 +295,7 @@ subroutine reitab(ncol, pver, t, re) 124.954_r8, 130.630_r8, 136.457_r8, 142.446_r8, 148.608_r8, 154.956_r8, & 161.503_r8, 168.262_r8, 175.248_r8, 182.473_r8, 189.952_r8, 197.699_r8, & 205.728_r8, 214.055_r8, 222.694_r8, 231.661_r8, 240.971_r8, 250.639_r8/ - ! save retab - ! do k = 1, pver do i = 1, ncol From c425129bc27bbdb5b5430c0ae4ae780cdae41c5f Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Thu, 6 Feb 2025 17:04:05 -0500 Subject: [PATCH 09/39] Sketch out convective_cloud_cover split out from cloud_fraction --- .../cloud_fraction/convective_cloud_cover.F90 | 105 ++++++++++++++++ .../convective_cloud_cover.meta | 113 ++++++++++++++++++ .../cloud_fraction/convective_cloud_cover.xml | 62 ++++++++++ 3 files changed, 280 insertions(+) create mode 100644 schemes/cloud_fraction/convective_cloud_cover.F90 create mode 100644 schemes/cloud_fraction/convective_cloud_cover.meta create mode 100644 schemes/cloud_fraction/convective_cloud_cover.xml diff --git a/schemes/cloud_fraction/convective_cloud_cover.F90 b/schemes/cloud_fraction/convective_cloud_cover.F90 new file mode 100644 index 00000000..84166169 --- /dev/null +++ b/schemes/cloud_fraction/convective_cloud_cover.F90 @@ -0,0 +1,105 @@ +! Copyright (C) 2025 National Science Foundation-National Center for Atmospheric Research +! SPDX-License-Identifier: Apache-2.0 +! +! Computes deep and shallow convective cloud fractions +! CCPP-ized: Haipeng Lin, February 2025 +module convective_cloud_cover + + use ccpp_kinds, only: kind_phys + + implicit none + private + save + + ! public CCPP-compliant subroutines + public :: convective_cloud_cover_init + public :: convective_cloud_cover_run + + ! Module variables for tuning parameters + real(kind_phys) :: sh1 ! Shallow convection tuning parameter 1 [fraction] + real(kind_phys) :: sh2 ! Shallow convection tuning parameter 2 [m2 s kg-1] + real(kind_phys) :: dp1 ! Deep convection tuning parameter 1 [fraction] + real(kind_phys) :: dp2 ! Deep convection tuning parameter 2 [m2 s kg-1] + +contains + +!> \section arg_table_convective_cloud_cover_init Argument Table +!! \htmlinclude convective_cloud_cover_init.html + subroutine convective_cloud_cover_init(sh1_in, sh2_in, dp1_in, dp2_in, errmsg, errflg) + real(kind_phys), intent(in) :: sh1_in ! Shallow convection parameter 1 + real(kind_phys), intent(in) :: sh2_in ! Shallow convection parameter 2 + real(kind_phys), intent(in) :: dp1_in ! Deep convection parameter 1 + real(kind_phys), intent(in) :: dp2_in ! Deep convection parameter 2 + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg + + errmsg = '' + errflg = 0 + + ! Set module variables from namelist + sh1 = sh1_in + sh2 = sh2_in + dp1 = dp1_in + dp2 = dp2_in + + end subroutine convective_cloud_cover_init + + ! Compute convective cloud cover (deep and shallow) +!> \section arg_table_convective_cloud_cover_run Argument Table +!! \htmlinclude convective_cloud_cover_run.html + subroutine convective_cloud_cover_run( & + ncol, pver, & + top_lev_cloudphys, & + use_shfrc, shfrc, & + cmfmc_total, cmfmc_sh, & + shallowcu, deepcu, & + errmsg, errflg) + + ! Input arguments + integer, intent(in) :: ncol + integer, intent(in) :: pver + integer, intent(in) :: top_lev_cloudphys ! Top vertical level for cloud physics [index] + + logical, intent(in) :: use_shfrc ! [flag] + real(kind_phys), intent(in) :: shfrc(:, :) ! Input shallow cloud fraction [fraction] + + real(kind_phys), intent(in) :: cmfmc_total(:, :) ! atmosphere_convective_mass_flux_due_to_all_convection [kg m-2 s-1] + real(kind_phys), intent(in) :: cmfmc_sh(:, :) ! atmosphere_convective_mass_flux_due_to_shallow_convection [kg m-2 s-1] + + ! Output arguments + real(kind_phys), intent(out) :: shallowcu(:, :) ! Shallow convective cloud fraction [fraction] + real(kind_phys), intent(out) :: deepcu(:, :) ! Deep convective cloud fraction [fraction] + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg + + ! Local variables + integer :: i, k + + errmsg = '' + errflg = 0 + + do k = top_lev_cloudphys, pver + do i = 1, ncol + if (.not. use_shfrc) then + ! Compute the shallow convection cloud cover using the shallow convective mass flux. + shallowcu(i, k) = max(0.0_kind_phys, & + min(sh1*log(1.0_kind_phys + sh2*cmfmc_sh(i, k + 1)), 0.30_kind_phys)) + else + ! If use shallow convective calculated clouds, then just assign + shallowcu(i, k) = shfrc(i, k) + end if + + ! REMOVECAM: This could be changed to use deep convective mass flux + ! since it is independently available in CCPP, once CAM is retired + deepcu(i, k) = max(0.0_kind_phys, & + min(dp1 * & + log(1.0_kind_phys + & + dp2 * (cmfmc_total(i, k + 1) - cmfmc_sh(i, k + 1)) & + ), & + 0.60_kind_phys)) + end do + end do + + end subroutine convective_cloud_cover_run + +end module convective_cloud_cover diff --git a/schemes/cloud_fraction/convective_cloud_cover.meta b/schemes/cloud_fraction/convective_cloud_cover.meta new file mode 100644 index 00000000..83b0f527 --- /dev/null +++ b/schemes/cloud_fraction/convective_cloud_cover.meta @@ -0,0 +1,113 @@ +[ccpp-table-properties] + name = convective_cloud_cover + type = scheme + +[ccpp-arg-table] + name = convective_cloud_cover_init + type = scheme +[ sh1_in ] + standard_name = tunable_parameter_for_shallow_convection_1_for_cloud_fraction + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ sh2_in ] + standard_name = tunable_parameter_for_shallow_convection_2_for_cloud_fraction + units = s kg-1 m2 + type = real | kind = kind_phys + dimensions = () + intent = in +[ dp1_in ] + standard_name = tunable_parameter_for_deep_convection_1_for_cloud_fraction + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ dp2_in ] + standard_name = tunable_parameter_for_deep_convection_2_for_cloud_fraction + units = s kg-1 m2 + type = real | kind = kind_phys + dimensions = () + intent = in +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out + +[ccpp-arg-table] + name = convective_cloud_cover_run + type = scheme +[ 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 +[ top_lev_cloudphys ] + standard_name = vertical_layer_index_of_cloud_physics_top_tbd + units = index + type = integer + dimensions = () + intent = in +[ use_shfrc ] + standard_name = flag_for_cloud_fraction_use_shallow_convection_calculated_clouds_tbd + units = flag + type = logical + dimensions = () + intent = in +[ shfrc ] + standard_name = convective_cloud_fraction_due_to_shallow_convection_tbd + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ cmfmc_total ] + standard_name = atmosphere_convective_mass_flux_due_to_all_convection + units = kg m-2 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ cmfmc_sh ] + standard_name = atmosphere_convective_mass_flux_due_to_shallow_convection + units = kg m-2 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ shallowcu ] + standard_name = shallow_convective_cloud_area_fraction_tbd + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ deepcu ] + standard_name = shallow_convective_cloud_area_fraction_tbd + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out diff --git a/schemes/cloud_fraction/convective_cloud_cover.xml b/schemes/cloud_fraction/convective_cloud_cover.xml new file mode 100644 index 00000000..596084ee --- /dev/null +++ b/schemes/cloud_fraction/convective_cloud_cover.xml @@ -0,0 +1,62 @@ + + + + + + + real + kind_phys + cldfrc + convective_cloud_cover_nl + tunable_parameter_for_shallow_convection_1_for_cloud_fraction + 1 + + Tunable parameter 1 for shallow convection cloud fraction. + + + 0.04D0 + + + + real + kind_phys + cldfrc + convective_cloud_cover_nl + tunable_parameter_for_shallow_convection_2_for_cloud_fraction + s kg-1 m2 + + Tunable parameter 2 for shallow convection cloud fraction. + + + 500.0D0 + + + + real + kind_phys + cldfrc + convective_cloud_cover_nl + tunable_parameter_for_deep_convection_1_for_cloud_fraction + 1 + + Tunable parameter 1 for deep convection cloud fraction. + + + 0.10D0 + + + + real + kind_phys + cldfrc + convective_cloud_cover_nl + tunable_parameter_for_deep_convection_2_for_cloud_fraction + s kg-1 m2 + + Tunable parameter 2 for deep convection cloud fraction. + + + 500.0D0 + + + From 5c489e247f5e9fc7aa0bb08f56f1f3f5b313aa4d Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Tue, 11 Feb 2025 16:00:20 -0500 Subject: [PATCH 10/39] Sketch cloud_fraction --- .../cloud_fraction/compute_cloud_fraction.F90 | 568 ++++++++++++++++++ .../cloud_fraction/convective_cloud_cover.F90 | 33 +- .../convective_cloud_cover.meta | 10 +- 3 files changed, 602 insertions(+), 9 deletions(-) create mode 100644 schemes/cloud_fraction/compute_cloud_fraction.F90 diff --git a/schemes/cloud_fraction/compute_cloud_fraction.F90 b/schemes/cloud_fraction/compute_cloud_fraction.F90 new file mode 100644 index 00000000..44b2ff61 --- /dev/null +++ b/schemes/cloud_fraction/compute_cloud_fraction.F90 @@ -0,0 +1,568 @@ +module compute_cloud_fraction + use ccpp_kinds, only: kind_phys + private + save + + public :: compute_cloud_fraction_init + public :: compute_cloud_fraction_timestep_init + public :: compute_cloud_fraction_run + + ! Namelist variables + logical :: cldfrc_freeze_dry ! flag for Vavrus correction + logical :: cldfrc_ice ! flag to compute ice cloud fraction + integer :: iceopt ! option for ice cloud closure + ! 1=wang & sassen 2=schiller (iciwc) + ! 3=wood & field, 4=Wilson (based on smith) + real(kind_phys) :: rhminl ! minimum rh for low stable clouds + real(kind_phys) :: rhminl_adj_land ! rhminl adjustment for snowfree land + real(kind_phys) :: rhminh ! minimum rh for high stable clouds + real(kind_phys) :: premit ! top pressure bound for mid level cloud + real(kind_phys) :: premib ! bottom pressure bound for mid level cloud + real(kind_phys) :: icecrit ! critical RH for ice clouds in Wilson and Ballard closure (smaller = more ice clouds) + + ! flags + logical :: inversion_cld_off ! turn off stratification-based cloud fraction (inversion_cld) + + integer :: k700 ! model level nearest to 700 mb [index] + + ! constants + real(kind_phys), parameter :: pnot = 1.e5_kind_phys ! reference pressure + real(kind_phys), parameter :: lapse = 6.5e-3_kind_phys ! U.S. Standard Atmosphere lapse rate + real(kind_phys), parameter :: pretop = 1.0e2_kind_phys ! pressure bounding high cloud + +contains + ! Initialize cloud_fraction from namelist parameters + subroutine compute_cloud_fraction_init( & + amIRoot, iulog, & + pver, & + pref_mid, & + inversion_cld_off_in, & + cldfrc_freeze_dry_in, cldfrc_ice_in, iceopt_in, & + rhminl_in, rhminl_adj_land_in, & + rhminh_in, & + premit_in, premib_in, & + icecrit_in, & + errmsg, errflg) + + ! Input arguments + logical, intent(in) :: amIRoot + integer, intent(in) :: iulog + integer, intent(in) :: pver + real(kind_phys), intent(in) :: pref_mid(:) ! reference_pressure [Pa] + logical, intent(in) :: inversion_cld_off_in ! flag for turn off inversion_cld? + logical, intent(in) :: cldfrc_freeze_dry_in ! flag for Vavrus correction + logical, intent(in) :: cldfrc_ice_in ! flag to compute ice cloud fraction + integer, intent(in) :: iceopt_in ! option for ice cloud closure + real(kind_phys), intent(in) :: rhminl_in ! minimum rh for low stable clouds + real(kind_phys), intent(in) :: rhminl_adj_land_in ! rhminl adjustment for snowfree land + real(kind_phys), intent(in) :: rhminh_in ! minimum rh for high stable clouds + real(kind_phys), intent(in) :: premit_in ! top pressure bound for mid level cloud + real(kind_phys), intent(in) :: premib_in ! bottom pressure bound for mid level cloud + real(kind_phys), intent(in) :: icecrit_in ! critical RH for ice clouds in Wilson and Ballard closure + + ! Output arguments + character(len=512), intent(out) :: errmsg ! error message + integer, intent(out) :: errflg ! error flag + + errflg = 0 + errmsg = '' + + ! Set module variables from input arguments + cldfrc_freeze_dry = cldfrc_freeze_dry_in + cldfrc_ice = cldfrc_ice_in + iceopt = iceopt_in + rhminl = rhminl_in + rhminl_adj_land = rhminl_adj_land_in + rhminh = rhminh_in + premit = premit_in + premib = premib_in + icecrit = icecrit_in + + ! Find vertical level nearest 700 mb. + k700 = minloc(abs(pref_mid(:) - 7.e4_kind_phys), 1) + + if(amIRoot) then + write(iulog,*) 'compute_cloud_fraction: model level nearest 700 mb is',k700,'which is',pref_mid(k700),'pascals' + endif + + end subroutine compute_cloud_fraction_init + + ! Timestep initialization for cloud fraction + ! Specify the perturbation to RH to none by default. + ! If a scheme has to perturb RH this quantity should be set by an interstitial + ! before calling cloud_fraction a second time. +!> \section arg_table_compute_cloud_fraction_timestep_init Argument Table +!! \htmlinclude compute_cloud_fraction_timestep_init.html + subroutine compute_cloud_fraction_timestep_init(rhpert_flag, errmsg, errflg) + logical, intent(out) :: rhpert_flag + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg + + errmsg = '' + errflg = 0 + + rhpert_flag = .false. + end subroutine compute_cloud_fraction_timestep_init + + ! Compute cloud fraction. + ! + ! Calculates cloud fraction using a relative humidity threshold + ! The threshold depends upon pressure, and upon the presence or absence + ! of convection as defined by a reasonably large vertical mass flux + ! entering that layer from below. + ! + ! Original authors: Many, including Jim McCaa. + + ! previous call routine + ! subroutine cldfrc(lchnk ,ncol , pbuf, & + ! pmid ,temp ,q ,omga , phis, & + ! shfrc ,use_shfrc, & + ! cloud ,rhcloud, clc ,pdel , & + ! cmfmc ,cmfmc2 ,landfrac,snowh ,concld ,cldst , & + ! ts ,sst ,ps ,zdu ,ocnfrac ,& + ! rhu00 ,cldice ,icecldf ,liqcldf ,relhum ,dindex ) +!> \section arg_table_compute_cloud_fraction_run Argument Table +!! \htmlinclude compute_cloud_fraction_run.html + subroutine compute_cloud_fraction_run( & + ncol, pver, & + cappa, gravit, rair, tmelt, & + top_lev_cloudphys, & + pmid, ps, temp, sst, & + q, cldice, & + phis, & + shallowcu, deepcu, concld, & ! convective cloud cover + landfrac, ocnfrac, snowh, & + rhpert_flag, & ! todo: decide what to do with this + cloud, rhcloud, clc, & + cldst, & + rhu00, icecldf, liqcldf, relhum, & + errmsg, errflg) + + ! To-be-ccppized dependencies + use wv_saturation, only: qsat, qsat_water, svp_ice_vect + + ! Arguments + integer, intent(in) :: ncol + integer, intent(in) :: pver + real(kind_phys), intent(in) :: cappa + real(kind_phys), intent(in) :: gravit + real(kind_phys), intent(in) :: rair + real(kind_phys), intent(in) :: tmelt + integer, intent(in) :: top_lev_cloudphys ! vertical_layer_index_of_cloud_fraction_top [index] + real(kind_phys), intent(in) :: pmid(:, :) ! air_pressure [Pa] + real(kind_phys), intent(in) :: ps(:) ! surface_air_pressure [Pa] + real(kind_phys), intent(in) :: temp(:, :) ! air_temperature [K] + real(kind_phys), intent(in) :: sst(:) ! sea_surface_temperature [K] + real(kind_phys), intent(in) :: q(:, :) ! water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + real(kind_phys), intent(in) :: cldice(:, :) ! cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + real(kind_phys), intent(in) :: phis(:) ! surface_geopotential [m2 s-2] + real(kind_phys), intent(in) :: shallowcu(:, :) ! shallow convective cloud fraction + real(kind_phys), intent(in) :: deepcu(:, :) ! deep convective cloud fraction + real(kind_phys), intent(in) :: concld(:, :) ! convective_cloud_area_fraction [fraction] + real(kind_phys), intent(in) :: landfrac(:) ! land_area_fraction [fraction] + real(kind_phys), intent(in) :: ocnfrac(:) ! ocean_area_fraction [fraction] + real(kind_phys), intent(in) :: snowh(:) ! lwe_surface_snow_depth_over_land [m] + logical, intent(in) :: rhpert_flag ! 0 or 1 to perturb rh + + ! Output arguments + real(kind_phys), intent(out) :: cloud(:, :) ! cloud fraction + real(kind_phys), intent(out) :: rhcloud(:, :) ! cloud fraction + real(kind_phys), intent(out) :: clc(:) ! column convective cloud amount + real(kind_phys), intent(out) :: cldst(:, :) ! stratiform_cloud_area_fraction [fraction] + real(kind_phys), intent(out) :: rhu00(:, :) ! RH threshold for cloud + real(kind_phys), intent(out) :: relhum(:, :) ! RH + real(kind_phys), intent(out) :: icecldf(:, :) ! ice cloud fraction + real(kind_phys), intent(out) :: liqcldf(:, :) ! liquid cloud fraction (combined into cloud) + character(len=512), intent(out) :: errmsg ! error message + integer, intent(out) :: errflg ! error flag + + ! Local variables: + real(kind_phys) :: cld ! intermediate scratch variable (low cld) + real(kind_phys) :: dthdpmn(ncol) ! most stable lapse rate below 750 mb + real(kind_phys) :: dthdp ! lapse rate (intermediate variable) + real(kind_phys) :: es(ncol, pver) ! saturation vapor pressure + real(kind_phys) :: qs(ncol, pver) ! saturation specific humidity + real(kind_phys) :: rhwght ! weighting function for rhlim transition + real(kind_phys) :: rh(ncol, pver) ! relative humidity + real(kind_phys) :: rhdif ! intermediate scratch variable + real(kind_phys) :: strat ! intermediate scratch variable + real(kind_phys) :: theta(ncol, pver) ! potential temperature + real(kind_phys) :: thetas(ncol) ! ocean surface potential temperature + real(kind_phys) :: rhlim ! local rel. humidity threshold estimate + real(kind_phys) :: coef1 ! coefficient to convert mass flux to mb/d + real(kind_phys) :: clrsky(ncol) ! temporary used in random overlap calc + real(kind_phys) :: rpdeli(ncol, pver - 1) ! 1./(pmid(k+1)-pmid(k)) + real(kind_phys) :: rhpert ! the specified perturbation to rh + + logical :: cldbnd(ncol) ! region below high cloud boundary + + integer :: i, ierror, k ! column, level indices + integer :: kp1, ifld + integer :: kdthdp(ncol) + integer :: numkcld ! number of levels in which to allow clouds + + ! In Cloud Ice Content variables + real(kind_phys) :: a, b, c, as, bs, cs ! fit parameters + real(kind_phys) :: Kc ! constant for ice cloud calc (wood & field) + real(kind_phys) :: ttmp ! limited temperature + real(kind_phys) :: icicval ! empirical iwc value + real(kind_phys) :: rho ! local air density + real(kind_phys) :: esl(ncol, pver) ! liq sat vapor pressure + real(kind_phys) :: esi(ncol, pver) ! ice sat vapor pressure + real(kind_phys) :: ncf, phi ! Wilson and Ballard parameters + + ! Statement functions + logical land + land(i) = nint(landfrac(i)) == 1 + + errmsg = '' + errflg = 0 + + !================================================================================== + ! PHILOSOPHY OF PRESENT IMPLEMENTATION + ! Modification to philosophy for ice supersaturation + ! philosophy below is based on RH water only. This is 'liquid condensation' + ! or liquid cloud (even though it will freeze immediately to ice) + ! The idea is that the RH limits for condensation are strict only for + ! water saturation + ! + ! Ice clouds are formed by explicit parameterization of ice nucleation. + ! Closure for ice cloud fraction is done on available cloud ice, such that + ! the in-cloud ice content matches an empirical fit + ! thus, icecldf = min(cldice/icicval,1) where icicval = f(temp,cldice,numice) + ! for a first cut, icicval=f(temp) only. + ! Combined cloud fraction is maximum overlap cloud=max(1,max(icecldf,liqcldf)) + ! No dA/dt term for ice? + ! + ! There are three co-existing cloud types: convective, inversion related low-level + ! stratocumulus, and layered cloud (based on relative humidity). Layered and + ! stratocumulus clouds do not compete with convective cloud for which one creates + ! the most cloud. They contribute collectively to the total grid-box average cloud + ! amount. This is reflected in the way in which the total cloud amount is evaluated + ! (a sum as opposed to a logical "or" operation) + ! + !================================================================================== + ! set defaults for rhu00 + rhu00(:, :) = 2.0_kind_phys + ! define rh perturbation in order to estimate rhdfda + rhpert = 0.01_kind_phys + + !set Wang and Sassen IWC paramters + a = 26.87_kind_phys + b = 0.569_kind_phys + c = 0.002892_kind_phys + !set schiller parameters + as = -68.4202_kind_phys + bs = 0.983917_kind_phys + cs = 2.81795_kind_phys + !set wood and field paramters... + Kc = 75._kind_phys + + ! Evaluate potential temperature and relative humidity + ! If not computing ice cloud fraction then hybrid RH, if MG then water RH + if (cldfrc_ice) then + do k = top_lev_cloudphys, pver + call qsat_water(temp(1:ncol, k), pmid(1:ncol, k), esl(1:ncol, k), qs(1:ncol, k), ncol) + call svp_ice_vect(temp(1:ncol, k), esi(1:ncol, k), ncol) + end do + else + do k = top_lev_cloudphys, pver + call qsat(temp(1:ncol, k), pmid(1:ncol, k), es(1:ncol, k), qs(1:ncol, k), ncol) + end do + end if + + cloud = 0._kind_phys + icecldf = 0._kind_phys + liqcldf = 0._kind_phys + rhcloud = 0._kind_phys + cldst = 0._kind_phys + + do k = top_lev_cloudphys, pver + theta(:ncol, k) = temp(:ncol, k)*(pnot/pmid(:ncol, k))**cappa + + do i = 1, ncol + if(.not. rhpert_flag) then + ! default: no RH perturbation + rh(i, k) = q(i, k)/qs(i, k) + else + rh(i, k) = q(i, k)/qs(i, k)*(1.0_kind_phys + rhpert) + endif + ! record relhum, rh itself will later be modified related with concld + relhum(i, k) = rh(i, k) + end do + end do + + ! Initialize other temporary variables + ierror = 0 + do i = 1, ncol + ! Adjust thetas(i) in the presence of non-zero ocean heights. + ! This reduces the temperature for positive heights according to a standard lapse rate. + if (ocnfrac(i) .gt. 0.01_kind_phys) thetas(i) = & + (sst(i) - lapse*phis(i)/gravit)*(pnot/ps(i))**cappa + if (ocnfrac(i) .gt. 0.01_kind_phys .and. sst(i) .lt. 260._kind_phys) ierror = i + clc(i) = 0.0_kind_phys + end do + coef1 = gravit*864.0_kind_phys ! conversion to millibars/day + + if (ierror > 0) then + write (iulog, *) 'COLDSST: encountered in cldfrc:', ierror, ocnfrac(ierror), sst(ierror) + end if + + do k = top_lev_cloudphys, pver - 1 + rpdeli(:ncol, k) = 1._kind_phys/(pmid(:ncol, k + 1) - pmid(:ncol, k)) + end do + + ! shallow and deep convective cloudiness are calculated in the + ! convective_cloud_cover CCPP scheme. +#ifndef PERGRO + do k = top_lev_cloudphys, pver + do i = 1, ncol + rh(i, k) = (rh(i, k) - concld(i, k))/(1.0_kind_phys - concld(i, k)) + end do + end do +#endif + !================================================================================== + ! + ! ****** Compute layer cloudiness ****** + ! + !==================================================================== + ! Begin the evaluation of layered cloud amount based on (modified) RH + !==================================================================== + ! + numkcld = pver + do k = top_lev_cloudphys + 1, numkcld + kp1 = min(k + 1, pver) + do i = 1, ncol + + ! This is now designed to apply FOR LIQUID CLOUDS (condensation > RH water) + + cldbnd(i) = pmid(i, k) .ge. pretop + + if (pmid(i, k) .ge. premib) then + !============================================================== + ! This is the low cloud (below premib) block + !============================================================== + ! enhance low cloud activation over land with no snow cover + if (land(i) .and. (snowh(i) <= 0.000001_kind_phys)) then + rhlim = rhminl - rhminl_adj_land + else + rhlim = rhminl + end if + + rhdif = (rh(i, k) - rhlim)/(1.0_kind_phys - rhlim) + rhcloud(i, k) = min(0.999_kind_phys, (max(rhdif, 0.0_kind_phys))**2) + + ! SJV: decrease cloud amount if very low water vapor content + ! (thus very cold): "freeze dry" + if (cldfrc_freeze_dry) then + rhcloud(i, k) = rhcloud(i, k)*max(0.15_kind_phys, min(1.0_kind_phys, q(i, k)/0.0030_kind_phys)) + end if + + else if (pmid(i, k) .lt. premit) then + !============================================================== + ! This is the high cloud (above premit) block + !============================================================== + ! + rhlim = rhminh + ! + rhdif = (rh(i, k) - rhlim)/(1.0_kind_phys - rhlim) + rhcloud(i, k) = min(0.999_kind_phys, (max(rhdif, 0.0_kind_phys))**2) + else + !============================================================== + ! This is the middle cloud block + !============================================================== + ! + ! linear rh threshold transition between thresholds for low & high cloud + ! + rhwght = (premib - (max(pmid(i, k), premit)))/(premib - premit) + + if (land(i) .and. (snowh(i) <= 0.000001_kind_phys)) then + rhlim = rhminh*rhwght + (rhminl - rhminl_adj_land)*(1.0_kind_phys - rhwght) + else + rhlim = rhminh*rhwght + rhminl*(1.0_kind_phys - rhwght) + end if + rhdif = (rh(i, k) - rhlim)/(1.0_kind_phys - rhlim) + rhcloud(i, k) = min(0.999_kind_phys, (max(rhdif, 0.0_kind_phys))**2) + end if + !================================================================================== + ! WE NEED TO DOCUMENT THE PURPOSE OF THIS TYPE OF CODE (ASSOCIATED WITH 2ND CALL) + !================================================================================== + ! ! + ! ! save rhlim to rhu00, it handles well by itself for low/high cloud + ! ! + rhu00(i, k) = rhlim + !================================================================================== + + if (cldfrc_ice) then + + ! Evaluate ice cloud fraction based on in-cloud ice content + + !--------ICE CLOUD OPTION 1--------Wang & Sassen 2002 + ! Evaluate desired in-cloud water content + ! icicval = f(temp,cldice,numice) + ! Start with a function of temperature. + ! Wang & Sassen 2002 (JAS), based on ARM site MMCR (midlat cirrus) + ! parameterization valid for 203-253K + ! icival > 0 for t>195K + if (iceopt .lt. 3) then + if (iceopt .eq. 1) then + ttmp = max(195._kind_phys, min(temp(i, k), 253._kind_phys)) - 273.16_kind_phys + icicval = a + b*ttmp + c*ttmp**2._kind_phys + !convert units + rho = pmid(i, k)/(rair*temp(i, k)) + icicval = icicval*1.e-6_kind_phys/rho + else + !--------ICE CLOUD OPTION 2--------Schiller 2008 (JGR) + ! Use a curve based on FISH measurements in + ! tropics, mid-lats and arctic. Curve is for 180-250K (raise to 273K?) + ! use median all flights + + ttmp = max(190._kind_phys, min(temp(i, k), 273.16_kind_phys)) + icicval = 10._kind_phys**(as*bs**ttmp + cs) + !convert units from ppmv to kg/kg + icicval = icicval*1.e-6_kind_phys*18._kind_phys/28.97_kind_phys + end if + !set icecldfraction for OPTION 1 or OPTION2 + icecldf(i, k) = max(0._kind_phys, min(cldice(i, k)/icicval, 1._kind_phys)) + + else if (iceopt .eq. 3) then + + !--------ICE CLOUD OPTION 3--------Wood & Field 2000 (JAS) + ! eq 6: cloud fraction = 1 - exp (-K * qc/qsati) + + icecldf(i, k) = 1._kind_phys - exp(-Kc*cldice(i, k)/(qs(i, k)*(esi(i, k)/esl(i, k)))) + icecldf(i, k) = max(0._kind_phys, min(icecldf(i, k), 1._kind_phys)) + else + !--------ICE CLOUD OPTION 4--------Wilson and ballard 1999 + ! inversion of smith.... + ! ncf = cldice / ((1-RHcrit)*qs) + ! then a function of ncf.... + ncf = cldice(i, k)/((1._kind_phys - icecrit)*qs(i, k)) + if (ncf .le. 0._kind_phys) then + icecldf(i, k) = 0._kind_phys + else if (ncf .gt. 0._kind_phys .and. ncf .le. 1._kind_phys/6._kind_phys) then + icecldf(i, k) = 0.5_kind_phys*(6._kind_phys*ncf)**(2._kind_phys/3._kind_phys) + else if (ncf .gt. 1._kind_phys/6._kind_phys .and. ncf .lt. 1._kind_phys) then + phi = (acos(3._kind_phys*(1._kind_phys - ncf)/2._kind_phys**(3._kind_phys/2._kind_phys)) + 4._kind_phys*3.1415927_kind_phys)/3._kind_phys + icecldf(i, k) = (1._kind_phys - 4._kind_phys*cos(phi)*cos(phi)) + else + icecldf(i, k) = 1._kind_phys + end if + icecldf(i, k) = max(0._kind_phys, min(icecldf(i, k), 1._kind_phys)) + end if + !TEST: if ice present, icecldf=1. + ! if (cldice(i,k).ge.1.e-8_kind_phys) then + ! icecldf(i,k) = 0.99_kind_phys + ! endif + + !! if ((cldice(i,k) .gt. icicval) .or. ((cldice(i,k) .gt. 0._kind_phys) .and. (icecldf(i,k) .eq. 0._kind_phys))) then + ! if (cldice(i,k) .gt. 1.e-8_kind_phys) then + ! write(iulog,*) 'i,k,pmid,rho,t,cldice,icicval,icecldf,rhcloud: ', & + ! i,k,pmid(i,k),rho,temp(i,k),cldice(i,k),icicval,icecldf(i,k),rhcloud(i,k) + ! endif + + ! Combine ice and liquid cloud fraction assuming maximum overlap. + ! Combined cloud fraction is maximum overlap + ! cloud(i,k)=min(1._kind_phys,max(icecldf(i,k),rhcloud(i,k))) + + liqcldf(i, k) = (1._kind_phys - icecldf(i, k))*rhcloud(i, k) + cloud(i, k) = liqcldf(i, k) + icecldf(i, k) + else + ! For RK microphysics + cloud(i, k) = rhcloud(i, k) + end if + end do + end do + + ! + ! Add in the marine strat + ! MARINE STRATUS SHOULD BE A SPECIAL CASE OF LAYERED CLOUD + ! CLOUD CURRENTLY CONTAINS LAYERED CLOUD DETERMINED BY RH CRITERIA + ! TAKE THE MAXIMUM OF THE DIAGNOSED LAYERED CLOUD OR STRATOCUMULUS + ! + !=================================================================================== + ! + ! SOME OBSERVATIONS ABOUT THE FOLLOWING SECTION OF CODE (missed in earlier look) + ! K700 IS SET AS A CONSTANT BASED ON HYBRID COORDINATE: IT DOES NOT DEPEND ON + ! LOCAL PRESSURE; THERE IS NO PRESSURE RAMP => LOOKS LEVEL DEPENDENT AND + ! DISCONTINUOUS IN SPACE (I.E., STRATUS WILL END SUDDENLY WITH NO TRANSITION) + ! + ! IT APPEARS THAT STRAT IS EVALUATED ACCORDING TO KLEIN AND HARTMANN; HOWEVER, + ! THE ACTUAL STRATUS AMOUNT (CLDST) APPEARS TO DEPEND DIRECTLY ON THE RH BELOW + ! THE STRONGEST PART OF THE LOW LEVEL INVERSION. + !PJR answers: 1) the rh limitation is a physical/mathematical limitation + ! cant have more cloud than there is RH + ! allowed the cloud to exist two layers below the inversion + ! because the numerics frequently make 50% relative humidity + ! in level below the inversion which would allow no cloud + ! 2) since the cloud is only allowed over ocean, it should + ! be very insensitive to surface pressure (except due to + ! spectral ringing, which also causes so many other problems + ! I didnt worry about it. + ! + !================================================================================== + if (.not. inversion_cld_off) then + ! + ! Find most stable level below 750 mb for evaluating stratus regimes + ! + do i = 1, ncol + ! Nothing triggers unless a stability greater than this minimum threshold is found + dthdpmn(i) = -0.125_kind_phys + kdthdp(i) = 0 + end do + + do k = top_lev_cloudphys + 1, pver + do i = 1, ncol + if (pmid(i, k) >= premib .and. ocnfrac(i) .gt. 0.01_kind_phys) then + ! I think this is done so that dtheta/dp is in units of dg/mb (JJH) + dthdp = 100.0_kind_phys*(theta(i, k) - theta(i, k - 1))*rpdeli(i, k - 1) + if (dthdp < dthdpmn(i)) then + dthdpmn(i) = dthdp + kdthdp(i) = k ! index of interface of max inversion + end if + end if + end do + end do + + ! Also check between the bottom layer and the surface + ! Only perform this check if the criteria were not met above + do i = 1, ncol + if (kdthdp(i) .eq. 0 .and. ocnfrac(i) .gt. 0.01_kind_phys) then + dthdp = 100.0_kind_phys*(thetas(i) - theta(i, pver))/(ps(i) - pmid(i, pver)) + if (dthdp < dthdpmn(i)) then + dthdpmn(i) = dthdp + kdthdp(i) = pver ! index of interface of max inversion + end if + end if + end do + + do i = 1, ncol + if (kdthdp(i) /= 0) then + k = kdthdp(i) + kp1 = min(k + 1, pver) + ! Note: strat will be zero unless ocnfrac > 0.01 + strat = min(1._kind_phys, max(0._kind_phys, ocnfrac(i)*((theta(i, k700) - thetas(i))*.057_kind_phys - .5573_kind_phys))) + ! + ! assign the stratus to the layer just below max inversion + ! the relative humidity changes so rapidly across the inversion + ! that it is not safe to just look immediately below the inversion + ! so limit the stratus cloud by rh in both layers below the inversion + ! + cldst(i, k) = min(strat, max(rh(i, k), rh(i, kp1))) + end if + end do + end if ! .not.inversion_cld_off + + do k = top_lev_cloudphys, pver + do i = 1, ncol + ! which is greater; standard layered cloud amount or stratocumulus diagnosis + cloud(i, k) = max(rhcloud(i, k), cldst(i, k)) + + ! add in the contributions of convective cloud (determined separately and accounted + ! for by modifications to the large-scale relative humidity. + cloud(i, k) = min(cloud(i, k) + concld(i, k), 1.0_kind_phys) + end do + end do + + end subroutine compute_cloud_fraction_run +end module compute_cloud_fraction diff --git a/schemes/cloud_fraction/convective_cloud_cover.F90 b/schemes/cloud_fraction/convective_cloud_cover.F90 index 84166169..8b22640f 100644 --- a/schemes/cloud_fraction/convective_cloud_cover.F90 +++ b/schemes/cloud_fraction/convective_cloud_cover.F90 @@ -25,13 +25,18 @@ module convective_cloud_cover !> \section arg_table_convective_cloud_cover_init Argument Table !! \htmlinclude convective_cloud_cover_init.html - subroutine convective_cloud_cover_init(sh1_in, sh2_in, dp1_in, dp2_in, errmsg, errflg) - real(kind_phys), intent(in) :: sh1_in ! Shallow convection parameter 1 - real(kind_phys), intent(in) :: sh2_in ! Shallow convection parameter 2 - real(kind_phys), intent(in) :: dp1_in ! Deep convection parameter 1 - real(kind_phys), intent(in) :: dp2_in ! Deep convection parameter 2 + subroutine convective_cloud_cover_init( & + amIRoot, iulog, & + sh1_in, sh2_in, dp1_in, dp2_in, errmsg, errflg) + + logical, intent(in) :: amIRoot + integer, intent(in) :: iulog ! log output unit + real(kind_phys), intent(in) :: sh1_in ! Shallow convection parameter 1 + real(kind_phys), intent(in) :: sh2_in ! Shallow convection parameter 2 + real(kind_phys), intent(in) :: dp1_in ! Deep convection parameter 1 + real(kind_phys), intent(in) :: dp2_in ! Deep convection parameter 2 character(len=512), intent(out) :: errmsg - integer, intent(out) :: errflg + integer, intent(out) :: errflg errmsg = '' errflg = 0 @@ -42,9 +47,16 @@ subroutine convective_cloud_cover_init(sh1_in, sh2_in, dp1_in, dp2_in, errmsg, e dp1 = dp1_in dp2 = dp2_in + if(amIRoot) then + write(iulog,*) 'tuning parameters convective_cloud_cover: dp1',dp1,'dp2',dp2,'sh1',sh1,'sh2',sh2 + endif + end subroutine convective_cloud_cover_init ! Compute convective cloud cover (deep and shallow) + ! Should produce typical numbers of 20% + ! Shallow and deep convective cloudiness are evaluated separately and summed + ! because the processes are evaluated separately. !> \section arg_table_convective_cloud_cover_run Argument Table !! \htmlinclude convective_cloud_cover_run.html subroutine convective_cloud_cover_run( & @@ -52,7 +64,7 @@ subroutine convective_cloud_cover_run( & top_lev_cloudphys, & use_shfrc, shfrc, & cmfmc_total, cmfmc_sh, & - shallowcu, deepcu, & + shallowcu, deepcu, concld, & errmsg, errflg) ! Input arguments @@ -69,6 +81,7 @@ subroutine convective_cloud_cover_run( & ! Output arguments real(kind_phys), intent(out) :: shallowcu(:, :) ! Shallow convective cloud fraction [fraction] real(kind_phys), intent(out) :: deepcu(:, :) ! Deep convective cloud fraction [fraction] + real(kind_phys), intent(out) :: concld(:, :) ! Convective cloud cover [fraction] character(len=512), intent(out) :: errmsg integer, intent(out) :: errflg @@ -78,6 +91,7 @@ subroutine convective_cloud_cover_run( & errmsg = '' errflg = 0 + concld(:ncol, :) = 0.0_kind_phys do k = top_lev_cloudphys, pver do i = 1, ncol if (.not. use_shfrc) then @@ -97,6 +111,11 @@ subroutine convective_cloud_cover_run( & dp2 * (cmfmc_total(i, k + 1) - cmfmc_sh(i, k + 1)) & ), & 0.60_kind_phys)) + + ! Estimate of local convective cloud cover based on convective mass flux + ! Modify local large-scale relative humidity to account for presence of + ! convective cloud when evaluating relative humidity based layered cloud amount + concld(i, k) = min(shallowcu(i, k) + deepcu(i, k), 0.80_kind_phys) end do end do diff --git a/schemes/cloud_fraction/convective_cloud_cover.meta b/schemes/cloud_fraction/convective_cloud_cover.meta index 83b0f527..2c7b077b 100644 --- a/schemes/cloud_fraction/convective_cloud_cover.meta +++ b/schemes/cloud_fraction/convective_cloud_cover.meta @@ -64,13 +64,13 @@ dimensions = () intent = in [ use_shfrc ] - standard_name = flag_for_cloud_fraction_use_shallow_convection_calculated_clouds_tbd + standard_name = flag_for_cloud_area_fraction_to_use_shallow_convection_calculated_cloud_area_fraction units = flag type = logical dimensions = () intent = in [ shfrc ] - standard_name = convective_cloud_fraction_due_to_shallow_convection_tbd + standard_name = shallow_convective_cloud_area_fraction units = fraction type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) @@ -99,6 +99,12 @@ type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out +[ concld ] + standard_name = convective_cloud_area_fraction + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out [ errmsg ] standard_name = ccpp_error_message units = none From ad8c8946c0bc7c48c516f3c188df050204209f6c Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Fri, 28 Feb 2025 20:11:01 -0500 Subject: [PATCH 11/39] Cleanup compute_cloud_fraction; sketch out perturbation code --- .../cloud_fraction/compute_cloud_fraction.F90 | 10 +- .../compute_cloud_fraction.meta | 310 ++++++++++++++++++ .../compute_cloud_fraction_namelist.xml | 148 +++++++++ .../convective_cloud_cover.meta | 4 +- schemes/rasch_kristjansson/rk_stratiform.F90 | 128 +++++++- test/test_suites/suite_rasch_kristjansson.xml | 12 +- 6 files changed, 600 insertions(+), 12 deletions(-) create mode 100644 schemes/cloud_fraction/compute_cloud_fraction.meta create mode 100644 schemes/cloud_fraction/compute_cloud_fraction_namelist.xml diff --git a/schemes/cloud_fraction/compute_cloud_fraction.F90 b/schemes/cloud_fraction/compute_cloud_fraction.F90 index 44b2ff61..f4c5b371 100644 --- a/schemes/cloud_fraction/compute_cloud_fraction.F90 +++ b/schemes/cloud_fraction/compute_cloud_fraction.F90 @@ -32,6 +32,8 @@ module compute_cloud_fraction contains ! Initialize cloud_fraction from namelist parameters +!> \section arg_table_compute_cloud_fraction_init Argument Table +!! \htmlinclude compute_cloud_fraction_init.html subroutine compute_cloud_fraction_init( & amIRoot, iulog, & pver, & @@ -133,7 +135,7 @@ subroutine compute_cloud_fraction_run( & shallowcu, deepcu, concld, & ! convective cloud cover landfrac, ocnfrac, snowh, & rhpert_flag, & ! todo: decide what to do with this - cloud, rhcloud, clc, & + cloud, rhcloud, & cldst, & rhu00, icecldf, liqcldf, relhum, & errmsg, errflg) @@ -165,12 +167,11 @@ subroutine compute_cloud_fraction_run( & logical, intent(in) :: rhpert_flag ! 0 or 1 to perturb rh ! Output arguments - real(kind_phys), intent(out) :: cloud(:, :) ! cloud fraction + real(kind_phys), intent(out) :: cloud(:, :) ! cloud_area_fraction [fraction] real(kind_phys), intent(out) :: rhcloud(:, :) ! cloud fraction - real(kind_phys), intent(out) :: clc(:) ! column convective cloud amount real(kind_phys), intent(out) :: cldst(:, :) ! stratiform_cloud_area_fraction [fraction] real(kind_phys), intent(out) :: rhu00(:, :) ! RH threshold for cloud - real(kind_phys), intent(out) :: relhum(:, :) ! RH + real(kind_phys), intent(out) :: relhum(:, :) ! RH for prognostic cldwat [percent] real(kind_phys), intent(out) :: icecldf(:, :) ! ice cloud fraction real(kind_phys), intent(out) :: liqcldf(:, :) ! liquid cloud fraction (combined into cloud) character(len=512), intent(out) :: errmsg ! error message @@ -300,7 +301,6 @@ subroutine compute_cloud_fraction_run( & if (ocnfrac(i) .gt. 0.01_kind_phys) thetas(i) = & (sst(i) - lapse*phis(i)/gravit)*(pnot/ps(i))**cappa if (ocnfrac(i) .gt. 0.01_kind_phys .and. sst(i) .lt. 260._kind_phys) ierror = i - clc(i) = 0.0_kind_phys end do coef1 = gravit*864.0_kind_phys ! conversion to millibars/day diff --git a/schemes/cloud_fraction/compute_cloud_fraction.meta b/schemes/cloud_fraction/compute_cloud_fraction.meta new file mode 100644 index 00000000..665786bb --- /dev/null +++ b/schemes/cloud_fraction/compute_cloud_fraction.meta @@ -0,0 +1,310 @@ +[ccpp-table-properties] + name = compute_cloud_fraction + type = scheme + dependencies = ../../to_be_ccppized/wv_saturation.F90 + +[ccpp-arg-table] + name = compute_cloud_fraction_init + type = scheme +[ amIRoot ] + standard_name = flag_for_mpi_root + units = flag + type = logical + dimensions = () + intent = in +[ iulog ] + standard_name = log_output_unit + units = 1 + type = integer + dimensions = () + intent = in +[ pver ] + standard_name = vertical_layer_dimension + units = count + type = integer + dimensions = () + intent = in +[ pref_mid ] + standard_name = reference_pressure_in_atmosphere_layer + units = Pa + type = real | kind = kind_phys + dimensions = (vertical_layer_dimension) + intent = in +[ inversion_cld_off_in ] + standard_name = flag_for_turning_off_stratification_based_for_cloud_fraction + units = flag + type = logical + dimensions = () + intent = in +[ cldfrc_freeze_dry_in ] + standard_name = flag_for_vavrus_freeze_dry_adjustment_for_cloud_fraction + units = flag + type = logical + dimensions = () + intent = in +[ cldfrc_ice_in ] + standard_name = flag_for_ice_cloud_fraction_for_cloud_fraction + units = flag + type = logical + dimensions = () + intent = in +[ iceopt_in ] + standard_name = scheme_for_ice_cloud_fraction + units = 1 + type = integer + dimensions = () + intent = in +[ rhminl_in ] + standard_name = tunable_parameter_for_minimum_relative_humidity_for_low_stable_clouds_for_cloud_fraction + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ rhminl_adj_land_in ] + standard_name = tunable_parameter_for_adjustment_to_minimum_relative_humidity_for_low_stable_clouds_for_land_without_snow_cover_for_cloud_fraction + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ rhminh_in ] + standard_name = tunable_parameter_for_minimum_relative_humidity_for_high_stable_clouds_for_cloud_fraction + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ premit_in ] + standard_name = tunable_parameter_for_top_pressure_bound_for_mid_level_clouds_for_cloud_fraction + units = Pa + type = real | kind = kind_phys + dimensions = () + intent = in +[ premib_in ] + standard_name = tunable_parameter_for_bottom_pressure_bound_for_mid_level_liquid_stratus_for_cloud_fraction + units = Pa + type = real | kind = kind_phys + dimensions = () + intent = in +[ icecrit_in ] + standard_name = scheme_for_ice_cloud_fraction + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out + +[ccpp-arg-table] + name = compute_cloud_fraction_timestep_init + type = scheme +[ rhpert_flag ] + standard_name = flag_for_relative_humidity_perturbation_for_cloud_fraction + units = flag + type = logical + dimensions = () + intent = out +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out + +[ccpp-arg-table] + name = compute_cloud_fraction_run + type = scheme +[ 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 +[ cappa ] + 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 +[ 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 +[ tmelt ] + standard_name = freezing_point_of_water + units = K + type = real | kind = kind_phys + dimensions = () + intent = in +[ top_lev_cloudphys ] + standard_name = vertical_layer_index_of_cloud_fraction_top + units = index + type = integer + dimensions = () + intent = in +[ pmid ] + standard_name = air_pressure + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ ps ] + standard_name = surface_air_pressure + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ temp ] + standard_name = air_temperature + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ sst ] + standard_name = sea_surface_temperature + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ q ] + standard_name = water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ cldice ] + standard_name = cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ phis ] + standard_name = surface_geopotential + units = m2 s-2 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ shallowcu ] + standard_name = shallow_convective_cloud_area_fraction_tbd + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ deepcu ] + standard_name = deep_convective_cloud_area_fraction_tbd + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ concld ] + standard_name = convective_cloud_area_fraction + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ landfrac ] + standard_name = land_area_fraction + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ ocnfrac ] + standard_name = ocean_area_fraction + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ snowh ] + standard_name = lwe_surface_snow_depth_over_land + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ rhpert_flag ] + standard_name = flag_for_relative_humidity_perturbation_for_cloud_fraction + units = flag + type = logical + dimensions = () + intent = in +[ cloud ] + standard_name = cloud_area_fraction + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ rhcloud ] + standard_name = cloud_area_fraction_from_relative_humidity_method_tbd + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ cldst ] + standard_name = stratiform_cloud_area_fraction + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ rhu00 ] + standard_name = relative_humidity_threshold_for_prognostic_cloud_water_tbd + units = percent + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ icecldf ] + standard_name = stratiform_cloud_ice_area_fraction + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ liqcldf ] + standard_name = stratiform_cloud_liquid_area_fraction + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ relhum ] + standard_name = relative_humidity_for_prognostic_cloud_water_tbd + units = percent + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out diff --git a/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml b/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml new file mode 100644 index 00000000..2a843553 --- /dev/null +++ b/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml @@ -0,0 +1,148 @@ + + + + + + + logical + cldfrc + cldfrc_nl + flag_for_vavrus_freeze_dry_adjustment_for_cloud_fraction + flag + + Turn on for Vavrus "freeze dry" adjustment in cloud fraction. + Default: TRUE + + + true + + + + logical + cldfrc + cldfrc_nl + flag_for_ice_cloud_fraction_for_cloud_fraction + flag + + Turn on ice cloud fraction calculation + Default: TRUE (CAM5 and CAM6) or FALSE + + + false + + + + logical + cldfrc + cldfrc_nl + flag_for_turning_off_stratification_based_for_cloud_fraction + flag + + Turn off stratification-based cloud fraction + Default: FALSE + + + false + + + + + real + cldfrc + cldfrc_nl + tunable_parameter_for_minimum_relative_humidity_for_low_stable_clouds_for_cloud_fraction + 1 + + Minimum rh for low stable clouds. + + + 0.900D0 + + + + real + cldfrc + cldfrc_nl + tunable_parameter_for_adjustment_to_minimum_relative_humidity_for_low_stable_clouds_for_land_without_snow_cover_for_cloud_fraction + 1 + + Adjustment to rhminl for land without snow cover. + Default: 0.0 for CAM6, CAM7; 0.10 for all others + + + 0.1D0 + + + + real + cldfrc + cldfrc_nl + tunable_parameter_for_minimum_relative_humidity_for_high_stable_clouds_for_cloud_fraction + 1 + + Minimum rh for high stable clouds. + + + 0.800D0 + + + + real + cldfrc + cldfrc_nl + tunable_parameter_for_top_pressure_bound_for_mid_level_clouds_for_cloud_fraction + Pa + + Top pressure bound for mid level cloud. + + + 75000.0D0 + 40000.0D0 + 40000.0D0 + + + + real + cldfrc + cldfrc_nl + tunable_parameter_for_bottom_pressure_bound_for_mid_level_liquid_stratus_for_cloud_fraction + Pa + + Bottom height for mid-level liquid stratus fraction. + + + 750.0D2 + + + + integer + cldfrc + cldfrc_nl + scheme_for_ice_cloud_fraction + 1 + + Scheme for ice cloud fraction. + 1 = Wang and Sassen + 2 = Schiller (iciwc) + 3 = Wood and Field + 4 = Wilson (based on Smith) + 5 = modified Slingo (ssat and empty cloud) + + + 5 + + + + real + cldfrc + cldfrc_nl + tunable_parameter_for_critical_relative_humidity_for_ice_clouds_for_cloud_fraction_using_wilson_from_ballard_scheme + 1 + + Critical RH for ice clouds using the Wilson and Ballard scheme + + + 0.95D0 + + + diff --git a/schemes/cloud_fraction/convective_cloud_cover.meta b/schemes/cloud_fraction/convective_cloud_cover.meta index 2c7b077b..9887fc2a 100644 --- a/schemes/cloud_fraction/convective_cloud_cover.meta +++ b/schemes/cloud_fraction/convective_cloud_cover.meta @@ -58,7 +58,7 @@ dimensions = () intent = in [ top_lev_cloudphys ] - standard_name = vertical_layer_index_of_cloud_physics_top_tbd + standard_name = vertical_layer_index_of_cloud_fraction_top units = index type = integer dimensions = () @@ -94,7 +94,7 @@ dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out [ deepcu ] - standard_name = shallow_convective_cloud_area_fraction_tbd + standard_name = deep_convective_cloud_area_fraction_tbd units = fraction type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) diff --git a/schemes/rasch_kristjansson/rk_stratiform.F90 b/schemes/rasch_kristjansson/rk_stratiform.F90 index 8622613b..f01be544 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.F90 +++ b/schemes/rasch_kristjansson/rk_stratiform.F90 @@ -11,11 +11,14 @@ module rk_stratiform save ! public CCPP-compliant subroutines + ! note: cloud_fraction_perturbation_run is NOT a fully CCPP-compliant scheme + ! because it calls the compute_cloud_fraction scheme for perturbation. + ! this is currently not possible to elegantly handle in the framework. public :: rk_stratiform_init public :: rk_stratiform_timestep_init public :: rk_stratiform_sedimentation_run public :: rk_stratiform_detrain_convective_condensate_run - ! public :: rk_stratiform_cloud_fractions_run + public :: rk_stratiform_cloud_fraction_perturbation_run ! see note. ! public :: rk_stratiform_microphysics_run public :: rk_stratiform_prognostic_cloud_water_tendencies_run ! public :: rk_stratiform_ice_and_liquid_water_content_run @@ -124,6 +127,129 @@ subroutine rk_stratiform_detrain_convective_condensate_run( & end subroutine rk_stratiform_detrain_convective_condensate_run + ! Call perturbed cloud fraction and compute perturbation threshold criteria + ! necessary for prognostic_cloud_water scheme + subroutine rk_stratiform_cloud_fraction_perturbation_run( & + ncol, pver, & + cappa, gravit, rair, tmelt, & + top_lev_cloudphys, & + pmid, ps, temp, sst, & + q_wv, cldice, & + phis, & + shallowcu, deepcu, concld, & ! inputs from convective_cloud_cover + landfrac, ocnfrac, snowh, & + cloud, relhum, & ! inputs from unperturbed compute_cloud_fraction + rhdfda, & ! output for prognostic_cloud_water + errmsg, errflg) + + ! WARN: This is NOT CCPP-compliant! + use compute_cloud_fraction, only: compute_cloud_fraction_run + + ! Input arguments + integer, intent(in) :: ncol + integer, intent(in) :: pver + real(kind_phys), intent(in) :: cappa + real(kind_phys), intent(in) :: gravit + real(kind_phys), intent(in) :: rair + real(kind_phys), intent(in) :: tmelt + integer, intent(in) :: top_lev_cloudphys ! vertical_layer_index_of_cloud_fraction_top [index] + real(kind_phys), intent(in) :: pmid(:, :) ! air_pressure [Pa] + real(kind_phys), intent(in) :: ps(:) ! surface_air_pressure [Pa] + real(kind_phys), intent(in) :: temp(:, :) ! air_temperature [K] + real(kind_phys), intent(in) :: sst(:) ! sea_surface_temperature [K] + real(kind_phys), intent(in) :: q_wv(:, :) ! water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + real(kind_phys), intent(in) :: cldice(:, :) ! cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + real(kind_phys), intent(in) :: phis(:) ! surface_geopotential [m2 s-2] + real(kind_phys), intent(in) :: shallowcu(:, :) ! shallow convective cloud fraction + real(kind_phys), intent(in) :: deepcu(:, :) ! deep convective cloud fraction + real(kind_phys), intent(in) :: concld(:, :) ! convective_cloud_area_fraction [fraction] + real(kind_phys), intent(in) :: landfrac(:) ! land_area_fraction [fraction] + real(kind_phys), intent(in) :: ocnfrac(:) ! ocean_area_fraction [fraction] + real(kind_phys), intent(in) :: snowh(:) ! lwe_surface_snow_depth_over_land [m] + + real(kind_phys), intent(in) :: cloud(:, :) ! cloud_area_fraction [fraction] + real(kind_phys), intent(in) :: relhum(:, :) ! RH for prognostic cldwat [percent] + + ! Input/output arguments + ! Note: CAM4 intentionally mutates the top level of rhu00 so this is inout here. + real(kind_phys), intent(inout) :: rhu00(:, :) ! RH threshold for cloud + + ! Output arguments + real(kind_phys), intent(out) :: rhdfda(:, :) ! derivative of RH w.r.t. cloud fraction for prognostic cloud water [percent] + character(len=512), intent(out) :: errmsg ! error message + integer, intent(out) :: errflg ! error flag + + ! Local variables (outputs from perturbed compute_cloud_fraction) + real(kind_phys) :: cloud2(ncol, pver) + + ! Dummy outputs (unused) + real(kind_phys) :: rhcloud2(ncol, pver) + real(kind_phys) :: cldst2(ncol, pver) + real(kind_phys) :: rhu002(ncol, pver) + real(kind_phys) :: icecldf2(ncol, pver) + real(kind_phys) :: liqcldf2(ncol, pver) + real(kind_phys) :: relhum2(ncol, pver) + + errmsg = '' + errflg = 0 + + ! Call perturbed version of compute_cloud_fraction + ! WARN: This is NOT CCPP-compliant! + call compute_cloud_fraction_run( & + ncol = ncol, & + pver = pver, & + cappa = cappa, & + gravit = gravit, & + rair = rair, & + tmelt = tmelt, & + top_lev_cloudphys = top_lev_cloudphys, & ! CAM4 macrophysics - top lev is 1 + pmid = pmid(:ncol,:), & + ps = ps(:ncol), & + temp = t(:ncol,:), & + sst = sst(:ncol), & + q = q_wv(:ncol,:), & + cldice = cldice(:ncol,:), & + phis = phis(:ncol), & + shallowcu = shallowcu(:ncol,:), & + deepcu = deepcu(:ncol,:), & + concld = concld(:ncol,:), & + landfrac = landfrac(:ncol), & + ocnfrac = ocnfrac(:ncol), & + snowh = snowh(:ncol), & + rhpert_flag = .true., & ! ** apply perturbation here ** + cloud = cloud2(:ncol, :), & + rhcloud = rhcloud2(:ncol, :), & + cldst = cldst2(:ncol,:), & + rhu00 = rhu002(:ncol,:), & + icecldf = icecldf2(:ncol,:), & + liqcldf = liqcldf2(:ncol,:), & + relhum = relhum2(:ncol,:), & + errmsg = errmsg, & + errflg = errflg) + + ! Compute rhdfda (derivative of RH w.r.t. cloud fraction) + ! for use in the prognostic_cloud_water scheme. + rhu00(:ncol,1) = 2.0_kind_phys + do k = 1, pver + do i = 1, ncol + if( relhum(i,k) < rhu00(i,k) ) then + rhdfda(i,k) = 0.0_kind_phys + elseif( relhum(i,k) >= 1.0_kind_phys ) then + rhdfda(i,k) = 0.0_kind_phys + else + ! Under certain circumstances, rh+ cause cld not to changed + ! when at an upper limit, or w/ strong subsidence + if( ( cloud2(i,k) - cloud(i,k) ) < 1.e-4_kind_phys ) then + rhdfda(i,k) = 0.01_kind_phys*relhum(i,k)*1.e+4_kind_phys + else + rhdfda(i,k) = 0.01_kind_phys*relhum(i,k)/(cloud2(i,k)-cloud(i,k)) + endif + endif + enddo + enddo + + end subroutine rk_stratiform_cloud_fraction_perturbation_run + ! Determine tendencies from prognostic cloud water subroutine rk_stratiform_prognostic_cloud_water_tendencies_run( & ncol, pver, & diff --git a/test/test_suites/suite_rasch_kristjansson.xml b/test/test_suites/suite_rasch_kristjansson.xml index 92898876..707ec5d5 100644 --- a/test/test_suites/suite_rasch_kristjansson.xml +++ b/test/test_suites/suite_rasch_kristjansson.xml @@ -18,13 +18,15 @@ rk_stratiform_detrain_convective_condensate - + compute_cloud_fraction + rk_stratiform_cloud_fraction_perturbation_run cldfrc_fice @@ -47,6 +49,8 @@ geopotential_temp + compute_cloud_fraction + From 59314ae93c8687c2ded7ba9ff7f5d37c4d1543c1 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Fri, 28 Feb 2025 21:44:14 -0500 Subject: [PATCH 12/39] Further sketch out RK parts near prognostic_cloud_water --- .../cloud_fraction/compute_cloud_fraction.F90 | 5 + .../prognostic_cloud_water.F90 | 10 +- .../prognostic_cloud_water.meta | 6 +- schemes/rasch_kristjansson/rk_stratiform.F90 | 109 ++++++++++++++++-- test/test_suites/suite_rasch_kristjansson.xml | 23 ++-- 5 files changed, 128 insertions(+), 25 deletions(-) diff --git a/schemes/cloud_fraction/compute_cloud_fraction.F90 b/schemes/cloud_fraction/compute_cloud_fraction.F90 index f4c5b371..f9c22bc0 100644 --- a/schemes/cloud_fraction/compute_cloud_fraction.F90 +++ b/schemes/cloud_fraction/compute_cloud_fraction.F90 @@ -1,3 +1,8 @@ +! Copyright (C) 2025 National Science Foundation-National Center for Atmospheric Research +! SPDX-License-Identifier: Apache-2.0 +! +! Compute cloud fractions using RH threshold and other methods. +! CCPP-ized: Haipeng Lin, February 2025 module compute_cloud_fraction use ccpp_kinds, only: kind_phys private diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 index 1a666ca1..bda12388 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 @@ -231,7 +231,7 @@ subroutine prognostic_cloud_water_run( & troplev, & ttend, tn, & qtend, qn, & - lctend, cwat, & + ltend, cwat, & omega, & cldn, & fice, fsnow, & @@ -270,11 +270,11 @@ subroutine prognostic_cloud_water_run( & real(kind_phys), intent(in) :: zi(:,:) ! geopotential_height_wrt_surface_at_interface [m] integer, intent(in) :: tropLev(:) ! tropopause_vertical_layer_index [index] - real(kind_phys), intent(in) :: ttend(:,:) ! Temperature tendency [K s-1] -- from what...? + real(kind_phys), intent(in) :: ttend(:,:) ! Temperature tendency [K s-1] -- from non-micro/macrophysics real(kind_phys), intent(in) :: tn(:,:) ! New Temperature [K] - real(kind_phys), intent(in) :: qtend(:,:) ! Water vapor tendency [kg kg-1 s-1] -- from what...? + real(kind_phys), intent(in) :: qtend(:,:) ! Water vapor tendency [kg kg-1 s-1] -- from non-micro/macrophysics real(kind_phys), intent(in) :: qn(:,:) ! New Water vapor mixing ratio [kg kg-1] - real(kind_phys), intent(in) :: lctend(:,:) ! Cloud liquid water tendency [kg kg-1 s-1] -- from what...? + real(kind_phys), intent(in) :: ltend(:,:) ! Cloud liquid water tendency [kg kg-1 s-1] -- from non-micro/macrophysics real(kind_phys), intent(in) :: cwat(:,:) ! Cloud water mixing ratio (ixcldice+ixcldliq) [kg kg-1] real(kind_phys), intent(in) :: omega(:,:) ! lagrangian_tendency_of_air_pressure [Pa s-1] @@ -539,7 +539,7 @@ subroutine prognostic_cloud_water_run( & qmec4(i) = csigma(i)*cgamma(i)*icwc(i) ! Q = C-E = -C1*Al + C2*Aq - C3*At + C4*Er - qme(i,k) = -qmec1(i)*lctend(i,k) + qmec2(i)*qtend(i,k) & + qme(i,k) = -qmec1(i)*ltend(i,k) + qmec2(i)*qtend(i,k) & -qmec3(i)*ttend(i,k) + qmec4(i)*evapprec(i,k) endif ! 3. when rh < rhu00, evaporate existing cloud water diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.meta b/schemes/rasch_kristjansson/prognostic_cloud_water.meta index a1ca174c..27219e3a 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.meta +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.meta @@ -208,7 +208,7 @@ dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in [ qtend ] - standard_name = tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water_not_due_to_microphysics? + standard_name = tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water_not_due_to_microphysics_tbd units = kg kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) @@ -219,8 +219,8 @@ type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in -[ lctend ] - standard_name = tendency_of_cloud_water_mixing_ratio_wrt_moist_air_and_condensed_water_not_due_to_microphysics? +[ ltend ] + standard_name = tendency_of_cloud_water_mixing_ratio_wrt_moist_air_and_condensed_water_not_due_to_microphysics_tbd units = kg kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) diff --git a/schemes/rasch_kristjansson/rk_stratiform.F90 b/schemes/rasch_kristjansson/rk_stratiform.F90 index f01be544..a325a1aa 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.F90 +++ b/schemes/rasch_kristjansson/rk_stratiform.F90 @@ -14,26 +14,24 @@ module rk_stratiform ! note: cloud_fraction_perturbation_run is NOT a fully CCPP-compliant scheme ! because it calls the compute_cloud_fraction scheme for perturbation. ! this is currently not possible to elegantly handle in the framework. + ! + ! refer to test SDF suite_rasch_kristjansson.xml for total order of operations, + ! as the full RK-stratiform requires other schemes not included in this module. public :: rk_stratiform_init public :: rk_stratiform_timestep_init public :: rk_stratiform_sedimentation_run public :: rk_stratiform_detrain_convective_condensate_run public :: rk_stratiform_cloud_fraction_perturbation_run ! see note. ! public :: rk_stratiform_microphysics_run + public :: rk_stratiform_condensate_repartioning_run + public :: rk_stratiform_external_forcings_run + ! -- prognostic_cloud_water -- public :: rk_stratiform_prognostic_cloud_water_tendencies_run - ! public :: rk_stratiform_ice_and_liquid_water_content_run ! public :: rk_stratiform_cloud_optical_properties_run ! public :: rk_stratiform_save_qtlcwat_run ! - ! temp: convect_shallow_use_shfrc() is not available so set it to - ! false for now. it is used for UW and UNICON shallow convection schemes - ! but is unavailable in the pbuf anyway... - logical :: use_shfrc = .false. - - - contains ! Initialize rk_stratiform @@ -157,8 +155,8 @@ subroutine rk_stratiform_cloud_fraction_perturbation_run( & real(kind_phys), intent(in) :: ps(:) ! surface_air_pressure [Pa] real(kind_phys), intent(in) :: temp(:, :) ! air_temperature [K] real(kind_phys), intent(in) :: sst(:) ! sea_surface_temperature [K] - real(kind_phys), intent(in) :: q_wv(:, :) ! water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] - real(kind_phys), intent(in) :: cldice(:, :) ! cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + real(kind_phys), intent(in) :: q_wv(:, :) ! adv: water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + real(kind_phys), intent(in) :: cldice(:, :) ! adv: cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] real(kind_phys), intent(in) :: phis(:) ! surface_geopotential [m2 s-2] real(kind_phys), intent(in) :: shallowcu(:, :) ! shallow convective cloud fraction real(kind_phys), intent(in) :: deepcu(:, :) ! deep convective cloud fraction @@ -250,6 +248,97 @@ subroutine rk_stratiform_cloud_fraction_perturbation_run( & end subroutine rk_stratiform_cloud_fraction_perturbation_run + ! Repartitioning of stratiform condensate, + ! and compute repartition heating from change in cloud ice + subroutine rk_stratiform_condensate_repartioning_run( & + ncol, pver, & + dtime, & + latice, & + cldice, cldliq, & + fice, & ! from cloud_fraction_fice + repartht, & + tend_cldice, & + tend_cldliq, & + errmsg, errflg) + + ! Input arguments + integer, intent(in) :: ncol + integer, intent(in) :: pver + real(kind_phys), intent(in) :: dtime + real(kind_phys), intent(in) :: latice + real(kind_phys), intent(in) :: cldliq(:,:) ! adv: cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + real(kind_phys), intent(in) :: cldice(:,:) ! adv: cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + real(kind_phys), intent(in) :: fice(:,:) ! mass_fraction_of_ice_content_within_stratiform_cloud [fraction] + + ! Input/output arguments + real(kind_phys), intent(inout) :: repartht(:,:) ! [J kg-1 s-1] + + ! Output arguments + real(kind_phys), intent(out) :: tend_cldice(:,:) ! tendency_of_cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1 s-1] + real(kind_phys), intent(out) :: tend_cldliq(:,:) ! tendency_of_cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1 s-1] + character(len=512), intent(out) :: errmsg ! error message + integer, intent(out) :: errflg ! error flag + + ! Local arguments + real(kind_phys) :: totcw(ncol, pver) + + errmsg = '' + errflg = 0 + + totcw(:ncol,:) = cldice(:ncol,:) + cldliq(:ncol,:) + tend_cldice(:ncol,:) = 1.0_kind_phys / dtime * ( totcw(:ncol,:)*fice(:ncol,:) - cldice(:ncol,:) ) + tend_cldliq(:ncol,:) = 1.0_kind_phys / dtime * ( totcw(:ncol,:)*(1.0_kind_phys-fice(:ncol,:)) - cldliq(:ncol,:) ) + + repartht(:ncol,:pver) = latice * tend_cldice(:ncol,:pver) + + end subroutine rk_stratiform_condensate_repartioning_run + + ! Compute non-micro and non-macrophysical external forcings + ! for computing of net condensation rate. + ! Note: advective forcing of condensate is aggregated into liquid phase. + subroutine rk_stratiform_external_forcings_run( & + ncol, pver, & + dtime, & + t, & + q_wv, cldice, cldliq, & + qcwat, tcwat, lcwat, & ! ? + qtend, ttend, ltend, & ! output for prognostic_cloud_water + errmsg, errflg) + + ! Input arguments + integer, intent(in) :: ncol + integer, intent(in) :: pver + real(kind_phys), intent(in) :: dtime + real(kind_phys), intent(in) :: t(:,:) ! air_temperature [K] + real(kind_phys), intent(in) :: q_wv(:,:) ! adv: water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + real(kind_phys), intent(in) :: cldice(:,:) ! adv: cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + real(kind_phys), intent(in) :: cldliq(:,:) ! adv: cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + + real(kind_phys), intent(in) :: qcwat(:,:) ! [kg kg-1] + real(kind_phys), intent(in) :: tcwat(:,:) ! [K] + real(kind_phys), intent(in) :: lcwat(:,:) ! [kg kg-1] + + ! Output arguments (for prognostic_cloud_water) + real(kind_phys), intent(in) :: qtend(:,:) ! not due to micro/macrophysics [kg kg-1 s-1] + real(kind_phys), intent(in) :: ttend(:,:) ! not due to micro/macrophysics [K s-1] + real(kind_phys), intent(in) :: ltend(:,:) ! not due to micro/macrophysics [kg kg-1 s-1] + character(len=512), intent(out) :: errmsg ! error message + integer, intent(out) :: errflg ! error flag + + ! Local arguments + real(kind_phys) :: totcw(ncol, pver) + + errmsg = '' + errflg = 0 + + totcw(:ncol,:) = cldice(:ncol,:) + cldliq(:ncol,:) + + qtend(:ncol,:pver) = (q_wv (:ncol,:) - qcwat(:ncol,:)) / dtime + ttend(:ncol,:pver) = (t (:ncol,:) - tcwat(:ncol,:)) / dtime + ltend(:ncol,:pver) = (totcw (:ncol,:) - lcwat(:ncol,:)) / dtime + + end subroutine rk_stratiform_external_forcings_run + ! Determine tendencies from prognostic cloud water subroutine rk_stratiform_prognostic_cloud_water_tendencies_run( & ncol, pver, & diff --git a/test/test_suites/suite_rasch_kristjansson.xml b/test/test_suites/suite_rasch_kristjansson.xml index 707ec5d5..97c17ba3 100644 --- a/test/test_suites/suite_rasch_kristjansson.xml +++ b/test/test_suites/suite_rasch_kristjansson.xml @@ -17,7 +17,7 @@ rk_stratiform_detrain_convective_condensate - + cldfrc_fice - + + + + prognostic_cloud_water rk_stratiform_prognostic_cloud_water_tendencies + compute_cloud_fraction - + - + From 75026a1a9820cb303261f193ffe02cc07aa58250 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 3 Mar 2025 15:08:44 -0500 Subject: [PATCH 13/39] Update relative importance variables out from prognostic_cloud_water (pcond) --- .../prognostic_cloud_water.F90 | 13 ++++---- .../prognostic_cloud_water.meta | 30 +++++++++++++++++++ schemes/rasch_kristjansson/rk_stratiform.F90 | 13 ++++---- 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 index bda12388..a1b93038 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 @@ -246,6 +246,7 @@ subroutine prognostic_cloud_water_run( & lsflxprc, & lsflxsnw, & pracwo, psacwo, psacio, & + fwaut, fsaut, fracw, fsacw, fsaci, & errmsg, errflg) ! Dependencies to-be-ccppized. use wv_saturation, only: qsat, estblf, svp_to_qsat, findsp_vc @@ -309,6 +310,11 @@ subroutine prognostic_cloud_water_run( & real(kind_phys), intent(out) :: pracwo(:,:) ! accretion of cloud water by rain [s-1] real(kind_phys), intent(out) :: psacwo(:,:) ! accretion of cloud water by snow [s-1] real(kind_phys), intent(out) :: psacio(:,:) ! accretion of cloud ice by snow [s-1] + real(kind_phys), intent(out) :: fwaut(ncol,pver) ! Relative importance of liquid autoconversion [fraction] + real(kind_phys), intent(out) :: fsaut(ncol,pver) ! Relative importance of ice autoconversion [fraction] + real(kind_phys), intent(out) :: fracw(ncol,pver) ! Relative importance of liquid collection by rain [fraction] + real(kind_phys), intent(out) :: fsacw(ncol,pver) ! Relative importance of liquid collection by snow [fraction] + real(kind_phys), intent(out) :: fsaci(ncol,pver) ! Relative importance of ice collection by snow [fraction] ! Output arguments character(len=512), intent(out) :: errmsg ! error message @@ -336,13 +342,6 @@ subroutine prognostic_cloud_water_run( & !real(kind_phys) :: ice(ncol,pver) ! Ice mixing ratio [kg kg-1] !real(kind_phys) :: liq(ncol,pver) ! Liquid water mixing ratio [kg kg-1] - ! Relative importance factors - real(kind_phys) :: fracw(ncol,pver) ! Relative importance of liquid collection by rain [1] - real(kind_phys) :: fsaci(ncol,pver) ! Relative importance of ice collection by snow [1] - real(kind_phys) :: fsacw(ncol,pver) ! Relative importance of liquid collection by snow [1] - real(kind_phys) :: fsaut(ncol,pver) ! Relative importance of ice autoconversion [1] - real(kind_phys) :: fwaut(ncol,pver) ! Relative importance of warm cloud autoconversion [1] - ! Thermodynamic variables real(kind_phys) :: t(ncol,pver) ! Temperature before timestep [K] real(kind_phys) :: tsp(ncol,pver) ! Saturation point temperature [K] diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.meta b/schemes/rasch_kristjansson/prognostic_cloud_water.meta index 27219e3a..6432d964 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.meta +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.meta @@ -393,6 +393,36 @@ type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out +[ fwaut ] + standard_name = relative_importance_of_liquid_autoconversion_tbd + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ fsaut ] + standard_name = relative_importance_of_ice_autoconversion_tbd + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ fracw ] + standard_name = relative_importance_of_rain_axcreting_liquid_tbd + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ fsacw ] + standard_name = relative_importance_of_snow_accreting_liquid_tbd + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ fsaci ] + standard_name = relative_importance_of_snow_accreting_ice_tbd + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out [ errmsg ] standard_name = ccpp_error_message units = none diff --git a/schemes/rasch_kristjansson/rk_stratiform.F90 b/schemes/rasch_kristjansson/rk_stratiform.F90 index a325a1aa..a246ed8a 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.F90 +++ b/schemes/rasch_kristjansson/rk_stratiform.F90 @@ -136,7 +136,7 @@ subroutine rk_stratiform_cloud_fraction_perturbation_run( & phis, & shallowcu, deepcu, concld, & ! inputs from convective_cloud_cover landfrac, ocnfrac, snowh, & - cloud, relhum, & ! inputs from unperturbed compute_cloud_fraction + cloud, relhum, rhu00, & ! inputs from unperturbed compute_cloud_fraction rhdfda, & ! output for prognostic_cloud_water errmsg, errflg) @@ -177,6 +177,9 @@ subroutine rk_stratiform_cloud_fraction_perturbation_run( & character(len=512), intent(out) :: errmsg ! error message integer, intent(out) :: errflg ! error flag + ! Local variables + integer :: i, k + ! Local variables (outputs from perturbed compute_cloud_fraction) real(kind_phys) :: cloud2(ncol, pver) @@ -203,7 +206,7 @@ subroutine rk_stratiform_cloud_fraction_perturbation_run( & top_lev_cloudphys = top_lev_cloudphys, & ! CAM4 macrophysics - top lev is 1 pmid = pmid(:ncol,:), & ps = ps(:ncol), & - temp = t(:ncol,:), & + temp = temp(:ncol,:), & sst = sst(:ncol), & q = q_wv(:ncol,:), & cldice = cldice(:ncol,:), & @@ -319,9 +322,9 @@ subroutine rk_stratiform_external_forcings_run( & real(kind_phys), intent(in) :: lcwat(:,:) ! [kg kg-1] ! Output arguments (for prognostic_cloud_water) - real(kind_phys), intent(in) :: qtend(:,:) ! not due to micro/macrophysics [kg kg-1 s-1] - real(kind_phys), intent(in) :: ttend(:,:) ! not due to micro/macrophysics [K s-1] - real(kind_phys), intent(in) :: ltend(:,:) ! not due to micro/macrophysics [kg kg-1 s-1] + real(kind_phys), intent(out) :: qtend(:,:) ! not due to micro/macrophysics [kg kg-1 s-1] + real(kind_phys), intent(out) :: ttend(:,:) ! not due to micro/macrophysics [K s-1] + real(kind_phys), intent(out) :: ltend(:,:) ! not due to micro/macrophysics [kg kg-1 s-1] character(len=512), intent(out) :: errmsg ! error message integer, intent(out) :: errflg ! error flag From 4e54ff2194048eeddb286620ed731d1697db720a Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Thu, 6 Mar 2025 22:26:04 -0500 Subject: [PATCH 14/39] Fix bit-for-bitness in rk_stratiform_external_forcings_run --- .../cloud_fraction/compute_cloud_fraction.F90 | 2 +- .../cloud_fraction/convective_cloud_cover.F90 | 2 +- .../cloud_particle_sedimentation.F90 | 2 +- .../prognostic_cloud_water.F90 | 8 +++--- schemes/rasch_kristjansson/rk_stratiform.F90 | 17 ++++++------ test/test_suites/suite_rasch_kristjansson.xml | 27 ++++++++++++------- 6 files changed, 33 insertions(+), 25 deletions(-) diff --git a/schemes/cloud_fraction/compute_cloud_fraction.F90 b/schemes/cloud_fraction/compute_cloud_fraction.F90 index f9c22bc0..232ba61e 100644 --- a/schemes/cloud_fraction/compute_cloud_fraction.F90 +++ b/schemes/cloud_fraction/compute_cloud_fraction.F90 @@ -1,4 +1,4 @@ -! Copyright (C) 2025 National Science Foundation-National Center for Atmospheric Research +! Copyright (C) 2025 University Corporation for Atmospheric Research ! SPDX-License-Identifier: Apache-2.0 ! ! Compute cloud fractions using RH threshold and other methods. diff --git a/schemes/cloud_fraction/convective_cloud_cover.F90 b/schemes/cloud_fraction/convective_cloud_cover.F90 index 8b22640f..802f2138 100644 --- a/schemes/cloud_fraction/convective_cloud_cover.F90 +++ b/schemes/cloud_fraction/convective_cloud_cover.F90 @@ -1,4 +1,4 @@ -! Copyright (C) 2025 National Science Foundation-National Center for Atmospheric Research +! Copyright (C) 2025 University Corporation for Atmospheric Research ! SPDX-License-Identifier: Apache-2.0 ! ! Computes deep and shallow convective cloud fractions diff --git a/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 b/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 index fe0df2d7..122ef445 100644 --- a/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 +++ b/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 @@ -1,4 +1,4 @@ -! Copyright (C) 2002-2025 National Science Foundation-National Center for Atmospheric Research +! Copyright (C) 2025 University Corporation for Atmospheric Research ! SPDX-License-Identifier: Apache-2.0 ! ! Compute tendencies from sedimentation of cloud liquid and ice particles diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 index a1b93038..923c02e5 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 @@ -1,4 +1,4 @@ -! Copyright (C) 2025 National Science Foundation-National Center for Atmospheric Research +! Copyright (C) 2025 University Corporation for Atmospheric Research ! SPDX-License-Identifier: Apache-2.0 ! ! Prognostic cloud water data and methods (cldwat) @@ -199,9 +199,9 @@ subroutine prognostic_cloud_water_init( & ciautb = 5.e-4_kind_phys if(amIRoot) then - write(iulog,*) 'tuning parameters cldwat: capnw',capnw,'capnc',capnc,'capnsi',capnsi,'kconst',kconst - write(iulog,*) 'tuning parameters cldwat: effc',effc,'alpha',alpha,'capc',capc - write(iulog,*) 'tuning parameters cldwat: critpr',critpr,'convfw',convfw,'cracw',cracw,'ciautb',ciautb + write(iulog,*) 'tuning parameters prognostic_cloud_water_init: capnw',capnw,'capnc',capnc,'capnsi',capnsi,'kconst',kconst + write(iulog,*) 'tuning parameters prognostic_cloud_water_init: effc',effc,'alpha',alpha,'capc',capc + write(iulog,*) 'tuning parameters prognostic_cloud_water_init: critpr',critpr,'convfw',convfw,'cracw',cracw,'ciautb',ciautb endif end subroutine prognostic_cloud_water_init diff --git a/schemes/rasch_kristjansson/rk_stratiform.F90 b/schemes/rasch_kristjansson/rk_stratiform.F90 index a246ed8a..2d18ed4f 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.F90 +++ b/schemes/rasch_kristjansson/rk_stratiform.F90 @@ -1,4 +1,4 @@ -! Copyright (C) 2025 National Science Foundation-National Center for Atmospheric Research +! Copyright (C) 2025 University Corporation for Atmospheric Research ! SPDX-License-Identifier: Apache-2.0 ! ! Rasch and Kristjansson prognostic cloud microphysics and CAM4 macrophysics @@ -19,10 +19,10 @@ module rk_stratiform ! as the full RK-stratiform requires other schemes not included in this module. public :: rk_stratiform_init public :: rk_stratiform_timestep_init + ! -- cloud_particle_sedimentation -- public :: rk_stratiform_sedimentation_run public :: rk_stratiform_detrain_convective_condensate_run public :: rk_stratiform_cloud_fraction_perturbation_run ! see note. - ! public :: rk_stratiform_microphysics_run public :: rk_stratiform_condensate_repartioning_run public :: rk_stratiform_external_forcings_run ! -- prognostic_cloud_water -- @@ -35,7 +35,7 @@ module rk_stratiform contains ! Initialize rk_stratiform - subroutine rk_stratiform_init(& + subroutine rk_stratiform_init( & errmsg, errflg) ! If qcwat, tcwat, lcwat are not initialized, eventually init them character(len=512), intent(out) :: errmsg ! error message @@ -46,7 +46,7 @@ subroutine rk_stratiform_init(& end subroutine rk_stratiform_init - subroutine rk_stratiform_timestep_init(& + subroutine rk_stratiform_timestep_init( & errmsg, errflg) character(len=512), intent(out) :: errmsg ! error message integer, intent(out) :: errflg ! error flag @@ -289,7 +289,7 @@ subroutine rk_stratiform_condensate_repartioning_run( & errflg = 0 totcw(:ncol,:) = cldice(:ncol,:) + cldliq(:ncol,:) - tend_cldice(:ncol,:) = 1.0_kind_phys / dtime * ( totcw(:ncol,:)*fice(:ncol,:) - cldice(:ncol,:) ) + tend_cldice(:ncol,:) = 1.0_kind_phys / dtime * ( totcw(:ncol,:)*fice(:ncol,:) - cldice(:ncol,:) ) tend_cldliq(:ncol,:) = 1.0_kind_phys / dtime * ( totcw(:ncol,:)*(1.0_kind_phys-fice(:ncol,:)) - cldliq(:ncol,:) ) repartht(:ncol,:pver) = latice * tend_cldice(:ncol,:pver) @@ -336,9 +336,9 @@ subroutine rk_stratiform_external_forcings_run( & totcw(:ncol,:) = cldice(:ncol,:) + cldliq(:ncol,:) - qtend(:ncol,:pver) = (q_wv (:ncol,:) - qcwat(:ncol,:)) / dtime - ttend(:ncol,:pver) = (t (:ncol,:) - tcwat(:ncol,:)) / dtime - ltend(:ncol,:pver) = (totcw (:ncol,:) - lcwat(:ncol,:)) / dtime + qtend(:ncol,:pver) = 1.0_kind_phys / dtime * (q_wv (:ncol,:pver) - qcwat(:ncol,:pver)) + ttend(:ncol,:pver) = 1.0_kind_phys / dtime * (t (:ncol,:pver) - tcwat(:ncol,:pver)) + ltend(:ncol,:pver) = 1.0_kind_phys / dtime * (totcw (:ncol,:pver) - lcwat(:ncol,:pver)) end subroutine rk_stratiform_external_forcings_run @@ -409,6 +409,7 @@ subroutine rk_stratiform_prognostic_cloud_water_tendencies_run( & ! Rate of cond-evap of liq within the cloud [kg kg-1 s-1] cmeliq(i,k) = qme(i,k)*(1._kind_phys-fice(i,k)) + ! Tendencies from after prognostic_cloud_water... tend_s(i,k) = cmeheat(i,k) + & evapheat(i,k) + prfzheat(i,k) + meltheat(i,k) + repartht(i,k) tend_q(i,k) = - qme(i,k) + evapprec(i,k) diff --git a/test/test_suites/suite_rasch_kristjansson.xml b/test/test_suites/suite_rasch_kristjansson.xml index 97c17ba3..69296726 100644 --- a/test/test_suites/suite_rasch_kristjansson.xml +++ b/test/test_suites/suite_rasch_kristjansson.xml @@ -1,5 +1,13 @@ + @@ -27,26 +35,25 @@ --> compute_cloud_fraction rk_stratiform_cloud_fraction_perturbation_run + - + rk_stratiform_external_forcings + + cldfrc_fice - - - - + prognostic_cloud_water rk_stratiform_prognostic_cloud_water_tendencies compute_cloud_fraction - + From e1d05c20d91dd9ab1028444b7aaa3404cffec69f Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 10 Mar 2025 12:01:14 -0400 Subject: [PATCH 15/39] Populate rk_stratiform metadata --- schemes/rasch_kristjansson/rk_stratiform.F90 | 164 ++-- schemes/rasch_kristjansson/rk_stratiform.meta | 747 ++++++++++++++++++ 2 files changed, 862 insertions(+), 49 deletions(-) create mode 100644 schemes/rasch_kristjansson/rk_stratiform.meta diff --git a/schemes/rasch_kristjansson/rk_stratiform.F90 b/schemes/rasch_kristjansson/rk_stratiform.F90 index 2d18ed4f..a5016eb8 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.F90 +++ b/schemes/rasch_kristjansson/rk_stratiform.F90 @@ -23,29 +23,42 @@ module rk_stratiform public :: rk_stratiform_sedimentation_run public :: rk_stratiform_detrain_convective_condensate_run public :: rk_stratiform_cloud_fraction_perturbation_run ! see note. - public :: rk_stratiform_condensate_repartioning_run public :: rk_stratiform_external_forcings_run + public :: rk_stratiform_condensate_repartioning_run ! -- prognostic_cloud_water -- public :: rk_stratiform_prognostic_cloud_water_tendencies_run ! public :: rk_stratiform_cloud_optical_properties_run - ! public :: rk_stratiform_save_qtlcwat_run + public :: rk_stratiform_save_qtlcwat_run ! contains ! Initialize rk_stratiform +!> \section arg_table_rk_stratiform_init Argument Table +!! \htmlinclude arg_table_rk_stratiform_init.html subroutine rk_stratiform_init( & + qcwat, tcwat, lcwat, & ! from end of last microphysics/macrophysics call. errmsg, errflg) - ! If qcwat, tcwat, lcwat are not initialized, eventually init them + ! Input/output arguments + real(kind_phys), intent(inout) :: qcwat(:,:) ! [kg kg-1] + real(kind_phys), intent(inout) :: tcwat(:,:) ! [K] + real(kind_phys), intent(inout) :: lcwat(:,:) ! [kg kg-1] + + ! Output arguments character(len=512), intent(out) :: errmsg ! error message integer, intent(out) :: errflg ! error flag errmsg = '' errflg = 0 + ! If qcwat, tcwat, lcwat are not initialized, eventually init them + ! (here or in timestep_init? check if initial values are ready at this point.) + end subroutine rk_stratiform_init +!> \section arg_table_rk_stratiform_timestep_init Argument Table +!! \htmlinclude arg_table_rk_stratiform_timestep_init.html subroutine rk_stratiform_timestep_init( & errmsg, errflg) character(len=512), intent(out) :: errmsg ! error message @@ -57,7 +70,8 @@ subroutine rk_stratiform_timestep_init( & end subroutine rk_stratiform_timestep_init - +!> \section arg_table_rk_stratiform_sedimentation_run Argument Table +!! \htmlinclude arg_table_rk_stratiform_sedimentation_run.html subroutine rk_stratiform_sedimentation_run( & ncol, & sfliq, snow_sed, & @@ -91,6 +105,8 @@ subroutine rk_stratiform_sedimentation_run( & end subroutine rk_stratiform_sedimentation_run +!> \section arg_table_rk_stratiform_detrain_convective_condensate_run Argument Table +!! \htmlinclude arg_table_rk_stratiform_detrain_convective_condensate_run.html subroutine rk_stratiform_detrain_convective_condensate_run( & ncol, & dlf, & @@ -127,6 +143,8 @@ end subroutine rk_stratiform_detrain_convective_condensate_run ! Call perturbed cloud fraction and compute perturbation threshold criteria ! necessary for prognostic_cloud_water scheme +!> \section arg_table_rk_stratiform_cloud_fraction_perturbation_run Argument Table +!! \htmlinclude arg_table_rk_stratiform_cloud_fraction_perturbation_run.html subroutine rk_stratiform_cloud_fraction_perturbation_run( & ncol, pver, & cappa, gravit, rair, tmelt, & @@ -251,60 +269,18 @@ subroutine rk_stratiform_cloud_fraction_perturbation_run( & end subroutine rk_stratiform_cloud_fraction_perturbation_run - ! Repartitioning of stratiform condensate, - ! and compute repartition heating from change in cloud ice - subroutine rk_stratiform_condensate_repartioning_run( & - ncol, pver, & - dtime, & - latice, & - cldice, cldliq, & - fice, & ! from cloud_fraction_fice - repartht, & - tend_cldice, & - tend_cldliq, & - errmsg, errflg) - - ! Input arguments - integer, intent(in) :: ncol - integer, intent(in) :: pver - real(kind_phys), intent(in) :: dtime - real(kind_phys), intent(in) :: latice - real(kind_phys), intent(in) :: cldliq(:,:) ! adv: cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] - real(kind_phys), intent(in) :: cldice(:,:) ! adv: cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] - real(kind_phys), intent(in) :: fice(:,:) ! mass_fraction_of_ice_content_within_stratiform_cloud [fraction] - - ! Input/output arguments - real(kind_phys), intent(inout) :: repartht(:,:) ! [J kg-1 s-1] - - ! Output arguments - real(kind_phys), intent(out) :: tend_cldice(:,:) ! tendency_of_cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1 s-1] - real(kind_phys), intent(out) :: tend_cldliq(:,:) ! tendency_of_cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1 s-1] - character(len=512), intent(out) :: errmsg ! error message - integer, intent(out) :: errflg ! error flag - - ! Local arguments - real(kind_phys) :: totcw(ncol, pver) - - errmsg = '' - errflg = 0 - - totcw(:ncol,:) = cldice(:ncol,:) + cldliq(:ncol,:) - tend_cldice(:ncol,:) = 1.0_kind_phys / dtime * ( totcw(:ncol,:)*fice(:ncol,:) - cldice(:ncol,:) ) - tend_cldliq(:ncol,:) = 1.0_kind_phys / dtime * ( totcw(:ncol,:)*(1.0_kind_phys-fice(:ncol,:)) - cldliq(:ncol,:) ) - - repartht(:ncol,:pver) = latice * tend_cldice(:ncol,:pver) - - end subroutine rk_stratiform_condensate_repartioning_run ! Compute non-micro and non-macrophysical external forcings ! for computing of net condensation rate. ! Note: advective forcing of condensate is aggregated into liquid phase. +!> \section arg_table_rk_stratiform_external_forcings_run Argument Table +!! \htmlinclude arg_table_rk_stratiform_external_forcings_run.html subroutine rk_stratiform_external_forcings_run( & ncol, pver, & dtime, & t, & q_wv, cldice, cldliq, & - qcwat, tcwat, lcwat, & ! ? + qcwat, tcwat, lcwat, & ! from end of last physics timestep. qtend, ttend, ltend, & ! output for prognostic_cloud_water errmsg, errflg) @@ -342,7 +318,56 @@ subroutine rk_stratiform_external_forcings_run( & end subroutine rk_stratiform_external_forcings_run + ! Repartitioning of stratiform condensate, + ! and compute repartition heating from change in cloud ice +!> \section arg_table_rk_stratiform_condensate_repartioning_run Argument Table +!! \htmlinclude arg_table_rk_stratiform_condensate_repartioning_run.html + subroutine rk_stratiform_condensate_repartioning_run( & + ncol, pver, & + dtime, & + latice, & + cldice, cldliq, & + fice, & ! from cloud_fraction_fice + repartht, & + tend_cldice, & + tend_cldliq, & + errmsg, errflg) + + ! Input arguments + integer, intent(in) :: ncol + integer, intent(in) :: pver + real(kind_phys), intent(in) :: dtime + real(kind_phys), intent(in) :: latice + real(kind_phys), intent(in) :: cldice(:,:) ! adv: cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + real(kind_phys), intent(in) :: cldliq(:,:) ! adv: cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + real(kind_phys), intent(in) :: fice(:,:) ! mass_fraction_of_ice_content_within_stratiform_cloud [fraction] + + ! Input/output arguments + real(kind_phys), intent(inout) :: repartht(:,:) ! [J kg-1 s-1] + + ! Output arguments + real(kind_phys), intent(out) :: tend_cldice(:,:) ! tendency_of_cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1 s-1] + real(kind_phys), intent(out) :: tend_cldliq(:,:) ! tendency_of_cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1 s-1] + character(len=512), intent(out) :: errmsg ! error message + integer, intent(out) :: errflg ! error flag + + ! Local arguments + real(kind_phys) :: totcw(ncol, pver) + + errmsg = '' + errflg = 0 + + totcw(:ncol,:) = cldice(:ncol,:) + cldliq(:ncol,:) + tend_cldice(:ncol,:) = 1.0_kind_phys / dtime * ( totcw(:ncol,:)*fice(:ncol,:) - cldice(:ncol,:) ) + tend_cldliq(:ncol,:) = 1.0_kind_phys / dtime * ( totcw(:ncol,:)*(1.0_kind_phys-fice(:ncol,:)) - cldliq(:ncol,:) ) + + repartht(:ncol,:pver) = latice * tend_cldice(:ncol,:pver) + + end subroutine rk_stratiform_condensate_repartioning_run + ! Determine tendencies from prognostic cloud water +!> \section arg_table_rk_stratiform_prognostic_cloud_water_tendencies_run Argument Table +!! \htmlinclude arg_table_rk_stratiform_prognostic_cloud_water_tendencies_run.html subroutine rk_stratiform_prognostic_cloud_water_tendencies_run( & ncol, pver, & dtime, & @@ -423,6 +448,47 @@ subroutine rk_stratiform_prognostic_cloud_water_tendencies_run( & end subroutine rk_stratiform_prognostic_cloud_water_tendencies_run + ! Save Q, T, cloud water at end of stratiform microphysics for use in next timestep + ! to determine non-microphysical/macrophysical tendencies +!> \section arg_table_rk_stratiform_save_qtlcwat_run Argument Table +!! \htmlinclude arg_table_rk_stratiform_save_qtlcwat_run.html + subroutine rk_stratiform_save_qtlcwat_run( & + ncol, pver, & + t, & + q_wv, cldice, cldliq, & + qcwat, tcwat, lcwat, & + errmsg, errflg) + + ! Input arguments + integer, intent(in) :: ncol + integer, intent(in) :: pver + + real(kind_phys), intent(in) :: t(:,:) ! air_temperature [K] + real(kind_phys), intent(in) :: q_wv(:, :) ! adv: water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + real(kind_phys), intent(in) :: cldice(:,:) ! adv: cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + real(kind_phys), intent(in) :: cldliq(:,:) ! adv: cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + + ! Output arguments + real(kind_phys), intent(out) :: qcwat(:,:) ! [kg kg-1] + real(kind_phys), intent(out) :: tcwat(:,:) ! [K] + real(kind_phys), intent(out) :: lcwat(:,:) ! [kg kg-1] + character(len=512), intent(out) :: errmsg ! error message + integer, intent(out) :: errflg ! error flag + + ! Local variables + integer :: k + + errmsg = '' + errflg = 0 + + do k = 1, pver + qcwat(:ncol,k) = q_wv(:ncol,k) + tcwat(:ncol,k) = t(:ncol,k) + lcwat(:ncol,k) = cldice(:ncol,k) + cldliq(:ncol,k) + enddo + + end subroutine rk_stratiform_save_qtlcwat_run + ! might be better suited for diagnostics ... ! subroutine rk_stratiform_ice_and_liquid_water_content_run( & ! ncol, pver, & diff --git a/schemes/rasch_kristjansson/rk_stratiform.meta b/schemes/rasch_kristjansson/rk_stratiform.meta new file mode 100644 index 00000000..db46ed39 --- /dev/null +++ b/schemes/rasch_kristjansson/rk_stratiform.meta @@ -0,0 +1,747 @@ +[ccpp-table-properties] + name = rk_stratiform + type = scheme + +[ccpp-arg-table] + name = rk_stratiform_init + type = scheme +[ qcwat ] + standard_name = water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water_at_end_of_microphysics + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = inout +[ tcwat ] + standard_name = air_temperature_at_end_of_microphysics + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = inout +[ lcwat ] + standard_name = cloud_water_mixing_ratio_wrt_moist_air_and_condensed_water_at_end_of_microphysics + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = inout +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out + +[ccpp-arg-table] + name = rk_stratiform_timestep_init + type = scheme +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out + +[ccpp-table-properties] + name = rk_stratiform_sedimentation + type = scheme + +[ccpp-arg-table] + name = rk_stratiform_sedimentation_run + type = scheme +[ ncol ] + standard_name = horizontal_loop_extent + units = count + type = integer + dimensions = () + intent = in +[ sfliq ] + standard_name = stratiform_rain_surface_flux_due_to_sedimentation + units = kg m-2 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ snow_sed ] + standard_name = lwe_cloud_ice_sedimentation_rate_at_surface_due_to_microphysics + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ prec_sed ] + standard_name = stratiform_cloud_water_surface_flux_due_to_sedimentation + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ prec_str ] + standard_name = stratiform_rain_and_snow_surface_flux + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ 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 = out +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out + +[ccpp-table-properties] + name = rk_stratiform_detrain_convective_condensate + type = scheme + +[ccpp-arg-table] + name = rk_stratiform_detrain_convective_condensate_run + type = scheme +[ ncol ] + standard_name = horizontal_loop_extent + units = count + type = integer + dimensions = () + intent = in +[ dlf ] + standard_name = detrainment_of_water_due_to_all_convection + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ rliq ] + standard_name = vertically_integrated_liquid_water_tendency_due_to_all_convection_to_be_applied_later_in_time_loop + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ prec_str ] + standard_name = stratiform_rain_and_snow_surface_flux + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ tend_cldliq ] + standard_name = tendency_of_cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out + constituent = true +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out + +[ccpp-table-properties] + name = rk_stratiform_cloud_fraction_perturbation + type = scheme + +[ccpp-arg-table] + name = rk_stratiform_cloud_fraction_perturbation_run + type = scheme +[ 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 +[ cappa ] + 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 +[ 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 +[ tmelt ] + standard_name = freezing_point_of_water + units = K + type = real | kind = kind_phys + dimensions = () + intent = in +[ top_lev_cloudphys ] + standard_name = vertical_layer_index_of_cloud_fraction_top + units = index + type = integer + dimensions = () + intent = in +[ pmid ] + standard_name = air_pressure + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ ps ] + standard_name = surface_air_pressure + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ temp ] + standard_name = air_temperature + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ sst ] + standard_name = sea_surface_temperature + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ q_wv ] + standard_name = water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ cldice ] + standard_name = cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ phis ] + standard_name = surface_geopotential + units = m2 s-2 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ shallowcu ] + standard_name = shallow_convective_cloud_area_fraction_tbd + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ deepcu ] + standard_name = deep_convective_cloud_area_fraction_tbd + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ concld ] + standard_name = convective_cloud_area_fraction + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ landfrac ] + standard_name = land_area_fraction + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ ocnfrac ] + standard_name = ocean_area_fraction + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ snowh ] + standard_name = lwe_surface_snow_depth_over_land + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ cloud ] + standard_name = cloud_area_fraction + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ relhum ] + standard_name = relative_humidity_for_prognostic_cloud_water_tbd + units = percent + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ rhu00 ] + standard_name = relative_humidity_threshold_for_prognostic_cloud_water_tbd + units = percent + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = inout +[ rhdfda ] + standard_name = derivative_of_relative_humidity_wrt_cloud_fraction_tbd + units = percent + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out + +[ccpp-table-properties] + name = rk_stratiform_external_forcings + type = scheme + +[ccpp-arg-table] + name = rk_stratiform_external_forcings_run + type = scheme +[ 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 +[ dtime ] + standard_name = timestep_for_physics + units = s + type = real | kind = kind_phys + dimensions = () + intent = in +[ t ] + standard_name = air_temperature + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ q_wv ] + standard_name = water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ cldice ] + standard_name = cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ cldliq ] + standard_name = cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ qcwat ] + standard_name = water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water_at_end_of_microphysics + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ tcwat ] + standard_name = air_temperature_at_end_of_microphysics + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ lcwat ] + standard_name = cloud_water_mixing_ratio_wrt_moist_air_and_condensed_water_at_end_of_microphysics + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ qtend ] + standard_name = tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water_not_due_to_microphysics_tbd + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ ttend ] + standard_name = tendency_of_air_temperature_not_due_to_microphysics_tbd + units = K s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ ltend ] + standard_name = tendency_of_cloud_water_mixing_ratio_wrt_moist_air_and_condensed_water_not_due_to_microphysics_tbd + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out + +[ccpp-table-properties] + name = rk_stratiform_condensate_repartioning + type = scheme + +[ccpp-arg-table] + name = rk_stratiform_condensate_repartioning_run + type = scheme +[ 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 +[ dtime ] + standard_name = timestep_for_physics + units = s + type = real | kind = kind_phys + dimensions = () + intent = in +[ latice ] + standard_name = latent_heat_of_fusion_of_water_at_0c + units = J kg-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ cldice ] + standard_name = cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ cldliq ] + standard_name = cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ fice ] + standard_name = mass_fraction_of_ice_content_within_stratiform_cloud + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ repartht ] + standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure_due_to_precipitation_repartitioning_tbd + units = J kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = inout +[ tend_cldice ] + standard_name = tendency_of_cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out + constituent = true +[ tend_cldliq ] + standard_name = tendency_of_cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out + constituent = true +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out + +[ccpp-table-properties] + name = rk_stratiform_prognostic_cloud_water_tendencies + type = scheme + +[ccpp-arg-table] + name = rk_stratiform_prognostic_cloud_water_tendencies_run + type = scheme +[ 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 +[ dtime ] + standard_name = timestep_for_physics + units = s + type = real | kind = kind_phys + dimensions = () + intent = in +[ latvap ] + standard_name = latent_heat_of_vaporization_of_water_at_0c + units = J kg-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ latice ] + standard_name = latent_heat_of_fusion_of_water_at_0c + units = J kg-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ qme ] + standard_name = net_condensation_rate_due_to_microphysics + units = s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ fice ] + standard_name = mass_fraction_of_ice_content_within_stratiform_cloud + units = fraction + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ evapheat ] + standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure_due_to_precipitation_evaporation_tbd + units = J kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ prfzheat ] + standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure_due_to_precipitation_freezing_tbd + units = J kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ meltheat ] + standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure_due_to_precipitation_phase_change_tbd + units = J kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ repartht ] + standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure_due_to_precipitation_repartitioning_tbd + units = J kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ evapprec ] + standard_name = precipitation_evaporation_due_to_microphysics + units = s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ ice2pr ] + standard_name = tendency_of_cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water_due_to_microphysics_tbd + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ liq2pr ] + standard_name = tendency_of_cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water_due_to_microphysics_tbd + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ prec_pcw ] + standard_name = lwe_stratiform_precipitation_rate_at_surface + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ snow_pcw ] + standard_name = lwe_snow_precipitation_rate_at_surface_due_to_microphysics + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ prec_str ] + standard_name = stratiform_rain_and_snow_surface_flux + units = m s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = inout +[ 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 = inout +[ cmeheat ] + standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure_due_to_condensation_evaporation_within_stratiform_cloud_tbd + units = J kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ cmeice ] + standard_name = rate_of_condensation_evaporation_of_cloud_ice_within_stratiform_cloud_tbd + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ cmeliq ] + standard_name = rate_of_condensation_evaporation_of_cloud_liquid_water_within_stratiform_cloud_tbd + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ tend_s ] + standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure + units = J kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ tend_q ] + standard_name = tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out + constituent = true +[ tend_cldice ] + standard_name = tendency_of_cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out + constituent = true +[ tend_cldliq ] + standard_name = tendency_of_cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 s-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out + constituent = true +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out + +[ccpp-arg-table] + name = rk_stratiform_save_qtlcwat_run + type = scheme +[ 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 +[ t ] + standard_name = air_temperature + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ q_wv ] + standard_name = water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ cldice ] + standard_name = cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ cldliq ] + standard_name = cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ qcwat ] + standard_name = water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water_at_end_of_microphysics + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ tcwat ] + standard_name = air_temperature_at_end_of_microphysics + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ lcwat ] + standard_name = cloud_water_mixing_ratio_wrt_moist_air_and_condensed_water_at_end_of_microphysics + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out From 408adb2e192753968c73eb09bbea1e4abd52f684 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 10 Mar 2025 12:54:50 -0400 Subject: [PATCH 16/39] Update metadata for build. --- .../cloud_fraction/compute_cloud_fraction.meta | 2 +- .../cloud_fraction/convective_cloud_cover.meta | 16 ++++++++++++++-- ...r.xml => convective_cloud_cover_namelist.xml} | 0 schemes/rasch_kristjansson/rk_stratiform.F90 | 4 ++-- schemes/rasch_kristjansson/rk_stratiform.meta | 10 +++++++--- test/test_suites/suite_rasch_kristjansson.xml | 9 ++++++--- 6 files changed, 30 insertions(+), 11 deletions(-) rename schemes/cloud_fraction/{convective_cloud_cover.xml => convective_cloud_cover_namelist.xml} (100%) diff --git a/schemes/cloud_fraction/compute_cloud_fraction.meta b/schemes/cloud_fraction/compute_cloud_fraction.meta index 665786bb..425b796c 100644 --- a/schemes/cloud_fraction/compute_cloud_fraction.meta +++ b/schemes/cloud_fraction/compute_cloud_fraction.meta @@ -85,7 +85,7 @@ dimensions = () intent = in [ icecrit_in ] - standard_name = scheme_for_ice_cloud_fraction + standard_name = tunable_parameter_for_critical_relative_humidity_for_ice_clouds_for_cloud_fraction_using_wilson_from_ballard_scheme units = 1 type = real | kind = kind_phys dimensions = () diff --git a/schemes/cloud_fraction/convective_cloud_cover.meta b/schemes/cloud_fraction/convective_cloud_cover.meta index 9887fc2a..7340b8f6 100644 --- a/schemes/cloud_fraction/convective_cloud_cover.meta +++ b/schemes/cloud_fraction/convective_cloud_cover.meta @@ -5,6 +5,18 @@ [ccpp-arg-table] name = convective_cloud_cover_init type = scheme +[ amIRoot ] + standard_name = flag_for_mpi_root + units = flag + type = logical + dimensions = () + intent = in +[ iulog ] + standard_name = log_output_unit + units = 1 + type = integer + dimensions = () + intent = in [ sh1_in ] standard_name = tunable_parameter_for_shallow_convection_1_for_cloud_fraction units = 1 @@ -79,13 +91,13 @@ standard_name = atmosphere_convective_mass_flux_due_to_all_convection units = kg m-2 s-1 type = real | kind = kind_phys - dimensions = (horizontal_loop_extent, vertical_layer_dimension) + dimensions = (horizontal_loop_extent, vertical_interface_dimension) intent = in [ cmfmc_sh ] standard_name = atmosphere_convective_mass_flux_due_to_shallow_convection units = kg m-2 s-1 type = real | kind = kind_phys - dimensions = (horizontal_loop_extent, vertical_layer_dimension) + dimensions = (horizontal_loop_extent, vertical_interface_dimension) intent = in [ shallowcu ] standard_name = shallow_convective_cloud_area_fraction_tbd diff --git a/schemes/cloud_fraction/convective_cloud_cover.xml b/schemes/cloud_fraction/convective_cloud_cover_namelist.xml similarity index 100% rename from schemes/cloud_fraction/convective_cloud_cover.xml rename to schemes/cloud_fraction/convective_cloud_cover_namelist.xml diff --git a/schemes/rasch_kristjansson/rk_stratiform.F90 b/schemes/rasch_kristjansson/rk_stratiform.F90 index a5016eb8..10007abd 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.F90 +++ b/schemes/rasch_kristjansson/rk_stratiform.F90 @@ -117,8 +117,8 @@ subroutine rk_stratiform_detrain_convective_condensate_run( & ! Input arguments integer, intent(in) :: ncol - real(kind_phys), intent(in) :: dlf(:,:) ! detrainment_of_water_due_to_all_convection [kg kg-1 s-1] - real(kind_phys), intent(in) :: rliq(:) ! vertically_integrated_liquid_water_tendency_due_to_all_convection_to_be_applied_later_in_time_loop [kg kg-1 s-1] + real(kind_phys), intent(in) :: dlf(:,:) ! detrainment_of_cloud_liquid_water_wrt_moist_air_and_condensed_water_due_to_all_convection [kg kg-1 s-1] + real(kind_phys), intent(in) :: rliq(:) ! vertically_integrated_cloud_liquid_water_tendency_due_to_all_convection_to_be_applied_later_in_time_loop [m s-1] ! Input/output arguments real(kind_phys), intent(inout) :: prec_str(:) ! stratiform_rain_and_snow_surface_flux [m s-1] diff --git a/schemes/rasch_kristjansson/rk_stratiform.meta b/schemes/rasch_kristjansson/rk_stratiform.meta index db46ed39..05a2ea74 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.meta +++ b/schemes/rasch_kristjansson/rk_stratiform.meta @@ -122,14 +122,14 @@ dimensions = () intent = in [ dlf ] - standard_name = detrainment_of_water_due_to_all_convection + standard_name = detrainment_of_cloud_liquid_water_wrt_moist_air_and_condensed_water_due_to_all_convection units = kg kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in [ rliq ] - standard_name = vertically_integrated_liquid_water_tendency_due_to_all_convection_to_be_applied_later_in_time_loop - units = kg kg-1 s-1 + standard_name = vertically_integrated_cloud_liquid_water_tendency_due_to_all_convection_to_be_applied_later_in_time_loop + units = m s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = in @@ -676,6 +676,10 @@ dimensions = () intent = out +[ccpp-table-properties] + name = rk_stratiform_save_qtlcwat + type = scheme + [ccpp-arg-table] name = rk_stratiform_save_qtlcwat_run type = scheme diff --git a/test/test_suites/suite_rasch_kristjansson.xml b/test/test_suites/suite_rasch_kristjansson.xml index 69296726..830b8292 100644 --- a/test/test_suites/suite_rasch_kristjansson.xml +++ b/test/test_suites/suite_rasch_kristjansson.xml @@ -22,7 +22,7 @@ geopotential_temp rk_stratiform_sedimentation - + rk_stratiform_detrain_convective_condensate + convective_cloud_cover + compute_cloud_fraction - rk_stratiform_cloud_fraction_perturbation_run + rk_stratiform_cloud_fraction_perturbation - cldfrc_fice + cloud_fraction_fice rk_stratiform_condensate_repartioning apply_constituent_tendencies qneg @@ -65,6 +67,7 @@ geopotential_temp + convective_cloud_cover compute_cloud_fraction From 71516640425e203714975b6603a14d0bb87363fc Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 10 Mar 2025 13:26:22 -0400 Subject: [PATCH 17/39] Update repartht intent --- schemes/rasch_kristjansson/rk_stratiform.F90 | 2 +- schemes/rasch_kristjansson/rk_stratiform.meta | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/schemes/rasch_kristjansson/rk_stratiform.F90 b/schemes/rasch_kristjansson/rk_stratiform.F90 index 10007abd..b034bc14 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.F90 +++ b/schemes/rasch_kristjansson/rk_stratiform.F90 @@ -343,9 +343,9 @@ subroutine rk_stratiform_condensate_repartioning_run( & real(kind_phys), intent(in) :: fice(:,:) ! mass_fraction_of_ice_content_within_stratiform_cloud [fraction] ! Input/output arguments - real(kind_phys), intent(inout) :: repartht(:,:) ! [J kg-1 s-1] ! Output arguments + real(kind_phys), intent(out) :: repartht(:,:) ! [J kg-1 s-1] real(kind_phys), intent(out) :: tend_cldice(:,:) ! tendency_of_cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1 s-1] real(kind_phys), intent(out) :: tend_cldliq(:,:) ! tendency_of_cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1 s-1] character(len=512), intent(out) :: errmsg ! error message diff --git a/schemes/rasch_kristjansson/rk_stratiform.meta b/schemes/rasch_kristjansson/rk_stratiform.meta index 05a2ea74..234a6cc8 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.meta +++ b/schemes/rasch_kristjansson/rk_stratiform.meta @@ -475,7 +475,7 @@ units = J kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) - intent = inout + intent = out [ tend_cldice ] standard_name = tendency_of_cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water units = kg kg-1 s-1 From e264d2f2e0aeb9f60351c8fd4c973afa0a395913 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 10 Mar 2025 13:52:48 -0400 Subject: [PATCH 18/39] Attempt to remove cwat in prognostic_cloud_water for bit-for-bitness --- .../rasch_kristjansson/prognostic_cloud_water.F90 | 15 +++++++++++---- .../prognostic_cloud_water.meta | 14 ++++++++++---- test/test_suites/suite_rasch_kristjansson.xml | 4 +++- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 index 923c02e5..44588d61 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 @@ -231,7 +231,8 @@ subroutine prognostic_cloud_water_run( & troplev, & ttend, tn, & qtend, qn, & - ltend, cwat, & + ltend, & + cldice, cldliq, & omega, & cldn, & fice, fsnow, & @@ -254,7 +255,7 @@ subroutine prognostic_cloud_water_run( & ! Input arguments integer, intent(in) :: ncol integer, intent(in) :: pver - integer, intent(in) :: top_lev ! index_of_pressure_at_troposphere_cloud_top [index] + integer, intent(in) :: top_lev ! vertical_layer_index_of_troposphere_cloud_physics_top [index] real(kind_phys), intent(in) :: deltat ! timestep [s] integer, intent(in) :: iulog ! log output unit [1] real(kind_phys), intent(in) :: pi ! pi_constant [1] @@ -276,7 +277,8 @@ subroutine prognostic_cloud_water_run( & real(kind_phys), intent(in) :: qtend(:,:) ! Water vapor tendency [kg kg-1 s-1] -- from non-micro/macrophysics real(kind_phys), intent(in) :: qn(:,:) ! New Water vapor mixing ratio [kg kg-1] real(kind_phys), intent(in) :: ltend(:,:) ! Cloud liquid water tendency [kg kg-1 s-1] -- from non-micro/macrophysics - real(kind_phys), intent(in) :: cwat(:,:) ! Cloud water mixing ratio (ixcldice+ixcldliq) [kg kg-1] + real(kind_phys), intent(in) :: cldice(:,:) ! adv: cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] + real(kind_phys), intent(in) :: cldliq(:,:) ! adv: cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] real(kind_phys), intent(in) :: omega(:,:) ! lagrangian_tendency_of_air_pressure [Pa s-1] real(kind_phys), intent(in) :: cldn(:,:) ! New Cloud fraction [fraction] @@ -325,6 +327,9 @@ subroutine prognostic_cloud_water_run( & integer :: iter ! # of iterations for precipitation calculation [1] logical :: error_found ! Flag for error detection [flag] + ! Total cloud water (from cldice+cldliq) + real(kind_phys) :: cwat(:,:) ! Cloud water mixing ratio [kg kg-1] + ! Precipitation and conversion rates real(kind_phys) :: nice2pr ! Rate of conversion from ice to snow [kg kg-1 s-1] real(kind_phys) :: nliq2pr ! Rate of conversion from liquid to precipitation [kg kg-1 s-1] @@ -367,7 +372,6 @@ subroutine prognostic_cloud_water_run( & real(kind_phys) :: qmec3(ncol) ! Cloud condensation coefficient 3 C-E formulation [1] real(kind_phys) :: qmec4(ncol) ! Cloud condensation coefficient 4 C-E formulation [1] - ! Diagnostic arrays for cloud water budget ! Hardcoded 2 here = number of iterations (iter below) real(kind_phys) :: rcwn(ncol,2,pver) ! Cloud water ratio evolution [kg kg-1] @@ -414,6 +418,9 @@ subroutine prognostic_cloud_water_run( & iter = 2 #endif + ! initialize total cloud water [kg kg-1] + cwat(:ncol,:pver) = cldice(:ncol,:pver) + cldliq(:ncol,:pver) + ! initialize single level and multi level fields do i = 1, ncol precip(i) = 0.0_kind_phys diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.meta b/schemes/rasch_kristjansson/prognostic_cloud_water.meta index 6432d964..83fabcc8 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.meta +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.meta @@ -100,7 +100,7 @@ dimensions = () intent = in [ top_lev ] - standard_name = index_of_pressure_at_troposhere_cloud_top + standard_name = vertical_layer_index_of_troposphere_cloud_physics_top units = index type = integer dimensions = () @@ -225,9 +225,15 @@ type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in -[ cwat ] - standard_name = cloud_water_mixing_ratio_wrt_moist_air_and_condensed_water_tbd - units = kg kg-1 s-1 +[ cldice ] + standard_name = cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ cldliq ] + standard_name = cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water + units = kg kg-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in diff --git a/test/test_suites/suite_rasch_kristjansson.xml b/test/test_suites/suite_rasch_kristjansson.xml index 830b8292..e3f21540 100644 --- a/test/test_suites/suite_rasch_kristjansson.xml +++ b/test/test_suites/suite_rasch_kristjansson.xml @@ -55,7 +55,9 @@ rk_stratiform_condensate_repartioning_diagnostics --> - + prognostic_cloud_water rk_stratiform_prognostic_cloud_water_tendencies - + - + rk_stratiform_save_qtlcwat diff --git a/to_be_ccppized/cloud_optical_properties.F90 b/to_be_ccppized/cloud_optical_properties.F90 index 21bd259f..fe5961aa 100644 --- a/to_be_ccppized/cloud_optical_properties.F90 +++ b/to_be_ccppized/cloud_optical_properties.F90 @@ -1,4 +1,4 @@ -! Copyright (C) 2002-2025 National Science Foundation-National Center for Atmospheric Research +! Copyright (C) 2002-2025 University Corporation for Atmospheric Research ! SPDX-License-Identifier: Apache-2.0 ! ! Cloud optical properties (to-be-ccppized utility module) From 261d077ad81169970d6486485cb2d9c1ea3f91e3 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Tue, 11 Mar 2025 12:49:08 -0400 Subject: [PATCH 20/39] Fix build --- schemes/rasch_kristjansson/rk_stratiform.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schemes/rasch_kristjansson/rk_stratiform.F90 b/schemes/rasch_kristjansson/rk_stratiform.F90 index de12f05d..9cc85c58 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.F90 +++ b/schemes/rasch_kristjansson/rk_stratiform.F90 @@ -563,7 +563,7 @@ subroutine rk_stratiform_cloud_optical_properties_run( & landm = landm(:ncol), & t = t(:ncol,:), & ps = ps(:ncol), & - pmid = pmid(:ncol), & ! below output: + pmid = pmid(:ncol,:), & ! below output: rel = rel(:ncol,:), & rei = rei(:ncol,:)) From c62eb0b01d585a5f6637ce06c8336476dcf5329a Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Thu, 13 Mar 2025 14:49:31 -0400 Subject: [PATCH 21/39] Add missing dependency flag; fix namelist definition --- schemes/rasch_kristjansson/cloud_particle_sedimentation.meta | 1 + schemes/rasch_kristjansson/prognostic_cloud_water_namelist.xml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta b/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta index bb60ba0a..1255df07 100644 --- a/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta +++ b/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta @@ -1,6 +1,7 @@ [ccpp-table-properties] name = cloud_particle_sedimentation type = scheme + dependencies = ../../to_be_ccppized/cloud_optical_properties.F90 [ccpp-arg-table] name = cloud_particle_sedimentation_init diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water_namelist.xml b/schemes/rasch_kristjansson/prognostic_cloud_water_namelist.xml index 7d9078df..4abb7282 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water_namelist.xml +++ b/schemes/rasch_kristjansson/prognostic_cloud_water_namelist.xml @@ -76,7 +76,7 @@ - real + logical conv rk_stratiform_nl flag_for_relative_humidity_threshold_for_cloud_formation_in_polar_stratosphere_for_rk_microphysics From 396983afdc5f911fdd1afe20a93953bec1e9b0bf Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 17 Mar 2025 11:31:39 -0400 Subject: [PATCH 22/39] Update correct units for prognostic_cloud_water; cleanup compute_cloud_fraction --- .../cloud_fraction/compute_cloud_fraction.F90 | 17 +- .../prognostic_cloud_water.F90 | 236 +++++++++--------- .../prognostic_cloud_water.meta | 12 +- schemes/rasch_kristjansson/rk_stratiform.F90 | 68 +---- schemes/rasch_kristjansson/rk_stratiform.meta | 19 +- 5 files changed, 154 insertions(+), 198 deletions(-) diff --git a/schemes/cloud_fraction/compute_cloud_fraction.F90 b/schemes/cloud_fraction/compute_cloud_fraction.F90 index 232ba61e..b94d6634 100644 --- a/schemes/cloud_fraction/compute_cloud_fraction.F90 +++ b/schemes/cloud_fraction/compute_cloud_fraction.F90 @@ -84,6 +84,14 @@ subroutine compute_cloud_fraction_init( & premit = premit_in premib = premib_in icecrit = icecrit_in + inversion_cld_off = inversion_cld_off_in + + if(amIRoot) then + write(iulog,*) 'tuning parameters compute_cloud_fraction_init: inversion_cld_off', inversion_cld_off + write(iulog,*) 'tuning parameters compute_cloud_fraction_init: rhminl',rhminl,'rhminl_adj_land',rhminl_adj_land, & + 'rhminh',rhminh,'premit',premit,'premib',premib + write(iulog,*) 'tuning parameters compute_cloud_fraction_init: iceopt',iceopt,'icecrit',icecrit + endif ! Find vertical level nearest 700 mb. k700 = minloc(abs(pref_mid(:) - 7.e4_kind_phys), 1) @@ -119,15 +127,6 @@ end subroutine compute_cloud_fraction_timestep_init ! entering that layer from below. ! ! Original authors: Many, including Jim McCaa. - - ! previous call routine - ! subroutine cldfrc(lchnk ,ncol , pbuf, & - ! pmid ,temp ,q ,omga , phis, & - ! shfrc ,use_shfrc, & - ! cloud ,rhcloud, clc ,pdel , & - ! cmfmc ,cmfmc2 ,landfrac,snowh ,concld ,cldst , & - ! ts ,sst ,ps ,zdu ,ocnfrac ,& - ! rhu00 ,cldice ,icecldf ,liqcldf ,relhum ,dindex ) !> \section arg_table_compute_cloud_fraction_run Argument Table !! \htmlinclude compute_cloud_fraction_run.html subroutine compute_cloud_fraction_run( & diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 index cc24ebfc..d4e22855 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 @@ -112,7 +112,8 @@ subroutine prognostic_cloud_water_init( & psrhmin = psrhmin_in if(amIRoot) then - write(iulog,*) 'tuning parameters cldwat: icritw',icritw,'icritc',icritc,'conke',conke,'r3lcrit',r3lcrit + write(iulog,*) 'tuning parameters prognostic_cloud_water_init: icritw',icritw,'icritc',icritc,'conke',conke,'r3lcrit',r3lcrit + write(iulog,*) 'prognostic_cloud_water_init: do_psrhmin = ', do_psrhmin endif !-------------------------------------------------- @@ -292,11 +293,11 @@ subroutine prognostic_cloud_water_run( & real(kind_phys), intent(in) :: snowh(:) ! Snow depth over land, water equivalent [m] ! Output arguments - real(kind_phys), intent(out) :: qme(:,:) ! Rate of condensation-evaporation of condensate (net_condensation_rate_due_to_microphysics) [s-1] - real(kind_phys), intent(out) :: prodprec(:,:) ! Conversion rate of condensate to precip (precipitation_production_due_to_microphysics) [s-1] - real(kind_phys), intent(out) :: prodsnow(:,:) ! Snow production rate (ignored in RK?) [s-1] - real(kind_phys), intent(out) :: evapprec(:,:) ! Falling precipitation evaporation rate (precipitation_evaporation_due_to_microphysics) [s-1] -- & combined to apply q(wv) tendency - real(kind_phys), intent(out) :: evapsnow(:,:) ! Falling snow evaporation rate [s-1] + real(kind_phys), intent(out) :: qme(:,:) ! Rate of condensation-evaporation of condensate (net_condensation_rate_due_to_microphysics) [kg kg-1 s-1] + real(kind_phys), intent(out) :: prodprec(:,:) ! Conversion rate of condensate to precip (precipitation_production_due_to_microphysics) [kg kg-1 s-1] + real(kind_phys), intent(out) :: prodsnow(:,:) ! Snow production rate (ignored in RK?) [kg kg-1 s-1] + real(kind_phys), intent(out) :: evapprec(:,:) ! Falling precipitation evaporation rate (precipitation_evaporation_due_to_microphysics) [kg kg-1 s-1] -- & combined to apply q(wv) tendency + real(kind_phys), intent(out) :: evapsnow(:,:) ! Falling snow evaporation rate [kg kg-1 s-1] real(kind_phys), intent(out) :: evapheat(:,:) ! heating rate due to evaporation of precipitation [J kg-1 s-1] real(kind_phys), intent(out) :: prfzheat(:,:) ! heating rate due to freezing of precipitation [J kg-1 s-1] real(kind_phys), intent(out) :: meltheat(:,:) ! heating rate due to snow melt [J kg-1 s-1] @@ -561,7 +562,7 @@ subroutine prognostic_cloud_water_run( & ! Because of the finite time step, place a bound here not to exceed wet bulb point ! and not to evaporate more than available water - do i = 1, ncol + qme_bound_loop: do i = 1, ncol qtmp = qn(i,k) - qme(i,k)*deltat ! possibilities to have qtmp > qsp @@ -584,7 +585,7 @@ subroutine prognostic_cloud_water_run( & ! limit qme for roundoff errors (multiply by slightly less than unity) qme(i,k) = qme(i,k) * omsm - end do + end do qme_bound_loop do i = 1, ncol ! as a safe limit, condensation should not reduce grid mean rh below rhu00 @@ -599,18 +600,17 @@ subroutine prognostic_cloud_water_run( & enddo ! provisional precipitation falling through model layer - do i = 1, ncol + prprov_update_loop: do i = 1, ncol ! prprov(i) = precab(i) + prodprec(i,k)*pdel(i,k)/gravit ! rain produced in this layer not too effective in collection process wtthick = max(0._kind_phys,min(0.5_kind_phys,((zi(i,k)-zi(i,k+1))/1000._kind_phys)**2)) prprov(i) = precab(i) + wtthick*prodprec(i,k)*pdel(i,k)/gravit - end do + end do prprov_update_loop ! calculate conversion of condensate to precipitation by cloud microphysics call findmcnew( & ncol = ncol, & pver = pver, & - rlat = rlat(:ncol), & pi = pi, & k = k, & precab = prprov(:ncol), & @@ -637,130 +637,129 @@ subroutine prognostic_cloud_water_run( & ! calculate the precip rate error_found = .false. - do i = 1, ncol - if (cldm(i) > 0) then - ! first predict the cloud water - cdt = coef(i)*deltat - if(cdt > 0.01_kind_phys) then - pol = qme(i,k)/coef(i) ! production over loss - cwn(i) = max(0._kind_phys,(cwat(i,k)-pol)*exp(-cdt)+ pol) - else - cwn(i) = max(0._kind_phys,(cwat(i,k) + qme(i,k)*deltat)/(1+cdt)) - endif - - ! now back out the tendency of net rain production - prodprec(i,k) = max(0._kind_phys,qme(i,k)-(cwn(i)-cwat(i,k))/deltat) + precip_update_loop: do i = 1, ncol + if (cldm(i) > 0) then + ! first predict the cloud water + cdt = coef(i)*deltat + if(cdt > 0.01_kind_phys) then + pol = qme(i,k)/coef(i) ! production over loss + cwn(i) = max(0._kind_phys,(cwat(i,k)-pol)*exp(-cdt)+ pol) else - prodprec(i,k) = 0.0_kind_phys - cwn(i) = 0._kind_phys + cwn(i) = max(0._kind_phys,(cwat(i,k) + qme(i,k)*deltat)/(1+cdt)) endif - ! provisional calculation of conversion terms - ice2pr(i,k) = prodprec(i,k)*(fsaut(i,k)+fsaci(i,k)) - liq2pr(i,k) = prodprec(i,k)*(fwaut(i,k)+fsacw(i,k)+fracw(i,k)) - + ! now back out the tendency of net rain production + prodprec(i,k) = max(0._kind_phys,qme(i,k)-(cwn(i)-cwat(i,k))/deltat) + else + prodprec(i,k) = 0.0_kind_phys + cwn(i) = 0._kind_phys + endif - ! revision suggested by Jim McCaa - ! it controls the amount of snow hitting the sfc - ! by forcing a lot of conversion of cloud liquid to snow phase - ! it might be better done later by an explicit representation of - ! rain accreting ice (and freezing), or by an explicit freezing of raindrops - ! - ! old: - ! liq2snow(i,k) = prodprec(i,k)*fsacw(i,k) - liq2snow(i,k) = max(prodprec(i,k)*fsacw(i,k), fsnow(i,k)*liq2pr(i,k)) + ! provisional calculation of conversion terms + ice2pr(i,k) = prodprec(i,k)*(fsaut(i,k)+fsaci(i,k)) + liq2pr(i,k) = prodprec(i,k)*(fwaut(i,k)+fsacw(i,k)+fracw(i,k)) - ! bounds - nice2pr = min(ice2pr(i,k),(cwat(i,k)+qme(i,k)*deltat)*fice(i,k)/deltat) - nliq2pr = min(liq2pr(i,k),(cwat(i,k)+qme(i,k)*deltat)*(1._kind_phys-fice(i,k))/deltat) + ! revision suggested by Jim McCaa + ! it controls the amount of snow hitting the sfc + ! by forcing a lot of conversion of cloud liquid to snow phase + ! it might be better done later by an explicit representation of + ! rain accreting ice (and freezing), or by an explicit freezing of raindrops + ! + ! old: + ! liq2snow(i,k) = prodprec(i,k)*fsacw(i,k) + liq2snow(i,k) = max(prodprec(i,k)*fsacw(i,k), fsnow(i,k)*liq2pr(i,k)) - if (liq2pr(i,k) .ne. 0._kind_phys) then - nliq2snow = liq2snow(i,k)*nliq2pr/liq2pr(i,k) ! correction - else - nliq2snow = liq2snow(i,k) - endif + ! bounds + nice2pr = min(ice2pr(i,k),(cwat(i,k)+qme(i,k)*deltat)*fice(i,k)/deltat) + nliq2pr = min(liq2pr(i,k),(cwat(i,k)+qme(i,k)*deltat)*(1._kind_phys-fice(i,k))/deltat) - ! avoid roundoff problems generating negatives - nliq2snow = nliq2snow*omsm - nliq2pr = nliq2pr*omsm - nice2pr = nice2pr*omsm - - ! final estimates of conversion to precip and snow - prodprec(i,k) = (nliq2pr + nice2pr) - prodsnow(i,k) = (nice2pr + nliq2snow) - - rcwn(i,l,k) = cwat(i,k) + (qme(i,k) - prodprec(i,k))*deltat - rliq(i,l,k) = (cwat(i,k) + qme(i,k)*deltat)*(1._kind_phys-fice(i,k)) - nliq2pr*deltat - rice(i,l,k) = (cwat(i,k) + qme(i,k)*deltat) * fice(i,k) - nice2pr*deltat - - ! Sanity checks - if(abs(rcwn(i,l,k)) < 1.e-300_kind_phys) rcwn(i,l,k) = 0._kind_phys - if(abs(rliq(i,l,k)) < 1.e-300_kind_phys) rliq(i,l,k) = 0._kind_phys - if(abs(rice(i,l,k)) < 1.e-300_kind_phys) rice(i,l,k) = 0._kind_phys - if(rcwn(i,l,k) < 0._kind_phys) error_found = .true. - if(rliq(i,l,k) < 0._kind_phys) error_found = .true. - if(rice(i,l,k) < 0._kind_phys) error_found = .true. - if(error_found) then - if(rcwn(i,l,k) < 0._kind_phys) then - write(iulog,*) 'prognostic_cloud_water: prob with neg rcwn1 ', rcwn(i,l,k), cwn(i) - write(iulog,*) ' cwat, qme*deltat, prodprec*deltat ', & - cwat(i,k), qme(i,k)*deltat, & - prodprec(i,k)*deltat, & - (qme(i,k)-prodprec(i,k))*deltat + if (liq2pr(i,k) .ne. 0._kind_phys) then + nliq2snow = liq2snow(i,k)*nliq2pr/liq2pr(i,k) ! correction + else + nliq2snow = liq2snow(i,k) + endif - errflg = 1 - errmsg = 'prognostic_cloud_water: negative rcwn1' - return - endif + ! avoid roundoff problems generating negatives + nliq2snow = nliq2snow*omsm + nliq2pr = nliq2pr*omsm + nice2pr = nice2pr*omsm + + ! final estimates of conversion to precip and snow + prodprec(i,k) = (nliq2pr + nice2pr) + prodsnow(i,k) = (nice2pr + nliq2snow) + + rcwn(i,l,k) = cwat(i,k) + (qme(i,k) - prodprec(i,k))*deltat + rliq(i,l,k) = (cwat(i,k) + qme(i,k)*deltat)*(1._kind_phys-fice(i,k)) - nliq2pr*deltat + rice(i,l,k) = (cwat(i,k) + qme(i,k)*deltat) * fice(i,k) - nice2pr*deltat + + ! Sanity checks + if(abs(rcwn(i,l,k)) < 1.e-300_kind_phys) rcwn(i,l,k) = 0._kind_phys + if(abs(rliq(i,l,k)) < 1.e-300_kind_phys) rliq(i,l,k) = 0._kind_phys + if(abs(rice(i,l,k)) < 1.e-300_kind_phys) rice(i,l,k) = 0._kind_phys + if(rcwn(i,l,k) < 0._kind_phys) error_found = .true. + if(rliq(i,l,k) < 0._kind_phys) error_found = .true. + if(rice(i,l,k) < 0._kind_phys) error_found = .true. + if(error_found) then + if(rcwn(i,l,k) < 0._kind_phys) then + write(iulog,*) 'prognostic_cloud_water: prob with neg rcwn1 ', rcwn(i,l,k), cwn(i) + write(iulog,*) ' cwat, qme*deltat, prodprec*deltat ', & + cwat(i,k), qme(i,k)*deltat, & + prodprec(i,k)*deltat, & + (qme(i,k)-prodprec(i,k))*deltat + + errflg = 1 + errmsg = 'prognostic_cloud_water: negative rcwn1' + return + endif - if (rliq(i,l,k) < 0._kind_phys) then - write(iulog,*) 'prognostic_cloud_water: prob with neg rliq1 ', rliq(i,l,k) - errflg = 1 - errmsg = 'prognostic_cloud_water: negative rliq1' - return - endif + if (rliq(i,l,k) < 0._kind_phys) then + write(iulog,*) 'prognostic_cloud_water: prob with neg rliq1 ', rliq(i,l,k) + errflg = 1 + errmsg = 'prognostic_cloud_water: negative rliq1' + return + endif - if (rice(i,l,k) < 0._kind_phys) then - write(iulog,*) 'prognostic_cloud_water: prob with neg rice ', rice(i,l,k) - errflg = 1 - errmsg = 'prognostic_cloud_water: negative rice' - return - endif + if (rice(i,l,k) < 0._kind_phys) then + write(iulog,*) 'prognostic_cloud_water: prob with neg rice ', rice(i,l,k) + errflg = 1 + errmsg = 'prognostic_cloud_water: negative rice' + return endif + endif - ! Final version of condensate to precip terms - liq2pr(i,k) = nliq2pr - liq2snow(i,k) = nliq2snow - ice2pr(i,k) = nice2pr - cwn(i) = rcwn(i,l,k) + ! Final version of condensate to precip terms + liq2pr(i,k) = nliq2pr + liq2snow(i,k) = nliq2snow + ice2pr(i,k) = nice2pr + cwn(i) = rcwn(i,l,k) - ! update any remaining provisional values - cwm(i) = (cwn(i) + cwat(i,k))*0.5_kind_phys + ! update any remaining provisional values + cwm(i) = (cwn(i) + cwat(i,k))*0.5_kind_phys - ! update in cloud water - if(cldm(i) > mincld) then - icwc(i) = cwm(i)/cldm(i) - else - icwc(i) = 0.0_kind_phys - endif - ! PJR the above logic give zero icwc with nonzero cwat, dont like it! - ! PJR generates problems with csigma - ! PJR set the icwc to a very small number, so we can start from zero cloud cover and make some clouds - ! icwc(i) = max(1.e-8_kind_phys,cwm(i)/cldm(i)) - end do + ! update in cloud water + if(cldm(i) > mincld) then + icwc(i) = cwm(i)/cldm(i) + else + icwc(i) = 0.0_kind_phys + endif + ! PJR the above logic give zero icwc with nonzero cwat, dont like it! + ! PJR generates problems with csigma + ! PJR set the icwc to a very small number, so we can start from zero cloud cover and make some clouds + ! icwc(i) = max(1.e-8_kind_phys,cwm(i)/cldm(i)) + end do precip_update_loop ! calculate provisional value of cloud water for ! evaporation of precipitate (evapprec) calculation - do i = 1,ncol + qtl_update_loop: do i = 1, ncol qtmp = qn(i,k) - qme(i,k)*deltat ttmp = tn(i,k) + deltat/cpair * ( meltheat(i,k) + (latvap + latice*fice(i,k)) * qme(i,k) ) esn = estblf(ttmp) qsn = svp_to_qsat(esn, pmid(i,k)) qtl(i) = max((qsn - qtmp)/deltat,0._kind_phys) relhum1(i) = qtmp/qsn - end do + end do qtl_update_loop - do i = 1,ncol + evap_update_loop: do i = 1, ncol #ifdef PERGRO evapprec(i,k) = conke*(1._kind_phys - max(cldm(i),mincld))* & sqrt(precab(i))*(1._kind_phys - min(relhum1(i),1._kind_phys)) @@ -792,7 +791,7 @@ subroutine prognostic_cloud_water_run( & ! Account for the latent heat of fusion for liquid drops collected by falling snow prfzheat(i,k) = latice * liq2snow(i,k) - end do + end do evap_update_loop ! now remove the residual of any over-saturation. Normally, ! the oversaturated water vapor should have been removed by @@ -802,7 +801,7 @@ subroutine prognostic_cloud_water_run( & ! a very small amount of over saturation. It is called a ! residual of over-saturation because theoretically, qme ! should have taken care of all of large scale condensation. - do i = 1,ncol + qmeres_update_loop: do i = 1, ncol qtmp = qn(i,k)-(qme(i,k)-evapprec(i,k))*deltat ttmp = tn(i,k) + deltat/cpair * ( meltheat(i,k) + evapheat(i,k) + prfzheat(i,k) & + (latvap + latice*fice(i,k)) * qme(i,k) ) @@ -819,11 +818,11 @@ subroutine prognostic_cloud_water_run( & else qmeres(i) = 0.0_kind_phys endif - end do + end do qmeres_update_loop end do qme_iter_loop ! loop over l (iteration) ! precipitation - do i = 1, ncol + precip_snow_loop: do i = 1, ncol precip(i) = precip(i) + pdel(i,k)/gravit * (prodprec(i,k) - evapprec(i,k)) precab(i) = precab(i) + pdel(i,k)/gravit * (prodprec(i,k) - evapprec(i,k)) if(precab(i) < 0._kind_phys) then @@ -837,7 +836,7 @@ subroutine prognostic_cloud_water_run( & lsflxprc(i,k+1) = precab(i) !! making this consistent with other precip fluxes. prc = rain + snow ! lsflxprc(i,k+1) = precab(i) - snowab(i) lsflxsnw(i,k+1) = snowab(i) - end do + end do precip_snow_loop end do mp_level_loop ! loop over k (level) ! Convert precip (lwe_stratiform_precipitation_rate_at_surface) @@ -857,7 +856,6 @@ end subroutine prognostic_cloud_water_run ! Original author: P. Rasch subroutine findmcnew( & ncol, pver, & - rlat, & ! was get_rlat_all_p pi, & k, & precab, snowab, t, p, cwm, cldm, cldmax, fice, & @@ -869,7 +867,6 @@ subroutine findmcnew( & ! input arguments integer, intent(in) :: ncol ! number of atmospheric columns integer, intent(in) :: pver ! number of levels - real(kind_phys), intent(in) :: rlat(:) ! latitudes [rad] real(kind_phys), intent(in) :: pi ! pi_constant [1] integer, intent(in) :: k ! level index @@ -900,7 +897,6 @@ subroutine findmcnew( & integer :: i, ii ! Loop index [index] integer :: ncols ! Number of active columns for microphysics (different from ncol!!) [count] integer :: ind(ncol) ! Active column indices [index] - real(kind_phys), parameter :: degrad = 57.296_kind_phys ! Degrees per radian [deg rad-1] real(kind_phys) :: capn ! Local cloud particle number concentration [cm-3] real(kind_phys) :: capnoice ! Cloud particle concentration excluding sea ice [cm-3] real(kind_phys) :: cldloc(ncol) ! Non-zero cloud fraction [1] @@ -1103,7 +1099,7 @@ subroutine findmcnew( & ! total conversion of condensate to precipitate ptot = pwaut + psaut + pracw + psacw + psaci - ! the recipricol of cloud water amnt (or zero if no cloud water) + ! the reciprocal of cloud water amount (or zero if no cloud water) ! rcwm = totmr(i)/(max(totmr(i),small)**2) ! turn the tendency back into a loss rate [s-1] diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.meta b/schemes/rasch_kristjansson/prognostic_cloud_water.meta index 83fabcc8..297ad11f 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.meta +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.meta @@ -293,31 +293,31 @@ intent = in [ qme ] standard_name = net_condensation_rate_due_to_microphysics - units = s-1 + units = kg kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out [ prodprec ] standard_name = precipitation_production_due_to_microphysics - units = s-1 + units = kg kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out [ prodsnow ] standard_name = snow_production_due_to_microphysics - units = s-1 + units = kg kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out [ evapprec ] standard_name = precipitation_evaporation_due_to_microphysics - units = s-1 + units = kg kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out [ evapsnow ] standard_name = rate_of_evaporation_of_falling_snow_due_to_microphysics_tbd - units = s-1 + units = kg kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out @@ -412,7 +412,7 @@ dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out [ fracw ] - standard_name = relative_importance_of_rain_axcreting_liquid_tbd + standard_name = relative_importance_of_rain_accreting_liquid_tbd units = fraction type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) diff --git a/schemes/rasch_kristjansson/rk_stratiform.F90 b/schemes/rasch_kristjansson/rk_stratiform.F90 index 9cc85c58..38f5f3a7 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.F90 +++ b/schemes/rasch_kristjansson/rk_stratiform.F90 @@ -18,7 +18,7 @@ module rk_stratiform ! refer to test SDF suite_rasch_kristjansson.xml for total order of operations, ! as the full RK-stratiform requires other schemes not included in this module. public :: rk_stratiform_init - public :: rk_stratiform_timestep_init + public :: rk_stratiform_check_qtlcwat_run ! -- cloud_particle_sedimentation -- public :: rk_stratiform_sedimentation_run public :: rk_stratiform_detrain_convective_condensate_run @@ -49,9 +49,9 @@ subroutine rk_stratiform_init( & end subroutine rk_stratiform_init -!> \section arg_table_rk_stratiform_timestep_init Argument Table -!! \htmlinclude arg_table_rk_stratiform_timestep_init.html - subroutine rk_stratiform_timestep_init( & +!> \section arg_table_rk_stratiform_check_qtlcwat_run Argument Table +!! \htmlinclude arg_table_rk_stratiform_check_qtlcwat_run.html + subroutine rk_stratiform_check_qtlcwat_run( & ncol, pver, & t, q_wv, cldice, cldliq, & qcwat, tcwat, lcwat, & ! from end of last microphysics/macrophysics call. @@ -78,9 +78,7 @@ subroutine rk_stratiform_timestep_init( & errflg = 0 ! Check that qcwat and tcwat were initialized - if not then initialize - ! Note: this is done in timestep_init to be consistent with how rk_stratiform_tend has - ! this in the run phase. But maybe it can be moved to the init phase, so that it - ! does not have to be checked at every timestep. + ! this is made as a separate "run" scheme so it does not have to be used in current CAM ! The registry will set default values of negative if not read from snapshot. if(qcwat(1,1) < 0._kind_phys) then @@ -93,10 +91,11 @@ subroutine rk_stratiform_timestep_init( & ! lcwat is initialized from initial conditions of cldice, cldliq ! TODO: check if this is always done (appears to be from physpkg.F90) or should be read from snapshot. - lcwat(:ncol,:) = cldice(:ncol,:) + cldliq(:ncol,:) - + if(qcwat(1,1) < 0._kind_phys .or. tcwat(1,1) < 0._kind_phys) then + lcwat(:ncol,:) = cldice(:ncol,:) + cldliq(:ncol,:) + endif - end subroutine rk_stratiform_timestep_init + end subroutine rk_stratiform_check_qtlcwat_run !> \section arg_table_rk_stratiform_sedimentation_run Argument Table !! \htmlinclude arg_table_rk_stratiform_sedimentation_run.html @@ -429,8 +428,8 @@ subroutine rk_stratiform_prognostic_cloud_water_tendencies_run( & real(kind_phys), intent(in) :: evapprec(:,:) ! real(kind_phys), intent(in) :: ice2pr(:,:) ! real(kind_phys), intent(in) :: liq2pr(:,:) ! - real(kind_phys), intent(inout) :: prec_pcw(:) ! lwe_stratiform_precipitation_rate_at_surface [m s-1] - real(kind_phys), intent(inout) :: snow_pcw(:) ! lwe_snow_precipitation_rate_at_surface_due_to_microphysics [m s-1] + real(kind_phys), intent(in) :: prec_pcw(:) ! lwe_stratiform_precipitation_rate_at_surface [m s-1] + real(kind_phys), intent(in) :: snow_pcw(:) ! lwe_snow_precipitation_rate_at_surface_due_to_microphysics [m s-1] ! Input/output arguments real(kind_phys), intent(inout) :: prec_str(:) ! stratiform_rain_and_snow_surface_flux [m s-1] @@ -569,49 +568,4 @@ subroutine rk_stratiform_cloud_optical_properties_run( & end subroutine rk_stratiform_cloud_optical_properties_run - ! might be better suited for diagnostics ... - ! subroutine rk_stratiform_ice_and_liquid_water_content_run( & - ! ncol, pver, & - ! pmid, & - ! t, & - ! cldice, cldliq, & - ! rhcloud, & - ! iwc, lwc, & - ! icimr, icwmr, & - ! errmsg, errflg) - - ! ! Input arguments - ! integer, intent(in) :: ncol - ! integer, intent(in) :: pver - ! real(kind_phys), intent(in) :: pmid(:,:) ! air_pressure [Pa] - ! real(kind_phys), intent(in) :: t(:,:) ! air_temperature [K] - ! real(kind_phys), intent(in) :: cldliq(:,:) ! adv: cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] - ! real(kind_phys), intent(in) :: cldice(:,:) ! adv: cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] - ! real(kind_phys), intent(in) :: rhcloud(:,:) ! ? [fraction] - - ! ! Output arguments - ! real(kind_phys), intent(out) :: iwc(:) ! stratiform_cloud_ice_water_content [kg m-3] - ! real(kind_phys), intent(out) :: lwc(:) ! stratiform_cloud_liquid_water_content [kg m-3] - ! real(kind_phys), intent(out) :: icimr(:) ! stratiform_cloud_ice_water_mixing_ratio [kg kg-1] - ! real(kind_phys), intent(out) :: icwmr(:) ! stratiform_cloud_liquid_water_mixing_ratio [kg kg-1] - ! character(len=512), intent(out) :: errmsg ! error message - ! integer, intent(out) :: errflg ! error flag - - ! integer :: i, k - ! errmsg = '' - ! errflg = 0 - - ! do k = 1, pver - ! do i = 1, ncol - ! iwc(i,k) = cldice(i,k)*pmid(i,k)/(287.15_kind_phys*t(i,k)) - ! lwc(i,k) = cldliq(i,k)*pmid(i,k) / & - ! (287.15_kind_phys*t(i,k)) - ! icimr(i,k) = cldice(i,k) / max(0.01_kind_phys,rhcloud(i,k)) - ! icwmr(i,k) = cldliq(i,k) / max(0.01_kind_phys,rhcloud(i,k)) - ! end do - ! end do - - ! end subroutine rk_stratiform_ice_and_liquid_water_content_run - - end module rk_stratiform diff --git a/schemes/rasch_kristjansson/rk_stratiform.meta b/schemes/rasch_kristjansson/rk_stratiform.meta index 5c2379db..af2dfcab 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.meta +++ b/schemes/rasch_kristjansson/rk_stratiform.meta @@ -1,7 +1,6 @@ [ccpp-table-properties] name = rk_stratiform type = scheme - dependencies = ../../to_be_ccppized/cloud_optical_properties.F90 [ccpp-arg-table] name = rk_stratiform_init @@ -19,8 +18,12 @@ dimensions = () intent = out +[ccpp-table-properties] + name = rk_stratiform_check_qtlcwat + type = scheme + [ccpp-arg-table] - name = rk_stratiform_timestep_init + name = rk_stratiform_check_qtlcwat_run type = scheme [ ncol ] standard_name = horizontal_loop_extent @@ -46,18 +49,21 @@ type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in + advected = true [ cldice ] standard_name = cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water units = kg kg-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in + advected = true [ cldliq ] standard_name = cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water units = kg kg-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in + advected = true [ qcwat ] standard_name = water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water_at_end_of_microphysics units = kg kg-1 @@ -579,7 +585,7 @@ intent = in [ qme ] standard_name = net_condensation_rate_due_to_microphysics - units = s-1 + units = kg kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in @@ -615,7 +621,7 @@ intent = in [ evapprec ] standard_name = precipitation_evaporation_due_to_microphysics - units = s-1 + units = kg kg-1 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in @@ -636,13 +642,13 @@ units = m s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent) - intent = inout + intent = in [ snow_pcw ] standard_name = lwe_snow_precipitation_rate_at_surface_due_to_microphysics units = m s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent) - intent = inout + intent = in [ prec_str ] standard_name = stratiform_rain_and_snow_surface_flux units = m s-1 @@ -790,6 +796,7 @@ [ccpp-table-properties] name = rk_stratiform_cloud_optical_properties type = scheme + dependencies = ../../to_be_ccppized/cloud_optical_properties.F90 [ccpp-arg-table] name = rk_stratiform_cloud_optical_properties_run From 74a3f9e49411437c958c76d0d2385bafe1a2f5b9 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Wed, 19 Mar 2025 10:48:03 -0400 Subject: [PATCH 23/39] Update SDF; cldwat initialization --- .../prognostic_cloud_water.F90 | 6 +++ test/test_suites/suite_rasch_kristjansson.xml | 45 ++++++++++++------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 index d4e22855..5761f2f1 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 @@ -461,6 +461,11 @@ subroutine prognostic_cloud_water_run( & psacwo(:ncol,:) = 0._kind_phys psacio(:ncol,:) = 0._kind_phys + ! reset diagnostic arrays + rcwn(:,:,:) = 0._kind_phys + rliq(:,:,:) = 0._kind_phys + rice(:,:,:) = 0._kind_phys + ! find the wet bulb temp and saturation value ! for the provisional t and q without condensation mp_level_loop: do k = top_lev, pver @@ -688,6 +693,7 @@ subroutine prognostic_cloud_water_run( & prodprec(i,k) = (nliq2pr + nice2pr) prodsnow(i,k) = (nice2pr + nliq2snow) + ! compute diagnostics and sanity checks rcwn(i,l,k) = cwat(i,k) + (qme(i,k) - prodprec(i,k))*deltat rliq(i,l,k) = (cwat(i,k) + qme(i,k)*deltat)*(1._kind_phys-fice(i,k)) - nliq2pr*deltat rice(i,l,k) = (cwat(i,k) + qme(i,k)*deltat) * fice(i,k) - nice2pr*deltat diff --git a/test/test_suites/suite_rasch_kristjansson.xml b/test/test_suites/suite_rasch_kristjansson.xml index 33fc83b0..cd488cee 100644 --- a/test/test_suites/suite_rasch_kristjansson.xml +++ b/test/test_suites/suite_rasch_kristjansson.xml @@ -10,12 +10,20 @@ --> + to_be_ccppized_temporary + tropopause_find + + rk_stratiform_diagnostics + + + rk_stratiform_check_qtlcwat + cloud_particle_sedimentation - + apply_constituent_tendencies apply_heating_rate qneg @@ -24,6 +32,9 @@ rk_stratiform_detrain_convective_condensate + apply_constituent_tendencies + qneg + geopotential_temp compute_cloud_fraction rk_stratiform_cloud_fraction_perturbation - + rk_stratiform_external_forcings - + cloud_fraction_fice + + + prognostic_cloud_water + + rk_stratiform_condensate_repartioning + apply_constituent_tendencies qneg geopotential_temp - - - prognostic_cloud_water rk_stratiform_prognostic_cloud_water_tendencies - + apply_constituent_tendencies apply_heating_rate qneg geopotential_temp - convective_cloud_cover compute_cloud_fraction - - - + rk_stratiform_cloud_optical_properties From b433d2b4da126ac76c8fad6c95b718955fdf115f Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Fri, 21 Mar 2025 13:46:07 -0400 Subject: [PATCH 24/39] Remove unused rlat in prognostic_cloud_water --- schemes/rasch_kristjansson/prognostic_cloud_water.F90 | 3 +-- schemes/rasch_kristjansson/prognostic_cloud_water.meta | 6 ------ 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 index 5761f2f1..39acfcaf 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 @@ -226,7 +226,7 @@ subroutine prognostic_cloud_water_run( & ncol, pver, top_lev, deltat, & iulog, & pi, gravit, rh2o, epsilo, latvap, latice, cpair, & - dlat, rlat, & + dlat, & pmid, pdel, & zi, & troplev, & @@ -267,7 +267,6 @@ subroutine prognostic_cloud_water_run( & real(kind_phys), intent(in) :: latice ! latent_heat_of_fusion_of_water_at_0c [J kg-1] real(kind_phys), intent(in) :: cpair ! specific_heat_of_dry_air_at_constant_pressure [J K-1 kg-1] real(kind_phys), intent(in) :: dlat(:) ! latitude_degrees_north [degrees] - real(kind_phys), intent(in) :: rlat(:) ! latitude [rad] real(kind_phys), intent(in) :: pmid(:,:) ! air_pressure [Pa] real(kind_phys), intent(in) :: pdel(:,:) ! air_pressure_thickness [Pa] real(kind_phys), intent(in) :: zi(:,:) ! geopotential_height_wrt_surface_at_interface [m] diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.meta b/schemes/rasch_kristjansson/prognostic_cloud_water.meta index 297ad11f..b66a7e04 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.meta +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.meta @@ -165,12 +165,6 @@ type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = in -[ rlat ] - standard_name = latitude - units = rad - type = real | kind = kind_phys - dimensions = (horizontal_loop_extent) - intent = in [ pmid ] standard_name = air_pressure units = Pa From c67c21f863a458b4e053664b04bc22e3cf25055d Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 24 Mar 2025 12:25:39 -0400 Subject: [PATCH 25/39] Update schemes/cloud_fraction/compute_cloud_fraction.F90 Co-authored-by: Jesse Nusbaumer --- schemes/cloud_fraction/compute_cloud_fraction.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/schemes/cloud_fraction/compute_cloud_fraction.F90 b/schemes/cloud_fraction/compute_cloud_fraction.F90 index b94d6634..74410526 100644 --- a/schemes/cloud_fraction/compute_cloud_fraction.F90 +++ b/schemes/cloud_fraction/compute_cloud_fraction.F90 @@ -31,9 +31,9 @@ module compute_cloud_fraction integer :: k700 ! model level nearest to 700 mb [index] ! constants - real(kind_phys), parameter :: pnot = 1.e5_kind_phys ! reference pressure - real(kind_phys), parameter :: lapse = 6.5e-3_kind_phys ! U.S. Standard Atmosphere lapse rate - real(kind_phys), parameter :: pretop = 1.0e2_kind_phys ! pressure bounding high cloud + real(kind_phys), parameter :: pnot = 1.e5_kind_phys ! reference pressure [Pa] + real(kind_phys), parameter :: lapse = 6.5e-3_kind_phys ! U.S. Standard Atmosphere lapse rate [K m-1] + real(kind_phys), parameter :: pretop = 1.0e2_kind_phys ! pressure bounding high cloud [Pa] contains ! Initialize cloud_fraction from namelist parameters From 9c23a1e8857a69dbe3aaeabfb5989c5b6a3d8860 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 24 Mar 2025 12:26:01 -0400 Subject: [PATCH 26/39] Update schemes/cloud_fraction/compute_cloud_fraction.F90 Co-authored-by: Jesse Nusbaumer --- schemes/cloud_fraction/compute_cloud_fraction.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schemes/cloud_fraction/compute_cloud_fraction.F90 b/schemes/cloud_fraction/compute_cloud_fraction.F90 index 74410526..53ce983c 100644 --- a/schemes/cloud_fraction/compute_cloud_fraction.F90 +++ b/schemes/cloud_fraction/compute_cloud_fraction.F90 @@ -56,7 +56,7 @@ subroutine compute_cloud_fraction_init( & integer, intent(in) :: iulog integer, intent(in) :: pver real(kind_phys), intent(in) :: pref_mid(:) ! reference_pressure [Pa] - logical, intent(in) :: inversion_cld_off_in ! flag for turn off inversion_cld? + logical, intent(in) :: inversion_cld_off_in ! flag to turn off inversion_cld? logical, intent(in) :: cldfrc_freeze_dry_in ! flag for Vavrus correction logical, intent(in) :: cldfrc_ice_in ! flag to compute ice cloud fraction integer, intent(in) :: iceopt_in ! option for ice cloud closure From 5e47894686a566651a401c88d86c9b65c1c75935 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 24 Mar 2025 12:54:00 -0400 Subject: [PATCH 27/39] Fix failing MUSICA docker test --- test/docker/Dockerfile.musica | 6 +++--- test/docker/Dockerfile.musica.no_install | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/docker/Dockerfile.musica b/test/docker/Dockerfile.musica index 8c1dfdcc..89b5f0eb 100644 --- a/test/docker/Dockerfile.musica +++ b/test/docker/Dockerfile.musica @@ -85,10 +85,10 @@ RUN cd atmospheric_physics/test \ ENV CCPP_SRC_PATH="lib/ccpp-framework/src" ENV CCPP_FORTRAN_TOOLS_PATH="lib/ccpp-framework/scripts/fortran_tools" -# Make the CCPPStandardNames available +# Make the ESMStandardNames available RUN cd atmospheric_physics/test/lib \ - && git clone --depth 1 https://github.com/ESCOMP/CCPPStandardNames.git -ENV CCPP_STD_NAMES_PATH="lib/CCPPStandardNames" + && git clone --depth 1 https://github.com/ESCOMP/ESMStandardNames.git +ENV CCPP_STD_NAMES_PATH="lib/ESMStandardNames" RUN cd atmospheric_physics/test \ && cmake -S . -B build \ diff --git a/test/docker/Dockerfile.musica.no_install b/test/docker/Dockerfile.musica.no_install index 6abec992..b9e1fdb4 100644 --- a/test/docker/Dockerfile.musica.no_install +++ b/test/docker/Dockerfile.musica.no_install @@ -67,10 +67,10 @@ RUN cd atmospheric_physics/test \ ENV CCPP_SRC_PATH="lib/ccpp-framework/src" ENV CCPP_FORTRAN_TOOLS_PATH="lib/ccpp-framework/scripts/fortran_tools" -# Make the CCPPStandardNames available +# Make the ESMStandardNames available RUN cd atmospheric_physics/test/lib \ - && git clone --depth 1 https://github.com/ESCOMP/CCPPStandardNames.git -ENV CCPP_STD_NAMES_PATH="lib/CCPPStandardNames" + && git clone --depth 1 https://github.com/ESCOMP/ESMStandardNames.git +ENV CCPP_STD_NAMES_PATH="lib/ESMStandardNames" RUN cd atmospheric_physics/test \ && cmake -S . -B build \ From b2d57f4e58c116ae10248941770eee711582eb37 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 24 Mar 2025 12:54:11 -0400 Subject: [PATCH 28/39] Fix typo --- schemes/dry_adiabatic_adjust/dadadj_namelist.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schemes/dry_adiabatic_adjust/dadadj_namelist.xml b/schemes/dry_adiabatic_adjust/dadadj_namelist.xml index 27504b75..020aeaa2 100644 --- a/schemes/dry_adiabatic_adjust/dadadj_namelist.xml +++ b/schemes/dry_adiabatic_adjust/dadadj_namelist.xml @@ -67,7 +67,7 @@ to this variable when the namelist generator is run. If the tag has no attributes, it is a default value. In general, the namelist generator attempts to find a value with the - maximium number of attribute matches (and no non-matches). + maximum number of attribute matches (and no non-matches). standard_name This is the CCPP Standard Name of the variable From 9fc886a3552d4b12e905cc85f88e7cfe6bf5624d Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 24 Mar 2025 12:55:39 -0400 Subject: [PATCH 29/39] Address review comments --- .../cloud_fraction/compute_cloud_fraction.F90 | 28 +++--- .../compute_cloud_fraction.meta | 18 ++-- .../compute_cloud_fraction_namelist.xml | 92 +++++++++++++++++-- .../cloud_fraction/convective_cloud_cover.F90 | 4 +- .../convective_cloud_cover_namelist.xml | 72 +++++++++++++++ .../cloud_particle_sedimentation.F90 | 13 +-- .../cloud_particle_sedimentation.meta | 2 +- .../cloud_particle_sedimentation_namelist.xml | 72 +++++++++++++++ .../prognostic_cloud_water.F90 | 15 +-- .../prognostic_cloud_water_namelist.xml | 74 ++++++++++++++- schemes/rasch_kristjansson/rk_stratiform.F90 | 42 +++------ schemes/rasch_kristjansson/rk_stratiform.meta | 28 ++---- 12 files changed, 359 insertions(+), 101 deletions(-) diff --git a/schemes/cloud_fraction/compute_cloud_fraction.F90 b/schemes/cloud_fraction/compute_cloud_fraction.F90 index 53ce983c..b823792d 100644 --- a/schemes/cloud_fraction/compute_cloud_fraction.F90 +++ b/schemes/cloud_fraction/compute_cloud_fraction.F90 @@ -87,17 +87,17 @@ subroutine compute_cloud_fraction_init( & inversion_cld_off = inversion_cld_off_in if(amIRoot) then - write(iulog,*) 'tuning parameters compute_cloud_fraction_init: inversion_cld_off', inversion_cld_off - write(iulog,*) 'tuning parameters compute_cloud_fraction_init: rhminl',rhminl,'rhminl_adj_land',rhminl_adj_land, & - 'rhminh',rhminh,'premit',premit,'premib',premib - write(iulog,*) 'tuning parameters compute_cloud_fraction_init: iceopt',iceopt,'icecrit',icecrit + write(iulog,*) 'tuning parameters compute_cloud_fraction_init: inversion_cld_off ', inversion_cld_off + write(iulog,*) 'tuning parameters compute_cloud_fraction_init: rhminl ',rhminl,'rhminl_adj_land ',rhminl_adj_land, & + ' rhminh ',rhminh,' premit ',premit,' premib ',premib + write(iulog,*) 'tuning parameters compute_cloud_fraction_init: iceopt ',iceopt,' icecrit ',icecrit endif ! Find vertical level nearest 700 mb. k700 = minloc(abs(pref_mid(:) - 7.e4_kind_phys), 1) if(amIRoot) then - write(iulog,*) 'compute_cloud_fraction: model level nearest 700 mb is',k700,'which is',pref_mid(k700),'pascals' + write(iulog,*) 'compute_cloud_fraction: model level nearest 700 mb is ',k700,' which is',pref_mid(k700),' pascals ' endif end subroutine compute_cloud_fraction_init @@ -162,8 +162,8 @@ subroutine compute_cloud_fraction_run( & real(kind_phys), intent(in) :: q(:, :) ! water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] real(kind_phys), intent(in) :: cldice(:, :) ! cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1] real(kind_phys), intent(in) :: phis(:) ! surface_geopotential [m2 s-2] - real(kind_phys), intent(in) :: shallowcu(:, :) ! shallow convective cloud fraction - real(kind_phys), intent(in) :: deepcu(:, :) ! deep convective cloud fraction + real(kind_phys), intent(in) :: shallowcu(:, :) ! shallow convective cloud fraction [fraction] + real(kind_phys), intent(in) :: deepcu(:, :) ! deep convective cloud fraction [fraction] real(kind_phys), intent(in) :: concld(:, :) ! convective_cloud_area_fraction [fraction] real(kind_phys), intent(in) :: landfrac(:) ! land_area_fraction [fraction] real(kind_phys), intent(in) :: ocnfrac(:) ! ocean_area_fraction [fraction] @@ -174,10 +174,10 @@ subroutine compute_cloud_fraction_run( & real(kind_phys), intent(out) :: cloud(:, :) ! cloud_area_fraction [fraction] real(kind_phys), intent(out) :: rhcloud(:, :) ! cloud fraction real(kind_phys), intent(out) :: cldst(:, :) ! stratiform_cloud_area_fraction [fraction] - real(kind_phys), intent(out) :: rhu00(:, :) ! RH threshold for cloud - real(kind_phys), intent(out) :: relhum(:, :) ! RH for prognostic cldwat [percent] - real(kind_phys), intent(out) :: icecldf(:, :) ! ice cloud fraction - real(kind_phys), intent(out) :: liqcldf(:, :) ! liquid cloud fraction (combined into cloud) + real(kind_phys), intent(out) :: rhu00(:, :) ! RH threshold for cloud [fraction] + real(kind_phys), intent(out) :: relhum(:, :) ! RH for prognostic cldwat [fraction] + real(kind_phys), intent(out) :: icecldf(:, :) ! ice cloud fraction [fraction] + real(kind_phys), intent(out) :: liqcldf(:, :) ! liquid cloud fraction (combined into cloud) [fraction] character(len=512), intent(out) :: errmsg ! error message integer, intent(out) :: errflg ! error flag @@ -247,7 +247,7 @@ subroutine compute_cloud_fraction_run( & ! (a sum as opposed to a logical "or" operation) ! !================================================================================== - ! set defaults for rhu00 + ! set defaults for rhu00 - arbitrary number larger than 1.0 (100%) rhu00(:, :) = 2.0_kind_phys ! define rh perturbation in order to estimate rhdfda rhpert = 0.01_kind_phys @@ -406,6 +406,7 @@ subroutine compute_cloud_fraction_run( & ! icicval = f(temp,cldice,numice) ! Start with a function of temperature. ! Wang & Sassen 2002 (JAS), based on ARM site MMCR (midlat cirrus) + ! https://doi.org/10.1175/1520-0469(2002)059<2291:CCMPRU>2.0.CO;2 ! parameterization valid for 203-253K ! icival > 0 for t>195K if (iceopt .lt. 3) then @@ -417,6 +418,7 @@ subroutine compute_cloud_fraction_run( & icicval = icicval*1.e-6_kind_phys/rho else !--------ICE CLOUD OPTION 2--------Schiller 2008 (JGR) + ! https://doi.org/10.1029/2008JD010342 ! Use a curve based on FISH measurements in ! tropics, mid-lats and arctic. Curve is for 180-250K (raise to 273K?) ! use median all flights @@ -432,12 +434,14 @@ subroutine compute_cloud_fraction_run( & else if (iceopt .eq. 3) then !--------ICE CLOUD OPTION 3--------Wood & Field 2000 (JAS) + ! https://doi.org/10.1175/1520-0469(2000)057<1888:RBTWCW>2.0.CO;2 ! eq 6: cloud fraction = 1 - exp (-K * qc/qsati) icecldf(i, k) = 1._kind_phys - exp(-Kc*cldice(i, k)/(qs(i, k)*(esi(i, k)/esl(i, k)))) icecldf(i, k) = max(0._kind_phys, min(icecldf(i, k), 1._kind_phys)) else !--------ICE CLOUD OPTION 4--------Wilson and ballard 1999 + ! https://doi.org/10.1002/qj.49712555707 ! inversion of smith.... ! ncf = cldice / ((1-RHcrit)*qs) ! then a function of ncf.... diff --git a/schemes/cloud_fraction/compute_cloud_fraction.meta b/schemes/cloud_fraction/compute_cloud_fraction.meta index 425b796c..39434f67 100644 --- a/schemes/cloud_fraction/compute_cloud_fraction.meta +++ b/schemes/cloud_fraction/compute_cloud_fraction.meta @@ -31,25 +31,25 @@ dimensions = (vertical_layer_dimension) intent = in [ inversion_cld_off_in ] - standard_name = flag_for_turning_off_stratification_based_for_cloud_fraction + standard_name = do_no_stratification_based_cloud_fraction units = flag type = logical dimensions = () intent = in [ cldfrc_freeze_dry_in ] - standard_name = flag_for_vavrus_freeze_dry_adjustment_for_cloud_fraction + standard_name = do_vavrus_freeze_dry_adjustment_for_cloud_fraction units = flag type = logical dimensions = () intent = in [ cldfrc_ice_in ] - standard_name = flag_for_ice_cloud_fraction_for_cloud_fraction + standard_name = do_ice_cloud_fraction_for_cloud_fraction units = flag type = logical dimensions = () intent = in [ iceopt_in ] - standard_name = scheme_for_ice_cloud_fraction + standard_name = control_for_ice_cloud_fraction units = 1 type = integer dimensions = () @@ -85,7 +85,7 @@ dimensions = () intent = in [ icecrit_in ] - standard_name = tunable_parameter_for_critical_relative_humidity_for_ice_clouds_for_cloud_fraction_using_wilson_from_ballard_scheme + standard_name = tunable_parameter_for_critical_relative_humidity_for_ice_clouds_for_cloud_fraction_using_wilson_and_ballard_scheme units = 1 type = real | kind = kind_phys dimensions = () @@ -107,7 +107,7 @@ name = compute_cloud_fraction_timestep_init type = scheme [ rhpert_flag ] - standard_name = flag_for_relative_humidity_perturbation_for_cloud_fraction + standard_name = do_relative_humidity_perturbation_for_cloud_fraction units = flag type = logical dimensions = () @@ -249,7 +249,7 @@ dimensions = (horizontal_loop_extent) intent = in [ rhpert_flag ] - standard_name = flag_for_relative_humidity_perturbation_for_cloud_fraction + standard_name = do_relative_humidity_perturbation_for_cloud_fraction units = flag type = logical dimensions = () @@ -274,7 +274,7 @@ intent = out [ rhu00 ] standard_name = relative_humidity_threshold_for_prognostic_cloud_water_tbd - units = percent + units = fraction type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out @@ -292,7 +292,7 @@ intent = out [ relhum ] standard_name = relative_humidity_for_prognostic_cloud_water_tbd - units = percent + units = fraction type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out diff --git a/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml b/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml index 2a843553..a9b1b168 100644 --- a/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml +++ b/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml @@ -3,46 +3,120 @@ + + logical cldfrc cldfrc_nl - flag_for_vavrus_freeze_dry_adjustment_for_cloud_fraction + do_vavrus_freeze_dry_adjustment_for_cloud_fraction flag Turn on for Vavrus "freeze dry" adjustment in cloud fraction. Default: TRUE - true + .true. logical cldfrc cldfrc_nl - flag_for_ice_cloud_fraction_for_cloud_fraction + do_ice_cloud_fraction_for_cloud_fraction flag Turn on ice cloud fraction calculation Default: TRUE (CAM5 and CAM6) or FALSE - false + .false. + .true. + .true. logical cldfrc cldfrc_nl - flag_for_turning_off_stratification_based_for_cloud_fraction + do_no_stratification_based_cloud_fraction flag Turn off stratification-based cloud fraction Default: FALSE - false + .false. @@ -108,7 +182,7 @@ tunable_parameter_for_bottom_pressure_bound_for_mid_level_liquid_stratus_for_cloud_fraction Pa - Bottom height for mid-level liquid stratus fraction. + Bottom pressure bound for mid-level liquid stratus fraction. 750.0D2 @@ -118,7 +192,7 @@ integer cldfrc cldfrc_nl - scheme_for_ice_cloud_fraction + control_for_ice_cloud_fraction 1 Scheme for ice cloud fraction. @@ -136,7 +210,7 @@ real cldfrc cldfrc_nl - tunable_parameter_for_critical_relative_humidity_for_ice_clouds_for_cloud_fraction_using_wilson_from_ballard_scheme + tunable_parameter_for_critical_relative_humidity_for_ice_clouds_for_cloud_fraction_using_wilson_and_ballard_scheme 1 Critical RH for ice clouds using the Wilson and Ballard scheme diff --git a/schemes/cloud_fraction/convective_cloud_cover.F90 b/schemes/cloud_fraction/convective_cloud_cover.F90 index 802f2138..3e82a698 100644 --- a/schemes/cloud_fraction/convective_cloud_cover.F90 +++ b/schemes/cloud_fraction/convective_cloud_cover.F90 @@ -48,7 +48,7 @@ subroutine convective_cloud_cover_init( & dp2 = dp2_in if(amIRoot) then - write(iulog,*) 'tuning parameters convective_cloud_cover: dp1',dp1,'dp2',dp2,'sh1',sh1,'sh2',sh2 + write(iulog,*) 'tuning parameters convective_cloud_cover: dp1 ',dp1,' dp2 ',dp2,' sh1 ',sh1,' sh2 ',sh2 endif end subroutine convective_cloud_cover_init @@ -72,7 +72,7 @@ subroutine convective_cloud_cover_run( & integer, intent(in) :: pver integer, intent(in) :: top_lev_cloudphys ! Top vertical level for cloud physics [index] - logical, intent(in) :: use_shfrc ! [flag] + logical, intent(in) :: use_shfrc ! Use cloud area fraction provided by shallow convection? [flag] real(kind_phys), intent(in) :: shfrc(:, :) ! Input shallow cloud fraction [fraction] real(kind_phys), intent(in) :: cmfmc_total(:, :) ! atmosphere_convective_mass_flux_due_to_all_convection [kg m-2 s-1] diff --git a/schemes/cloud_fraction/convective_cloud_cover_namelist.xml b/schemes/cloud_fraction/convective_cloud_cover_namelist.xml index 596084ee..ab4dc32c 100644 --- a/schemes/cloud_fraction/convective_cloud_cover_namelist.xml +++ b/schemes/cloud_fraction/convective_cloud_cover_namelist.xml @@ -3,6 +3,78 @@ + + real kind_phys diff --git a/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 b/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 index 122ef445..3f4baad4 100644 --- a/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 +++ b/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 @@ -139,12 +139,13 @@ subroutine cloud_particle_sedimentation_run( & real(kind_phys), intent(in) :: landm(:) ! smoothed_land_area_fraction [fraction] ! Output arguments - ! note: pvel is at the interfaces (loss from cell is based on pvel(k+1)) - real(kind_phys), intent(out) :: pvliq(:,:) ! vertical velocity of cloud liquid drops [Pa s-1] pverp - real(kind_phys), intent(out) :: pvice(:,:) ! vertical velocity of cloud ice particles [Pa s-1] pverp - real(kind_phys), intent(out) :: liqtend(:,:) ! liquid condensate tendency -- to apply cldliq tendency - real(kind_phys), intent(out) :: icetend(:,:) ! ice condensate tendency -- to apply cldice tendency - real(kind_phys), intent(out) :: wvtend(:,:) ! water vapor tendency -- to apply wv tendency + ! note: pvliq, pvice are at the interfaces (loss from cell is based on pvel(k+1)) + real(kind_phys), intent(out) :: pvliq(:,:) ! vertical velocity of cloud liquid drops [Pa s-1] + real(kind_phys), intent(out) :: pvice(:,:) ! vertical velocity of cloud ice particles [Pa s-1] + + real(kind_phys), intent(out) :: liqtend(:,:) ! liquid condensate tendency [kg kg-1 s-1] -- to apply cldliq tendency + real(kind_phys), intent(out) :: icetend(:,:) ! ice condensate tendency [kg kg-1 s-1] -- to apply cldice tendency + real(kind_phys), intent(out) :: wvtend(:,:) ! water vapor tendency [kg kg-1 s-1] -- to apply wv tendency real(kind_phys), intent(out) :: htend(:,:) ! heating rate [J kg-1 s-1] -- to apply s tendency real(kind_phys), intent(out) :: sfliq(:) ! surface flux of liquid (rain) [kg m-2 s-1] real(kind_phys), intent(out) :: sfice(:) ! lwe_cloud_ice_sedimentation_rate_at_surface_due_to_microphysics [m s-1] diff --git a/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta b/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta index 1255df07..22d589e6 100644 --- a/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta +++ b/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta @@ -232,7 +232,7 @@ dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out [ sfliq ] - standard_name = stratiform_rain_surface_flux_due_to_sedimentation + standard_name = stratiform_rain_flux_at_surface_due_to_sedimentation units = kg m-2 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent) diff --git a/schemes/rasch_kristjansson/cloud_particle_sedimentation_namelist.xml b/schemes/rasch_kristjansson/cloud_particle_sedimentation_namelist.xml index 209c580e..6a32eb23 100644 --- a/schemes/rasch_kristjansson/cloud_particle_sedimentation_namelist.xml +++ b/schemes/rasch_kristjansson/cloud_particle_sedimentation_namelist.xml @@ -3,6 +3,78 @@ + + real cldsed diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 index 39acfcaf..f40f0bf5 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 @@ -112,7 +112,7 @@ subroutine prognostic_cloud_water_init( & psrhmin = psrhmin_in if(amIRoot) then - write(iulog,*) 'tuning parameters prognostic_cloud_water_init: icritw',icritw,'icritc',icritc,'conke',conke,'r3lcrit',r3lcrit + write(iulog,*) 'tuning parameters prognostic_cloud_water_init: icritw ',icritw,' icritc ',icritc,' conke ',conke,' r3lcrit ',r3lcrit write(iulog,*) 'prognostic_cloud_water_init: do_psrhmin = ', do_psrhmin endif @@ -200,9 +200,9 @@ subroutine prognostic_cloud_water_init( & ciautb = 5.e-4_kind_phys if(amIRoot) then - write(iulog,*) 'tuning parameters prognostic_cloud_water_init: capnw',capnw,'capnc',capnc,'capnsi',capnsi,'kconst',kconst - write(iulog,*) 'tuning parameters prognostic_cloud_water_init: effc',effc,'alpha',alpha,'capc',capc - write(iulog,*) 'tuning parameters prognostic_cloud_water_init: critpr',critpr,'convfw',convfw,'cracw',cracw,'ciautb',ciautb + write(iulog,*) 'tuning parameters prognostic_cloud_water_init: capnw ',capnw,' capnc ',capnc,' capnsi ',capnsi,' kconst',kconst + write(iulog,*) 'tuning parameters prognostic_cloud_water_init: effc ',effc,' alpha ',alpha,' capc ',capc + write(iulog,*) 'tuning parameters prognostic_cloud_water_init: critpr ',critpr,' convfw ',convfw,' cracw ',cracw,' ciautb ',ciautb endif end subroutine prognostic_cloud_water_init @@ -283,7 +283,7 @@ subroutine prognostic_cloud_water_run( & real(kind_phys), intent(in) :: omega(:,:) ! lagrangian_tendency_of_air_pressure [Pa s-1] real(kind_phys), intent(in) :: cldn(:,:) ! New Cloud fraction [fraction] real(kind_phys), intent(in) :: fice(:,:) ! Ice fraction within cwat [fraction] - real(kind_phys), intent(in) :: fsnow(:,:) ! Fraction of rain that freezes to show [fraction] + real(kind_phys), intent(in) :: fsnow(:,:) ! Fraction of rain that freezes to snow [fraction] real(kind_phys), intent(in) :: rhdfda(:,:) ! dG(a)/da, rh=G(a), when rh>u00 [??] real(kind_phys), intent(in) :: rhu00(:,:) ! Rhlim for cloud [percent] @@ -344,8 +344,6 @@ subroutine prognostic_cloud_water_run( & real(kind_phys) :: cwm(ncol) ! Cloud water mixing ratio at midpoint of timestep [kg kg-1] real(kind_phys) :: cwn(ncol) ! Cloud water mixing ratio at end of timestep [kg kg-1] real(kind_phys) :: coef(ncol) ! Conversion timescale for condensate to rain [s-1] - !real(kind_phys) :: ice(ncol,pver) ! Ice mixing ratio [kg kg-1] - !real(kind_phys) :: liq(ncol,pver) ! Liquid water mixing ratio [kg kg-1] ! Thermodynamic variables real(kind_phys) :: t(ncol,pver) ! Temperature before timestep [K] @@ -998,9 +996,6 @@ subroutine findmcnew( & i = ind(ii) rhocgs = rho(i)*1.e-3_kind_phys ! density in cgs units - ! exponential temperature factor - ! efact = exp(0.025*(t(i,k)-t0)) - ! some temperature dependent constants wt = fice(i) icrit = icritc*wt + icritw*(1-wt) diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water_namelist.xml b/schemes/rasch_kristjansson/prognostic_cloud_water_namelist.xml index 4abb7282..0f30d5da 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water_namelist.xml +++ b/schemes/rasch_kristjansson/prognostic_cloud_water_namelist.xml @@ -3,6 +3,78 @@ + + real conv @@ -86,7 +158,7 @@ cloud water condensation. Used for special WACCM/CAM-chem cases with CAM4 physics. - false + .false. diff --git a/schemes/rasch_kristjansson/rk_stratiform.F90 b/schemes/rasch_kristjansson/rk_stratiform.F90 index 38f5f3a7..d2054b89 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.F90 +++ b/schemes/rasch_kristjansson/rk_stratiform.F90 @@ -17,7 +17,6 @@ module rk_stratiform ! ! refer to test SDF suite_rasch_kristjansson.xml for total order of operations, ! as the full RK-stratiform requires other schemes not included in this module. - public :: rk_stratiform_init public :: rk_stratiform_check_qtlcwat_run ! -- cloud_particle_sedimentation -- public :: rk_stratiform_sedimentation_run @@ -34,21 +33,6 @@ module rk_stratiform contains - ! Initialize rk_stratiform -!> \section arg_table_rk_stratiform_init Argument Table -!! \htmlinclude arg_table_rk_stratiform_init.html - subroutine rk_stratiform_init( & - errmsg, errflg) - - ! Output arguments - character(len=512), intent(out) :: errmsg ! error message - integer, intent(out) :: errflg ! error flag - - errmsg = '' - errflg = 0 - - end subroutine rk_stratiform_init - !> \section arg_table_rk_stratiform_check_qtlcwat_run Argument Table !! \htmlinclude arg_table_rk_stratiform_check_qtlcwat_run.html subroutine rk_stratiform_check_qtlcwat_run( & @@ -80,7 +64,13 @@ subroutine rk_stratiform_check_qtlcwat_run( & ! Check that qcwat and tcwat were initialized - if not then initialize ! this is made as a separate "run" scheme so it does not have to be used in current CAM - ! The registry will set default values of negative if not read from snapshot. + ! lcwat is initialized from initial conditions of cldice, cldliq + ! TODO: check if this is always done (appears to be from physpkg.F90) or should be read from snapshot. + if(qcwat(1,1) < 0._kind_phys .or. tcwat(1,1) < 0._kind_phys) then + lcwat(:ncol,:) = cldice(:ncol,:) + cldliq(:ncol,:) + endif + + ! The registry will set default negative values if not read from snapshot. if(qcwat(1,1) < 0._kind_phys) then qcwat(:ncol,:) = q_wv(:ncol,:) endif @@ -89,12 +79,6 @@ subroutine rk_stratiform_check_qtlcwat_run( & tcwat(:ncol,:) = t(:ncol,:) endif - ! lcwat is initialized from initial conditions of cldice, cldliq - ! TODO: check if this is always done (appears to be from physpkg.F90) or should be read from snapshot. - if(qcwat(1,1) < 0._kind_phys .or. tcwat(1,1) < 0._kind_phys) then - lcwat(:ncol,:) = cldice(:ncol,:) + cldliq(:ncol,:) - endif - end subroutine rk_stratiform_check_qtlcwat_run !> \section arg_table_rk_stratiform_sedimentation_run Argument Table @@ -108,12 +92,12 @@ subroutine rk_stratiform_sedimentation_run( & ! Input arguments integer, intent(in) :: ncol - real(kind_phys), intent(in) :: sfliq(:) ! stratiform_rain_surface_flux_due_to_sedimentation [kg m-2 s-1] + real(kind_phys), intent(in) :: sfliq(:) ! stratiform_rain_flux_at_surface_due_to_sedimentation [kg m-2 s-1] real(kind_phys), intent(in) :: snow_sed(:) ! sfice = lwe_cloud_ice_sedimentation_rate_at_surface_due_to_microphysics [m s-1] ! Output arguments real(kind_phys), intent(out) :: prec_sed(:) ! stratiform_cloud_water_surface_flux_due_to_sedimentation [m s-1] - real(kind_phys), intent(out) :: prec_str(:) ! stratiform_rain_and_snow_surface_flux [m s-1] + real(kind_phys), intent(out) :: prec_str(:) ! lwe_large_scale_precipitation_rate_at_surface [m s-1] real(kind_phys), intent(out) :: snow_str(:) ! lwe_snow_and_cloud_ice_precipitation_rate_at_surface_due_to_microphysics [m s-1] character(len=512), intent(out) :: errmsg ! error message integer, intent(out) :: errflg ! error flag @@ -148,7 +132,7 @@ subroutine rk_stratiform_detrain_convective_condensate_run( & real(kind_phys), intent(in) :: rliq(:) ! vertically_integrated_cloud_liquid_water_tendency_due_to_all_convection_to_be_applied_later_in_time_loop [m s-1] ! Input/output arguments - real(kind_phys), intent(inout) :: prec_str(:) ! stratiform_rain_and_snow_surface_flux [m s-1] + real(kind_phys), intent(inout) :: prec_str(:) ! lwe_large_scale_precipitation_rate_at_surface [m s-1] ! Output arguments real(kind_phys), intent(out) :: tend_cldliq(:,:) ! tendency_of_cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water [kg kg-1 s-1] @@ -215,7 +199,7 @@ subroutine rk_stratiform_cloud_fraction_perturbation_run( & ! Input/output arguments ! Note: CAM4 intentionally mutates the top level of rhu00 so this is inout here. - real(kind_phys), intent(inout) :: rhu00(:, :) ! RH threshold for cloud + real(kind_phys), intent(inout) :: rhu00(:, :) ! RH threshold for cloud [fraction] ! Output arguments real(kind_phys), intent(out) :: rhdfda(:, :) ! derivative of RH w.r.t. cloud fraction for prognostic cloud water [percent] @@ -275,7 +259,7 @@ subroutine rk_stratiform_cloud_fraction_perturbation_run( & ! Compute rhdfda (derivative of RH w.r.t. cloud fraction) ! for use in the prognostic_cloud_water scheme. - rhu00(:ncol,1) = 2.0_kind_phys + rhu00(:ncol,1) = 2.0_kind_phys ! arbitrary number larger than 1 (100%) do k = 1, pver do i = 1, ncol if( relhum(i,k) < rhu00(i,k) ) then @@ -432,7 +416,7 @@ subroutine rk_stratiform_prognostic_cloud_water_tendencies_run( & real(kind_phys), intent(in) :: snow_pcw(:) ! lwe_snow_precipitation_rate_at_surface_due_to_microphysics [m s-1] ! Input/output arguments - real(kind_phys), intent(inout) :: prec_str(:) ! stratiform_rain_and_snow_surface_flux [m s-1] + real(kind_phys), intent(inout) :: prec_str(:) ! lwe_large_scale_precipitation_rate_at_surface [m s-1] real(kind_phys), intent(inout) :: snow_str(:) ! lwe_snow_and_cloud_ice_precipitation_rate_at_surface_due_to_microphysics [m s-1] ! Output arguments diff --git a/schemes/rasch_kristjansson/rk_stratiform.meta b/schemes/rasch_kristjansson/rk_stratiform.meta index af2dfcab..23c391f5 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.meta +++ b/schemes/rasch_kristjansson/rk_stratiform.meta @@ -2,22 +2,6 @@ name = rk_stratiform type = scheme -[ccpp-arg-table] - name = rk_stratiform_init - type = scheme -[ errmsg ] - standard_name = ccpp_error_message - units = none - type = character | kind = len=512 - dimensions = () - intent = out -[ errflg ] - standard_name = ccpp_error_code - units = 1 - type = integer - dimensions = () - intent = out - [ccpp-table-properties] name = rk_stratiform_check_qtlcwat type = scheme @@ -109,7 +93,7 @@ dimensions = () intent = in [ sfliq ] - standard_name = stratiform_rain_surface_flux_due_to_sedimentation + standard_name = stratiform_rain_flux_at_surface_due_to_sedimentation units = kg m-2 s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent) @@ -127,7 +111,7 @@ dimensions = (horizontal_loop_extent) intent = out [ prec_str ] - standard_name = stratiform_rain_and_snow_surface_flux + standard_name = lwe_large_scale_precipitation_rate_at_surface units = m s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent) @@ -177,7 +161,7 @@ dimensions = (horizontal_loop_extent) intent = in [ prec_str ] - standard_name = stratiform_rain_and_snow_surface_flux + standard_name = lwe_large_scale_precipitation_rate_at_surface units = m s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent) @@ -337,13 +321,13 @@ intent = in [ relhum ] standard_name = relative_humidity_for_prognostic_cloud_water_tbd - units = percent + units = fraction type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in [ rhu00 ] standard_name = relative_humidity_threshold_for_prognostic_cloud_water_tbd - units = percent + units = fraction type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = inout @@ -650,7 +634,7 @@ dimensions = (horizontal_loop_extent) intent = in [ prec_str ] - standard_name = stratiform_rain_and_snow_surface_flux + standard_name = lwe_large_scale_precipitation_rate_at_surface units = m s-1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent) From f06c38889664e42dc7e62370350f824ba40ad412 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 24 Mar 2025 13:22:15 -0400 Subject: [PATCH 30/39] Update namelist defaults --- .../compute_cloud_fraction_namelist.xml | 29 ++++++++++++++----- .../convective_cloud_cover_namelist.xml | 15 ++++++---- .../cloud_particle_sedimentation.meta | 2 +- .../cloud_particle_sedimentation_namelist.xml | 8 ++--- .../prognostic_cloud_water_namelist.xml | 13 +++++---- 5 files changed, 44 insertions(+), 23 deletions(-) diff --git a/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml b/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml index a9b1b168..d237dc0b 100644 --- a/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml +++ b/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml @@ -19,9 +19,9 @@ Valid declarations are: char*n - integer - logical - real + integer + logical + real Any of these types may be followed by a comma separated list of integers enclosed in parenthesis to indicate an array. @@ -97,12 +97,13 @@ flag Turn on ice cloud fraction calculation - Default: TRUE (CAM5 and CAM6) or FALSE + Default: TRUE (CAM5, 6, 7) or FALSE .false. .true. .true. + .true. @@ -131,6 +132,9 @@ 0.900D0 + 0.8975D0 + 0.8975D0 + 0.8975D0 @@ -145,6 +149,8 @@ 0.1D0 + 0.0D0 + 0.0D0 @@ -170,9 +176,7 @@ Top pressure bound for mid level cloud. - 75000.0D0 - 40000.0D0 - 40000.0D0 + 75000.0D0 @@ -186,6 +190,9 @@ 750.0D2 + 700.0D2 + 700.0D2 + 700.0D2 @@ -203,7 +210,10 @@ 5 = modified Slingo (ssat and empty cloud) - 5 + 1 + 5 + 5 + 5 @@ -217,6 +227,9 @@ 0.95D0 + 0.93D0 + 0.93D0 + 0.93D0 diff --git a/schemes/cloud_fraction/convective_cloud_cover_namelist.xml b/schemes/cloud_fraction/convective_cloud_cover_namelist.xml index ab4dc32c..4960d704 100644 --- a/schemes/cloud_fraction/convective_cloud_cover_namelist.xml +++ b/schemes/cloud_fraction/convective_cloud_cover_namelist.xml @@ -19,9 +19,9 @@ Valid declarations are: char*n - integer - logical - real + integer + logical + real Any of these types may be followed by a comma separated list of integers enclosed in parenthesis to indicate an array. @@ -86,7 +86,8 @@ Tunable parameter 1 for shallow convection cloud fraction. - 0.04D0 + 0.07D0 + 0.04D0 @@ -114,7 +115,11 @@ Tunable parameter 1 for deep convection cloud fraction. - 0.10D0 + 0.14D0 + 0.10D0 + 0.10D0 + 0.10D0 + 0.10D0 diff --git a/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta b/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta index 22d589e6..4b318031 100644 --- a/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta +++ b/schemes/rasch_kristjansson/cloud_particle_sedimentation.meta @@ -19,7 +19,7 @@ dimensions = () intent = in [ cldsed_ice_stokes_fac_in ] - standard_name = tunable_parameter_for_ice_fall_velocity_for_cloud_sedimentation + standard_name = tunable_parameter_for_ice_fall_velocity_for_rk_microphysics units = 1 type = real | kind = kind_phys dimensions = () diff --git a/schemes/rasch_kristjansson/cloud_particle_sedimentation_namelist.xml b/schemes/rasch_kristjansson/cloud_particle_sedimentation_namelist.xml index 6a32eb23..ad09c34a 100644 --- a/schemes/rasch_kristjansson/cloud_particle_sedimentation_namelist.xml +++ b/schemes/rasch_kristjansson/cloud_particle_sedimentation_namelist.xml @@ -19,9 +19,9 @@ Valid declarations are: char*n - integer - logical - real + integer + logical + real Any of these types may be followed by a comma separated list of integers enclosed in parenthesis to indicate an array. @@ -79,7 +79,7 @@ real cldsed cldsed_nl - tunable_parameter_for_ice_fall_velocity_for_cloud_sedimentation + tunable_parameter_for_ice_fall_velocity_for_rk_microphysics 1 Factor applied to the ice fall velocity computed from Stokes terminal velocity. diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water_namelist.xml b/schemes/rasch_kristjansson/prognostic_cloud_water_namelist.xml index 0f30d5da..7e2250af 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water_namelist.xml +++ b/schemes/rasch_kristjansson/prognostic_cloud_water_namelist.xml @@ -19,9 +19,9 @@ Valid declarations are: char*n - integer - logical - real + integer + logical + real Any of these types may be followed by a comma separated list of integers enclosed in parenthesis to indicate an array. @@ -86,6 +86,7 @@ 5.0e-6 + 18.0e-6 @@ -99,6 +100,7 @@ 4.0e-4 + 2.0e-4 @@ -117,7 +119,8 @@ Tunable constant for evaporation of precip in RK microphysics scheme. - 5.0e-6 + 10.0e-6 + 5.0e-6 @@ -144,7 +147,7 @@ poleward of 50 degrees. Used if rk_strat_polstrat_dorhmin is set to true. - 1.200e0 + 1.200D0 From db67087cd0c2c0d72d35a97c2f84d8cf2b5ee0d6 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 24 Mar 2025 13:36:59 -0400 Subject: [PATCH 31/39] Fix build --- schemes/rasch_kristjansson/prognostic_cloud_water.meta | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.meta b/schemes/rasch_kristjansson/prognostic_cloud_water.meta index b66a7e04..6f59d935 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.meta +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.meta @@ -263,7 +263,7 @@ intent = in [ rhu00 ] standard_name = relative_humidity_threshold_for_prognostic_cloud_water_tbd - units = percent + units = fraction type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in From 70d56e9a22f4977afd53f523331db63b322f0742 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Wed, 26 Mar 2025 14:02:05 -0400 Subject: [PATCH 32/39] Change standard names check script to ccpp_meta_stdname_check.py --- test/musica/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/musica/CMakeLists.txt b/test/musica/CMakeLists.txt index 1b3e24ad..4db52ecb 100644 --- a/test/musica/CMakeLists.txt +++ b/test/musica/CMakeLists.txt @@ -43,7 +43,7 @@ add_test( # Test musica scheme metadata against the CCPP standard names add_test( NAME test_musica_metadata_against_ccpp_standard_names - COMMAND ${Python_EXECUTABLE} ${CMAKE_BINARY_DIR}/../$ENV{CCPP_STD_NAMES_PATH}/tools/meta_stdname_check.py + COMMAND ${Python_EXECUTABLE} ${CMAKE_BINARY_DIR}/../$ENV{CCPP_STD_NAMES_PATH}/tools/ccpp_meta_stdname_check.py --metafile-loc ${CMAKE_BINARY_DIR}/metadata_test/musica_ccpp.meta --stdname-dict ${CMAKE_BINARY_DIR}/../$ENV{CCPP_STD_NAMES_PATH}/standard_names.xml ) From 6fb82255acdda5784688e915dd977d8c2b6d9c6f Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Wed, 26 Mar 2025 15:47:20 -0400 Subject: [PATCH 33/39] Address review comments --- schemes/cloud_fraction/compute_cloud_fraction.F90 | 4 ++-- schemes/cloud_fraction/compute_cloud_fraction_namelist.xml | 6 ------ schemes/cloud_fraction/convective_cloud_cover_namelist.xml | 1 - schemes/rasch_kristjansson/prognostic_cloud_water.F90 | 2 +- 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/schemes/cloud_fraction/compute_cloud_fraction.F90 b/schemes/cloud_fraction/compute_cloud_fraction.F90 index b823792d..d28bed04 100644 --- a/schemes/cloud_fraction/compute_cloud_fraction.F90 +++ b/schemes/cloud_fraction/compute_cloud_fraction.F90 @@ -88,7 +88,7 @@ subroutine compute_cloud_fraction_init( & if(amIRoot) then write(iulog,*) 'tuning parameters compute_cloud_fraction_init: inversion_cld_off ', inversion_cld_off - write(iulog,*) 'tuning parameters compute_cloud_fraction_init: rhminl ',rhminl,'rhminl_adj_land ',rhminl_adj_land, & + write(iulog,*) 'tuning parameters compute_cloud_fraction_init: rhminl ',rhminl,' rhminl_adj_land ',rhminl_adj_land, & ' rhminh ',rhminh,' premit ',premit,' premib ',premib write(iulog,*) 'tuning parameters compute_cloud_fraction_init: iceopt ',iceopt,' icecrit ',icecrit endif @@ -97,7 +97,7 @@ subroutine compute_cloud_fraction_init( & k700 = minloc(abs(pref_mid(:) - 7.e4_kind_phys), 1) if(amIRoot) then - write(iulog,*) 'compute_cloud_fraction: model level nearest 700 mb is ',k700,' which is',pref_mid(k700),' pascals ' + write(iulog,*) 'compute_cloud_fraction: model level nearest 700 mb is ',k700,' which is ',pref_mid(k700),' pascals ' endif end subroutine compute_cloud_fraction_init diff --git a/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml b/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml index d237dc0b..5b5e9aa9 100644 --- a/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml +++ b/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml @@ -102,7 +102,6 @@ .false. .true. - .true. .true. @@ -133,7 +132,6 @@ 0.900D0 0.8975D0 - 0.8975D0 0.8975D0 @@ -149,7 +147,6 @@ 0.1D0 - 0.0D0 0.0D0 @@ -191,7 +188,6 @@ 750.0D2 700.0D2 - 700.0D2 700.0D2 @@ -212,7 +208,6 @@ 1 5 - 5 5 @@ -228,7 +223,6 @@ 0.95D0 0.93D0 - 0.93D0 0.93D0 diff --git a/schemes/cloud_fraction/convective_cloud_cover_namelist.xml b/schemes/cloud_fraction/convective_cloud_cover_namelist.xml index 4960d704..5efac053 100644 --- a/schemes/cloud_fraction/convective_cloud_cover_namelist.xml +++ b/schemes/cloud_fraction/convective_cloud_cover_namelist.xml @@ -117,7 +117,6 @@ 0.14D0 0.10D0 - 0.10D0 0.10D0 0.10D0 diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 index f40f0bf5..59505bd0 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 @@ -200,7 +200,7 @@ subroutine prognostic_cloud_water_init( & ciautb = 5.e-4_kind_phys if(amIRoot) then - write(iulog,*) 'tuning parameters prognostic_cloud_water_init: capnw ',capnw,' capnc ',capnc,' capnsi ',capnsi,' kconst',kconst + write(iulog,*) 'tuning parameters prognostic_cloud_water_init: capnw ',capnw,' capnc ',capnc,' capnsi ',capnsi,' kconst ',kconst write(iulog,*) 'tuning parameters prognostic_cloud_water_init: effc ',effc,' alpha ',alpha,' capc ',capc write(iulog,*) 'tuning parameters prognostic_cloud_water_init: critpr ',critpr,' convfw ',convfw,' cracw ',cracw,' ciautb ',ciautb endif From eeb41e5dca6094621b2c773d9108310bf39e6dbe Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Wed, 26 Mar 2025 16:49:43 -0400 Subject: [PATCH 34/39] Remove cam6 namelist default from ZM --- schemes/zhang_mcfarlane/zm_conv_options_namelist.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/schemes/zhang_mcfarlane/zm_conv_options_namelist.xml b/schemes/zhang_mcfarlane/zm_conv_options_namelist.xml index b744c1f1..001fde77 100644 --- a/schemes/zhang_mcfarlane/zm_conv_options_namelist.xml +++ b/schemes/zhang_mcfarlane/zm_conv_options_namelist.xml @@ -39,7 +39,6 @@ The number of negative buoyancy regions that are allowed before the convection top and CAPE calculations are completed. 5 - 1 1 From 03ffcff6dfd07ea72563b86ed470b1547087eb8e Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Wed, 26 Mar 2025 17:03:39 -0400 Subject: [PATCH 35/39] Remove not ccpp compliant comment and improve clarity of comment for the perturbation scheme. --- schemes/rasch_kristjansson/rk_stratiform.F90 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/schemes/rasch_kristjansson/rk_stratiform.F90 b/schemes/rasch_kristjansson/rk_stratiform.F90 index d2054b89..99e6ed47 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.F90 +++ b/schemes/rasch_kristjansson/rk_stratiform.F90 @@ -11,9 +11,8 @@ module rk_stratiform save ! public CCPP-compliant subroutines - ! note: cloud_fraction_perturbation_run is NOT a fully CCPP-compliant scheme - ! because it calls the compute_cloud_fraction scheme for perturbation. - ! this is currently not possible to elegantly handle in the framework. + ! note: cloud_fraction_perturbation_run calls the compute_cloud_fraction + ! scheme run phase for perturbation with a modified rhpert_flag = .true. ! ! refer to test SDF suite_rasch_kristjansson.xml for total order of operations, ! as the full RK-stratiform requires other schemes not included in this module. @@ -169,7 +168,10 @@ subroutine rk_stratiform_cloud_fraction_perturbation_run( & rhdfda, & ! output for prognostic_cloud_water errmsg, errflg) - ! WARN: This is NOT CCPP-compliant! + ! Dependency: compute_cloud_fraction CCPPized scheme run phase. + ! this scheme is called with an altered rhpert_flag = .true. + ! then the outputs are combined with the "regular" output of the compute_cloud_fraction + ! CCPP scheme to get the perturbed quantities for prognostic_cloud_water. use compute_cloud_fraction, only: compute_cloud_fraction_run ! Input arguments From e99b92b2b05a48aa869dfe2e30c191da925f10f4 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Fri, 4 Apr 2025 14:17:58 -0400 Subject: [PATCH 36/39] Remove comment on ccpp compliance --- schemes/rasch_kristjansson/rk_stratiform.F90 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/schemes/rasch_kristjansson/rk_stratiform.F90 b/schemes/rasch_kristjansson/rk_stratiform.F90 index 99e6ed47..1a405e92 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.F90 +++ b/schemes/rasch_kristjansson/rk_stratiform.F90 @@ -112,7 +112,6 @@ subroutine rk_stratiform_sedimentation_run( & prec_str(:ncol) = 0._kind_phys + prec_sed(:ncol) snow_str(:ncol) = 0._kind_phys + snow_sed(:ncol) - end subroutine rk_stratiform_sedimentation_run !> \section arg_table_rk_stratiform_detrain_convective_condensate_run Argument Table @@ -225,8 +224,7 @@ subroutine rk_stratiform_cloud_fraction_perturbation_run( & errmsg = '' errflg = 0 - ! Call perturbed version of compute_cloud_fraction - ! WARN: This is NOT CCPP-compliant! + ! Call perturbed version of compute_cloud_fraction scheme call compute_cloud_fraction_run( & ncol = ncol, & pver = pver, & From aa2dd1a8cc7e7a96b4191246777da9478227d752 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Wed, 9 Apr 2025 23:41:24 -0400 Subject: [PATCH 37/39] Address review comments --- .../cloud_fraction/compute_cloud_fraction.F90 | 107 ++++++++---------- .../compute_cloud_fraction.meta | 12 ++ .../compute_cloud_fraction_namelist.xml | 8 +- .../cloud_fraction/convective_cloud_cover.F90 | 3 - .../cloud_fraction/set_cloud_fraction_top.F90 | 3 - .../cloud_particle_sedimentation.F90 | 12 +- .../prognostic_cloud_water.F90 | 3 - schemes/rasch_kristjansson/rk_stratiform.F90 | 9 +- schemes/rasch_kristjansson/rk_stratiform.meta | 12 ++ test/test_suites/suite_rasch_kristjansson.xml | 2 +- to_be_ccppized/cloud_optical_properties.F90 | 2 +- 11 files changed, 86 insertions(+), 87 deletions(-) diff --git a/schemes/cloud_fraction/compute_cloud_fraction.F90 b/schemes/cloud_fraction/compute_cloud_fraction.F90 index d28bed04..29873730 100644 --- a/schemes/cloud_fraction/compute_cloud_fraction.F90 +++ b/schemes/cloud_fraction/compute_cloud_fraction.F90 @@ -1,7 +1,4 @@ -! Copyright (C) 2025 University Corporation for Atmospheric Research -! SPDX-License-Identifier: Apache-2.0 -! -! Compute cloud fractions using RH threshold and other methods. +! Compute cloud fractions using relative humidity (RH) threshold and other methods. ! CCPP-ized: Haipeng Lin, February 2025 module compute_cloud_fraction use ccpp_kinds, only: kind_phys @@ -30,9 +27,7 @@ module compute_cloud_fraction integer :: k700 ! model level nearest to 700 mb [index] - ! constants - real(kind_phys), parameter :: pnot = 1.e5_kind_phys ! reference pressure [Pa] - real(kind_phys), parameter :: lapse = 6.5e-3_kind_phys ! U.S. Standard Atmosphere lapse rate [K m-1] + ! tuning constants real(kind_phys), parameter :: pretop = 1.0e2_kind_phys ! pressure bounding high cloud [Pa] contains @@ -131,7 +126,7 @@ end subroutine compute_cloud_fraction_timestep_init !! \htmlinclude compute_cloud_fraction_run.html subroutine compute_cloud_fraction_run( & ncol, pver, & - cappa, gravit, rair, tmelt, & + cappa, gravit, rair, tmelt, pref, lapse_rate, & top_lev_cloudphys, & pmid, ps, temp, sst, & q, cldice, & @@ -154,6 +149,8 @@ subroutine compute_cloud_fraction_run( & real(kind_phys), intent(in) :: gravit real(kind_phys), intent(in) :: rair real(kind_phys), intent(in) :: tmelt + real(kind_phys), intent(in) :: pref + real(kind_phys), intent(in) :: lapse_rate integer, intent(in) :: top_lev_cloudphys ! vertical_layer_index_of_cloud_fraction_top [index] real(kind_phys), intent(in) :: pmid(:, :) ! air_pressure [Pa] real(kind_phys), intent(in) :: ps(:) ! surface_air_pressure [Pa] @@ -194,7 +191,6 @@ subroutine compute_cloud_fraction_run( & real(kind_phys) :: theta(ncol, pver) ! potential temperature real(kind_phys) :: thetas(ncol) ! ocean surface potential temperature real(kind_phys) :: rhlim ! local rel. humidity threshold estimate - real(kind_phys) :: coef1 ! coefficient to convert mass flux to mb/d real(kind_phys) :: clrsky(ncol) ! temporary used in random overlap calc real(kind_phys) :: rpdeli(ncol, pver - 1) ! 1./(pmid(k+1)-pmid(k)) real(kind_phys) :: rhpert ! the specified perturbation to rh @@ -252,25 +248,29 @@ subroutine compute_cloud_fraction_run( & ! define rh perturbation in order to estimate rhdfda rhpert = 0.01_kind_phys - !set Wang and Sassen IWC paramters + ! Parameters for ice cloud fraction methods + ! References for these parameters, and the corresponding methods, are in the compute section + ! below. + ! iceopt = 1. Wang and Sassen IWC a = 26.87_kind_phys b = 0.569_kind_phys c = 0.002892_kind_phys - !set schiller parameters + ! iceopt = 2. Schiller as = -68.4202_kind_phys bs = 0.983917_kind_phys cs = 2.81795_kind_phys - !set wood and field paramters... + ! iceopt = 3. Wood and Field Kc = 75._kind_phys ! Evaluate potential temperature and relative humidity - ! If not computing ice cloud fraction then hybrid RH, if MG then water RH if (cldfrc_ice) then + ! If computing ice cloud fraction (CAM5+ MG Morrison and Gettelman microphysics) then water RH do k = top_lev_cloudphys, pver call qsat_water(temp(1:ncol, k), pmid(1:ncol, k), esl(1:ncol, k), qs(1:ncol, k), ncol) call svp_ice_vect(temp(1:ncol, k), esi(1:ncol, k), ncol) end do else + ! If not computing ice cloud fraction (CAM4 RK Rasch-Kristjansson microphysics) then hybrid RH, do k = top_lev_cloudphys, pver call qsat(temp(1:ncol, k), pmid(1:ncol, k), es(1:ncol, k), qs(1:ncol, k), ncol) end do @@ -283,7 +283,7 @@ subroutine compute_cloud_fraction_run( & cldst = 0._kind_phys do k = top_lev_cloudphys, pver - theta(:ncol, k) = temp(:ncol, k)*(pnot/pmid(:ncol, k))**cappa + theta(:ncol, k) = temp(:ncol, k)*(pref/pmid(:ncol, k))**cappa do i = 1, ncol if(.not. rhpert_flag) then @@ -302,11 +302,13 @@ subroutine compute_cloud_fraction_run( & do i = 1, ncol ! Adjust thetas(i) in the presence of non-zero ocean heights. ! This reduces the temperature for positive heights according to a standard lapse rate. - if (ocnfrac(i) .gt. 0.01_kind_phys) thetas(i) = & - (sst(i) - lapse*phis(i)/gravit)*(pnot/ps(i))**cappa - if (ocnfrac(i) .gt. 0.01_kind_phys .and. sst(i) .lt. 260._kind_phys) ierror = i + if (ocnfrac(i) > 0.01_kind_phys) then + thetas(i) = (sst(i) - lapse_rate*phis(i)/gravit)*(pref/ps(i))**cappa + endif + if (ocnfrac(i) > 0.01_kind_phys .and. sst(i) < 260._kind_phys) then + ierror = i + endif end do - coef1 = gravit*864.0_kind_phys ! conversion to millibars/day if (ierror > 0) then write (iulog, *) 'COLDSST: encountered in cldfrc:', ierror, ocnfrac(ierror), sst(ierror) @@ -337,12 +339,10 @@ subroutine compute_cloud_fraction_run( & do k = top_lev_cloudphys + 1, numkcld kp1 = min(k + 1, pver) do i = 1, ncol - ! This is now designed to apply FOR LIQUID CLOUDS (condensation > RH water) + cldbnd(i) = pmid(i, k) >= pretop - cldbnd(i) = pmid(i, k) .ge. pretop - - if (pmid(i, k) .ge. premib) then + if (pmid(i, k) >= premib) then !============================================================== ! This is the low cloud (below premib) block !============================================================== @@ -362,7 +362,7 @@ subroutine compute_cloud_fraction_run( & rhcloud(i, k) = rhcloud(i, k)*max(0.15_kind_phys, min(1.0_kind_phys, q(i, k)/0.0030_kind_phys)) end if - else if (pmid(i, k) .lt. premit) then + else if (pmid(i, k) < premit) then !============================================================== ! This is the high cloud (above premit) block !============================================================== @@ -398,59 +398,54 @@ subroutine compute_cloud_fraction_run( & !================================================================================== if (cldfrc_ice) then - ! Evaluate ice cloud fraction based on in-cloud ice content - - !--------ICE CLOUD OPTION 1--------Wang & Sassen 2002 - ! Evaluate desired in-cloud water content - ! icicval = f(temp,cldice,numice) - ! Start with a function of temperature. - ! Wang & Sassen 2002 (JAS), based on ARM site MMCR (midlat cirrus) - ! https://doi.org/10.1175/1520-0469(2002)059<2291:CCMPRU>2.0.CO;2 - ! parameterization valid for 203-253K - ! icival > 0 for t>195K - if (iceopt .lt. 3) then + if (iceopt .eq. 1 .or. iceopt .eq. 2) then if (iceopt .eq. 1) then + ! ICE CLOUD OPTION 1 - Wang & Sassen 2002 + ! Evaluate desired in-cloud water content + ! icicval = f(temp,cldice,numice) + ! Start with a function of temperature. + ! Wang & Sassen 2002 (JAS), based on ARM site MMCR (midlat cirrus) + ! https://doi.org/10.1175/1520-0469(2002)059<2291:CCMPRU>2.0.CO;2 + ! parameterization valid for 203-253K + ! icival > 0 for t>195K ttmp = max(195._kind_phys, min(temp(i, k), 253._kind_phys)) - 273.16_kind_phys icicval = a + b*ttmp + c*ttmp**2._kind_phys !convert units rho = pmid(i, k)/(rair*temp(i, k)) icicval = icicval*1.e-6_kind_phys/rho else - !--------ICE CLOUD OPTION 2--------Schiller 2008 (JGR) + ! ICE CLOUD OPTION 2 - Schiller 2008 (JGR) ! https://doi.org/10.1029/2008JD010342 ! Use a curve based on FISH measurements in ! tropics, mid-lats and arctic. Curve is for 180-250K (raise to 273K?) ! use median all flights - ttmp = max(190._kind_phys, min(temp(i, k), 273.16_kind_phys)) icicval = 10._kind_phys**(as*bs**ttmp + cs) - !convert units from ppmv to kg/kg + ! convert units from ppmv to kg kg-1 icicval = icicval*1.e-6_kind_phys*18._kind_phys/28.97_kind_phys end if - !set icecldfraction for OPTION 1 or OPTION2 - icecldf(i, k) = max(0._kind_phys, min(cldice(i, k)/icicval, 1._kind_phys)) + ! Set ice cloud fraction for options 1 or 2 + icecldf(i, k) = max(0._kind_phys, min(cldice(i, k)/icicval, 1._kind_phys)) else if (iceopt .eq. 3) then - - !--------ICE CLOUD OPTION 3--------Wood & Field 2000 (JAS) + ! ICE CLOUD OPTION 3 - Wood & Field 2000 (JAS) ! https://doi.org/10.1175/1520-0469(2000)057<1888:RBTWCW>2.0.CO;2 ! eq 6: cloud fraction = 1 - exp (-K * qc/qsati) - icecldf(i, k) = 1._kind_phys - exp(-Kc*cldice(i, k)/(qs(i, k)*(esi(i, k)/esl(i, k)))) icecldf(i, k) = max(0._kind_phys, min(icecldf(i, k), 1._kind_phys)) else - !--------ICE CLOUD OPTION 4--------Wilson and ballard 1999 + ! ICE CLOUD OPTION 4 - Wilson and Ballard 1999 ! https://doi.org/10.1002/qj.49712555707 ! inversion of smith.... ! ncf = cldice / ((1-RHcrit)*qs) ! then a function of ncf.... ncf = cldice(i, k)/((1._kind_phys - icecrit)*qs(i, k)) - if (ncf .le. 0._kind_phys) then + if (ncf <= 0._kind_phys) then icecldf(i, k) = 0._kind_phys - else if (ncf .gt. 0._kind_phys .and. ncf .le. 1._kind_phys/6._kind_phys) then + else if (ncf > 0._kind_phys .and. ncf <= 1._kind_phys/6._kind_phys) then icecldf(i, k) = 0.5_kind_phys*(6._kind_phys*ncf)**(2._kind_phys/3._kind_phys) - else if (ncf .gt. 1._kind_phys/6._kind_phys .and. ncf .lt. 1._kind_phys) then + else if (ncf > 1._kind_phys/6._kind_phys .and. ncf < 1._kind_phys) then phi = (acos(3._kind_phys*(1._kind_phys - ncf)/2._kind_phys**(3._kind_phys/2._kind_phys)) + 4._kind_phys*3.1415927_kind_phys)/3._kind_phys icecldf(i, k) = (1._kind_phys - 4._kind_phys*cos(phi)*cos(phi)) else @@ -458,24 +453,14 @@ subroutine compute_cloud_fraction_run( & end if icecldf(i, k) = max(0._kind_phys, min(icecldf(i, k), 1._kind_phys)) end if - !TEST: if ice present, icecldf=1. - ! if (cldice(i,k).ge.1.e-8_kind_phys) then - ! icecldf(i,k) = 0.99_kind_phys - ! endif - - !! if ((cldice(i,k) .gt. icicval) .or. ((cldice(i,k) .gt. 0._kind_phys) .and. (icecldf(i,k) .eq. 0._kind_phys))) then - ! if (cldice(i,k) .gt. 1.e-8_kind_phys) then - ! write(iulog,*) 'i,k,pmid,rho,t,cldice,icicval,icecldf,rhcloud: ', & - ! i,k,pmid(i,k),rho,temp(i,k),cldice(i,k),icicval,icecldf(i,k),rhcloud(i,k) - ! endif - - ! Combine ice and liquid cloud fraction assuming maximum overlap. + + ! Test code: Combine ice and liquid cloud fraction assuming maximum overlap. ! Combined cloud fraction is maximum overlap ! cloud(i,k)=min(1._kind_phys,max(icecldf(i,k),rhcloud(i,k))) liqcldf(i, k) = (1._kind_phys - icecldf(i, k))*rhcloud(i, k) cloud(i, k) = liqcldf(i, k) + icecldf(i, k) - else + else ! cldfrc_ice = .false. ! For RK microphysics cloud(i, k) = rhcloud(i, k) end if @@ -521,7 +506,7 @@ subroutine compute_cloud_fraction_run( & do k = top_lev_cloudphys + 1, pver do i = 1, ncol - if (pmid(i, k) >= premib .and. ocnfrac(i) .gt. 0.01_kind_phys) then + if (pmid(i, k) >= premib .and. ocnfrac(i) > 0.01_kind_phys) then ! I think this is done so that dtheta/dp is in units of dg/mb (JJH) dthdp = 100.0_kind_phys*(theta(i, k) - theta(i, k - 1))*rpdeli(i, k - 1) if (dthdp < dthdpmn(i)) then @@ -535,7 +520,7 @@ subroutine compute_cloud_fraction_run( & ! Also check between the bottom layer and the surface ! Only perform this check if the criteria were not met above do i = 1, ncol - if (kdthdp(i) .eq. 0 .and. ocnfrac(i) .gt. 0.01_kind_phys) then + if (kdthdp(i) .eq. 0 .and. ocnfrac(i) > 0.01_kind_phys) then dthdp = 100.0_kind_phys*(thetas(i) - theta(i, pver))/(ps(i) - pmid(i, pver)) if (dthdp < dthdpmn(i)) then dthdpmn(i) = dthdp diff --git a/schemes/cloud_fraction/compute_cloud_fraction.meta b/schemes/cloud_fraction/compute_cloud_fraction.meta index 39434f67..c314e2cf 100644 --- a/schemes/cloud_fraction/compute_cloud_fraction.meta +++ b/schemes/cloud_fraction/compute_cloud_fraction.meta @@ -164,6 +164,18 @@ type = real | kind = kind_phys dimensions = () intent = in +[ pref ] + standard_name = surface_reference_pressure + units = Pa + type = real | kind = kind_phys + dimensions = () + intent = in +[ lapse_rate ] + standard_name = reference_temperature_lapse_rate + units = K m-1 + type = real | kind = kind_phys + dimensions = () + intent = in [ top_lev_cloudphys ] standard_name = vertical_layer_index_of_cloud_fraction_top units = index diff --git a/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml b/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml index 5b5e9aa9..18c511bd 100644 --- a/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml +++ b/schemes/cloud_fraction/compute_cloud_fraction_namelist.xml @@ -199,10 +199,10 @@ 1 Scheme for ice cloud fraction. - 1 = Wang and Sassen - 2 = Schiller (iciwc) - 3 = Wood and Field - 4 = Wilson (based on Smith) + 1 = Wang and Sassen (https://doi.org/10.1175/1520-0469(2002)059<2291:CCMPRU>2.0.CO;2) + 2 = Schiller (iciwc) (https://doi.org/10.1029/2008JD010342) + 3 = Wood and Field (https://doi.org/10.1175/1520-0469(2000)057<1888:RBTWCW>2.0.CO;2) + 4 = Wilson (based on Smith) (https://doi.org/10.1002/qj.49712555707) 5 = modified Slingo (ssat and empty cloud) diff --git a/schemes/cloud_fraction/convective_cloud_cover.F90 b/schemes/cloud_fraction/convective_cloud_cover.F90 index 3e82a698..97730edd 100644 --- a/schemes/cloud_fraction/convective_cloud_cover.F90 +++ b/schemes/cloud_fraction/convective_cloud_cover.F90 @@ -1,6 +1,3 @@ -! Copyright (C) 2025 University Corporation for Atmospheric Research -! SPDX-License-Identifier: Apache-2.0 -! ! Computes deep and shallow convective cloud fractions ! CCPP-ized: Haipeng Lin, February 2025 module convective_cloud_cover diff --git a/schemes/cloud_fraction/set_cloud_fraction_top.F90 b/schemes/cloud_fraction/set_cloud_fraction_top.F90 index f30e1045..a13bce30 100644 --- a/schemes/cloud_fraction/set_cloud_fraction_top.F90 +++ b/schemes/cloud_fraction/set_cloud_fraction_top.F90 @@ -1,6 +1,3 @@ -! Copyright (C) 2024 National Science Foundation-National Center for Atmospheric Research -! SPDX-License-Identifier: Apache-2.0 -! ! Stub scheme to set top of cloud physics to below top cloud level. ! Used for all macrophysical schemes except RK. module set_cloud_fraction_top diff --git a/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 b/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 index 3f4baad4..5732856a 100644 --- a/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 +++ b/schemes/rasch_kristjansson/cloud_particle_sedimentation.F90 @@ -1,6 +1,3 @@ -! Copyright (C) 2025 University Corporation for Atmospheric Research -! SPDX-License-Identifier: Apache-2.0 -! ! Compute tendencies from sedimentation of cloud liquid and ice particles ! Original authors: Byron Boville, September 2002 from code by P.J. Rasch ! CCPP-ized: Haipeng Lin, January 2025 @@ -21,18 +18,19 @@ module cloud_particle_sedimentation real(kind_phys), parameter :: vocean = 2.8_kind_phys ! liquid fall velocity over ocean [cm s-1] real(kind_phys), parameter :: mxsedfac = 0.99_kind_phys ! maximum sedimentation flux factor - ! tuning parameters for Stokes terminal velocity + ! use Stokes velocity method + ! or McFarquhar and Heymsfield (https://doi.org/10.1175/1520-0469(1997)054<2187:POTCIC>2.0.CO;2) logical, parameter :: stokes = .true. ! use Stokes velocity instead of McFarquhar and Heymsfield + + ! tuning parameters for Stokes terminal velocity real(kind_phys) :: cldsed_ice_stokes_fac ! factor applied to ice fall vel ! from Stokes terminal velocity real(kind_phys), parameter :: eta = 1.7e-5_kind_phys ! viscosity of air [kg m s-1] real(kind_phys), parameter :: r40 = 40._kind_phys ! 40 micron radius real(kind_phys), parameter :: r400 = 400._kind_phys ! 400 micron radius real(kind_phys), parameter :: v400 = 1.00_kind_phys ! fall velocity of 400 micron sphere [m s-1] - real(kind_phys) :: v40 ! Stokes fall velocity of 40 micron sphere (m/s) - ! v40 = (2._kind_phys/9._kind_phys) * rhoh2o * gravit/eta * r40**2 * 1.e-12_kind_phys + real(kind_phys) :: v40 ! Stokes fall velocity of 40 micron sphere [m s-1] real(kind_phys) :: vslope ! linear slope for large particles [m s-1 micron-1] - ! vslope = (v400 - v40)/(r400 -r40) ! tuning parameters for McFarquhar and Heymsfield terminal velocity real(kind_phys), parameter :: vice_small = 1._kind_phys ! ice fall velocity for small concentration [cm s-1] diff --git a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 index 59505bd0..b2484d6b 100644 --- a/schemes/rasch_kristjansson/prognostic_cloud_water.F90 +++ b/schemes/rasch_kristjansson/prognostic_cloud_water.F90 @@ -1,6 +1,3 @@ -! Copyright (C) 2025 University Corporation for Atmospheric Research -! SPDX-License-Identifier: Apache-2.0 -! ! Prognostic cloud water data and methods (cldwat) ! Original authors as marked in subroutines ! CCPP-ized: Haipeng Lin, January 2025 diff --git a/schemes/rasch_kristjansson/rk_stratiform.F90 b/schemes/rasch_kristjansson/rk_stratiform.F90 index 1a405e92..64da34dd 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.F90 +++ b/schemes/rasch_kristjansson/rk_stratiform.F90 @@ -1,6 +1,3 @@ -! Copyright (C) 2025 University Corporation for Atmospheric Research -! SPDX-License-Identifier: Apache-2.0 -! ! Rasch and Kristjansson prognostic cloud microphysics and CAM4 macrophysics ! CCPP-ized: Haipeng Lin, January 2025 module rk_stratiform @@ -156,7 +153,7 @@ end subroutine rk_stratiform_detrain_convective_condensate_run !! \htmlinclude arg_table_rk_stratiform_cloud_fraction_perturbation_run.html subroutine rk_stratiform_cloud_fraction_perturbation_run( & ncol, pver, & - cappa, gravit, rair, tmelt, & + cappa, gravit, rair, tmelt, pref, lapse_rate, & top_lev_cloudphys, & pmid, ps, temp, sst, & q_wv, cldice, & @@ -180,6 +177,8 @@ subroutine rk_stratiform_cloud_fraction_perturbation_run( & real(kind_phys), intent(in) :: gravit real(kind_phys), intent(in) :: rair real(kind_phys), intent(in) :: tmelt + real(kind_phys), intent(in) :: pref + real(kind_phys), intent(in) :: lapse_rate integer, intent(in) :: top_lev_cloudphys ! vertical_layer_index_of_cloud_fraction_top [index] real(kind_phys), intent(in) :: pmid(:, :) ! air_pressure [Pa] real(kind_phys), intent(in) :: ps(:) ! surface_air_pressure [Pa] @@ -232,6 +231,8 @@ subroutine rk_stratiform_cloud_fraction_perturbation_run( & gravit = gravit, & rair = rair, & tmelt = tmelt, & + pref = pref, & + lapse_rate = lapse_rate, & top_lev_cloudphys = top_lev_cloudphys, & ! CAM4 macrophysics - top lev is 1 pmid = pmid(:ncol,:), & ps = ps(:ncol), & diff --git a/schemes/rasch_kristjansson/rk_stratiform.meta b/schemes/rasch_kristjansson/rk_stratiform.meta index 23c391f5..f994c28b 100644 --- a/schemes/rasch_kristjansson/rk_stratiform.meta +++ b/schemes/rasch_kristjansson/rk_stratiform.meta @@ -229,6 +229,18 @@ type = real | kind = kind_phys dimensions = () intent = in +[ pref ] + standard_name = surface_reference_pressure + units = Pa + type = real | kind = kind_phys + dimensions = () + intent = in +[ lapse_rate ] + standard_name = reference_temperature_lapse_rate + units = K m-1 + type = real | kind = kind_phys + dimensions = () + intent = in [ top_lev_cloudphys ] standard_name = vertical_layer_index_of_cloud_fraction_top units = index diff --git a/test/test_suites/suite_rasch_kristjansson.xml b/test/test_suites/suite_rasch_kristjansson.xml index cd488cee..1281df89 100644 --- a/test/test_suites/suite_rasch_kristjansson.xml +++ b/test/test_suites/suite_rasch_kristjansson.xml @@ -1,7 +1,7 @@