diff --git a/ccpp/config/ccpp_prebuild_config_fv3.py b/ccpp/config/ccpp_prebuild_config_fv3.py
index ec69586ac..db5f6d639 100755
--- a/ccpp/config/ccpp_prebuild_config_fv3.py
+++ b/ccpp/config/ccpp_prebuild_config_fv3.py
@@ -189,6 +189,7 @@
'physics/physics/PBL/MYNN_EDMF/mynnedmf_wrapper.F90',
'physics/physics/PBL/SATMEDMF/satmedmfvdif.F',
'physics/physics/PBL/SATMEDMF/satmedmfvdifq.F',
+ 'physics/physics/PBL/SATMEDMF/canopy_driver.F',
'physics/physics/PBL/YSU/ysuvdif.F90',
'physics/physics/PBL/saYSU/shinhongvdif.F90',
'physics/physics/Radiation/RRTMG/radsw_main.F90',
diff --git a/ccpp/data/GFS_typedefs.F90 b/ccpp/data/GFS_typedefs.F90
index 29b9daf29..51b8893dd 100644
--- a/ccpp/data/GFS_typedefs.F90
+++ b/ccpp/data/GFS_typedefs.F90
@@ -40,7 +40,7 @@ module GFS_typedefs
integer, parameter :: dfi_radar_max_intervals = 4 !< Number of radar-derived temperature tendency and/or convection suppression intervals. Do not change.
real(kind=kind_phys), parameter :: limit_unspecified = 1e12 !< special constant for "namelist value was not provided" in radar-derived temperature tendency limit range
-
+
integer, parameter :: physics_no_tracer = -99
!> \section arg_table_GFS_typedefs
@@ -687,7 +687,7 @@ module GFS_typedefs
real (kind=kind_phys), pointer :: dqdt_qmicro(:,:) => null() !< instantanious microphysics tendency to be passed from MP to convection
!-- lake surface temperature from cdeps inline
- real (kind=kind_phys), pointer :: mask_dat (:) => null() !< land-sea mask from cdeps inline
+ real (kind=kind_phys), pointer :: mask_dat (:) => null() !< land-sea mask from cdeps inline
real (kind=kind_phys), pointer :: tsfco_dat (:) => null() !< sfc temperature from cdeps inline
real (kind=kind_phys), pointer :: tice_dat (:) => null() !< sfc temperature over ice from cdeps inline
real (kind=kind_phys), pointer :: hice_dat (:) => null() !< sfc ice thickness from cdeps inline
@@ -792,7 +792,7 @@ module GFS_typedefs
integer :: dycore_active !< Choice of dynamical core
integer :: dycore_fv3 = 1 !< Choice of FV3 dynamical core
integer :: dycore_mpas = 2 !< Choice of MPAS dynamical core
-
+
!--- coupling parameters
logical :: cplflx !< default no cplflx collection
logical :: cplice !< default no cplice collection (used together with cplflx)
@@ -1086,7 +1086,6 @@ module GFS_typedefs
real(kind=kind_phys) :: fs_fac_rain !< adjustment for rain fall speed
real(kind=kind_phys) :: fs_fac_snow !< adjustment for snow fall speed
-
!--- GFDL microphysical paramters
logical :: lgfdlmprad !< flag for GFDL mp scheme and radiation consistency
logical :: phys_hydrostatic
@@ -1573,6 +1572,11 @@ module GFS_typedefs
integer :: nchem !< number of prognostic chemical species (vertically mixied)
integer :: ndvel !< number of prognostic chemical species (which are deposited, usually =nchem)
integer :: ntchm !< number of prognostic chemical tracers (advected)
+! "cplaqm" tracers
+ integer :: nto3 !< tracer index for Ozone chemical species CMAQ
+ integer :: ntno !< tracer index for NO chemical species CMAQ
+ integer :: ntno2 !< tracer index for NO2 chemical species CMAQ
+
integer :: ntchs !< tracer index for first prognostic chemical tracer
integer :: ntche !< tracer index for last prognostic chemical tracer
integer :: ntdu1 !< tracer index for dust bin1
@@ -2156,6 +2160,11 @@ module GFS_typedefs
real (kind=kind_phys), pointer :: dkt(:,:) => null() !< Eddy diffusitivity for heat
real (kind=kind_phys), pointer :: dku(:,:) => null() !< Eddy diffusitivity for momentum
+!3-LAYER CANOPY
+ !--- Extra PBL diagnostics in canopy
+ real (kind=kind_phys), pointer :: dkt_can(:,:) => null() !< Eddy diffusitivity for heat
+ real (kind=kind_phys), pointer :: dku_can(:,:) => null() !< Eddy diffusitivity for momentum
+
!
!---vay-2018 UGWP-diagnostics instantaneous
!
@@ -2260,7 +2269,6 @@ module GFS_typedefs
! Diagnostics for coupled air quality model
real (kind=kind_phys), pointer :: aod (:) => null() !< instantaneous aerosol optical depth ( n/a )
-!IVAI
! Diagnostics for coupled air quality model
real (kind=kind_phys), pointer :: coszens(:) => null() ! Cosine SZA for photolysis
real (kind=kind_phys), pointer :: jo3o1d(:) => null() ! instantaneous O3O1D photolysis rate
@@ -2270,7 +2278,6 @@ module GFS_typedefs
real (kind=kind_phys), pointer :: cfrt (:) => null() ! Forest Fraction
real (kind=kind_phys), pointer :: cclu (:) => null() ! Clumping Index
real (kind=kind_phys), pointer :: cpopu(:) => null() ! Population density
-!IVAI
! Auxiliary output arrays for debugging
real (kind=kind_phys), pointer :: aux2d(:,:) => null() !< auxiliary 2d arrays in output (for debugging)
@@ -3432,7 +3439,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, &
communicator, ntasks, nthreads, &
tile_num, isc, jsc, nx, ny, cnx, &
cny, gnx, gny, ak, bk, hydrostatic)
-
+
!--- modules
use physcons, only: con_rerth, con_pi
use mersenne_twister, only: random_setseed, random_number
@@ -3613,7 +3620,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, &
logical :: lrseeds = .false. !< flag to use host-provided random seeds
integer :: nrstreams = 2 !< number of random number streams in host-provided random seed array
logical :: lextop = .false. !< flag for using an extra top layer for radiation
- real(kind_phys) :: xr_con = -999.0 !< Xu-Randall cloud fraction multiplicative constant
+ real(kind_phys) :: xr_con = -999.0 !< Xu-Randall cloud fraction multiplicative constant
real(kind_phys) :: xr_exp = -999.0 !< Xu-Randall cloud fraction exponent constant
! RRTMGP
logical :: do_RRTMGP = .false. !< Use RRTMGP?
@@ -4437,7 +4444,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, &
stop
endif
endif
-
+
! dtend selection: default is to match all variables:
dtend_select(1)='*'
do ipat=2,pat_count
@@ -5575,6 +5582,11 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, &
Model%dtidx = physics_no_tracer
if(Model%ntchm>0) then
+! GFS_v16 n=9 "no2" n=10 "no" n=11 "o3" (n=8,9, 10 in PBL resp.)
+ Model%ntno2 = get_physics_tracer_index('no2', Model) ! n=11 (index 10 "no2" in PBL scheme) GFS_v17_p8
+ Model%ntno = get_physics_tracer_index('no', Model) ! n=12 (index 11 "no" in PBL scheme) GFS_v17_p8
+ Model%nto3 = get_physics_tracer_index('o3', Model) ! n=13 (index 12 "o3" in PBL scheme) GFS_v17_p8
+
Model%ntdu1 = get_physics_tracer_index('dust1', Model)
Model%ntdu2 = get_physics_tracer_index('dust2', Model)
Model%ntdu3 = get_physics_tracer_index('dust3', Model)
@@ -5649,7 +5661,9 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, &
endif
! More specific chemical tracer names:
+! NB. ntchs is 1st chemical tracer (not so2 tracer)
call label_dtend_tracer(Model,100+Model%ntchs,'so2','sulfur dioxide concentration','kg kg-1 s-1')
+
if(Model%ntchm>0) then
! Need better descriptions of these.
call label_dtend_tracer(Model,100+Model%ntchm+Model%ntchs-1,'pp10','pp10 concentration','kg kg-1 s-1')
@@ -5658,6 +5672,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, &
if(itrac>0) then
call label_dtend_tracer(Model,100+itrac,'DMS','DMS concentration','kg kg-1 s-1')
endif
+
itrac=get_physics_tracer_index('msa', Model)
if(itrac>0) then
call label_dtend_tracer(Model,100+itrac,'msa','msa concentration','kg kg-1 s-1')
@@ -5665,7 +5680,6 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, &
endif
endif
-
call label_dtend_tracer(Model,Model%index_of_temperature,'temp','temperature','K s-1')
call label_dtend_tracer(Model,Model%index_of_x_wind,'u','x wind','m s-2')
call label_dtend_tracer(Model,Model%index_of_y_wind,'v','y wind','m s-2')
@@ -5698,6 +5712,11 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, &
call label_dtend_tracer(Model,100+Model%ntia,'ice_aero','number concentration of ice-friendly aerosols','kg-1 s-1')
call label_dtend_tracer(Model,100+Model%nto,'o_ion','oxygen ion concentration','kg kg-1 s-1')
call label_dtend_tracer(Model,100+Model%nto2,'o2','oxygen concentration','kg kg-1 s-1')
+! cplaqm tracers CMAQ
+ call label_dtend_tracer(Model,100+Model%ntno2,'no2_cpl','cplaqm NO2 concentration','kg kg-1 s-1')
+ call label_dtend_tracer(Model,100+Model%ntno, 'no_cpl', 'cplaqm NO concentration','kg kg-1 s-1')
+ call label_dtend_tracer(Model,100+Model%nto3, 'o3_cpl', 'cplaqm ozone concentration','kg kg-1 s-1')
+
call label_dtend_cause(Model,Model%index_of_process_pbl,'pbl','tendency due to PBL')
call label_dtend_cause(Model,Model%index_of_process_dcnv,'deepcnv','tendency due to deep convection')
call label_dtend_cause(Model,Model%index_of_process_scnv,'shalcnv','tendency due to shallow convection')
@@ -5780,6 +5799,12 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, &
enddo
endif
+! NB. In PBL scheme chemical tracers indexes are offset by 1
+! (qdiag3d) cplaqm tracers "no2", "no", "o3"
+ call fill_dtidx(Model,dtend_select,100+Model%ntno2,Model%index_of_process_pbl,have_pbl) ! ntno2= 11 (index 10 is "no2" in PBL scheme) GFS_v17_p8
+ call fill_dtidx(Model,dtend_select,100+Model%ntno ,Model%index_of_process_pbl,have_pbl) ! ntno = 12 (index 11 is "no" in PBL scheme) GFS_v17_p8
+ call fill_dtidx(Model,dtend_select,100+Model%nto3 ,Model%index_of_process_pbl,have_pbl) ! nto3 = 13 (index 12 is "o3" in PBL scheme) GFS_v17_p8
+
call fill_dtidx(Model,dtend_select,100+Model%ntoz,Model%index_of_process_pbl,have_pbl)
call fill_dtidx(Model,dtend_select,100+Model%ntoz,Model%index_of_process_prod_loss,have_oz_phys)
call fill_dtidx(Model,dtend_select,100+Model%ntoz,Model%index_of_process_ozmix,have_oz_phys)
@@ -6603,7 +6628,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, &
!--- BEGIN CODE FROM GLOOPB
!--- set up random number seed needed for RAS and old SAS and when cal_pre=.true.
! Model%imfdeepcnv < 0 when Model%ras = .true.
-
+
if (xr_con > 0.0 .and. xr_exp > 0.0) then !values have been read in from namelist, so set them to read values
Model%xr_con = xr_con
Model%xr_exp = xr_exp
@@ -6628,9 +6653,9 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, &
Model%xr_con = 2000.0
Model%xr_exp = 0.25
endif
- endif
+ endif
endif
-
+
if (Model%imfdeepcnv <= 0 .or. Model%cal_pre ) then
if (Model%random_clds) then
seed0 = Model%idate(1) + Model%idate(2) + Model%idate(3) + Model%idate(4)
@@ -7361,6 +7386,9 @@ subroutine control_print(Model)
print *, ' nqrimef : ', Model%nqrimef
print *, ' ntqv : ', Model%ntqv
print *, ' ntoz : ', Model%ntoz
+ print *, ' ntno2 : ', Model%ntno2 ! "no2" tracer cplaqm/CMAQ
+ print *, ' ntno : ', Model%ntno ! "no" tracer cplaqm/CMAQ
+ print *, ' nto3 : ', Model%nto3 ! "o3" tracer cplaqm/CMAQ
print *, ' ntcw : ', Model%ntcw
print *, ' ntiw : ', Model%ntiw
print *, ' ntrw : ', Model%ntrw
@@ -7775,7 +7803,7 @@ subroutine cldprop_create (Cldprop, Model)
Cldprop%cvt = clear_val
Cldprop%cvb = clear_val
Cldprop%cnvw = clear_val
-
+
end subroutine cldprop_create
@@ -8297,6 +8325,12 @@ subroutine diag_create (Diag, Model)
allocate (Diag%dkt(IM,Model%levs))
allocate (Diag%dku(IM,Model%levs))
+ !--- New PBL Diagnostics in 3-layer canopy
+ if (Model%do_canopy .and. Model%cplaqm) then
+ allocate (Diag%dkt_can(IM,Model%levs))
+ allocate (Diag%dku_can(IM,Model%levs))
+ endif
+
!-- New max hourly diag.
allocate (Diag%refdmax(IM))
allocate (Diag%refdmax263k(IM))
@@ -8373,12 +8407,11 @@ subroutine diag_create (Diag, Model)
Diag%aod = zero
end if
-!IVAI:
! Air quality diagnostics
! -- initialize diagnostic variables
if (Model%cplaqm) then
-!IVAI: photdiag arrays
+! photdiag arrays
allocate (Diag%coszens(IM))
Diag%coszens= zero
@@ -8388,7 +8421,7 @@ subroutine diag_create (Diag, Model)
allocate (Diag%jno2(IM))
Diag%jno2 = zero
-!IVAI: canopy arrays read via aqm_emis_read
+! Canopy arrays read via aqm_emis_read
if (Model%do_canopy) then
allocate (Diag%claie(IM))
Diag%claie = zero
@@ -8407,7 +8440,6 @@ subroutine diag_create (Diag, Model)
end if! (Model%do_canopy)
end if ! (Model%cplaqm)
-!IVAI
! Auxiliary arrays in output for debugging
if (Model%naux2d>0) then
@@ -8675,6 +8707,12 @@ subroutine diag_phys_zero (Diag, Model, linit, iauwindow_center)
Diag%dkt = zero
Diag%dku = zero
+! Extra PBL diagnostics in 3-layer canopy
+ if (Model%do_canopy .and. Model%cplaqm ) then
+ Diag%dkt_can = zero
+ Diag%dku_can = zero
+ endif
+
! max hourly diagnostics
Diag%refl_10cm = -35.
Diag%max_hail_diam_sfc = -999.
@@ -8708,22 +8746,22 @@ subroutine diag_phys_zero (Diag, Model, linit, iauwindow_center)
endif
end subroutine diag_phys_zero
-
+
function get_physics_tracer_index (name, Model)
!This function uses the FMS version of get_tracer_index, but changes the missing tracer index to the value used throughout the physics code, rather than the one used in FMS
use tracer_manager_mod, only: get_tracer_index, NO_TRACER
use field_manager_mod, only: MODEL_ATMOS
-
+
character(len=*), intent(in) :: name
type(GFS_control_type), intent(in) :: Model
-
+
!--- local variables
integer :: get_physics_tracer_index
-
+
get_physics_tracer_index = get_tracer_index(MODEL_ATMOS, name, verbose = (Model%me == Model%master) .and. Model%debug)
-
+
if (get_physics_tracer_index == NO_TRACER) get_physics_tracer_index = physics_no_tracer
-
+
end function get_physics_tracer_index
end module GFS_typedefs
diff --git a/ccpp/data/GFS_typedefs.meta b/ccpp/data/GFS_typedefs.meta
index 48200fc9a..9150e5aa1 100644
--- a/ccpp/data/GFS_typedefs.meta
+++ b/ccpp/data/GFS_typedefs.meta
@@ -6824,6 +6824,29 @@
units = index
dimensions = ()
type = integer
+### IVAI
+[ntno2]
+ standard_name = index_for_no2_chemical_tracer_in_tracer_concentration_array
+ long_name = tracer index for coupled AQM/CMAQ NO2 chemical tracer
+ units = index
+ dimensions = ()
+ type = integer
+## active = (flag_for_air_quality_coupling .and. flag_for_canopy_option)
+[ntno]
+ standard_name = index_for_no_chemical_tracer_in_tracer_concentration_array
+ long_name = tracer index for coupled AQM/CMAQ NO chemical tracer
+ units = index
+ dimensions = ()
+ type = integer
+## active = (flag_for_air_quality_coupling .and. flag_for_canopy_option)
+[nto3]
+ standard_name = index_for_ozone_chemical_tracer_in_tracer_concentration_array
+ long_name = tracer index for coupled AQM/CMAQ ozone chemical tracer
+ units = index
+ dimensions = ()
+ type = integer
+## active = (flag_for_air_quality_coupling .and. flag_for_canopy_option)
+### IVAI
[ntcw]
standard_name = index_of_cloud_liquid_water_mixing_ratio_in_tracer_concentration_array
long_name = tracer index for cloud condensate (or liquid water)
@@ -9916,6 +9939,22 @@
dimensions = (horizontal_dimension,vertical_layer_dimension)
type = real
kind = kind_phys
+[dkt_can]
+ standard_name = atmosphere_heat_diffusivity_in_canopy
+ long_name = atmospheric heat diffusivity in canopy
+ units = m2 s-1
+ dimensions = (horizontal_dimension,vertical_layer_dimension)
+ type = real
+ kind = kind_phys
+ active = (flag_for_air_quality_coupling .and. flag_for_canopy_option)
+[dku_can]
+ standard_name = atmosphere_momentum_diffusivity_in_canopy
+ long_name = atmospheric momentum diffusivity in canopy
+ units = m2 s-1
+ dimensions = (horizontal_dimension,vertical_layer_dimension)
+ type = real
+ kind = kind_phys
+ active = (flag_for_air_quality_coupling .and. flag_for_canopy_option)
[cldfra]
standard_name = instantaneous_3d_cloud_fraction
long_name = instantaneous 3D cloud fraction for all MPs
diff --git a/ccpp/physics b/ccpp/physics
index fa51a5610..9e709790d 160000
--- a/ccpp/physics
+++ b/ccpp/physics
@@ -1 +1 @@
-Subproject commit fa51a56100cb49dc39796090ae4dedb63a9e4800
+Subproject commit 9e709790d12301e697634e55af25224708b54a80
diff --git a/ccpp/suites/suite_FV3_GFS_v16.xml b/ccpp/suites/suite_FV3_GFS_v16.xml
index 5fba28575..a53926d86 100644
--- a/ccpp/suites/suite_FV3_GFS_v16.xml
+++ b/ccpp/suites/suite_FV3_GFS_v16.xml
@@ -57,6 +57,7 @@
GFS_surface_generic_post
GFS_PBL_generic_pre
satmedmfvdifq
+ canopy_driver
GFS_PBL_generic_post
GFS_GWD_generic_pre
cires_ugwp
diff --git a/ccpp/suites/suite_FV3_GFS_v17_p8.xml b/ccpp/suites/suite_FV3_GFS_v17_p8.xml
index 05b9c520b..473c69116 100644
--- a/ccpp/suites/suite_FV3_GFS_v17_p8.xml
+++ b/ccpp/suites/suite_FV3_GFS_v17_p8.xml
@@ -53,6 +53,7 @@
GFS_surface_generic_post
GFS_PBL_generic_pre
satmedmfvdifq
+ canopy_driver
GFS_PBL_generic_post
GFS_GWD_generic_pre
unified_ugwp